windowstate 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Phil Stewart
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
+ IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ windowstate
2
+ ===========
3
+
4
+ Windowstate is a utility for saving and restoring the sizes and positions of
5
+ application windows on Microsoft Windows systems.
6
+
7
+ Why?
8
+ ----
9
+
10
+ Windows 7 (and probably Vista) have a tendancy to mess up window positions and
11
+ sizes in certain circumstances, such as when disconnecting and reconnecting
12
+ the primary display. The usual symptom is that once the display is reconnected
13
+ all of the application windows have been shrunk and repositioned to the top-left
14
+ corner of the screen. This can be particularly irritating if you have a large
15
+ number of carefully sized and positioned windows open. So far as I can tell
16
+ there is no universal solution to this problem, so I wrote this program as a
17
+ workaround.
18
+
19
+ Installation
20
+ ------------
21
+
22
+ If you have a RubyInstaller for Windows installation, then you can install
23
+ the gem from a command prompt in the usual way:
24
+
25
+ ```
26
+ gem install windowstate
27
+ ```
28
+
29
+ Alternatively, you can download the standalone executable from github on
30
+
31
+ https://github.com/downloads/LichP/windowstate/windowstate.exe
32
+
33
+ Usage
34
+ -----
35
+
36
+ Windowstate is a command line application, so you will need to run it from the
37
+ command prompt. To save the current window states:
38
+
39
+ ```
40
+ windowstate save
41
+ ```
42
+
43
+ It is recommended you do this immediately before causing a display disconnect.
44
+ Once your display is reconnected, to restore the previously saved window
45
+ state:
46
+
47
+ ```
48
+ windowstate restore
49
+ ```
50
+
51
+ The saved state is stored as JSON in a file called `windowstate.json`, which is
52
+ save in your user local temp directory by default. You can override this with
53
+ the `--file` option - see `windowstate --help` for details.
54
+
55
+ Does it Work?
56
+ -------------
57
+
58
+ Windowstate has not been extensively tested: it works on my system with my
59
+ typical window set, but it might not catch some legitimate application
60
+ windows, and has not been tested in a multi-display environment. If you
61
+ run in to problems, please let me know and/or open an issue on Github.
62
+
63
+ Contact and Contributing
64
+ ------------------------
65
+
66
+ The homepage for this project is
67
+
68
+ http://github.com/LichP/windowstate
69
+
70
+ Any feedback, suggestions, etc are very welcome. If you have bugfixes and/or
71
+ contributions, feel free to fork, branch, and send a pull request.
72
+
73
+ Enjoy :-)
74
+
75
+ Phil Stewart, June 2012
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ #require 'erb'
2
+ #require './lib/windowstate/version'
3
+
4
+ #$app_name = 'WindowState'
5
+ $exe_name = 'windowstate'
6
+ #$app_version = ''
7
+
8
+ task :exe do
9
+ sh %{ ocra bin/#{$exe_name}.rb --output #{$exe_name}.exe }
10
+ end
11
+
12
+ #task :installer => :inno_iss_file do
13
+ # sh %{ ocra applaunch.rb app --output #{$app_name}.exe --chdir-first --no-lzma --innosetup #{$app_name}.iss }
14
+ #end
15
+
16
+ #task :inno_iss_file do
17
+ # File.open("#{$app_name}.iss", "w") do |f|
18
+ # f.write(ERB.new(File.read("template.iss.erb")).result(binding))
19
+ # end
20
+ #end
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2012 Phil Stewart
2
+ #
3
+ # License: BSD - see LICENSE file
4
+ # Homepage: https://github.com/LichP/windowstate
5
+
6
+ begin
7
+ require 'windowstate'
8
+ rescue LoadError
9
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
10
+ require 'windowstate'
11
+ end
12
+
13
+ require 'trollop'
14
+ require 'tmpdir'
15
+
16
+ exit if defined?(Ocra)
17
+
18
+ SUB_COMMANDS = %w(save restore debug)
19
+
20
+ global_opts = Trollop::options do
21
+ banner "Save and restore the position and size of application windows"
22
+ banner ""
23
+ banner "Usage:"
24
+ banner ""
25
+ banner " #{File.basename(ENV['OCRA_EXECUTABLE'] || $0)} [GLOBAL OPTIONS] COMMAND [COMMAND OPTIONS]"
26
+ banner ""
27
+ banner "Commands:"
28
+ banner ""
29
+ banner " save Save the state of current application windows"
30
+ banner " restore Restore the state of current application windows from an earlier save"
31
+ banner " debug Generate debugging information"
32
+ banner ""
33
+ banner "Global options:"
34
+ banner ""
35
+
36
+ opt :file, "File to use to save/restore state",
37
+ short: "-f",
38
+ default: File.join(Dir.tmpdir, "windowstate.json")
39
+
40
+ stop_on SUB_COMMANDS
41
+ end
42
+
43
+ cmd = ARGV.shift
44
+
45
+ cmd_opts = case cmd
46
+ when "save"
47
+ Trollop::options do
48
+ opt :stdout, "Write state JSON to stdout instead of to file",
49
+ short: "-c",
50
+ default: false
51
+ end
52
+ when "restore"
53
+ Trollop::options do
54
+ end
55
+ when "debug"
56
+ Trollop::options do
57
+ end
58
+ else
59
+ Trollop::die "unknown subcommand #{cmd.inspect}"
60
+ end
61
+
62
+ case cmd
63
+ when 'save'
64
+ if cmd_opts[:stdout]
65
+ puts WindowState.get_state_json
66
+ else
67
+ WindowState.save(global_opts[:file])
68
+ end
69
+ when 'restore'
70
+ WindowState.restore(global_opts[:file])
71
+ when 'debug'
72
+ debug_data = WindowState.debug
73
+ debug_data.each do |hash|
74
+ hash.each_pair do |key, value|
75
+ puts "%s: %s" % [key.to_s, value.inspect]
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,201 @@
1
+ # encoding: iso-8859-1
2
+ #
3
+ # Copyright (c) 2012 Phil Stewart
4
+ #
5
+ # License: BSD - see LICENSE file
6
+ # Homepage: https://github.com/Lichp/windowstate
7
+
8
+ require 'json'
9
+ require 'windows/window'
10
+
11
+ module Windows
12
+ module Window
13
+ API.new('SetWindowPlacement', 'LP', 'B', 'user32')
14
+ end
15
+ end
16
+
17
+ module WindowState
18
+ include Windows::Window
19
+ include Win32
20
+
21
+ class WindowPlacement
22
+ include Windows::Window
23
+
24
+ attr_reader :handle, :data_encoded, :title
25
+ attr_writer :title
26
+
27
+ def self.get(handle)
28
+ wp = new(handle)
29
+ wp.get
30
+ wp
31
+ end
32
+
33
+ def self.json_create(o)
34
+ wp = new(o['data'][0])
35
+ wp.title = o['data'][1]
36
+ wp.data = o['data'][2]
37
+ wp
38
+ end
39
+
40
+ def initialize(handle)
41
+ @handle = handle
42
+ end
43
+
44
+ def get
45
+ wp_buffer = [44].pack("L") + '\0' * 40
46
+ title_buffer = "\0" * 200
47
+
48
+ GetWindowPlacement(handle, wp_buffer)
49
+ @data_encoded = wp_buffer
50
+
51
+ GetWindowText(handle, title_buffer, 200)
52
+ @title = title_buffer.strip
53
+ end
54
+
55
+ def set
56
+ SetWindowPlacement(handle, data_encoded)
57
+ end
58
+
59
+ def data
60
+ data_encoded.unpack("L11")
61
+ end
62
+
63
+ def data=(array)
64
+ @data_encoded = array.pack("L11")
65
+ end
66
+
67
+ def to_json(*a)
68
+ {
69
+ 'json_class' => self.class.name,
70
+ 'data' => [handle, title, data]
71
+ }.to_json(*a)
72
+ end
73
+
74
+ def inspect
75
+ "#<WindowState::WindowPlacement:0x%08x @handle=%i, @title=\"%s\", data=%s>" % [object_id, handle, title, data]
76
+ end
77
+ end
78
+
79
+ class WindowInfo
80
+ include Windows::Window
81
+
82
+ WS_CAPTION = 0x00C00000
83
+ WS_CHILD = 0x40000000
84
+ WS_CLIPSIBLINGS = 0x04000000
85
+ WS_DISABLED = 0x08000000
86
+ WS_DLGFRAME = 0x00400000
87
+ WS_POPUP = 0x80000000
88
+ WS_SIZEBOX = 0x00040000
89
+ WS_SYSMENU = 0x00080000
90
+ WS_VISIBLE = 0x10000000
91
+
92
+ attr_reader :data_encoded, :handle
93
+
94
+ def self.get(handle)
95
+ wp = new(handle)
96
+ wp.get
97
+ wp
98
+ end
99
+
100
+ def initialize(handle)
101
+ @handle = handle
102
+ end
103
+
104
+ def get
105
+ buffer = [60].pack("L") + '\0' * 56
106
+ GetWindowInfo(handle, buffer)
107
+ @data_encoded = buffer
108
+ end
109
+
110
+ def data
111
+ data_encoded.unpack("L14S2")
112
+ end
113
+
114
+ def style
115
+ data[9]
116
+ end
117
+
118
+ def ignorable?
119
+ style & (WS_DISABLED | WS_CHILD) > 0
120
+ end
121
+
122
+ def application_window?
123
+ mask = (WS_SYSMENU | WS_VISIBLE)
124
+ (style & mask == mask) && !ignorable?
125
+ end
126
+
127
+ def data=(array)
128
+ @data_encoded = array.pack("L14S2")
129
+ end
130
+
131
+ def to_json(*a)
132
+ {
133
+ 'json_class' => self.class.name,
134
+ 'data' => [handle, data]
135
+ }.to_json(*a)
136
+ end
137
+
138
+ def inspect
139
+ "#<WindowState::WindowInfo:0x%08x @handle=%i, data=%s>" % [object_id, handle, data]
140
+ end
141
+ end
142
+
143
+ @wp_save = []
144
+ @debug = []
145
+
146
+ @save_proc = API::Callback.new('LP', 'I') do |handle, param|
147
+ wp = WindowPlacement.get(handle)
148
+ wi = WindowInfo.get(handle)
149
+
150
+ if wi.application_window?
151
+ @wp_save << wp
152
+ end
153
+ true
154
+ end
155
+
156
+ @debug_proc = API::Callback.new('LP', 'I') do |handle, param|
157
+ wp = WindowPlacement.get(handle)
158
+ wi = WindowInfo.get(handle)
159
+
160
+ @debug << {:wp => wp, :wi => wi}
161
+ true
162
+ end
163
+
164
+ class << self
165
+ include Windows::Window
166
+ include Win32
167
+
168
+ def get_state
169
+ EnumWindows(@save_proc, nil)
170
+ end
171
+
172
+ def get_state_json
173
+ get_state
174
+ JSON.generate(@wp_save, object_nl: "\n")
175
+ end
176
+
177
+ def set_state(wp_array)
178
+ wp_array.each { |wp| wp.set }
179
+ end
180
+
181
+ def set_state_json(wp_json)
182
+ set_state(JSON.parse(wp_json))
183
+ end
184
+
185
+ def save(filename)
186
+ File.open(filename, "w") do |dump_file|
187
+ dump_file.puts get_state_json
188
+ end
189
+ end
190
+
191
+ def restore(filename)
192
+ set_state_json(File.read(filename))
193
+ end
194
+
195
+ def debug
196
+ EnumWindows(@debug_proc, nil)
197
+ @debug
198
+ end
199
+ end
200
+ end
201
+
@@ -0,0 +1,3 @@
1
+ module WindowState
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: windowstate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Phil Stewart
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-10 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: windows-pr
16
+ requirement: &27383856 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.2'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *27383856
25
+ - !ruby/object:Gem::Dependency
26
+ name: trollop
27
+ requirement: &27383556 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *27383556
36
+ - !ruby/object:Gem::Dependency
37
+ name: ocra
38
+ requirement: &27383280 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '1.3'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *27383280
47
+ description: ! "WindowState is a utility for saving and restoring the\n positions
48
+ and sizes of your application windows, which is useful for\n monitor hotplugging
49
+ when Windows decides to shrink everything and\n shove it in the top-left corner
50
+ of your desktop."
51
+ email:
52
+ - phil.stewart@lichp.co.uk
53
+ executables:
54
+ - windowstate.rb
55
+ extensions: []
56
+ extra_rdoc_files: []
57
+ files:
58
+ - lib/windowstate/version.rb
59
+ - lib/windowstate.rb
60
+ - README.md
61
+ - LICENSE
62
+ - Rakefile
63
+ - bin/windowstate.rb
64
+ homepage: http://github.com/lichp/windowstate
65
+ licenses: []
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 1.7.2
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Save and restore window positions and sizes on MS Windows
88
+ test_files: []