source: branches/upstream/xdotool/current/xdo.c @ 1077

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

[svn-upgrade] Integrating new upstream version, xdotool (20080601)

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