source: trunk/xdotool/xdo.c @ 1092

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

xdotool: merging changes for 20080606

File size: 23.6 KB
Line 
1/* xdo library
2 *
3 * $Id: xdo.c 1917 2008-06-06 06:59:27Z 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  return _is_success("XSendEvent[EWMH:_NET_ACTIVE_WINDOW]", ret == 0);
263}
264
265int xdo_set_number_of_desktops(xdo_t *xdo, long ndesktops) {
266  /* XXX: This should support passing a screen number */
267  XEvent xev;
268  Window root;
269  int ret;
270
271  if (_xdo_ewmh_is_supported(xdo, "_NET_NUMBER_OF_DESKTOPS") == False) {
272    fprintf(stderr,
273            "Your windowmanager claims not to support _NET_NUMBER_OF_DESKTOPS, "
274            "so the attempt to change the number of desktops was aborted.\n");
275    return 1;
276  }
277
278  root = RootWindow(xdo->xdpy, 0);
279
280  memset(&xev, 0, sizeof(xev));
281  xev.type = ClientMessage;
282  xev.xclient.display = xdo->xdpy;
283  xev.xclient.window = root;
284  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_NUMBER_OF_DESKTOPS", 
285                                         False);
286  xev.xclient.format = 32;
287  xev.xclient.data.l[0] = ndesktops;
288
289  ret = XSendEvent(xdo->xdpy, root, False,
290                   SubstructureNotifyMask | SubstructureRedirectMask,
291                   &xev);
292
293  return _is_success("XSendEvent[EWMH:_NET_NUMBER_OF_DESKTOPS]", ret == 0);
294}
295
296int xdo_get_number_of_desktops(xdo_t *xdo, long *ndesktops) {
297  Atom type;
298  int size;
299  long nitems;
300  unsigned char *data;
301  Window root;
302  Atom request;
303
304  if (_xdo_ewmh_is_supported(xdo, "_NET_NUMBER_OF_DESKTOPS") == False) {
305    fprintf(stderr,
306            "Your windowmanager claims not to support _NET_NUMBER_OF_DESKTOPS, "
307            "so the attempt to query the number of desktops was aborted.\n");
308    return 1;
309  }
310
311  request = XInternAtom(xdo->xdpy, "_NET_NUMBER_OF_DESKTOPS", False);
312  root = XDefaultRootWindow(xdo->xdpy);
313
314  data = _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
315
316  if (nitems > 0)
317    *ndesktops = *((long*)data);
318  else
319    *ndesktops = 0;
320
321  return _is_success("XGetWindowProperty[_NET_NUMBER_OF_DESKTOPS]",
322                     *ndesktops == 0);
323
324}
325
326int xdo_set_current_desktop(xdo_t *xdo, long desktop) {
327  /* XXX: This should support passing a screen number */
328  XEvent xev;
329  Window root;
330  int ret;
331
332  root = RootWindow(xdo->xdpy, 0);
333
334  if (_xdo_ewmh_is_supported(xdo, "_NET_CURRENT_DESKTOP") == False) {
335    fprintf(stderr,
336            "Your windowmanager claims not to support _NET_CURRENT_DESKTOP, "
337            "so the attempt to change desktops was aborted.\n");
338    return 1;
339  }
340
341  memset(&xev, 0, sizeof(xev));
342  xev.type = ClientMessage;
343  xev.xclient.display = xdo->xdpy;
344  xev.xclient.window = root;
345  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_CURRENT_DESKTOP", 
346                                         False);
347  xev.xclient.format = 32;
348  xev.xclient.data.l[0] = desktop;
349  xev.xclient.data.l[1] = CurrentTime;
350
351  ret = XSendEvent(xdo->xdpy, root, False,
352                   SubstructureNotifyMask | SubstructureRedirectMask,
353                   &xev);
354
355  return _is_success("XSendEvent[EWMH:_NET_CURRENT_DESKTOP]", ret == 0);
356}
357
358int xdo_get_current_desktop(xdo_t *xdo, long *desktop) {
359  Atom type;
360  int size;
361  long nitems;
362  unsigned char *data;
363  Window root;
364
365  Atom request;
366
367  if (_xdo_ewmh_is_supported(xdo, "_NET_CURRENT_DESKTOP") == False) {
368    fprintf(stderr,
369            "Your windowmanager claims not to support _NET_CURRENT_DESKTOP, "
370            "so the query for the current desktop was aborted.\n");
371    return 1;
372  }
373
374  request = XInternAtom(xdo->xdpy, "_NET_CURRENT_DESKTOP", False);
375  root = XDefaultRootWindow(xdo->xdpy);
376
377  data = _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
378
379  if (nitems > 0)
380    *desktop = *((long*)data);
381  else
382    *desktop = -1;
383
384  return _is_success("XGetWindowProperty[_NET_CURRENT_DESKTOP]",
385                     *desktop == -1);
386}
387
388int xdo_set_desktop_for_window(xdo_t *xdo, Window wid, long desktop) {
389  XEvent xev;
390  int ret;
391  XWindowAttributes wattr;
392  XGetWindowAttributes(xdo->xdpy, wid, &wattr);
393
394  if (_xdo_ewmh_is_supported(xdo, "_NET_WM_DESKTOP") == False) {
395    fprintf(stderr,
396            "Your windowmanager claims not to support _NET_WM_DESKTOP, "
397            "so the attempt to change a window's desktop location was "
398            "aborted.\n");
399    return 1;
400  }
401
402  memset(&xev, 0, sizeof(xev));
403  xev.type = ClientMessage;
404  xev.xclient.display = xdo->xdpy;
405  xev.xclient.window = wid;
406  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_WM_DESKTOP", 
407                                         False);
408  xev.xclient.format = 32;
409  xev.xclient.data.l[0] = desktop;
410  xev.xclient.data.l[1] = 2; /* indicate we are messaging from a pager */
411
412  ret = XSendEvent(xdo->xdpy, wattr.screen->root, False,
413                   SubstructureNotifyMask | SubstructureRedirectMask,
414                   &xev);
415
416  return _is_success("XSendEvent[EWMH:_NET_WM_DESKTOP]", ret == 0);
417}
418
419int xdo_get_desktop_for_window(xdo_t *xdo, Window wid, long *desktop) {
420  Atom type;
421  int size;
422  long nitems;
423  unsigned char *data;
424  Atom request;
425
426  if (_xdo_ewmh_is_supported(xdo, "_NET_WM_DESKTOP") == False) {
427    fprintf(stderr,
428            "Your windowmanager claims not to support _NET_WM_DESKTOP, "
429            "so the attempt to query a window's desktop location was "
430            "aborted.\n");
431    return 1;
432  }
433
434  request = XInternAtom(xdo->xdpy, "_NET_WM_DESKTOP", False);
435
436  data = _xdo_getwinprop(xdo, wid, request, &nitems, &type, &size);
437
438  if (nitems > 0)
439    *desktop = *((long*)data);
440  else
441    *desktop = -1;
442
443  return _is_success("XGetWindowProperty[_NET_WM_DESKTOP]",
444                     *desktop == -1);
445}
446
447/* XRaiseWindow is ignored in ion3 and Gnome2. Is it even useful? */
448int xdo_window_raise(xdo_t *xdo, Window wid) {
449  int ret;
450  ret = XRaiseWindow(xdo->xdpy, wid);
451  XFlush(xdo->xdpy);
452  return _is_success("XRaiseWindow", ret == 0);
453}
454
455/* XXX: Include 'screen number' support? */
456int xdo_mousemove(xdo_t *xdo, int x, int y)  {
457  int ret;
458  ret = XTestFakeMotionEvent(xdo->xdpy, -1, x, y, CurrentTime);
459  XFlush(xdo->xdpy);
460  return _is_success("XTestFakeMotionEvent", ret == 0);
461}
462
463int xdo_mousemove_relative(xdo_t *xdo, int x, int y)  {
464  int ret;
465  ret = XTestFakeRelativeMotionEvent(xdo->xdpy, x, y, CurrentTime);
466  XFlush(xdo->xdpy);
467  return _is_success("XTestFakeRelativeMotionEvent", ret == 0);
468}
469
470int xdo_mousedown(xdo_t *xdo, int button) {
471  int ret;
472  ret = XTestFakeButtonEvent(xdo->xdpy, button, True, CurrentTime);
473  XFlush(xdo->xdpy);
474  return _is_success("XTestFakeButtonEvent(down)", ret == 0);
475}
476
477int xdo_mouseup(xdo_t *xdo, int button) {
478  int ret;
479  ret = XTestFakeButtonEvent(xdo->xdpy, button, False, CurrentTime);
480  XFlush(xdo->xdpy);
481  return _is_success("XTestFakeButtonEvent(up)", ret == 0);
482}
483
484int xdo_click(xdo_t *xdo, int button) {
485  int ret;
486  ret = xdo_mousedown(xdo, button);
487  if (ret)
488    return ret;
489  ret = xdo_mouseup(xdo, button);
490  return ret;
491}
492
493/* XXX: Return proper code if errors found */
494int xdo_type(xdo_t *xdo, char *string) {
495  int i = 0;
496  char key = '0';
497  int keycode = 0;
498  int shiftcode = 0;
499
500  /* XXX: Add error handling */
501  for (i = 0; string[i] != '\0'; i++) {
502    key = string[i];
503    keycode = _xdo_keycode_from_char(xdo, key);
504    shiftcode = _xdo_get_shiftcode_if_needed(xdo, key);
505
506    if (shiftcode)
507      XTestFakeKeyEvent(xdo->xdpy, shiftcode, True, CurrentTime);
508    XTestFakeKeyEvent(xdo->xdpy, keycode, True, CurrentTime);
509    XTestFakeKeyEvent(xdo->xdpy, keycode, False, CurrentTime);
510    if (shiftcode)
511      XTestFakeKeyEvent(xdo->xdpy, shiftcode, False, CurrentTime);
512
513    /* XXX: Flush here or at the end? */
514    XFlush(xdo->xdpy);
515  }
516
517  return 0;
518}
519
520int _xdo_keysequence_do(xdo_t *xdo, char *keyseq, int pressed) {
521  int ret = 0;
522  int *keys = NULL;
523  int nkeys;
524  int i;
525
526  if (_xdo_keysequence_to_keycode_list(xdo, keyseq, &keys, &nkeys) == False) {
527    fprintf(stderr, "Failure converting key sequence '%s' to keycodes\n", keyseq);
528    return False;
529  }
530
531  for (i = 0; i < nkeys; i++) {
532    ret += !XTestFakeKeyEvent(xdo->xdpy, keys[i], pressed, CurrentTime);
533  }
534
535  free(keys);
536  XFlush(xdo->xdpy);
537  return ret;
538}
539 
540int xdo_keysequence_down(xdo_t *xdo, char *keyseq) {
541  return _xdo_keysequence_do(xdo, keyseq, True);
542}
543
544int xdo_keysequence_up(xdo_t *xdo, char *keyseq) {
545  return _xdo_keysequence_do(xdo, keyseq, False);
546}
547
548int xdo_keysequence(xdo_t *xdo, char *keyseq) {
549  int ret;
550  ret += _xdo_keysequence_do(xdo, keyseq, True);
551  ret += _xdo_keysequence_do(xdo, keyseq, False);
552  return ret;
553}
554
555/* Add by Lee Pumphret 2007-07-28
556 * Modified slightly by Jordan Sissel */
557int xdo_window_get_focus(xdo_t *xdo, Window *window_ret) {
558  int ret;
559  int unused_revert_ret;
560  ret = XGetInputFocus(xdo->xdpy, window_ret, &unused_revert_ret);
561  return _is_success("XGetInputFocus", ret == 0);
562}
563
564/* Helper functions */
565static int _xdo_keycode_from_char(xdo_t *xdo, char key) {
566  int i = 0;
567  int len = xdo->keycode_high - xdo->keycode_low;
568
569  for (i = 0; i < len; i++)
570    if (xdo->charcodes[i].key == key)
571      return xdo->charcodes[i].code;
572
573  return -1;
574}
575
576static int _xdo_get_shiftcode_if_needed(xdo_t *xdo, char key) {
577  int i = 0;
578  int len = xdo->keycode_high - xdo->keycode_low;
579
580  for (i = 0; i < len; i++)
581    if (xdo->charcodes[i].key == key)
582      return xdo->charcodes[i].shift;
583
584  return -1;
585}
586
587static int _xdo_has_xtest(xdo_t *xdo) {
588  int dummy;
589  return (XTestQueryExtension(xdo->xdpy, &dummy, &dummy, &dummy, &dummy) == True);
590}
591
592static void _xdo_populate_charcode_map(xdo_t *xdo) {
593  /* assert xdo->display is valid */
594  int keycodes_length = 0;
595  int shift_keycode = 0;
596  int i, j;
597
598  XDisplayKeycodes(xdo->xdpy, &(xdo->keycode_low), &(xdo->keycode_high));
599
600  /* Double size of keycode range because some
601   * keys have "shift" values. ie; 'a' and 'A', '2' and '@' */
602  /* Add 2 to the size because the range [low, high] is inclusive */
603  keycodes_length = (xdo->keycode_high - xdo->keycode_low) * 2 + 2;
604  xdo->charcodes = malloc(keycodes_length * sizeof(charcodemap_t));
605  memset(xdo->charcodes, 0, keycodes_length * sizeof(charcodemap_t));
606
607  /* Fetch the keycode for Shift_L */
608  /* XXX: Make 'Shift_L' configurable? */
609  shift_keycode = XKeysymToKeycode(xdo->xdpy, XStringToKeysym("Shift_L"));
610
611  for (i = xdo->keycode_low; i <= xdo->keycode_high; i++) {
612    char *keybuf = 0;
613
614    /* Index '0' in KeycodeToKeysym == no shift key
615     * Index '1' in ... == shift key held
616     * hence this little loop. */
617    for (j = 0; j <= 1; j++) { 
618     int idx = (i - xdo->keycode_low) * 2 + j;
619     keybuf = XKeysymToString(XKeycodeToKeysym(xdo->xdpy, i, j));
620
621     xdo->charcodes[idx].key = _keysym_to_char(keybuf);
622     xdo->charcodes[idx].code = i;
623     xdo->charcodes[idx].shift = j ? shift_keycode : 0;
624    }
625  }
626}
627
628/* context-free functions */
629char _keysym_to_char(char *keysym) {
630  int i;
631
632  if (keysym == NULL)
633    return -1;
634
635  /* keysymcharmap comes from xdo_util.h */
636  for (i = 0; keysymcharmap[i].keysym; i++) {
637    if (!strcmp(keysymcharmap[i].keysym, keysym))
638      return keysymcharmap[i].key;
639  }
640
641  if (strlen(keysym) == 1)
642    return keysym[0];
643
644  return -1;
645}
646
647  /* regexec(&re, string, 0, NULL, 0) == 0 means MATCH */
648
649static void _xdo_get_child_windows(xdo_t *xdo, Window window,
650                                   Window **total_window_list, 
651                                   int *ntotal_windows,
652                                   int *window_list_size) {
653  Window dummy;
654  Window *children;
655  unsigned int i, nchildren;
656
657  if (*window_list_size == 0) {
658    *ntotal_windows = 0;
659    *window_list_size = 100;
660    *total_window_list = malloc(*window_list_size * sizeof(Window));
661  }
662
663  /* foo */
664  if (!XQueryTree(xdo->xdpy, window, &dummy, &dummy, &children, &nchildren))
665    return;
666
667  for (i = 0; i < nchildren; i++) {
668    Window w = children[i];
669    (*total_window_list)[*ntotal_windows] = w;
670    *ntotal_windows += 1;
671    if (*ntotal_windows == *window_list_size) {
672      *window_list_size *= 2;
673      *total_window_list = realloc(*total_window_list,
674                                   *window_list_size * sizeof(Window));
675    }
676    _xdo_get_child_windows(xdo, w, total_window_list,
677                           ntotal_windows, window_list_size);
678  }
679
680  XFree(children);
681}
682
683int _xdo_keysequence_to_keycode_list(xdo_t *xdo, char *keyseq, int **keys, int *nkeys) {
684  char *tokctx = NULL;
685  const char *tok = NULL;
686  char *strptr = NULL;
687  int i;
688 
689  /* Array of keys to press, in order given by keyseq */
690  int keys_size = 10;
691  *nkeys = 0;
692
693  if (strcspn(keyseq, " \t\n.-[]{}\\|") != strlen(keyseq)) {
694    fprintf(stderr, "Error: Invalid key sequence '%s'\n", keyseq);
695    return False;
696  }
697
698  *keys = malloc(keys_size * sizeof(int));
699  strptr = strdup(keyseq);
700  while ((tok = strtok_r(strptr, "+", &tokctx)) != NULL) {
701    int keysym;
702    if (strptr != NULL)
703      strptr = NULL;
704
705    /* Check if 'tok' (string keysym) is an alias to another key */
706    /* symbol_map comes from xdo.util */
707    for (i = 0; symbol_map[i] != NULL; i+=2)
708      if (!strcasecmp(tok, symbol_map[i]))
709        tok = symbol_map[i + 1];
710
711    keysym = XStringToKeysym(tok);
712    if (keysym == NoSymbol) {
713      fprintf(stderr, "(symbol) No such key name '%s'. Ignoring it.\n", tok);
714      continue;
715    }
716
717    (*keys)[*nkeys] = XKeysymToKeycode(xdo->xdpy, keysym);
718
719    if ((*keys)[*nkeys] == 0) {
720      fprintf(stderr, "No such key '%s'. Ignoring it.\n", tok);
721      continue;
722    }
723
724    (*nkeys)++;
725    if (*nkeys == keys_size) {
726      keys_size *= 2;
727      *keys = realloc(*keys, keys_size);
728    }
729  }
730
731  free(strptr);
732
733  return True;
734}
735
736int _xdo_regex_match_window(xdo_t *xdo, Window window, int flags, regex_t *re) {
737  XWindowAttributes attr;
738  XTextProperty tp;
739  XClassHint classhint;
740  int i;
741
742  XGetWindowAttributes(xdo->xdpy, window, &attr);
743
744  /* XXX: Memory leak here according to valgrind? */
745  XGetWMName(xdo->xdpy, window, &tp);
746
747  if (flags & SEARCH_TITLE) {
748    if (tp.nitems > 0) {
749      int count = 0;
750      char **list = NULL;
751      XmbTextPropertyToTextList(xdo->xdpy, &tp, &list, &count);
752      for (i = 0; i < count; i++) {
753        if (regexec(re, list[i], 0, NULL, 0) == 0) {
754          XFreeStringList(list);
755          return True;
756        }
757        XFreeStringList(list);
758      }
759    }
760  }
761
762  if (XGetClassHint(xdo->xdpy, window, &classhint)) {
763    if ((flags & SEARCH_NAME) && classhint.res_name) {
764      if (regexec(re, classhint.res_name, 0, NULL, 0) == 0) {
765        XFree(classhint.res_name);
766        XFree(classhint.res_class);
767        return True;
768      }
769      XFree(classhint.res_name);
770    }
771    if ((flags & SEARCH_CLASS) && classhint.res_class) {
772      if (regexec(re, classhint.res_class, 0, NULL, 0) == 0) {
773        XFree(classhint.res_class);
774        return True;
775      }
776      XFree(classhint.res_class);
777    }
778  }
779  return False;
780}
781
782int _is_success(const char *funcname, int code) {
783  if (code != 0)
784    fprintf(stderr, "%s failed (code=%d)\n", funcname, code);
785  return code;
786}
787
788int _xdo_is_window_visible(xdo_t *xdo, Window wid) {
789  XWindowAttributes wattr;
790
791  XGetWindowAttributes(xdo->xdpy, wid, &wattr);
792  if (wattr.map_state != IsViewable)
793    return False;
794
795  return True;
796}
797
798/* Arbitrary window property retrieval
799 * slightly modified version from xprop.c from Xorg */
800unsigned char * _xdo_getwinprop(xdo_t *xdo, Window window, Atom atom,
801                                long *nitems, Atom *type, int *size) {
802  Atom actual_type;
803  int actual_format;
804  unsigned long _nitems;
805  unsigned long nbytes;
806  unsigned long bytes_after; /* unused */
807  unsigned char *prop;
808  int status;
809
810  status = XGetWindowProperty(xdo->xdpy, window, atom, 0, (~0L),
811                              False, AnyPropertyType, &actual_type,
812                              &actual_format, &_nitems, &bytes_after,
813                              &prop);
814  if (status == BadWindow) {
815    fprintf(stderr, "window id # 0x%lx does not exists!", window);
816    return NULL;
817  } if (status != Success) {
818    fprintf(stderr, "XGetWindowProperty failed!");
819    return NULL;
820  }
821
822  if (actual_format == 32)
823    nbytes = sizeof(long);
824  else if (actual_format == 16)
825    nbytes = sizeof(short);
826  else if (actual_format == 8)
827    nbytes = 1;
828  else if (actual_format == 0)
829    nbytes = 0;
830
831  *nitems = _nitems;
832  *type = actual_type;
833  *size = actual_format;
834  return prop;
835}
836
837int _xdo_ewmh_is_supported(xdo_t *xdo, const char *feature) {
838  Atom type = 0;
839  long nitems = 0L;
840  int size = 0;
841  Atom *results = NULL;
842  long i = 0;
843
844  Window root;
845  Atom request;
846  Atom feature_atom;
847 
848  request = XInternAtom(xdo->xdpy, "_NET_SUPPORTED", False);
849  feature_atom = XInternAtom(xdo->xdpy, feature, False);
850  root = RootWindow(xdo->xdpy, 0);
851
852  results = (Atom *) _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
853  for (i = 0L; i < nitems; i++) {
854    if (results[i] == feature_atom)
855      return True;
856  }
857
858  return False;
859}
Note: See TracBrowser for help on using the repository browser.