movewin 1.3 → 1.4
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/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
|