movewin 1.3 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -47,6 +47,7 @@ void Init_movewin_ext();
47
47
  VALUE MW_is_authorized(VALUE module); /* MoveWin.authorized? */
48
48
  VALUE MW_display_size(VALUE module); /* MoveWin.display_size */
49
49
  VALUE MW_windows(VALUE module); /* MoveWin.windows */
50
+ VALUE MW_Window_id(VALUE self); /* MoveWin::Window.id */
50
51
  VALUE MW_Window_app_name(VALUE self); /* MoveWin::Window.app_name */
51
52
  VALUE MW_Window_title(VALUE self); /* MoveWin::Window.title */
52
53
  VALUE MW_Window_position(VALUE self); /* MoveWin::Window.position */
@@ -91,6 +92,7 @@ void Init_movewin_ext() {
91
92
 
92
93
  /* Define class MoveWin::Window and its methods */
93
94
  MW_WindowClass = rb_define_class_under(MW_Module, "Window", rb_cObject);
95
+ rb_define_method(MW_WindowClass, "id", MW_Window_id, 0);
94
96
  rb_define_method(MW_WindowClass, "app_name", MW_Window_app_name, 0);
95
97
  rb_define_method(MW_WindowClass, "title", MW_Window_title, 0);
96
98
  rb_define_method(MW_WindowClass, "position", MW_Window_position, 0);
@@ -127,6 +129,19 @@ VALUE MW_windows(VALUE module) {
127
129
  return retval;
128
130
  }
129
131
 
132
+ /* Return window ID a MoveWin::Window as an integer (nil for unknown) */
133
+ VALUE MW_Window_id(VALUE self) {
134
+ void *mwWindow;
135
+ int windowId;
136
+
137
+ Data_Get_Struct(self, MW_Window, mwWindow);
138
+ windowId = CFDictionaryGetInt(
139
+ ((MW_Window *)mwWindow)->cgWindow, kCGWindowNumber
140
+ );
141
+
142
+ return INT2NUM(windowId);
143
+ }
144
+
130
145
  /* Return application name (owner) of a MoveWin::Window as a Ruby string */
131
146
  VALUE MW_Window_app_name(VALUE self) {
132
147
  void *mwWindow;
@@ -244,28 +259,20 @@ VALUE MW_Window_to_string(VALUE self) {
244
259
 
245
260
  /* Given window CFDictionaryRef and Ruby array, push MW_Window to array */
246
261
  void StoreWindows(CFDictionaryRef cgWindow, void *rb_ary_ptr) {
247
- int i;
248
262
  AXUIElementRef axWindow;
249
263
  MW_Window *mwWindow;
250
264
  VALUE wrappedMwWindow;
251
- VALUE mwWindows;
252
-
253
- mwWindows = (VALUE)rb_ary_ptr;
254
-
255
- i = 0;
256
- while(1) {
257
- axWindow = AXWindowFromCGWindow(cgWindow, i);
258
- if(!axWindow) break;
259
- mwWindow = (MW_Window *)malloc(sizeof(MW_Window));
260
- mwWindow->cgWindow =
261
- CFDictionaryCreateCopy(kCFAllocatorDefault, cgWindow);
262
- mwWindow->axWindow = axWindow;
263
- wrappedMwWindow = Data_Wrap_Struct(
264
- MW_WindowClass, NULL, MW_Window_destroy, (void *)mwWindow
265
- );
266
- rb_ary_push(mwWindows, wrappedMwWindow);
267
- i++;
268
- }
265
+ VALUE mwWindows = (VALUE)rb_ary_ptr;
266
+
267
+ axWindow = AXWindowFromCGWindow(cgWindow);
268
+ mwWindow = (MW_Window *)malloc(sizeof(MW_Window));
269
+ mwWindow->cgWindow =
270
+ CFDictionaryCreateCopy(kCFAllocatorDefault, cgWindow);
271
+ mwWindow->axWindow = axWindow;
272
+ wrappedMwWindow = Data_Wrap_Struct(
273
+ MW_WindowClass, NULL, MW_Window_destroy, (void *)mwWindow
274
+ );
275
+ rb_ary_push(mwWindows, wrappedMwWindow);
269
276
  }
270
277
 
271
278
  /* Free up MW_Window resources, for Ruby finalizer in Data_Wrap_Struct() */
@@ -37,6 +37,12 @@
37
37
  #include <fnmatch.h>
38
38
  #include "winutils.h"
39
39
 
40
+ /* Undocumented accessibility API to get window ID:
41
+ * http://stackoverflow.com/a/10134254
42
+ * https://github.com/jmgao/metamove/blob/master/src/window.mm
43
+ */
44
+ extern AXError _AXUIElementGetWindow(AXUIElementRef, CGWindowID *out);
45
+
40
46
  /* Search windows for match (NULL for all), run function (NULL for none) */
41
47
  int EnumerateWindows(
42
48
  char *pattern,
@@ -165,17 +171,22 @@ bool isAuthorized() {
165
171
  #endif
166
172
  }
167
173
 
174
+ /* Silence warning that address of _AXUIElementGetWindow is always true */
175
+ #pragma GCC diagnostic ignored "-Waddress"
176
+
168
177
  /* Given window dictionary from CGWindowList, return accessibility object */
169
- AXUIElementRef AXWindowFromCGWindow(CFDictionaryRef window, int minIdx) {
178
+ AXUIElementRef AXWindowFromCGWindow(CFDictionaryRef window) {
179
+ CGWindowID targetWindowId, actualWindowId;
170
180
  CFStringRef targetWindowName, actualWindowTitle;
171
181
  CGPoint targetPosition, actualPosition;
172
182
  CGSize targetSize, actualSize;
173
183
  pid_t pid;
174
184
  AXUIElementRef app, appWindow, foundAppWindow;
185
+ int i;
175
186
  CFArrayRef appWindowList;
176
- int matchIdx, i;
177
187
 
178
- /* Save the window name, position, and size we are looking for */
188
+ /* Save the window ID, name, position, and size we are looking for */
189
+ targetWindowId = CFDictionaryGetInt(window, kCGWindowNumber);
179
190
  targetWindowName = CFDictionaryGetValue(window, kCGWindowName);
180
191
  targetPosition = CGWindowGetPosition(window);
181
192
  targetSize = CGWindowGetSize(window);
@@ -187,37 +198,45 @@ AXUIElementRef AXWindowFromCGWindow(CFDictionaryRef window, int minIdx) {
187
198
  app, kAXWindowsAttribute, (CFTypeRef *)&appWindowList
188
199
  );
189
200
 
190
- /* Search application windows for first matching title, position, size:
191
- * http://stackoverflow.com/questions/6178860/getting-window-number-through-osx-accessibility-api
192
- */
193
- matchIdx = 0;
201
+ /* Search application windows to find a match */
194
202
  foundAppWindow = NULL;
195
203
  for(i = 0; i < CFArrayGetCount(appWindowList); i++) {
196
204
  appWindow = CFArrayGetValueAtIndex(appWindowList, i);
197
205
 
198
- /* Window name must match */
199
- AXUIElementCopyAttributeValue(
200
- appWindow, kAXTitleAttribute, (CFTypeRef *)&actualWindowTitle
201
- );
202
- if( !actualWindowTitle ||
203
- CFStringCompare(targetWindowName, actualWindowTitle, 0) != 0)
204
- {
205
- continue;
206
- }
206
+ /* If possible, extract the window ID and match window by ID */
207
+ if(_AXUIElementGetWindow) {
208
+ _AXUIElementGetWindow(appWindow, &actualWindowId);
209
+ if(actualWindowId == targetWindowId) {
210
+ foundAppWindow = appWindow;
211
+ break;
212
+ } else {
213
+ continue;
214
+ }
215
+
216
+ /* Otherwise, search for first matching title, position, size:
217
+ * http://stackoverflow.com/questions/6178860/getting-window-number-through-osx-accessibility-api
218
+ */
219
+ } else {
207
220
 
208
- /* Position and size must match */
209
- actualPosition = AXWindowGetPosition(appWindow);
210
- if(!CGPointEqualToPoint(targetPosition, actualPosition)) continue;
211
- actualSize = AXWindowGetSize(appWindow);
212
- if(!CGSizeEqualToSize(targetSize, actualSize)) continue;
221
+ /* Window name must match */
222
+ AXUIElementCopyAttributeValue(
223
+ appWindow, kAXTitleAttribute, (CFTypeRef *)&actualWindowTitle
224
+ );
225
+ if( !actualWindowTitle ||
226
+ CFStringCompare(targetWindowName, actualWindowTitle, 0) != 0)
227
+ {
228
+ continue;
229
+ }
230
+
231
+ /* Position and size must match */
232
+ actualPosition = AXWindowGetPosition(appWindow);
233
+ if(!CGPointEqualToPoint(targetPosition, actualPosition)) continue;
234
+ actualSize = AXWindowGetSize(appWindow);
235
+ if(!CGSizeEqualToSize(targetSize, actualSize)) continue;
213
236
 
214
- /* Multiple windows may match, caller chooses which match to return */
215
- if(matchIdx >= minIdx) {
216
237
  /* Found the first matching window, save it and break */
217
238
  foundAppWindow = appWindow;
218
239
  break;
219
- } else {
220
- matchIdx++;
221
240
  }
222
241
  }
223
242
  CFRelease(app);
@@ -64,7 +64,7 @@ CGSize CGWindowGetSize(CFDictionaryRef window);
64
64
  bool isAuthorized();
65
65
 
66
66
  /* Given window dictionary from CGWindowList, return accessibility object */
67
- AXUIElementRef AXWindowFromCGWindow(CFDictionaryRef window, int minIdx);
67
+ AXUIElementRef AXWindowFromCGWindow(CFDictionaryRef window);
68
68
 
69
69
  /* Get a value from an accessibility object */
70
70
  void AXWindowGetValue(
data/lib/movewin.rb CHANGED
@@ -36,7 +36,7 @@
36
36
  require 'movewin/movewin_ext'
37
37
 
38
38
  module MoveWin
39
- VERSION = '1.3'
39
+ VERSION = '1.4'
40
40
 
41
41
  # Individual accessors for display size components
42
42
  def self.display_width; MoveWin.display_size[0]; end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: movewin
3
3
  version: !ruby/object:Gem::Version
4
- version: "1.3"
4
+ hash: 7
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 4
9
+ version: "1.4"
5
10
  platform: ruby
6
11
  authors:
7
12
  - Andrew Ho
@@ -9,7 +14,7 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2014-09-08 00:00:00 Z
17
+ date: 2014-10-30 00:00:00 Z
13
18
  dependencies: []
14
19
 
15
20
  description: List and move OS X windows from Ruby via the OS X accessibility APIs.
@@ -29,28 +34,35 @@ files:
29
34
  homepage: https://github.com/andrewgho/movewin-ruby
30
35
  licenses:
31
36
  - BSD-3-Clause
32
- metadata: {}
33
-
34
37
  post_install_message:
35
38
  rdoc_options: []
36
39
 
37
40
  require_paths:
38
41
  - lib
39
42
  required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
40
44
  requirements:
41
- - &id001
42
- - ">="
45
+ - - ">="
43
46
  - !ruby/object:Gem::Version
47
+ hash: 3
48
+ segments:
49
+ - 0
44
50
  version: "0"
45
51
  required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
46
53
  requirements:
47
- - *id001
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
48
60
  requirements: []
49
61
 
50
62
  rubyforge_project:
51
- rubygems_version: 2.0.5
63
+ rubygems_version: 1.8.7
52
64
  signing_key:
53
- specification_version: 4
65
+ specification_version: 3
54
66
  summary: List and move OS X windows from Ruby
55
67
  test_files: []
56
68
 
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 186d90a92e2cba238cb35a3dd4c0ca998ae39c32
4
- data.tar.gz: dbbebd61d13940f5e749697f81c0b121b9a57e5f
5
- SHA512:
6
- metadata.gz: 07394cd3f53cb282b2a606a46fc9802c5e773422f69a15b722cdf41aeea9e780ebb9d427e4ec95a1b22cf5feeb6cd582f6419a6ff39a8cf53ffbbc8868747ecd
7
- data.tar.gz: 0cd496ec1c9c9d462db9c483d7908f04fc5a4313fe55cfa6dbd7cfe705e660345c40e2de79261c8cf81963d98551439af189828ddcf905f379279ef468742175