source: trunk/xdotool/xdo.c @ 1087

Last change on this file since 1087 was 1087, checked in by dkg, 5 years ago

xdotool: packaged version 20080603

File size: 23.7 KB
Line 
1/* xdo library
2 *
3 * $Id: xdo.c 1891 2008-06-03 09:00:20Z jordansissel $
4 *
5 * - getwindowfocus contributed by Lee Pumphret
6 * - keysequence_{up,down} contributed by Magnus Boman
7 *
8 */
9
10#define _XOPEN_SOURCE 500
11#include <sys/select.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15#include <strings.h>
16#include <unistd.h>
17#include <regex.h>
18
19#include <X11/Xlib.h>
20#include <X11/Xresource.h>
21#include <X11/Xutil.h>
22#include <X11/extensions/XTest.h>
23
24#include "xdo.h"
25#include "xdo_util.h"
26
27static void _xdo_populate_charcode_map(xdo_t *xdo);
28static int _xdo_has_xtest(xdo_t *xdo);
29
30static int _xdo_keycode_from_char(xdo_t *xdo, char key);
31static int _xdo_get_shiftcode_if_needed(xdo_t *xdo, char key);
32
33static void _xdo_get_child_windows(xdo_t *xdo, Window window,
34                                   Window **total_window_list, 
35                                   int *ntotal_windows, 
36                                   int *window_list_size);
37
38static int _xdo_keysequence_to_keycode_list(xdo_t *xdo, char *keyseq, int **keys, int *nkeys);
39static int _xdo_keysequence_do(xdo_t *xdo, char *keyseq, int pressed);
40static int _xdo_regex_match_window(xdo_t *xdo, Window window, int flags, regex_t *re);
41static int _xdo_is_window_visible(xdo_t *xdo, Window wid);
42static unsigned char * _xdo_getwinprop(xdo_t *xdo, Window window, Atom atom,
43                                       long *nitems, Atom *type, int *size);
44static int _xdo_ewmh_is_supported(xdo_t *xdo, const char *feature);
45
46static int _is_success(const char *funcname, int code);
47
48/* context-free functions */
49char _keysym_to_char(char *keysym);
50
51xdo_t* xdo_new(char *display_name) {
52  Display *xdpy;
53
54  if ((xdpy = XOpenDisplay(display_name)) == NULL) {
55    fprintf(stderr, "Error: Can't open display: %s\n", display_name);
56    return NULL;
57  }
58
59  return xdo_new_with_opened_display(xdpy, display_name, 1);
60}
61
62xdo_t* xdo_new_with_opened_display(Display *xdpy, const char *display,
63                                   int close_display_when_freed) {
64  xdo_t *xdo = NULL;
65
66  if (xdpy == NULL) {
67    fprintf(stderr, "xdo_new: xdisplay I was given is a null pointer\n");
68    return NULL;
69  }
70
71  /* XXX: Check for NULL here */
72  xdo = malloc(sizeof(xdo_t));
73  memset(xdo, 0, sizeof(xdo_t));
74
75  xdo->xdpy = xdpy;
76  xdo->close_display_when_freed = close_display_when_freed;
77
78  if (display == NULL)
79    display = "unknown";
80
81  if (!_xdo_has_xtest(xdo)) {
82    fprintf(stderr, "Error: XTEST extension unavailable on '%s'.", 
83            xdo->display_name);
84    xdo_free(xdo);
85    return NULL;
86  }
87
88  /* populate the character map? */
89  _xdo_populate_charcode_map(xdo);
90
91  return xdo;
92}
93
94void xdo_free(xdo_t *xdo) {
95  if (xdo->display_name)
96    free(xdo->display_name);
97  if (xdo->charcodes)
98    free(xdo->charcodes);
99  if (xdo->xdpy && xdo->close_display_when_freed)
100    XCloseDisplay(xdo->xdpy);
101  free(xdo);
102}
103
104int xdo_window_map(xdo_t *xdo, Window wid) {
105  int ret;
106  ret = XMapWindow(xdo->xdpy, wid);
107  XFlush(xdo->xdpy);
108  return _is_success("XMapWindow", ret == 0);
109}
110
111int xdo_window_unmap(xdo_t *xdo, Window wid) {
112  int ret;
113  ret = XUnmapWindow(xdo->xdpy, wid);
114  XFlush(xdo->xdpy);
115  return _is_success("XUnmapWindow", ret == 0);
116}
117
118int xdo_window_list_by_regex(xdo_t *xdo, char *regex, int flags,
119                              Window **windowlist, int *nwindows) {
120  regex_t re;
121  Window *total_window_list = NULL;
122  int ntotal_windows = 0;
123  int window_list_size = 0;
124  int matched_window_list_size = 100;
125
126  int ret;
127  int i;
128
129  ret = regcomp(&re, regex, REG_EXTENDED | REG_ICASE);
130  if (ret != 0) {
131    fprintf(stderr, "Failed to compile regex: '%s'\n", regex);
132    return 1;
133  }
134
135  /* Default search settings:
136   * All windows (visible and hidden) and search all text pieces
137   */
138  if ((flags & (SEARCH_TITLE | SEARCH_CLASS | SEARCH_NAME)) == 0) {
139    fprintf(stderr, "No text fields specified for regex search. \nDefaulting to"
140            " window title, class, and name searching\n");
141    flags |= SEARCH_TITLE | SEARCH_CLASS | SEARCH_NAME;
142  }
143
144  *nwindows = 0;
145  *windowlist = malloc(matched_window_list_size * sizeof(Window));
146
147  _xdo_get_child_windows(xdo, RootWindow(xdo->xdpy, 0),
148                         &total_window_list, &ntotal_windows,
149                         &window_list_size);
150  for (i = 0; i < ntotal_windows; i++) {
151    Window wid = total_window_list[i];
152    if (flags & SEARCH_VISIBLEONLY && !_xdo_is_window_visible(xdo, wid))
153      continue;
154    if (!_xdo_regex_match_window(xdo, wid, flags, &re))
155      continue;
156
157    (*windowlist)[*nwindows] = wid;
158    (*nwindows)++;
159
160    if (matched_window_list_size == *nwindows) {
161      matched_window_list_size *= 2;
162      *windowlist = realloc(*windowlist, 
163                            matched_window_list_size * sizeof(Window));
164    }
165  }
166
167  regfree(&re);
168  return 0;
169}
170
171int xdo_window_move(xdo_t *xdo, Window wid, int x, int y) {
172  XWindowChanges wc;
173  int ret;
174  wc.x = x;
175  wc.y = y;
176
177  ret = XConfigureWindow(xdo->xdpy, wid, CWX | CWY, &wc);
178  return _is_success("XConfigureWindow", ret == 0);
179}
180
181int xdo_window_setsize(xdo_t *xdo, Window wid, int width, int height, int flags) {
182  XWindowChanges wc;
183  int ret;
184  int cw_flags = 0;
185
186  wc.width = width;
187  wc.height = height;
188
189  if (flags & SIZE_USEHINTS) {
190    XSizeHints hints;
191    long supplied_return;
192    memset(&hints, 0, sizeof(hints));
193    XGetWMNormalHints(xdo->xdpy, wid, &hints, &supplied_return);
194    if (supplied_return & PResizeInc) {
195      wc.width *= hints.width_inc;
196      wc.height *= hints.height_inc;
197    } else {
198      fprintf(stderr, "No size hints found for this window\n");
199    }
200
201    if (supplied_return & PBaseSize) {
202      wc.width += hints.base_width;
203      wc.height += hints.base_height;
204    }
205
206  }
207
208  if (width > 0)
209    cw_flags |= CWWidth;
210  if (height > 0)
211    cw_flags |= CWHeight;
212
213  ret = XConfigureWindow(xdo->xdpy, wid, cw_flags, &wc);
214  XFlush(xdo->xdpy);
215  return _is_success("XConfigureWindow", ret == 0);
216}
217
218int xdo_window_focus(xdo_t *xdo, Window wid) {
219  int ret;
220  ret = XSetInputFocus(xdo->xdpy, wid, RevertToParent, CurrentTime);
221  XFlush(xdo->xdpy);
222  return _is_success("XSetInputFocus", ret == 0);
223}
224
225int xdo_window_activate(xdo_t *xdo, Window wid) {
226  int ret;
227  long desktop = 0;
228  XEvent xev;
229  XWindowAttributes wattr;
230
231  if (_xdo_ewmh_is_supported(xdo, "_NET_ACTIVE_WINDOW") == False) {
232    fprintf(stderr,
233            "Your windowmanager claims not to support _NET_ACTIVE_WINDOW, "
234            "so the attempt to activate the window was aborted.\n");
235    return 1;
236  }
237
238  /* If this window is on another desktop, let's go to that desktop first */
239
240  if (_xdo_ewmh_is_supported(xdo, "_NET_WM_DESKTOP") == True
241      && _xdo_ewmh_is_supported(xdo, "_NET_CURRENT_DESKTOP") == True) {
242    xdo_get_desktop_for_window(xdo, wid, &desktop);
243    xdo_set_current_desktop(xdo, desktop);
244  }
245
246  memset(&xev, 0, sizeof(xev));
247  xev.type = ClientMessage;
248  xev.xclient.display = xdo->xdpy;
249  xev.xclient.window = wid;
250  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_ACTIVE_WINDOW", False);
251  xev.xclient.format = 32;
252  xev.xclient.data.l[0] = 2L; /* 2 == Message from a window pager */
253  xev.xclient.data.l[1] = CurrentTime;
254
255  XGetWindowAttributes(xdo->xdpy, wid, &wattr);
256  ret = XSendEvent(xdo->xdpy, wattr.screen->root, False,
257                   SubstructureNotifyMask | SubstructureRedirectMask,
258                   &xev);
259
260  /* XXX: XSendEvent returns 0 on conversion failure, nonzero otherwise.
261   * Manpage says it will only generate BadWindow or BadValue errors */
262  printf("netact:%d\n", ret);
263  return _is_success("XSendEvent[EWMH:_NET_ACTIVE_WINDOW]", ret == 0);
264}
265
266int xdo_set_number_of_desktops(xdo_t *xdo, long ndesktops) {
267  /* XXX: This should support passing a screen number */
268  XEvent xev;
269  Window root;
270  int ret;
271
272  if (_xdo_ewmh_is_supported(xdo, "_NET_NUMBER_OF_DESKTOPS") == False) {
273    fprintf(stderr,
274            "Your windowmanager claims not to support _NET_NUMBER_OF_DESKTOPS, "
275            "so the attempt to change the number of desktops was aborted.\n");
276    return 1;
277  }
278
279  root = RootWindow(xdo->xdpy, 0);
280
281  memset(&xev, 0, sizeof(xev));
282  xev.type = ClientMessage;
283  xev.xclient.display = xdo->xdpy;
284  xev.xclient.window = root;
285  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_NUMBER_OF_DESKTOPS", 
286                                         False);
287  xev.xclient.format = 32;
288  xev.xclient.data.l[0] = ndesktops;
289
290  ret = XSendEvent(xdo->xdpy, root, False,
291                   SubstructureNotifyMask | SubstructureRedirectMask,
292                   &xev);
293
294  return _is_success("XSendEvent[EWMH:_NET_NUMBER_OF_DESKTOPS]", ret == 0);
295}
296
297int xdo_get_number_of_desktops(xdo_t *xdo, long *ndesktops) {
298  Atom type;
299  int size;
300  long nitems;
301  unsigned char *data;
302  Window root;
303  Atom request;
304
305  if (_xdo_ewmh_is_supported(xdo, "_NET_NUMBER_OF_DESKTOPS") == False) {
306    fprintf(stderr,
307            "Your windowmanager claims not to support _NET_NUMBER_OF_DESKTOPS, "
308            "so the attempt to query the number of desktops was aborted.\n");
309    return 1;
310  }
311
312  request = XInternAtom(xdo->xdpy, "_NET_NUMBER_OF_DESKTOPS", False);
313  root = XDefaultRootWindow(xdo->xdpy);
314
315  data = _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
316
317  if (nitems > 0)
318    *ndesktops = *((long*)data);
319  else
320    *ndesktops = 0;
321
322  return _is_success("XGetWindowProperty[_NET_NUMBER_OF_DESKTOPS]",
323                     *ndesktops == 0);
324
325}
326
327int xdo_set_current_desktop(xdo_t *xdo, long desktop) {
328  /* XXX: This should support passing a screen number */
329  XEvent xev;
330  Window root;
331  int ret;
332
333  root = RootWindow(xdo->xdpy, 0);
334
335  if (_xdo_ewmh_is_supported(xdo, "_NET_CURRENT_DESKTOP") == False) {
336    fprintf(stderr,
337            "Your windowmanager claims not to support _NET_CURRENT_DESKTOP, "
338            "so the attempt to change desktops was aborted.\n");
339    return 1;
340  }
341
342  memset(&xev, 0, sizeof(xev));
343  xev.type = ClientMessage;
344  xev.xclient.display = xdo->xdpy;
345  xev.xclient.window = root;
346  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_CURRENT_DESKTOP", 
347                                         False);
348  xev.xclient.format = 32;
349  xev.xclient.data.l[0] = desktop;
350  xev.xclient.data.l[1] = CurrentTime;
351
352  ret = XSendEvent(xdo->xdpy, root, False,
353                   SubstructureNotifyMask | SubstructureRedirectMask,
354                   &xev);
355
356  return _is_success("XSendEvent[EWMH:_NET_CURRENT_DESKTOP]", ret == 0);
357}
358
359int xdo_get_current_desktop(xdo_t *xdo, long *desktop) {
360  Atom type;
361  int size;
362  long nitems;
363  unsigned char *data;
364  Window root;
365
366  Atom request;
367
368  if (_xdo_ewmh_is_supported(xdo, "_NET_CURRENT_DESKTOP") == False) {
369    fprintf(stderr,
370            "Your windowmanager claims not to support _NET_CURRENT_DESKTOP, "
371            "so the query for the current desktop was aborted.\n");
372    return 1;
373  }
374
375  request = XInternAtom(xdo->xdpy, "_NET_CURRENT_DESKTOP", False);
376  root = XDefaultRootWindow(xdo->xdpy);
377
378  data = _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
379
380  if (nitems > 0)
381    *desktop = *((long*)data);
382  else
383    *desktop = -1;
384
385  return _is_success("XGetWindowProperty[_NET_CURRENT_DESKTOP]",
386                     *desktop == -1);
387}
388
389int xdo_set_desktop_for_window(xdo_t *xdo, Window wid, long desktop) {
390  XEvent xev;
391  int ret;
392  XWindowAttributes wattr;
393  XGetWindowAttributes(xdo->xdpy, wid, &wattr);
394
395  if (_xdo_ewmh_is_supported(xdo, "_NET_WM_DESKTOP") == False) {
396    fprintf(stderr,
397            "Your windowmanager claims not to support _NET_WM_DESKTOP, "
398            "so the attempt to change a window's desktop location was "
399            "aborted.\n");
400    return 1;
401  }
402
403  memset(&xev, 0, sizeof(xev));
404  xev.type = ClientMessage;
405  xev.xclient.display = xdo->xdpy;
406  xev.xclient.window = wid;
407  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_WM_DESKTOP", 
408                                         False);
409  xev.xclient.format = 32;
410  xev.xclient.data.l[0] = desktop;
411  xev.xclient.data.l[1] = 2; /* indicate we are messaging from a pager */
412
413  ret = XSendEvent(xdo->xdpy, wattr.screen->root, False,
414                   SubstructureNotifyMask | SubstructureRedirectMask,
415                   &xev);
416
417  return _is_success("XSendEvent[EWMH:_NET_WM_DESKTOP]", ret == 0);
418}
419
420int xdo_get_desktop_for_window(xdo_t *xdo, Window wid, long *desktop) {
421  Atom type;
422  int size;
423  long nitems;
424  unsigned char *data;
425  Atom request;
426
427  if (_xdo_ewmh_is_supported(xdo, "_NET_WM_DESKTOP") == False) {
428    fprintf(stderr,
429            "Your windowmanager claims not to support _NET_WM_DESKTOP, "
430            "so the attempt to query a window's desktop location was "
431            "aborted.\n");
432    return 1;
433  }
434
435  request = XInternAtom(xdo->xdpy, "_NET_WM_DESKTOP", False);
436
437  data = _xdo_getwinprop(xdo, wid, request, &nitems, &type, &size);
438
439  if (nitems > 0)
440    *desktop = *((long*)data);
441  else
442    *desktop = -1;
443
444  return _is_success("XGetWindowProperty[_NET_WM_DESKTOP]",
445                     *desktop == -1);
446}
447
448/* XRaiseWindow is ignored in ion3 and Gnome2. Is it even useful? */
449int xdo_window_raise(xdo_t *xdo, Window wid) {
450  int ret;
451  ret = XRaiseWindow(xdo->xdpy, wid);
452  XFlush(xdo->xdpy);
453  return _is_success("XRaiseWindow", ret);
454}
455
456/* XXX: Include 'screen number' support? */
457int xdo_mousemove(xdo_t *xdo, int x, int y)  {
458  int ret;
459  ret = XTestFakeMotionEvent(xdo->xdpy, -1, x, y, CurrentTime);
460  XFlush(xdo->xdpy);
461  return _is_success("XTestFakeMotionEvent", ret == 0);
462}
463
464int xdo_mousemove_relative(xdo_t *xdo, int x, int y)  {
465  int ret;
466  ret = XTestFakeRelativeMotionEvent(xdo->xdpy, x, y, CurrentTime);
467  XFlush(xdo->xdpy);
468  return _is_success("XTestFakeRelativeMotionEvent", ret == 0);
469}
470
471int xdo_mousedown(xdo_t *xdo, int button) {
472  int ret;
473  ret = XTestFakeButtonEvent(xdo->xdpy, button, True, CurrentTime);
474  XFlush(xdo->xdpy);
475  return _is_success("XTestFakeButtonEvent(down)", ret == 0);
476}
477
478int xdo_mouseup(xdo_t *xdo, int button) {
479  int ret;
480  ret = XTestFakeButtonEvent(xdo->xdpy, button, False, CurrentTime);
481  XFlush(xdo->xdpy);
482  return _is_success("XTestFakeButtonEvent(up)", ret == 0);
483}
484
485int xdo_click(xdo_t *xdo, int button) {
486  int ret;
487  ret = xdo_mousedown(xdo, button);
488  if (ret)
489    return ret;
490  ret = xdo_mouseup(xdo, button);
491  return ret;
492}
493
494/* XXX: Return proper code if errors found */
495int xdo_type(xdo_t *xdo, char *string) {
496  int i = 0;
497  char key = '0';
498  int keycode = 0;
499  int shiftcode = 0;
500
501  /* XXX: Add error handling */
502  for (i = 0; string[i] != '\0'; i++) {
503    key = string[i];
504    keycode = _xdo_keycode_from_char(xdo, key);
505    shiftcode = _xdo_get_shiftcode_if_needed(xdo, key);
506
507    if (shiftcode)
508      XTestFakeKeyEvent(xdo->xdpy, shiftcode, True, CurrentTime);
509    XTestFakeKeyEvent(xdo->xdpy, keycode, True, CurrentTime);
510    XTestFakeKeyEvent(xdo->xdpy, keycode, False, CurrentTime);
511    if (shiftcode)
512      XTestFakeKeyEvent(xdo->xdpy, shiftcode, False, CurrentTime);
513
514    /* XXX: Flush here or at the end? */
515    XFlush(xdo->xdpy);
516  }
517
518  return 0;
519}
520
521int _xdo_keysequence_do(xdo_t *xdo, char *keyseq, int pressed) {
522  int ret = 0;
523  int *keys = NULL;
524  int nkeys;
525  int i;
526
527  if (_xdo_keysequence_to_keycode_list(xdo, keyseq, &keys, &nkeys) == False) {
528    fprintf(stderr, "Failure converting key sequence '%s' to keycodes\n", keyseq);
529    return False;
530  }
531
532  for (i = 0; i < nkeys; i++) {
533    ret += !XTestFakeKeyEvent(xdo->xdpy, keys[i], pressed, CurrentTime);
534  }
535
536  free(keys);
537  XFlush(xdo->xdpy);
538  return ret;
539}
540 
541int xdo_keysequence_down(xdo_t *xdo, char *keyseq) {
542  return _xdo_keysequence_do(xdo, keyseq, True);
543}
544
545int xdo_keysequence_up(xdo_t *xdo, char *keyseq) {
546  return _xdo_keysequence_do(xdo, keyseq, False);
547}
548
549int xdo_keysequence(xdo_t *xdo, char *keyseq) {
550  int ret;
551  ret += _xdo_keysequence_do(xdo, keyseq, True);
552  ret += _xdo_keysequence_do(xdo, keyseq, False);
553  return ret;
554}
555
556/* Add by Lee Pumphret 2007-07-28
557 * Modified slightly by Jordan Sissel */
558int xdo_window_get_focus(xdo_t *xdo, Window *window_ret) {
559  int ret;
560  int unused_revert_ret;
561  ret = XGetInputFocus(xdo->xdpy, window_ret, &unused_revert_ret);
562  return _is_success("XGetInputFocus", ret == 0);
563}
564
565/* Helper functions */
566static int _xdo_keycode_from_char(xdo_t *xdo, char key) {
567  int i = 0;
568  int len = xdo->keycode_high - xdo->keycode_low;
569
570  for (i = 0; i < len; i++)
571    if (xdo->charcodes[i].key == key)
572      return xdo->charcodes[i].code;
573
574  return -1;
575}
576
577static int _xdo_get_shiftcode_if_needed(xdo_t *xdo, char key) {
578  int i = 0;
579  int len = xdo->keycode_high - xdo->keycode_low;
580
581  for (i = 0; i < len; i++)
582    if (xdo->charcodes[i].key == key)
583      return xdo->charcodes[i].shift;
584
585  return -1;
586}
587
588static int _xdo_has_xtest(xdo_t *xdo) {
589  int dummy;
590  return (XTestQueryExtension(xdo->xdpy, &dummy, &dummy, &dummy, &dummy) == True);
591}
592
593static void _xdo_populate_charcode_map(xdo_t *xdo) {
594  /* assert xdo->display is valid */
595  int keycodes_length = 0;
596  int shift_keycode = 0;
597  int i, j;
598
599  XDisplayKeycodes(xdo->xdpy, &(xdo->keycode_low), &(xdo->keycode_high));
600
601  /* Double size of keycode range because some
602   * keys have "shift" values. ie; 'a' and 'A', '2' and '@' */
603  /* Add 2 to the size because the range [low, high] is inclusive */
604  keycodes_length = (xdo->keycode_high - xdo->keycode_low) * 2 + 2;
605  xdo->charcodes = malloc(keycodes_length * sizeof(charcodemap_t));
606  memset(xdo->charcodes, 0, keycodes_length * sizeof(charcodemap_t));
607
608  /* Fetch the keycode for Shift_L */
609  /* XXX: Make 'Shift_L' configurable? */
610  shift_keycode = XKeysymToKeycode(xdo->xdpy, XStringToKeysym("Shift_L"));
611
612  for (i = xdo->keycode_low; i <= xdo->keycode_high; i++) {
613    char *keybuf = 0;
614
615    /* Index '0' in KeycodeToKeysym == no shift key
616     * Index '1' in ... == shift key held
617     * hence this little loop. */
618    for (j = 0; j <= 1; j++) { 
619     int idx = (i - xdo->keycode_low) * 2 + j;
620     keybuf = XKeysymToString(XKeycodeToKeysym(xdo->xdpy, i, j));
621
622     xdo->charcodes[idx].key = _keysym_to_char(keybuf);
623     xdo->charcodes[idx].code = i;
624     xdo->charcodes[idx].shift = j ? shift_keycode : 0;
625    }
626  }
627}
628
629/* context-free functions */
630char _keysym_to_char(char *keysym) {
631  int i;
632
633  if (keysym == NULL)
634    return -1;
635
636  /* keysymcharmap comes from xdo_util.h */
637  for (i = 0; keysymcharmap[i].keysym; i++) {
638    if (!strcmp(keysymcharmap[i].keysym, keysym))
639      return keysymcharmap[i].key;
640  }
641
642  if (strlen(keysym) == 1)
643    return keysym[0];
644
645  return -1;
646}
647
648  /* regexec(&re, string, 0, NULL, 0) == 0 means MATCH */
649
650static void _xdo_get_child_windows(xdo_t *xdo, Window window,
651                                   Window **total_window_list, 
652                                   int *ntotal_windows,
653                                   int *window_list_size) {
654  Window dummy;
655  Window *children;
656  unsigned int i, nchildren;
657
658  if (*window_list_size == 0) {
659    *ntotal_windows = 0;
660    *window_list_size = 100;
661    *total_window_list = malloc(*window_list_size * sizeof(Window));
662  }
663
664  /* foo */
665  if (!XQueryTree(xdo->xdpy, window, &dummy, &dummy, &children, &nchildren))
666    return;
667
668  for (i = 0; i < nchildren; i++) {
669    Window w = children[i];
670    (*total_window_list)[*ntotal_windows] = w;
671    *ntotal_windows += 1;
672    if (*ntotal_windows == *window_list_size) {
673      *window_list_size *= 2;
674      *total_window_list = realloc(*total_window_list,
675                                   *window_list_size * sizeof(Window));
676    }
677    _xdo_get_child_windows(xdo, w, total_window_list,
678                           ntotal_windows, window_list_size);
679  }
680
681  XFree(children);
682}
683
684int _xdo_keysequence_to_keycode_list(xdo_t *xdo, char *keyseq, int **keys, int *nkeys) {
685  char *tokctx = NULL;
686  const char *tok = NULL;
687  char *strptr = NULL;
688  int i;
689 
690  /* Array of keys to press, in order given by keyseq */
691  int keys_size = 10;
692  *nkeys = 0;
693
694  if (strcspn(keyseq, " \t\n.-[]{}\\|") != strlen(keyseq)) {
695    fprintf(stderr, "Error: Invalid key sequence '%s'\n", keyseq);
696    return False;
697  }
698
699  *keys = malloc(keys_size * sizeof(int));
700  strptr = strdup(keyseq);
701  while ((tok = strtok_r(strptr, "+", &tokctx)) != NULL) {
702    int keysym;
703    if (strptr != NULL)
704      strptr = NULL;
705
706    /* Check if 'tok' (string keysym) is an alias to another key */
707    /* symbol_map comes from xdo.util */
708    for (i = 0; symbol_map[i] != NULL; i+=2)
709      if (!strcasecmp(tok, symbol_map[i]))
710        tok = symbol_map[i + 1];
711
712    keysym = XStringToKeysym(tok);
713    if (keysym == NoSymbol) {
714      fprintf(stderr, "(symbol) No such key name '%s'. Ignoring it.\n", tok);
715      continue;
716    }
717
718    (*keys)[*nkeys] = XKeysymToKeycode(xdo->xdpy, keysym);
719
720    if ((*keys)[*nkeys] == 0) {
721      fprintf(stderr, "No such key '%s'. Ignoring it.\n", tok);
722      continue;
723    }
724
725    (*nkeys)++;
726    if (*nkeys == keys_size) {
727      keys_size *= 2;
728      *keys = realloc(*keys, keys_size);
729    }
730  }
731
732  free(strptr);
733
734  return True;
735}
736
737int _xdo_regex_match_window(xdo_t *xdo, Window window, int flags, regex_t *re) {
738  XWindowAttributes attr;
739  XTextProperty tp;
740  XClassHint classhint;
741  int i;
742
743  XGetWindowAttributes(xdo->xdpy, window, &attr);
744
745  /* XXX: Memory leak here according to valgrind? */
746  XGetWMName(xdo->xdpy, window, &tp);
747
748  if (flags & SEARCH_TITLE) {
749    if (tp.nitems > 0) {
750      int count = 0;
751      char **list = NULL;
752      XmbTextPropertyToTextList(xdo->xdpy, &tp, &list, &count);
753      for (i = 0; i < count; i++) {
754        if (regexec(re, list[i], 0, NULL, 0) == 0) {
755          XFreeStringList(list);
756          return True;
757        }
758        XFreeStringList(list);
759      }
760    }
761  }
762
763  if (XGetClassHint(xdo->xdpy, window, &classhint)) {
764    if ((flags & SEARCH_NAME) && classhint.res_name) {
765      if (regexec(re, classhint.res_name, 0, NULL, 0) == 0) {
766        XFree(classhint.res_name);
767        XFree(classhint.res_class);
768        return True;
769      }
770      XFree(classhint.res_name);
771    }
772    if ((flags & SEARCH_CLASS) && classhint.res_class) {
773      if (regexec(re, classhint.res_class, 0, NULL, 0) == 0) {
774        XFree(classhint.res_class);
775        return True;
776      }
777      XFree(classhint.res_class);
778    }
779  }
780  return False;
781}
782
783int _is_success(const char *funcname, int code) {
784  if (code != 0)
785    fprintf(stderr, "%s failed (code=%d)\n", funcname, code);
786  return code;
787}
788
789int _xdo_is_window_visible(xdo_t *xdo, Window wid) {
790  XWindowAttributes wattr;
791
792  XGetWindowAttributes(xdo->xdpy, wid, &wattr);
793  if (wattr.map_state != IsViewable)
794    return False;
795
796  return True;
797}
798
799/* Arbitrary window property retrieval
800 * slightly modified version from xprop.c from Xorg */
801unsigned char * _xdo_getwinprop(xdo_t *xdo, Window window, Atom atom,
802                                long *nitems, Atom *type, int *size) {
803  Atom actual_type;
804  int actual_format;
805  unsigned long _nitems;
806  unsigned long nbytes;
807  unsigned long bytes_after; /* unused */
808  unsigned char *prop;
809  int status;
810
811  status = XGetWindowProperty(xdo->xdpy, window, atom, 0, (~0L),
812                              False, AnyPropertyType, &actual_type,
813                              &actual_format, &_nitems, &bytes_after,
814                              &prop);
815  if (status == BadWindow) {
816    fprintf(stderr, "window id # 0x%lx does not exists!", window);
817    return NULL;
818  } if (status != Success) {
819    fprintf(stderr, "XGetWindowProperty failed!");
820    return NULL;
821  }
822
823  if (actual_format == 32)
824    nbytes = sizeof(long);
825  else if (actual_format == 16)
826    nbytes = sizeof(short);
827  else if (actual_format == 8)
828    nbytes = 1;
829  else if (actual_format == 0)
830    nbytes = 0;
831
832  *nitems = _nitems;
833  *type = actual_type;
834  *size = actual_format;
835  return prop;
836}
837
838int _xdo_ewmh_is_supported(xdo_t *xdo, const char *feature) {
839  Atom type = 0;
840  long nitems = 0L;
841  int size = 0;
842  Atom *results = NULL;
843  long i = 0;
844
845  Window root;
846  Atom request;
847  Atom feature_atom;
848 
849  request = XInternAtom(xdo->xdpy, "_NET_SUPPORTED", False);
850  feature_atom = XInternAtom(xdo->xdpy, feature, False);
851  root = RootWindow(xdo->xdpy, 0);
852
853  results = (Atom *) _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
854  for (i = 0L; i < nitems; i++) {
855    if (results[i] == feature_atom)
856      return True;
857  }
858
859  return False;
860}
Note: See TracBrowser for help on using the repository browser.