imitator_x 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/COPYING.LESSER.rdoc +169 -0
- data/COPYING.rdoc +678 -0
- data/README.rdoc +70 -0
- data/Rakefile.rb +99 -0
- data/TODO.rdoc +8 -0
- data/ext/clipboard.c +429 -0
- data/ext/clipboard.h +61 -0
- data/ext/extconf.rb +55 -0
- data/ext/keyboard.c +711 -0
- data/ext/keyboard.h +29 -0
- data/ext/mouse.c +456 -0
- data/ext/mouse.h +28 -0
- data/ext/x.c +84 -0
- data/ext/x.h +48 -0
- data/ext/xwindow.c +1434 -0
- data/ext/xwindow.h +38 -0
- data/lib/imitator/x/drive.rb +179 -0
- data/lib/imitator/x.rb +29 -0
- data/lib/imitator_x_special_chars.yml +179 -0
- data/test/test_clipboard.rb +46 -0
- data/test/test_keyboard.rb +117 -0
- data/test/test_mouse.rb +40 -0
- data/test/test_xdrive.rb +47 -0
- data/test/test_xwindow.rb +106 -0
- metadata +123 -0
data/ext/xwindow.c
ADDED
@@ -0,0 +1,1434 @@
|
|
1
|
+
/*********************************************************************************
|
2
|
+
Imitator for X is a library allowing you to fake input to systems using X11.
|
3
|
+
Copyright � 2010 Marvin G�lker
|
4
|
+
|
5
|
+
This file is part of Imitator for X.
|
6
|
+
|
7
|
+
Imitator for X is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Imitator for X is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Lesser General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Lesser General Public License
|
18
|
+
along with Imitator for X. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
*********************************************************************************/
|
20
|
+
#include "x.h"
|
21
|
+
#include "xwindow.h"
|
22
|
+
#include "keyboard.h"
|
23
|
+
|
24
|
+
/*Always remember: The Window type is just a long containing the window handle.*/
|
25
|
+
/*Heavy use of the GET_WINDOW macro is made here*/
|
26
|
+
|
27
|
+
/*Document-class: Imitator::X::XWindow
|
28
|
+
*This class allows interaction with the windows of an X server. There are some important terms
|
29
|
+
*that have to be made clear:
|
30
|
+
*[window] This means a window on the X server.
|
31
|
+
*[screen] Each window resides on a screen. A screen is a physical monitor. Numbering starts with 0.
|
32
|
+
*[display] A display is a collection of screens. If you have for example 4 monitors connected, you get 4 screens on 1 display. Numbering starts with 0.
|
33
|
+
*[display_string] This is a string describing a screen on a display, of form <tt>":display.screen"</tt> (yes, it starts with a colon).
|
34
|
+
*[root window] Every display has a root window, which is the parent of all windows visible on that screen (including the desktop window).
|
35
|
+
*
|
36
|
+
*Every method in this class will raise XProtocolErrors if you try to operate on non-existant windows, e.g. trying to
|
37
|
+
*retrieve a killed window's position.
|
38
|
+
*
|
39
|
+
*All methods of this class that return strings return them encoded in UTF-8. However, it's assumed that your
|
40
|
+
*X Server's locale is ISO-8859-1 (that's Latin-1), since I couldn't figure out how to query X for that information.
|
41
|
+
*Change the value of XSTR_TO_RSTR (in xwindow.h) to your X Server's locale, than recompile this library if
|
42
|
+
*it's incorrect. If you know how to obtain X's locale, please tell me at sutniuq$gmx:net. A patch would be nice, too.
|
43
|
+
*
|
44
|
+
*The methods covering EWMH standard may be not available on every system. If such a method is called on a
|
45
|
+
*system that doesn't support that part of EWMH or doesn't support EWMH at all, a NotImplementedError is raised.
|
46
|
+
*The corresponding EWMH standard of a method is mentioned in it's _Remarks_ section.
|
47
|
+
*/
|
48
|
+
|
49
|
+
/*******************Helper functions**************************/
|
50
|
+
|
51
|
+
/*
|
52
|
+
*This function retrieves the display of the calling
|
53
|
+
*window. It's just shorthand for the two lines included in it.
|
54
|
+
*/
|
55
|
+
static Display * get_win_display(VALUE self)
|
56
|
+
{
|
57
|
+
Display * p_display;
|
58
|
+
VALUE rstr;
|
59
|
+
|
60
|
+
rstr = rb_ivar_get(self, rb_intern("@display_string"));
|
61
|
+
p_display = XOpenDisplay(StringValuePtr(rstr));
|
62
|
+
return p_display;
|
63
|
+
}
|
64
|
+
|
65
|
+
/*
|
66
|
+
*This function checks whather the specified EWMH standard is supported
|
67
|
+
*by the system's window manager. If not, it raises a NotImplementedError
|
68
|
+
*exception.
|
69
|
+
*/
|
70
|
+
static void check_for_ewmh(Display * p_display, const char * ewmh)
|
71
|
+
{
|
72
|
+
Window root = XRootWindow(p_display, 0);
|
73
|
+
Atom atom, actual_type, support_atom;
|
74
|
+
int actual_format;
|
75
|
+
unsigned long nitems, bytes;
|
76
|
+
unsigned char * props;
|
77
|
+
Atom * props2;
|
78
|
+
int ret, i, result = 0;
|
79
|
+
/*We don't use actual_type, actual_format and bytes. */
|
80
|
+
|
81
|
+
/*To check wheather any EWMH is supported*/
|
82
|
+
atom = XInternAtom(p_display, "_NET_SUPPORTED", False);
|
83
|
+
/*To check if the specified EWMH is supported*/
|
84
|
+
support_atom = XInternAtom(p_display, ewmh, False);
|
85
|
+
|
86
|
+
/*GetWindowProperty(_NET_SUPPORTED) gives us an array of supported EWMH standards
|
87
|
+
*or fails if no EWMH is supported.
|
88
|
+
*Many great thanks to Jordan Sissel whose xdotool code
|
89
|
+
*showed me how this function works. */
|
90
|
+
ret = XGetWindowProperty(p_display, root, atom, 0, (~0L), False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes, &props);
|
91
|
+
if (ret != Success)
|
92
|
+
{
|
93
|
+
XSetErrorHandler(NULL); /*Ensure the connection...*/
|
94
|
+
XCloseDisplay(p_display); /*...is properly closed. */
|
95
|
+
rb_raise(rb_eNotImpError, "EWMH is not supported by this window manager!");
|
96
|
+
}
|
97
|
+
|
98
|
+
/*Cast props to an Atom array, otherwise we get BadAtom errors. */
|
99
|
+
props2 = (Atom *) props;
|
100
|
+
for(i = 0L; ((i < nitems) && (result == 0)); i++)
|
101
|
+
{
|
102
|
+
if(props2[i] == support_atom)
|
103
|
+
result = 1; /*Found the atom.*/
|
104
|
+
}
|
105
|
+
XFree(props);
|
106
|
+
|
107
|
+
if (result == 0)
|
108
|
+
{
|
109
|
+
XSetErrorHandler(NULL);
|
110
|
+
XCloseDisplay(p_display);
|
111
|
+
rb_raise(rb_eNotImpError, "EWMH '%s' is not supported by this window manager!", ewmh);
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
/*************************Class methods***********************************/
|
116
|
+
|
117
|
+
/*
|
118
|
+
*call-seq:
|
119
|
+
* XWindow.xquery(display_string, window_id) ==> true
|
120
|
+
*
|
121
|
+
*<b>Don't call this method, it's used internally. </b>
|
122
|
+
*
|
123
|
+
*Raises a XProtocolError if the specified window doesn't exist on the specified +display_string+.
|
124
|
+
*/
|
125
|
+
static VALUE cm_xquery(VALUE self, VALUE display_string, VALUE window_id)
|
126
|
+
{
|
127
|
+
Display * p_display = XOpenDisplay(StringValuePtr(display_string));
|
128
|
+
Window win = (Window)NUM2LONG(window_id);
|
129
|
+
Window dummy, dummy2, *children = NULL;
|
130
|
+
unsigned int child_num;
|
131
|
+
|
132
|
+
XSetErrorHandler(handle_x_errors); /*Let Ruby handle the errors*/
|
133
|
+
XQueryTree(p_display, win, &dummy, &dummy2, &children, &child_num);
|
134
|
+
|
135
|
+
XSetErrorHandler(NULL); /*Let X handle the errors again*/
|
136
|
+
|
137
|
+
XFree(children);
|
138
|
+
XCloseDisplay(p_display);
|
139
|
+
return Qtrue;
|
140
|
+
}
|
141
|
+
|
142
|
+
/*
|
143
|
+
*call-seq:
|
144
|
+
* XWindow.default_root_window() ==> aXWindow
|
145
|
+
*
|
146
|
+
*Returns the default root window of the default screen.
|
147
|
+
*===Return value
|
148
|
+
*The default root window of the default screen as an XWindow object.
|
149
|
+
*===Example
|
150
|
+
* puts Imitator::X::XWindow.default_root_window.title #=> (null)
|
151
|
+
*/
|
152
|
+
static VALUE cm_default_root_window(VALUE self)
|
153
|
+
{
|
154
|
+
Display * p_display = XOpenDisplay(NULL);
|
155
|
+
Window root_win;
|
156
|
+
VALUE args[1];
|
157
|
+
|
158
|
+
root_win = XDefaultRootWindow(p_display);
|
159
|
+
args[0] = LONG2NUM(root_win);
|
160
|
+
|
161
|
+
XCloseDisplay(p_display);
|
162
|
+
return rb_class_new_instance(1, args, XWindow);
|
163
|
+
}
|
164
|
+
|
165
|
+
/*
|
166
|
+
*call-seq:
|
167
|
+
* XWindow.exists?(window_id, screen = 0, display = 0) ==> true or false
|
168
|
+
*
|
169
|
+
*Checks if the given window ID exists on the given display and screen.
|
170
|
+
*===Parameters
|
171
|
+
*[+window_id+] The window ID to check.
|
172
|
+
*[+screen+] (0) The screen to check.
|
173
|
+
*[+display+] (0) The display to check.
|
174
|
+
*===Return value
|
175
|
+
*true or false.
|
176
|
+
*===Example
|
177
|
+
* root_win = Imitator::X::XWindow.default_root_window
|
178
|
+
* puts Imitator::X::XWindow.exists?(root_win.window_id) #=> true
|
179
|
+
* puts Imitator::X::XWindow.exists?(12345) #=> false
|
180
|
+
*===Remarks
|
181
|
+
*This method rescues a XProtocolError exception you'll see when running
|
182
|
+
*under $DEBUG and get a +false+ result.
|
183
|
+
*/
|
184
|
+
static VALUE cm_exists(int argc, VALUE argv[], VALUE self)
|
185
|
+
{
|
186
|
+
VALUE window_id;
|
187
|
+
VALUE screen;
|
188
|
+
VALUE display;
|
189
|
+
VALUE result;
|
190
|
+
char display_string[100];
|
191
|
+
char eval_str[1000];
|
192
|
+
|
193
|
+
rb_scan_args(argc, argv, "12", &window_id, &screen, &display);
|
194
|
+
|
195
|
+
/*Assign the display or default to 0*/
|
196
|
+
if (NIL_P(display))
|
197
|
+
display = INT2FIX(0);
|
198
|
+
/*Assign the screen or default to 0*/
|
199
|
+
if (NIL_P(screen))
|
200
|
+
screen = INT2FIX(0);
|
201
|
+
|
202
|
+
/*Get the display string, form ":display.screen"*/
|
203
|
+
sprintf(display_string, ":%i.%i", FIX2INT(display), FIX2INT(screen));
|
204
|
+
/*
|
205
|
+
*eval is awful. rb_rescue too. I evaluate this string due to rb_rescue's inusability.
|
206
|
+
*This eval is quite safe, because before I put the two parts together in display_string, I convert
|
207
|
+
*screen and display into integers.
|
208
|
+
*/
|
209
|
+
sprintf(eval_str, "begin; Imitator::X::XWindow.xquery('%s', %i);true;rescue Imitator::X::XProtocolError;false;end", display_string, NUM2INT(window_id));
|
210
|
+
result = rb_eval_string(eval_str);
|
211
|
+
|
212
|
+
return result;
|
213
|
+
}
|
214
|
+
|
215
|
+
/*
|
216
|
+
*call-seq:
|
217
|
+
* XWindow.search(str , screen = 0 , display = 0) ==> anArray
|
218
|
+
* XWindow.search(regexp , screen = 0 , display = 0 ) ==> anArray
|
219
|
+
*
|
220
|
+
*Searches for a special window title.
|
221
|
+
*===Parameters
|
222
|
+
*[+str+] The title to look for. This will only match *exactly*.
|
223
|
+
*[+regexp+] The title to look for, as a Regular Expression to match.
|
224
|
+
*[+screen+] (0) The screen to look for the window.
|
225
|
+
*[+display+] (0) The display to look for the screen.
|
226
|
+
*===Return value
|
227
|
+
*An array containing the window IDs of all windows whose titles matched the string
|
228
|
+
*or Regular Expression. This may be empty if nothing matches.
|
229
|
+
*===Example
|
230
|
+
* #Search for a window whose name is exactly "x-nautilus-desktop"
|
231
|
+
* Imitator::X::XWindow.search("x-nautilus-desktop") #=> [33554464]
|
232
|
+
* #Search for a window whose name contains the string "imitator".
|
233
|
+
* Imitator::X::XWindow.search(/imitator/) #=> [...]
|
234
|
+
* #If a window isn't found, you get an empty array.
|
235
|
+
* Imitator::X::XWindow.search("nonexistant") #=> []
|
236
|
+
*===Remarks
|
237
|
+
*This method just searches the first children layer, i.e. the child windows of the root window.
|
238
|
+
*You can't find windows in windows with this method.
|
239
|
+
*/
|
240
|
+
static VALUE cm_search(int argc, VALUE argv[], VALUE self) /*title as string or regexp*/
|
241
|
+
{
|
242
|
+
VALUE title, screen, display;
|
243
|
+
char display_string[100];
|
244
|
+
Display * p_display;
|
245
|
+
Window root_win, parent_win, temp_win;
|
246
|
+
Window * p_children;
|
247
|
+
unsigned int num_children;
|
248
|
+
XTextProperty xtext;
|
249
|
+
char * p_title;
|
250
|
+
int i;
|
251
|
+
short is_regexp;
|
252
|
+
VALUE result = rb_ary_new();
|
253
|
+
|
254
|
+
rb_scan_args(argc, argv, "12", &title, &screen, &display);
|
255
|
+
/*Check wheather we're operating on a Regular Expression or a String. Strings mean exact matching later on. */
|
256
|
+
if (TYPE(title) == T_REGEXP)
|
257
|
+
is_regexp = 1;
|
258
|
+
else
|
259
|
+
is_regexp = 0;
|
260
|
+
/*Assign the display or default to 0*/
|
261
|
+
if (NIL_P(display))
|
262
|
+
display = INT2FIX(0);
|
263
|
+
/*Assign the screen or default to 0*/
|
264
|
+
if (NIL_P(screen))
|
265
|
+
screen = INT2FIX(0);
|
266
|
+
/*Get the display string, form ":display.screen"*/
|
267
|
+
sprintf(display_string, ":%i.%i", FIX2INT(display), FIX2INT(screen));
|
268
|
+
|
269
|
+
p_display = XOpenDisplay(display_string);
|
270
|
+
XSetErrorHandler(handle_x_errors); /*Let Ruby handle the errors*/
|
271
|
+
root_win = XDefaultRootWindow(p_display);
|
272
|
+
|
273
|
+
XQueryTree(p_display, root_win, &root_win, &parent_win, &p_children, &num_children);
|
274
|
+
|
275
|
+
if (p_children != NULL) /*This means there are child windows*/
|
276
|
+
{
|
277
|
+
for(i = 0; i < num_children; i++)
|
278
|
+
{
|
279
|
+
temp_win = *(p_children + i);
|
280
|
+
XGetWMName(p_display, temp_win, &xtext); /*We want to match against the title later*/
|
281
|
+
p_title = (char *) malloc(sizeof(char) * (xtext.nitems + 1)); /*Allocate one char more than neccassary, because we get an "invalid pointer" otherwise*/
|
282
|
+
sprintf(p_title, "%s", xtext.value);
|
283
|
+
|
284
|
+
if (is_regexp)
|
285
|
+
{
|
286
|
+
if (!NIL_P(rb_reg_match(title, XSTR_TO_RSTR(p_title)))) /*This performs the regexp match*/
|
287
|
+
rb_ary_push(result, LONG2NUM(temp_win));
|
288
|
+
}
|
289
|
+
else /*Not using a regular expression*/
|
290
|
+
{
|
291
|
+
if (strcmp(StringValuePtr(title), p_title) == 0)
|
292
|
+
rb_ary_push(result, LONG2NUM(temp_win));
|
293
|
+
}
|
294
|
+
XFree(xtext.value);
|
295
|
+
free(p_title);
|
296
|
+
}
|
297
|
+
XFree(p_children);
|
298
|
+
}
|
299
|
+
|
300
|
+
XSetErrorHandler(NULL); /*Let X handle it's errors again*/
|
301
|
+
XCloseDisplay(p_display);
|
302
|
+
return result;
|
303
|
+
}
|
304
|
+
|
305
|
+
/*
|
306
|
+
*call-seq:
|
307
|
+
* XWindow.from_title(str [, screen = 0 [, display = 0 ] ] ) ==> aXWindow
|
308
|
+
* XWindow.from_title(regexp [, screen = 0 [, display = 0 ] ] ) ==> aXWindow
|
309
|
+
*
|
310
|
+
*Creates a new XWindow object by passing on the given parameters to XWindow.search and
|
311
|
+
*using the first found window ID to make the XWindow object.
|
312
|
+
*===Parameters
|
313
|
+
*See the XWindow.search parameter description.
|
314
|
+
*===Return value
|
315
|
+
*The first matching window as a XWindow object.
|
316
|
+
*===Raises
|
317
|
+
*[ArgumentError] No matching window was found.
|
318
|
+
*===Example
|
319
|
+
* #Get the first found window which name includes the string "imitator".
|
320
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
321
|
+
*/
|
322
|
+
static VALUE cm_from_title(int argc, VALUE argv[], VALUE self)
|
323
|
+
{
|
324
|
+
VALUE args[1];
|
325
|
+
|
326
|
+
args[0] = rb_ary_entry(cm_search(argc, argv, self), 0);
|
327
|
+
if (NIL_P(args[0]))
|
328
|
+
rb_raise(rb_eArgError, "No matching window found!");
|
329
|
+
|
330
|
+
return rb_class_new_instance(1, args, XWindow);
|
331
|
+
}
|
332
|
+
|
333
|
+
/*
|
334
|
+
*call-seq:
|
335
|
+
* XWindow.from_focused( [screen = 0 [, display = 0 ] ] ) ==> aXWindow
|
336
|
+
*
|
337
|
+
*Creates a new XWindow from the actually focused window.
|
338
|
+
*===Parameters
|
339
|
+
*[screen] (0) The screen to look for the window.
|
340
|
+
*[display] (0) The display to look for the screen.
|
341
|
+
*===Return value
|
342
|
+
*The window having the input focus.
|
343
|
+
*===Example
|
344
|
+
* xwin = Imitator::X::XWindow.from_focused
|
345
|
+
*===Remarks
|
346
|
+
*This method is not reliable, since it's likely to find one of those
|
347
|
+
*invisible "InputOnly" windows. Have a look at XWindow.from_active
|
348
|
+
*for a more reliable variant.
|
349
|
+
*/
|
350
|
+
static VALUE cm_from_focused(int argc, VALUE argv[], VALUE self)
|
351
|
+
{
|
352
|
+
VALUE screen, display;
|
353
|
+
Display * p_display;
|
354
|
+
char display_string[100];
|
355
|
+
Window win;
|
356
|
+
int revert;
|
357
|
+
VALUE result;
|
358
|
+
VALUE args[1];
|
359
|
+
|
360
|
+
rb_scan_args(argc, argv, "02", &screen, &display);
|
361
|
+
|
362
|
+
/*Assign the display or default to 0*/
|
363
|
+
if (NIL_P(display))
|
364
|
+
display = INT2FIX(0);
|
365
|
+
/*Assign the screen or default to 0*/
|
366
|
+
if (NIL_P(screen))
|
367
|
+
screen = INT2FIX(0);
|
368
|
+
/*Get the display string, form ":display.screen"*/
|
369
|
+
sprintf(display_string, ":%i.%i", FIX2INT(display), FIX2INT(screen));
|
370
|
+
|
371
|
+
p_display = XOpenDisplay(display_string);
|
372
|
+
XSetErrorHandler(handle_x_errors);
|
373
|
+
|
374
|
+
XGetInputFocus(p_display, &win, &revert);
|
375
|
+
args[0] = LONG2NUM(win);
|
376
|
+
result = rb_class_new_instance(1, args, XWindow);
|
377
|
+
|
378
|
+
XSetErrorHandler(NULL);
|
379
|
+
XCloseDisplay(p_display);
|
380
|
+
return result;
|
381
|
+
}
|
382
|
+
|
383
|
+
/*
|
384
|
+
*call-seq:
|
385
|
+
* XWindow.from_active( [screen = 0 [, display = 0 ] ] ) ==> aXWindow
|
386
|
+
*
|
387
|
+
*Creates a new XWindow from the currently active window.
|
388
|
+
*===Parameters
|
389
|
+
*[screen] (0) The screen to look for the window.
|
390
|
+
*[display] (0) The display to look for the screen.
|
391
|
+
*===Return value
|
392
|
+
*The found window as a XWindow object.
|
393
|
+
*===Raises
|
394
|
+
*[NotImplementedError] The EWMH standard _NET_ACTIVE_WINDOW isn't supported.
|
395
|
+
*[XError] Failed to retrieve the active window from the X server. Did you specify a correct screen and display?
|
396
|
+
*===Example
|
397
|
+
* xwin = Imitator::X::XWindow.from_active
|
398
|
+
* #Active window of screen 3
|
399
|
+
* xwin = Imitator::X::XWindow.from_active(3)
|
400
|
+
* #Active window of screen 0 on display 2
|
401
|
+
* xwin = Imitator::X::XWindow.from_active(0, 2)
|
402
|
+
*===Remarks
|
403
|
+
*This method is part of the EWMH standard _NET_ACTIVE_WINDOW.
|
404
|
+
*
|
405
|
+
*If you can choose between this method and XWindow.from_focused, choose this one,
|
406
|
+
*because it doesn't find invisible windows.
|
407
|
+
*/
|
408
|
+
static VALUE cm_from_active(int argc, VALUE argv[], VALUE self)
|
409
|
+
{
|
410
|
+
Display * p_display;
|
411
|
+
VALUE screen, display, result;
|
412
|
+
VALUE args[1];
|
413
|
+
char display_string[100];
|
414
|
+
Atom atom, actual_type;
|
415
|
+
Window root, active_win;
|
416
|
+
int actual_format;
|
417
|
+
unsigned long nitems, bytes;
|
418
|
+
unsigned char * prop;
|
419
|
+
|
420
|
+
rb_scan_args(argc, argv, "02", &screen, &display);
|
421
|
+
/*Assign the display or default to 0*/
|
422
|
+
if (NIL_P(display))
|
423
|
+
display = INT2FIX(0);
|
424
|
+
/*Assign the screen or default to 0*/
|
425
|
+
if (NIL_P(screen))
|
426
|
+
screen = INT2FIX(0);
|
427
|
+
/*Get the display string, form ":display.screen"*/
|
428
|
+
sprintf(display_string, ":%i.%i", FIX2INT(display), FIX2INT(screen));
|
429
|
+
|
430
|
+
p_display = XOpenDisplay(display_string);
|
431
|
+
XSetErrorHandler(handle_x_errors);
|
432
|
+
check_for_ewmh(p_display, "_NET_ACTIVE_WINDOW");
|
433
|
+
|
434
|
+
atom = XInternAtom(p_display, "_NET_ACTIVE_WINDOW", False);
|
435
|
+
root = XDefaultRootWindow(p_display);
|
436
|
+
|
437
|
+
XGetWindowProperty(p_display, root, atom, 0, (~0L), False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes, &prop);
|
438
|
+
if (nitems > 0)
|
439
|
+
active_win = *((Window *) prop); /*We got a Window*/
|
440
|
+
else /*Shouldn't be the case*/
|
441
|
+
rb_raise(XError, "Couldn't retrieve the active window for some reason!");
|
442
|
+
args[0] = LONG2NUM(active_win);
|
443
|
+
result = rb_class_new_instance(1, args, XWindow);
|
444
|
+
|
445
|
+
XFree(prop);
|
446
|
+
XSetErrorHandler(NULL);
|
447
|
+
XCloseDisplay(p_display);
|
448
|
+
return result;
|
449
|
+
}
|
450
|
+
|
451
|
+
/*
|
452
|
+
*call-seq:
|
453
|
+
* XWindow.wait_for_window( str [, screen = 0 [, display = 0 ] ] ) ==> aXWindow
|
454
|
+
* XWindow.wait_for_window(regexp [, screen = 0 [, display = 0 ] ] ) ==> aXWindow
|
455
|
+
*
|
456
|
+
*Pauses execution until a window matching the given criteria is found.
|
457
|
+
*===Parameters
|
458
|
+
*[+str+] The *exact* title of the window you want to to wait for.
|
459
|
+
*[+regexp+] A Regular Expression matching the window title you want to wait for.
|
460
|
+
*[+screen+] (0) The screen the window will be mapped to.
|
461
|
+
*[+display+] (0) The display the window will be mapped to.
|
462
|
+
*===Return value
|
463
|
+
*The XWindow object of the matching window.
|
464
|
+
*===Example
|
465
|
+
* #Wait until a window with "gedit" in it's title exists
|
466
|
+
* gedit_win = Imitator::X::XWindow.wait_for_window(/gedit/)
|
467
|
+
*/
|
468
|
+
static VALUE cm_wait_for_window(int argc, VALUE argv[], VALUE self)
|
469
|
+
{
|
470
|
+
VALUE rstr;
|
471
|
+
VALUE rscreen;
|
472
|
+
VALUE rdisplay;
|
473
|
+
VALUE args[3];
|
474
|
+
|
475
|
+
rb_scan_args(argc, argv, "12", &rstr, &rscreen, &rdisplay);
|
476
|
+
args[0] = rstr;
|
477
|
+
args[1] = rscreen;
|
478
|
+
args[2] = rdisplay;
|
479
|
+
|
480
|
+
/*Hang around until we see a window matching the cirteria*/
|
481
|
+
while (RTEST(rb_funcall(cm_search(3, args, self), rb_intern("empty?"), 0)))
|
482
|
+
rb_thread_sleep(1);
|
483
|
+
|
484
|
+
/*Wait another second to be sure that the window can be worked with*/
|
485
|
+
rb_thread_sleep(1);
|
486
|
+
|
487
|
+
return cm_from_title(3, args, self);
|
488
|
+
}
|
489
|
+
|
490
|
+
/*
|
491
|
+
*call-seq:
|
492
|
+
* XWindow.wait_for_window_termination( str [, screen = 0 [, display = 0 ] ] ) ==> nil
|
493
|
+
* XWindow.wait_for_window_termination( regexp [, streen = 0 [, display = 0 ] ] ) ==> nil
|
494
|
+
*
|
495
|
+
*Pauses execution flow until *every* window matching the given criteria disappeared.
|
496
|
+
*===Parameters
|
497
|
+
*[+str+] The window's title. This must match *excatly*.
|
498
|
+
*[+regexp+] The window's title, as a Regular Expression to match.
|
499
|
+
*[+screen+] (0) The screen the window resides on.
|
500
|
+
*[+display+] (0) The screen's display.
|
501
|
+
*===Return value
|
502
|
+
*nil.
|
503
|
+
*===Example
|
504
|
+
* #Wait until all gedit windows are closed
|
505
|
+
* Imitator::X::XWindow.wait_for_window_termination(/gedit/)
|
506
|
+
* #Wait until Firefox on screen 1 closes
|
507
|
+
* Imitator::X::XWindow.wait_for_window_termination(/Mozilla Firefox/, 1)
|
508
|
+
*===Remarks
|
509
|
+
*If you want to wait for a specific window's termination and you already have
|
510
|
+
*a XWindow object for that one, you can also use the following code which is
|
511
|
+
*probably shorter:
|
512
|
+
* #... (Get your XWindow instance somewhere)
|
513
|
+
* sleep 0.1 while xwin.exists?
|
514
|
+
*This causes Ruby to check every tenth of a second to check if the reference
|
515
|
+
*hold by +xwin+ is still valid, and if not, the loop exits and program flow continues.
|
516
|
+
*/
|
517
|
+
static VALUE cm_wait_for_window_termination(int argc, VALUE argv[], VALUE self)
|
518
|
+
{
|
519
|
+
VALUE rstr;
|
520
|
+
VALUE rscreen;
|
521
|
+
VALUE rdisplay;
|
522
|
+
VALUE args[3];
|
523
|
+
|
524
|
+
rb_scan_args(argc, argv, "12", &rstr, &rscreen, &rdisplay);
|
525
|
+
args[0] = rstr;
|
526
|
+
args[1] = rscreen;
|
527
|
+
args[2] = rdisplay;
|
528
|
+
|
529
|
+
/*Hang around until every window matching the criteria has gone*/
|
530
|
+
while (!RTEST(rb_funcall(cm_search(3, args, self), rb_intern("empty?"), 0)))
|
531
|
+
rb_thread_sleep(1);
|
532
|
+
|
533
|
+
/*Wait another second to be sure that the window can't be worked with*/
|
534
|
+
rb_thread_sleep(1);
|
535
|
+
|
536
|
+
return Qnil;
|
537
|
+
}
|
538
|
+
/****************************Instance methods*************************************/
|
539
|
+
|
540
|
+
/*
|
541
|
+
*call-seq:
|
542
|
+
* XWindow.new(window_id, screen = 0, display = 0) ==> aXWindow
|
543
|
+
*
|
544
|
+
*Creates a new XWindow object which holds a pseudo reference to a real window.
|
545
|
+
*===Parameters
|
546
|
+
*[+window_id+] The ID of the window to get a reference to.
|
547
|
+
*[+screen+] (0) The number of the screen the window is shown on.
|
548
|
+
*[+display+] (0) The number of the display that contains the screen the window is mapped to.
|
549
|
+
*===Return value
|
550
|
+
*A brand new XWindow object.
|
551
|
+
*===Raises
|
552
|
+
*[XProtocolError] The window ID wasn't found (on the specified screen and/or display).
|
553
|
+
*===Example
|
554
|
+
* #Assume 12345 is an existing window on the default screen and display
|
555
|
+
* xwin = Imitator::X::XWindow.new(12345)
|
556
|
+
* #Or on screen 2 on display 0
|
557
|
+
* xwin = Imitator::X::XWindow.new(12345, 2)
|
558
|
+
* #Or on screen 3 on display 1 (you almost never need this)
|
559
|
+
* xwin = Imitator::X::XWindow.new(12345, 3, 1)
|
560
|
+
*/
|
561
|
+
static VALUE m_initialize(VALUE argc, VALUE argv[], VALUE self)
|
562
|
+
{
|
563
|
+
VALUE window_id;
|
564
|
+
VALUE screen;
|
565
|
+
VALUE display;
|
566
|
+
VALUE display_string = rb_class_new_instance(0, 0, rb_cString);
|
567
|
+
|
568
|
+
rb_scan_args(argc, argv, "12", &window_id, &screen, &display);
|
569
|
+
|
570
|
+
rb_str_concat(display_string, rb_str_new2(":")); /*Ommit hostname, we're only operating locally*/
|
571
|
+
/*Assign the display or default to 0*/
|
572
|
+
if (NIL_P(display))
|
573
|
+
rb_str_concat(display_string, rb_str_new2("0"));
|
574
|
+
else
|
575
|
+
rb_str_concat(display_string, display);
|
576
|
+
rb_str_concat(display_string, rb_str_new2(".")); /*Screen delimiter*/
|
577
|
+
/*Assign the screen or default to 0*/
|
578
|
+
if (NIL_P(screen))
|
579
|
+
rb_str_concat(display_string, rb_str_new2("0"));
|
580
|
+
else
|
581
|
+
rb_str_concat(display_string, screen);
|
582
|
+
|
583
|
+
rb_ivar_set(self, rb_intern("@window_id"), window_id);
|
584
|
+
rb_ivar_set(self, rb_intern("@display_string"), display_string);
|
585
|
+
return self;
|
586
|
+
}
|
587
|
+
|
588
|
+
/*
|
589
|
+
*Human-readable description of form <tt><Imitator::X::XWindow 'window_title' (window_id_as_hex)></tt>.
|
590
|
+
*/
|
591
|
+
static VALUE m_inspect(VALUE self)
|
592
|
+
{
|
593
|
+
char str[1000];
|
594
|
+
VALUE rstr;
|
595
|
+
VALUE handle;
|
596
|
+
|
597
|
+
rstr = rb_funcall(self, rb_intern("title"), 0);
|
598
|
+
handle = rb_funcall(rb_ivar_get(self, rb_intern("@window_id")), rb_intern("to_s"), 1, INT2NUM(16));
|
599
|
+
sprintf(str, "<Imitator::X::XWindow '%s' (0x%s)>", StringValuePtr(rstr), StringValuePtr(handle));
|
600
|
+
rstr = rb_enc_str_new(str, strlen(str), rb_utf8_encoding());
|
601
|
+
return rstr;
|
602
|
+
}
|
603
|
+
|
604
|
+
/*
|
605
|
+
*Returns the window's title.
|
606
|
+
*===Return value
|
607
|
+
*The window's title.
|
608
|
+
*===Example
|
609
|
+
* #Get the root window's title. This is not very useful, it's always "(null)".
|
610
|
+
* puts Imitator::X::XWindow.default_root_window.title #=> (null)
|
611
|
+
*/
|
612
|
+
static VALUE m_title(VALUE self)
|
613
|
+
{
|
614
|
+
Display * p_display;
|
615
|
+
Window win;
|
616
|
+
XTextProperty xtext;
|
617
|
+
char * cp;
|
618
|
+
VALUE rstr;
|
619
|
+
|
620
|
+
p_display = get_win_display(self);
|
621
|
+
XSetErrorHandler(handle_x_errors);
|
622
|
+
|
623
|
+
win = NUM2LONG(rb_ivar_get(self, rb_intern("@window_id")));
|
624
|
+
XGetWMName(p_display, win, &xtext);
|
625
|
+
cp = malloc(sizeof(char) * xtext.nitems);
|
626
|
+
sprintf(cp, "%s", xtext.value);
|
627
|
+
rstr = XSTR_TO_RSTR(cp);
|
628
|
+
|
629
|
+
XFree(xtext.value);
|
630
|
+
XSetErrorHandler(NULL);
|
631
|
+
XCloseDisplay(p_display);
|
632
|
+
return rstr;
|
633
|
+
}
|
634
|
+
|
635
|
+
/*
|
636
|
+
*Returns the window_id.
|
637
|
+
*===Return value
|
638
|
+
*The window ID as an integer.
|
639
|
+
*===Example
|
640
|
+
* #Get the root window's ID.
|
641
|
+
* puts Imitator::X::XWindow.default_root_window.window_id #=> 316
|
642
|
+
*/
|
643
|
+
static VALUE m_window_id(VALUE self)
|
644
|
+
{
|
645
|
+
return rb_ivar_get(self, rb_intern("@window_id"));
|
646
|
+
}
|
647
|
+
|
648
|
+
/*
|
649
|
+
*Returns the root window of the screen that holds this window.
|
650
|
+
*===Return value
|
651
|
+
*The root window of the screen holding this window, as a XWindow.
|
652
|
+
*===Example
|
653
|
+
* #Get a window with "imitator" in it's title and...
|
654
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
655
|
+
* #...get the root window of the screen it's mapped to.
|
656
|
+
* xwin.root_win #=> <Imitator::X::XWindow '(null)' (0x13c)>
|
657
|
+
*/
|
658
|
+
static VALUE m_root_win(VALUE self)
|
659
|
+
{
|
660
|
+
Display * p_display;
|
661
|
+
Window win = GET_WINDOW;
|
662
|
+
XWindowAttributes xattr;
|
663
|
+
VALUE args[1];
|
664
|
+
VALUE rroot_win;
|
665
|
+
|
666
|
+
p_display = get_win_display(self);
|
667
|
+
XSetErrorHandler(handle_x_errors);
|
668
|
+
|
669
|
+
XGetWindowAttributes(p_display, win, &xattr);
|
670
|
+
args[0] = LONG2NUM(xattr.root);
|
671
|
+
rroot_win = rb_class_new_instance(1, args, XWindow);
|
672
|
+
|
673
|
+
XSetErrorHandler(NULL);
|
674
|
+
XCloseDisplay(p_display);
|
675
|
+
return rroot_win;
|
676
|
+
}
|
677
|
+
|
678
|
+
/*
|
679
|
+
*Returns this window's parent window.
|
680
|
+
*===Return value
|
681
|
+
*This window's parent window as a XWindow object.
|
682
|
+
*===Example
|
683
|
+
* xwin = Imitator:X::XWindow.from_title(/imitator/)
|
684
|
+
* xwin.parent #=> <Imitator::X::XWindow '(null)' (0x13c)>
|
685
|
+
*/
|
686
|
+
static VALUE m_parent(VALUE self)
|
687
|
+
{
|
688
|
+
Display * p_display;
|
689
|
+
Window win = GET_WINDOW;
|
690
|
+
Window root_win, parent;
|
691
|
+
Window * p_children;
|
692
|
+
unsigned int nchildren;
|
693
|
+
VALUE args[1];
|
694
|
+
VALUE result;
|
695
|
+
|
696
|
+
p_display = get_win_display(self);
|
697
|
+
XSetErrorHandler(handle_x_errors);
|
698
|
+
|
699
|
+
XQueryTree(p_display, win, &root_win, &parent, &p_children, &nchildren);
|
700
|
+
args[0] = LONG2NUM(parent);
|
701
|
+
result = rb_class_new_instance(1, args, XWindow);
|
702
|
+
|
703
|
+
XFree(p_children);
|
704
|
+
XSetErrorHandler(NULL);
|
705
|
+
XCloseDisplay(p_display);
|
706
|
+
return result;
|
707
|
+
}
|
708
|
+
|
709
|
+
/*
|
710
|
+
*Returns the children of this window.
|
711
|
+
*===Return value
|
712
|
+
*The window IDs of the children of this window as integers.
|
713
|
+
*===Example
|
714
|
+
* #Get a list of all windows that are searched by XWindow.search
|
715
|
+
* Imitator::X::XWindow.default_root_window.children #=> [...]
|
716
|
+
*===Remarks
|
717
|
+
*I orginally wanted to return an array of XWindow obejcts, but everytime
|
718
|
+
*I tried to #inspect the created array, I got a segfault, memory corruption or
|
719
|
+
*malloc failed assertion. When only inspecting parts of the array, everything goes fine.
|
720
|
+
*So, don't try to map the list returned by this method into an array and then inspect it.
|
721
|
+
*E-mail me at sutniuq$gmx:net if you know a solution... See also the commented-out source
|
722
|
+
*in the for loop inside this function.
|
723
|
+
*/
|
724
|
+
static VALUE m_children(VALUE self)
|
725
|
+
{
|
726
|
+
Display * p_display;
|
727
|
+
Window win = GET_WINDOW;
|
728
|
+
Window root_win, parent;
|
729
|
+
Window * p_children;
|
730
|
+
unsigned int num_children;
|
731
|
+
int i;
|
732
|
+
//VALUE args[1];
|
733
|
+
VALUE result = rb_ary_new();
|
734
|
+
//VALUE rtemp;
|
735
|
+
|
736
|
+
p_display = get_win_display(self);
|
737
|
+
XSetErrorHandler(handle_x_errors);
|
738
|
+
|
739
|
+
XQueryTree(p_display, win, &root_win, &parent, &p_children, &num_children);
|
740
|
+
for(i = 0;i < num_children; i++)
|
741
|
+
{
|
742
|
+
//printf("%lu\n", *(p_children + i));
|
743
|
+
//args[0] = LONG2NUM(*(p_children + i));
|
744
|
+
//rtemp = rb_class_new_instance(1, args, XWindow);
|
745
|
+
//rb_ary_push(result, rtemp); /*Why causes this a segfault??? AND WHY ONLY WHEN INSPECTING THE WHOLE ARRAY?????*/
|
746
|
+
rb_ary_push(result, LONG2NUM(*(p_children + i)));
|
747
|
+
}
|
748
|
+
|
749
|
+
XFree(p_children);
|
750
|
+
XSetErrorHandler(NULL);
|
751
|
+
XCloseDisplay(p_display);
|
752
|
+
return result;
|
753
|
+
}
|
754
|
+
|
755
|
+
/*
|
756
|
+
*Returns true if +self+ is a root window.
|
757
|
+
*===Return value
|
758
|
+
*true or false.
|
759
|
+
*===Example
|
760
|
+
* root = Imitator::X::XWindow.default_root_window
|
761
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
762
|
+
* root.root_win? #=> true
|
763
|
+
* xwin.root_win? #=> false
|
764
|
+
*/
|
765
|
+
static VALUE m_is_root_win(VALUE self)
|
766
|
+
{
|
767
|
+
Display * p_display;
|
768
|
+
Window win = GET_WINDOW;
|
769
|
+
Window root_win, parent;
|
770
|
+
Window * p_children;
|
771
|
+
unsigned int num_children;
|
772
|
+
VALUE result;
|
773
|
+
|
774
|
+
p_display = get_win_display(self);
|
775
|
+
XSetErrorHandler(handle_x_errors);
|
776
|
+
|
777
|
+
XQueryTree(p_display, win, &root_win, &parent, &p_children, &num_children);
|
778
|
+
|
779
|
+
if (parent == 0)
|
780
|
+
result = Qtrue;
|
781
|
+
else
|
782
|
+
result = Qfalse;
|
783
|
+
|
784
|
+
XFree(p_children);
|
785
|
+
XSetErrorHandler(NULL);
|
786
|
+
XCloseDisplay(p_display);
|
787
|
+
return result;
|
788
|
+
}
|
789
|
+
|
790
|
+
/*
|
791
|
+
*Returns the window's current position.
|
792
|
+
*===Return value
|
793
|
+
*The position as a two-element array of form <tt>[x, y]</tt>.
|
794
|
+
*===Example
|
795
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
796
|
+
* p xwin.position #=> [3, 47]
|
797
|
+
*/
|
798
|
+
static VALUE m_position(VALUE self)
|
799
|
+
{
|
800
|
+
Display * p_display;
|
801
|
+
Window win = GET_WINDOW;
|
802
|
+
XWindowAttributes xattr;
|
803
|
+
VALUE pos = rb_ary_new();
|
804
|
+
|
805
|
+
p_display = get_win_display(self);
|
806
|
+
XSetErrorHandler(handle_x_errors);
|
807
|
+
|
808
|
+
XGetWindowAttributes(p_display, win, &xattr);
|
809
|
+
rb_ary_push(pos, INT2NUM(xattr.x));
|
810
|
+
rb_ary_push(pos, INT2NUM(xattr.y));
|
811
|
+
|
812
|
+
XSetErrorHandler(NULL);
|
813
|
+
XCloseDisplay(p_display);
|
814
|
+
return pos;
|
815
|
+
}
|
816
|
+
|
817
|
+
/*
|
818
|
+
*Return the window's current size.
|
819
|
+
*===Return value
|
820
|
+
*The window's size as a two-element array of form <tt>[width, height]</tt>.
|
821
|
+
*===Example
|
822
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
823
|
+
* p xwin.size #=> [801, 551]
|
824
|
+
*/
|
825
|
+
static VALUE m_size(VALUE self)
|
826
|
+
{
|
827
|
+
Display * p_display;
|
828
|
+
Window win = GET_WINDOW;
|
829
|
+
XWindowAttributes xattr;
|
830
|
+
VALUE size = rb_ary_new();
|
831
|
+
|
832
|
+
p_display = get_win_display(self);
|
833
|
+
XSetErrorHandler(handle_x_errors);
|
834
|
+
|
835
|
+
XGetWindowAttributes(p_display, win, &xattr);
|
836
|
+
rb_ary_push(size, INT2NUM(xattr.width));
|
837
|
+
rb_ary_push(size, INT2NUM(xattr.height));
|
838
|
+
|
839
|
+
XSetErrorHandler(NULL);
|
840
|
+
XCloseDisplay(p_display);
|
841
|
+
return size;
|
842
|
+
}
|
843
|
+
|
844
|
+
/*
|
845
|
+
*Determines wheather or not +self+ is visible on the screen.
|
846
|
+
*===Return value
|
847
|
+
*true or false.
|
848
|
+
*===Example
|
849
|
+
* Imitator::X::XWindow.from_title(/imitator/).visible? #=> true
|
850
|
+
*===Remarks
|
851
|
+
*Generally invisible, so-called InputOnly-windows, are treated as
|
852
|
+
*invisible and return false. If you want to check the map state of such
|
853
|
+
*a window, use #mapped?.
|
854
|
+
*
|
855
|
+
*This method returns also false if an ancestor is unmapped.
|
856
|
+
*/
|
857
|
+
static VALUE m_is_visible(VALUE self)
|
858
|
+
{
|
859
|
+
Display * p_display;
|
860
|
+
Window win = GET_WINDOW;
|
861
|
+
XWindowAttributes xattr;
|
862
|
+
VALUE result;
|
863
|
+
|
864
|
+
p_display = get_win_display(self);
|
865
|
+
XSetErrorHandler(handle_x_errors);
|
866
|
+
|
867
|
+
XGetWindowAttributes(p_display, win, &xattr);
|
868
|
+
if (xattr.class == InputOnly)
|
869
|
+
result = Qfalse; /*Input-only windows are always invisible*/
|
870
|
+
else
|
871
|
+
{
|
872
|
+
if (xattr.map_state == IsUnmapped || xattr.map_state == IsUnviewable)
|
873
|
+
result = Qfalse; /*Only mapped windows are visible (their ancestors must be mapped, too)*/
|
874
|
+
else
|
875
|
+
result = Qtrue;
|
876
|
+
}
|
877
|
+
|
878
|
+
XSetErrorHandler(NULL);
|
879
|
+
XCloseDisplay(p_display);
|
880
|
+
return result;
|
881
|
+
}
|
882
|
+
|
883
|
+
/*
|
884
|
+
*Checkes wheather or not +self+ is mapped to the screen.
|
885
|
+
*===Return value
|
886
|
+
*true or false.
|
887
|
+
*===Example
|
888
|
+
* Imitator::X::XWindow.from_title(/imitator/).mapped? #=> true
|
889
|
+
*===Remarks
|
890
|
+
*This method doesn't give reliable information about a window's
|
891
|
+
*visibility, because it returns true for InputOnly-windows which
|
892
|
+
*are generally invisible. If you don't want this behaviour, use #visible?.
|
893
|
+
*
|
894
|
+
*This method returns also false if an ancestor is unmapped.
|
895
|
+
*/
|
896
|
+
static VALUE m_is_mapped(VALUE self)
|
897
|
+
{
|
898
|
+
Display * p_display;
|
899
|
+
Window win = GET_WINDOW;
|
900
|
+
XWindowAttributes xattr;
|
901
|
+
VALUE result;
|
902
|
+
|
903
|
+
p_display = get_win_display(self);
|
904
|
+
XSetErrorHandler(handle_x_errors);
|
905
|
+
|
906
|
+
XGetWindowAttributes(p_display, win, &xattr);
|
907
|
+
if (xattr.map_state == IsUnmapped || xattr.map_state == IsUnviewable)
|
908
|
+
result = Qfalse;
|
909
|
+
else
|
910
|
+
result = Qtrue;
|
911
|
+
|
912
|
+
XSetErrorHandler(NULL);
|
913
|
+
XCloseDisplay(p_display);
|
914
|
+
return result;
|
915
|
+
}
|
916
|
+
|
917
|
+
/*
|
918
|
+
*call-seq:
|
919
|
+
* move(x, y) ==> anArray
|
920
|
+
*
|
921
|
+
*Moves +self+ to the specified position.
|
922
|
+
*===Parameters
|
923
|
+
*[+x+] The goal X coordinate.
|
924
|
+
*[+y+] The goal Y coordinate.
|
925
|
+
*===Return value
|
926
|
+
*The window's new position.
|
927
|
+
*===Example
|
928
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
929
|
+
* #Move the window to (100|100)
|
930
|
+
* xwin.move(100, 100) #=> [103, 123]
|
931
|
+
* xwin.pos #=> [103, 123] #See remarks
|
932
|
+
*===Remarks
|
933
|
+
*It's impossible to set a window exactly to that coordinate you want. It seems,
|
934
|
+
*that X sets and retrieves a window's position at the upper-left coordinate of a window's client area,
|
935
|
+
*that is, beyond the border and the title bar. Therefore, to make an exact position movement, you would have
|
936
|
+
*to subtract the width of those elements. Unfortunally, aXWindowAttributes.border_width always returns 0 on my
|
937
|
+
*system. :(
|
938
|
+
*
|
939
|
+
*Also, this function can't move the window off the screen. If you try to, the window will
|
940
|
+
*be moved as near to the screen's edge as possible.
|
941
|
+
*/
|
942
|
+
static VALUE m_move(VALUE self, VALUE rx, VALUE ry)
|
943
|
+
{
|
944
|
+
Display * p_display;
|
945
|
+
Window win = GET_WINDOW;
|
946
|
+
int x = NUM2INT(rx);
|
947
|
+
int y = NUM2INT(ry);
|
948
|
+
|
949
|
+
p_display = get_win_display(self);
|
950
|
+
XSetErrorHandler(handle_x_errors);
|
951
|
+
|
952
|
+
XMoveWindow(p_display, win, x, y);
|
953
|
+
|
954
|
+
XSetErrorHandler(NULL);
|
955
|
+
XCloseDisplay(p_display);
|
956
|
+
return m_position(self);
|
957
|
+
}
|
958
|
+
|
959
|
+
/*
|
960
|
+
*call-seq:
|
961
|
+
* resize(width, height) ==> anArray
|
962
|
+
*
|
963
|
+
*Resizes a window.
|
964
|
+
*===Parameters
|
965
|
+
*[+width+] The desired width, in pixels.
|
966
|
+
*[+height+] The desired height, in pixels.
|
967
|
+
*===Return value
|
968
|
+
*The new window size.
|
969
|
+
*===Example
|
970
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
971
|
+
* #Resize the window to 400x400px
|
972
|
+
* xwin.resize(400, 400) #=> [400, 400]
|
973
|
+
* xwin.size #=> [400, 400]
|
974
|
+
*===Remarks
|
975
|
+
*Some windows have a minumum width value set. If a windows has, you can't change it's size
|
976
|
+
*to a smaller value than that one. Also, it's impossible to make a window larger than the screen.
|
977
|
+
*In any of those cases, the window will be resized to the minimum/maximum acceptable value.
|
978
|
+
*/
|
979
|
+
static VALUE m_resize(VALUE self, VALUE rwidth, VALUE rheight)
|
980
|
+
{
|
981
|
+
Display * p_display;
|
982
|
+
Window win = GET_WINDOW;
|
983
|
+
unsigned int width = NUM2UINT(rwidth);
|
984
|
+
unsigned int height = NUM2UINT(rheight);
|
985
|
+
|
986
|
+
p_display = get_win_display(self);
|
987
|
+
XSetErrorHandler(handle_x_errors);
|
988
|
+
|
989
|
+
XResizeWindow(p_display, win, width, height);
|
990
|
+
|
991
|
+
XSetErrorHandler(NULL);
|
992
|
+
XCloseDisplay(p_display);
|
993
|
+
return m_size(self);
|
994
|
+
}
|
995
|
+
|
996
|
+
/*
|
997
|
+
*Raises a window to the top, but doesn't give it the input focus.
|
998
|
+
*===Return value
|
999
|
+
*nil.
|
1000
|
+
*===Example
|
1001
|
+
* wxin = Imitator::X::XWindow.from_title(/imitator/)
|
1002
|
+
* xwin.raise_win
|
1003
|
+
*===Remarks
|
1004
|
+
*This method isn't named "raise", because that would conflict with the
|
1005
|
+
*Kernel module's "raise" method. You can define an alias if you want to.
|
1006
|
+
*
|
1007
|
+
*Instead of combining this method with #focus you may should have a
|
1008
|
+
*look at #activate.
|
1009
|
+
*/
|
1010
|
+
static VALUE m_raise_win(VALUE self)
|
1011
|
+
{
|
1012
|
+
Display * p_display;
|
1013
|
+
Window win = GET_WINDOW;
|
1014
|
+
|
1015
|
+
p_display = get_win_display(self);
|
1016
|
+
XSetErrorHandler(handle_x_errors);
|
1017
|
+
|
1018
|
+
XRaiseWindow(p_display, win);
|
1019
|
+
|
1020
|
+
XSetErrorHandler(NULL);
|
1021
|
+
XCloseDisplay(p_display);
|
1022
|
+
return Qnil;
|
1023
|
+
}
|
1024
|
+
|
1025
|
+
/*
|
1026
|
+
*Gives +self+ the input focus, but doesn't bring it to the front.
|
1027
|
+
*===Return value
|
1028
|
+
*nil.
|
1029
|
+
*===Example
|
1030
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
1031
|
+
* xwin.focus
|
1032
|
+
*===Remarks
|
1033
|
+
*Instead of combining this method with #raise_win you may should
|
1034
|
+
*have a look at #activate.
|
1035
|
+
*/
|
1036
|
+
static VALUE m_focus(VALUE self)
|
1037
|
+
{
|
1038
|
+
Display * p_display;
|
1039
|
+
Window win = GET_WINDOW;
|
1040
|
+
|
1041
|
+
p_display = get_win_display(self);
|
1042
|
+
XSetErrorHandler(handle_x_errors);
|
1043
|
+
|
1044
|
+
XSetInputFocus(p_display, win, RevertToNone, CurrentTime);
|
1045
|
+
|
1046
|
+
XSetErrorHandler(NULL);
|
1047
|
+
XCloseDisplay(p_display);
|
1048
|
+
return Qnil;
|
1049
|
+
}
|
1050
|
+
|
1051
|
+
/*
|
1052
|
+
*Makes +self+ lose the input focus. The window will continue looking focused.
|
1053
|
+
*===Return value
|
1054
|
+
*nil.
|
1055
|
+
*===Example
|
1056
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
1057
|
+
* #Try to type after this, your input won't get anywhere:
|
1058
|
+
* xwin.focus;sleep 2;xwin.unfocus
|
1059
|
+
*/
|
1060
|
+
static VALUE m_unfocus(VALUE self)
|
1061
|
+
{
|
1062
|
+
Display * p_display;
|
1063
|
+
|
1064
|
+
p_display = get_win_display(self);
|
1065
|
+
XSetErrorHandler(handle_x_errors);
|
1066
|
+
|
1067
|
+
XSetInputFocus(p_display, None, RevertToNone, CurrentTime);
|
1068
|
+
|
1069
|
+
XSetErrorHandler(NULL);
|
1070
|
+
XCloseDisplay(p_display);
|
1071
|
+
return Qnil;
|
1072
|
+
}
|
1073
|
+
|
1074
|
+
/*
|
1075
|
+
*Maps a window to the screen, i.e. make it visible. Only possible after a previous
|
1076
|
+
*call to #unmap.
|
1077
|
+
*===Return value
|
1078
|
+
*nil.
|
1079
|
+
*===Example
|
1080
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
1081
|
+
* p xwin.visible? #=> true
|
1082
|
+
* p xwin.size #=> [804, 550]
|
1083
|
+
* xwin.unmap
|
1084
|
+
* p xwin.visible? #=> false
|
1085
|
+
* p xwin.size #=> [804, 550]
|
1086
|
+
* xwin.map
|
1087
|
+
* p xwin.visible? #=> true
|
1088
|
+
* p xwin.size #=> [804, 550]
|
1089
|
+
*/
|
1090
|
+
static VALUE m_map(VALUE self)
|
1091
|
+
{
|
1092
|
+
Display * p_display;
|
1093
|
+
Window win = GET_WINDOW;
|
1094
|
+
|
1095
|
+
p_display = get_win_display(self);
|
1096
|
+
XSetErrorHandler(handle_x_errors);
|
1097
|
+
|
1098
|
+
XMapWindow(p_display, win);
|
1099
|
+
|
1100
|
+
XSetErrorHandler(NULL);
|
1101
|
+
XCloseDisplay(p_display);
|
1102
|
+
return Qnil;
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
/*
|
1106
|
+
*Unmaps a window from the screen, i.e. make it invisible. The window <b>is not</b> deleted.
|
1107
|
+
*===Return value
|
1108
|
+
*nil.
|
1109
|
+
*===Example
|
1110
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
1111
|
+
* xwin.unmap
|
1112
|
+
*===Remarks
|
1113
|
+
*Perhaps it's not a good idea to unmap the root window...
|
1114
|
+
*/
|
1115
|
+
static VALUE m_unmap(VALUE self)
|
1116
|
+
{
|
1117
|
+
Display * p_display;
|
1118
|
+
Window win = GET_WINDOW;
|
1119
|
+
|
1120
|
+
p_display = get_win_display(self);
|
1121
|
+
XSetErrorHandler(handle_x_errors);
|
1122
|
+
|
1123
|
+
XUnmapWindow(p_display, win);
|
1124
|
+
|
1125
|
+
XSetErrorHandler(NULL);
|
1126
|
+
XCloseDisplay(p_display);
|
1127
|
+
return Qnil;
|
1128
|
+
}
|
1129
|
+
|
1130
|
+
/*
|
1131
|
+
*Activates a window, that is, bring it to the front and give it the input focus.
|
1132
|
+
*===Return value
|
1133
|
+
*nil.
|
1134
|
+
*===Raises
|
1135
|
+
*[NotImplementedError] The EWMH standard _NET_ACTIVE_WINDOW is not supported.
|
1136
|
+
*===Example
|
1137
|
+
* Imitator::X::XWindow.from_title(/imitator/).activate
|
1138
|
+
*===Remarks
|
1139
|
+
*This method is part of the EWMH standard _NET_ACTIVE_WINDOW. It's usually more reliable
|
1140
|
+
*than #raise_win combined with #focus.
|
1141
|
+
*/
|
1142
|
+
static VALUE m_activate(VALUE self)
|
1143
|
+
{
|
1144
|
+
Display * p_display;
|
1145
|
+
Window win = GET_WINDOW;
|
1146
|
+
XEvent xevt;
|
1147
|
+
XWindowAttributes xattr;
|
1148
|
+
Window root;
|
1149
|
+
|
1150
|
+
p_display = get_win_display(self);
|
1151
|
+
XSetErrorHandler(handle_x_errors);
|
1152
|
+
|
1153
|
+
check_for_ewmh(p_display, "_NET_ACTIVE_WINDOW");
|
1154
|
+
/*We're going to notify the root window*/
|
1155
|
+
XGetWindowAttributes(p_display, win, &xattr);
|
1156
|
+
root = xattr.root;
|
1157
|
+
|
1158
|
+
xevt.type = ClientMessage; /*It's a message for a client*/
|
1159
|
+
xevt.xclient.display = p_display;
|
1160
|
+
xevt.xclient.window = win;
|
1161
|
+
xevt.xclient.message_type = XInternAtom(p_display, "_NET_ACTIVE_WINDOW", False); /*Activate request*/
|
1162
|
+
xevt.xclient.format = 32; /*Using 32-bit messages*/
|
1163
|
+
xevt.xclient.data.l[0] = 2L;
|
1164
|
+
xevt.xclient.data.l[1] = CurrentTime;
|
1165
|
+
|
1166
|
+
/*Actually send the event; this has to happen to all child windows of the target window. */
|
1167
|
+
XSendEvent(p_display, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &xevt);
|
1168
|
+
|
1169
|
+
XSetErrorHandler(NULL);
|
1170
|
+
XCloseDisplay(p_display);
|
1171
|
+
return Qnil;
|
1172
|
+
}
|
1173
|
+
|
1174
|
+
/*
|
1175
|
+
*Gets a window process' process identification number (PID).
|
1176
|
+
*===Return value
|
1177
|
+
*The PID of the window process.
|
1178
|
+
*===Raises
|
1179
|
+
*[XError] Failed to retrieve the window's PID. Either your window manager does not support EWMH at all, _NET_WM_PID in special, or your queried window hasn't set this property (see _Remarks_).
|
1180
|
+
*===Example
|
1181
|
+
* puts Imitator::X::XWindow.from_title(/imitator/).pid #=> 4478
|
1182
|
+
*===Remarks
|
1183
|
+
*This method is part of the EWMH standard _NET_WM_PID.
|
1184
|
+
*
|
1185
|
+
*This method may fail even if the window manager supports the _NET_WM_PID standard, beacuse
|
1186
|
+
*the use of _NET_WM_PID isn't enforced. Some programs don't use it, and those will cause this
|
1187
|
+
*method to fail. The most prominent example is the default root window, which doesn't have the
|
1188
|
+
*_NET_WM_PID property set (at least on my Ubuntu Karmic).
|
1189
|
+
*/
|
1190
|
+
static VALUE m_pid(VALUE self)
|
1191
|
+
{
|
1192
|
+
Display * p_display;
|
1193
|
+
Window win = GET_WINDOW;
|
1194
|
+
Atom actual_type;
|
1195
|
+
int obtain_prop, actual_format, pid;
|
1196
|
+
unsigned long nitems;
|
1197
|
+
unsigned long bytes;
|
1198
|
+
unsigned char * property;
|
1199
|
+
VALUE result;
|
1200
|
+
|
1201
|
+
p_display = get_win_display(self);
|
1202
|
+
XSetErrorHandler(handle_x_errors);
|
1203
|
+
|
1204
|
+
//check_for_ewmh(p_display, "_NET_WM_PID"); /*For some unknown reason, this always fails*/
|
1205
|
+
obtain_prop = XInternAtom(p_display, "_NET_WM_PID", True);
|
1206
|
+
|
1207
|
+
XGetWindowProperty(p_display, win, obtain_prop, 0, 1000000, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes, &property);
|
1208
|
+
if (property == None)
|
1209
|
+
rb_raise(XError, "Could not get _NET_WM_PID attribute!");
|
1210
|
+
|
1211
|
+
/*OK, got the property. Compute the PID. I don't know why this works, I
|
1212
|
+
*just saw the arithmetic somewhere on the Internet. */
|
1213
|
+
pid = property[1] * 256;
|
1214
|
+
pid += property[0];
|
1215
|
+
result = INT2NUM(pid);
|
1216
|
+
|
1217
|
+
XFree(property);
|
1218
|
+
XSetErrorHandler(NULL);
|
1219
|
+
XCloseDisplay(p_display);
|
1220
|
+
return result;
|
1221
|
+
}
|
1222
|
+
|
1223
|
+
/*
|
1224
|
+
*Requests the X server to destroy +self+.
|
1225
|
+
*===Return value
|
1226
|
+
*nil.
|
1227
|
+
*===Example
|
1228
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
1229
|
+
* xwin.kill
|
1230
|
+
*===Remarks
|
1231
|
+
*This method requests the X server to send a DestroyNotify event to
|
1232
|
+
*+self+. A window may choose not to react on this (although this is quite
|
1233
|
+
*seldom).
|
1234
|
+
*/
|
1235
|
+
static VALUE m_kill(VALUE self)
|
1236
|
+
{
|
1237
|
+
Display * p_display;
|
1238
|
+
Window win = GET_WINDOW;
|
1239
|
+
|
1240
|
+
p_display = get_win_display(self);
|
1241
|
+
XSetErrorHandler(handle_x_errors);
|
1242
|
+
|
1243
|
+
XDestroyWindow(p_display, win);
|
1244
|
+
|
1245
|
+
XSetErrorHandler(NULL);
|
1246
|
+
XCloseDisplay(p_display);
|
1247
|
+
return Qnil;
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
/*
|
1251
|
+
*Forces the X server to close the connection to +self+, effectively
|
1252
|
+
*destroying the window.
|
1253
|
+
*===Return value
|
1254
|
+
*nil.
|
1255
|
+
*===Example
|
1256
|
+
* Imitator::X::XWindow.from_title(/imitator/).kill!
|
1257
|
+
*===Remarks
|
1258
|
+
*From all window closing methods, this should be the most reliable one.
|
1259
|
+
*If a window's connection to the X server was closed, the window's process
|
1260
|
+
*will crash in nearly all cases. Even if not, the window is not usable anymore.
|
1261
|
+
*/
|
1262
|
+
static VALUE m_bang_kill(VALUE self)
|
1263
|
+
{
|
1264
|
+
Display * p_display;
|
1265
|
+
Window win = GET_WINDOW;
|
1266
|
+
|
1267
|
+
p_display = get_win_display(self);
|
1268
|
+
XSetErrorHandler(handle_x_errors);
|
1269
|
+
|
1270
|
+
XKillClient(p_display, win);
|
1271
|
+
|
1272
|
+
XSetErrorHandler(NULL);
|
1273
|
+
XCloseDisplay(p_display);
|
1274
|
+
return Qnil;
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
/*
|
1278
|
+
*call-seq:
|
1279
|
+
* kill_process( [ term = true ] ) ==> nil
|
1280
|
+
*
|
1281
|
+
*Kills a window's process.
|
1282
|
+
*===Parameters
|
1283
|
+
*[+term+] (true) If true, SIGTERM is sent to the window process; if false or nil, SIGKILL is sent.
|
1284
|
+
*===Return value
|
1285
|
+
*nil.
|
1286
|
+
*===Raises
|
1287
|
+
*[XError] _NET_WM_PID is unsupported or the target window does not have the _NET_WM_PID property set.
|
1288
|
+
*===Example
|
1289
|
+
* #Send SIGTERM to a window process
|
1290
|
+
* Imitator::X::XWindow.from_title(/imitator/).kill_process
|
1291
|
+
* #Send SIGKILL to a window process
|
1292
|
+
* Imitator::X::XWindow.from_title(/imitator/).kill_process(false)
|
1293
|
+
*===Remarks
|
1294
|
+
*This method is part of the EWMH standard _NET_WM_PID.
|
1295
|
+
*
|
1296
|
+
*This method is by far the most aggressive variant to destroy a window,
|
1297
|
+
*especially if +term+ is false, but since not every window has set the _NET_WM_PID property,
|
1298
|
+
*it may fail. See also #close, #kill and #kill!, also have a look at #pid.
|
1299
|
+
*/
|
1300
|
+
static VALUE m_kill_process(int argc, VALUE argv[], VALUE self)
|
1301
|
+
{
|
1302
|
+
VALUE rterm;
|
1303
|
+
int signal = SIGTERM;
|
1304
|
+
|
1305
|
+
rb_scan_args(argc, argv, "01", &rterm);
|
1306
|
+
|
1307
|
+
if (rterm == Qfalse || rterm == Qnil)
|
1308
|
+
signal = SIGKILL;
|
1309
|
+
|
1310
|
+
kill(NUM2INT(m_pid(self)), signal);
|
1311
|
+
return Qnil;
|
1312
|
+
}
|
1313
|
+
|
1314
|
+
/*
|
1315
|
+
*Closes +self+ by activating it and then sending [ALT]+[F4].
|
1316
|
+
*===Return value
|
1317
|
+
*nil.
|
1318
|
+
*===Example
|
1319
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
1320
|
+
* xwin.close
|
1321
|
+
*===Remarks
|
1322
|
+
*This method doesn't force a window to close. If you have unsaved data,
|
1323
|
+
*a program may ask you to save instead of closing. Have a look at the
|
1324
|
+
*various kill methods to achieve this.
|
1325
|
+
*/
|
1326
|
+
static VALUE m_close(VALUE self)
|
1327
|
+
{
|
1328
|
+
m_activate(self);
|
1329
|
+
rb_funcall(Keyboard, rb_intern("key"), 1, rb_enc_str_new("Alt+F4", strlen("Alt+F4"), rb_utf8_encoding()));
|
1330
|
+
return Qnil;
|
1331
|
+
}
|
1332
|
+
|
1333
|
+
/*
|
1334
|
+
*Checks weather +self+ exists or not by calling XWindow.exists? with
|
1335
|
+
*the information of this object.
|
1336
|
+
*===Return value
|
1337
|
+
*true or false.
|
1338
|
+
*===Example
|
1339
|
+
* xwin = Imitator::X::XWindow.from_title(/imitator/)
|
1340
|
+
* puts xwin.exists? #=> true
|
1341
|
+
* xwin.kill
|
1342
|
+
* puts xwin.exists? #=> false
|
1343
|
+
*/
|
1344
|
+
static VALUE m_exists(VALUE self)
|
1345
|
+
{
|
1346
|
+
VALUE args[3];
|
1347
|
+
VALUE rmatch_data, screen, display;
|
1348
|
+
|
1349
|
+
rmatch_data = rb_funcall(rb_ivar_get(self, rb_intern("@display_string")), rb_intern("match"), 1, rb_reg_new("\\:(\\d+?)\\.(\\d+?)", strlen("\\:(\\d+?)\\.(\\d+?)"), 0));
|
1350
|
+
display = rb_funcall(rb_reg_nth_match(1, rmatch_data), rb_intern("to_i"), 0);
|
1351
|
+
screen = rb_funcall(rb_reg_nth_match(2, rmatch_data), rb_intern("to_i"), 0);
|
1352
|
+
args[0] = rb_ivar_get(self, rb_intern("@window_id"));
|
1353
|
+
args[1] = screen;
|
1354
|
+
args[2] = display;
|
1355
|
+
return cm_exists(3, args, XWindow);
|
1356
|
+
}
|
1357
|
+
|
1358
|
+
/*
|
1359
|
+
*call-seq:
|
1360
|
+
* xwin.eql?( other_xwin ) ==> true or false
|
1361
|
+
* xwin == other_xwin ==> true or false
|
1362
|
+
*
|
1363
|
+
*Checks wheather or not two XWindow objects are the same. Two
|
1364
|
+
*Xwindow objects are the same if they refer to the same window id.
|
1365
|
+
*===Parameters
|
1366
|
+
*[+other_xwin+] The window to compare with.
|
1367
|
+
*===Return value
|
1368
|
+
*true or false.
|
1369
|
+
*===Example
|
1370
|
+
* xwin1 = Imitator::X::XWindow.from_title(/imitator/)
|
1371
|
+
* xwin2 = Imitator::X::XWindow.from_title(/imitat/)
|
1372
|
+
* xwin3 = Imitator::X::XWindow.from_active
|
1373
|
+
* p xwin.window_id #=> 69206019
|
1374
|
+
* p xwin2.window_id #=> 69206019
|
1375
|
+
* p xwin3.window_id #=> 73401172
|
1376
|
+
* p(xwin1 == xwin2) #=> true
|
1377
|
+
* p(xwin1 == xwin3) #=> false
|
1378
|
+
*/
|
1379
|
+
static VALUE m_is_equal_to(VALUE self, VALUE other)
|
1380
|
+
{
|
1381
|
+
VALUE self_id = rb_ivar_get(self, rb_intern("@window_id"));
|
1382
|
+
VALUE other_id = rb_ivar_get(other, rb_intern("@window_id"));
|
1383
|
+
|
1384
|
+
return rb_funcall(self_id, rb_intern("=="), 1, other_id);
|
1385
|
+
}
|
1386
|
+
/***********************Init-Function*******************************/
|
1387
|
+
|
1388
|
+
void Init_xwindow(void)
|
1389
|
+
{
|
1390
|
+
XWindow = rb_define_class_under(X, "XWindow", rb_cObject);
|
1391
|
+
|
1392
|
+
rb_define_singleton_method(XWindow, "default_root_window", cm_default_root_window, 0);
|
1393
|
+
rb_define_singleton_method(XWindow, "exists?", cm_exists, -1);
|
1394
|
+
rb_define_singleton_method(XWindow, "xquery", cm_xquery, 2); /* :nodoc: */
|
1395
|
+
rb_define_singleton_method(XWindow, "search", cm_search, -1);
|
1396
|
+
rb_define_singleton_method(XWindow, "from_title", cm_from_title, -1);
|
1397
|
+
rb_define_singleton_method(XWindow, "from_focused", cm_from_focused, -1);
|
1398
|
+
rb_define_singleton_method(XWindow, "from_active", cm_from_active, -1);
|
1399
|
+
rb_define_singleton_method(XWindow, "wait_for_window", cm_wait_for_window, -1);
|
1400
|
+
rb_define_singleton_method(XWindow, "wait_for_window_termination", cm_wait_for_window_termination, -1);
|
1401
|
+
|
1402
|
+
rb_define_method(XWindow, "initialize", m_initialize, -1);
|
1403
|
+
rb_define_method(XWindow, "inspect", m_inspect, 0);
|
1404
|
+
rb_define_method(XWindow, "title", m_title, 0);
|
1405
|
+
rb_define_method(XWindow, "window_id", m_window_id, 0);
|
1406
|
+
rb_define_method(XWindow, "root_win", m_root_win, 0);
|
1407
|
+
rb_define_method(XWindow, "parent", m_parent, 0);
|
1408
|
+
rb_define_method(XWindow, "children", m_children, 0);
|
1409
|
+
rb_define_method(XWindow, "root_win?", m_is_root_win, 0);
|
1410
|
+
rb_define_method(XWindow, "position", m_position, 0);
|
1411
|
+
rb_define_method(XWindow, "size", m_size, 0);
|
1412
|
+
rb_define_method(XWindow, "visible?", m_is_visible, 0);
|
1413
|
+
rb_define_method(XWindow, "mapped?", m_is_mapped, 0);
|
1414
|
+
rb_define_method(XWindow, "move", m_move, 2);
|
1415
|
+
rb_define_method(XWindow, "resize", m_resize, 2);
|
1416
|
+
rb_define_method(XWindow, "raise_win", m_raise_win, 0);
|
1417
|
+
rb_define_method(XWindow, "focus", m_focus, 0);
|
1418
|
+
rb_define_method(XWindow, "unfocus", m_unfocus, 0);
|
1419
|
+
rb_define_method(XWindow, "map", m_map, 0);
|
1420
|
+
rb_define_method(XWindow, "unmap", m_unmap, 0);
|
1421
|
+
rb_define_method(XWindow, "activate", m_activate, 0);
|
1422
|
+
rb_define_method(XWindow, "pid", m_pid, 0);
|
1423
|
+
rb_define_method(XWindow, "kill", m_kill, 0);
|
1424
|
+
rb_define_method(XWindow, "kill!", m_bang_kill, 0);
|
1425
|
+
rb_define_method(XWindow, "kill_process", m_kill_process, -1);
|
1426
|
+
rb_define_method(XWindow, "close", m_close, 0);
|
1427
|
+
rb_define_method(XWindow, "exists?", m_exists, 0);
|
1428
|
+
rb_define_method(XWindow, "eql?", m_is_equal_to, 1);
|
1429
|
+
|
1430
|
+
rb_define_alias(XWindow, "to_s", "title");
|
1431
|
+
rb_define_alias(XWindow, "to_i", "window_id");
|
1432
|
+
rb_define_alias(XWindow, "pos", "position");
|
1433
|
+
rb_define_alias(XWindow, "==", "eql?");
|
1434
|
+
}
|