movewin 1.3 → 1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/movewin/movewin_ext.c +26 -19
- data/ext/movewin/winutils.c +44 -25
- data/ext/movewin/winutils.h +1 -1
- data/lib/movewin.rb +1 -1
- metadata +21 -9
- checksums.yaml +0 -7
data/ext/movewin/movewin_ext.c
CHANGED
@@ -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
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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() */
|
data/ext/movewin/winutils.c
CHANGED
@@ -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
|
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
|
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
|
-
/*
|
199
|
-
|
200
|
-
appWindow,
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
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
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
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);
|
data/ext/movewin/winutils.h
CHANGED
@@ -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
|
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
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: movewin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
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-
|
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
|
-
-
|
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
|
-
-
|
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:
|
63
|
+
rubygems_version: 1.8.7
|
52
64
|
signing_key:
|
53
|
-
specification_version:
|
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
|