added a Makefile to use it as a C library. no python dependencies. added 2 example...
[rofl0r-libxauto.git] / src / xaut_window.c
blob088e5fa15fbb0c6cabd941c1f8c1e3f477079839
1 /***************************************************************************
2 * Copyright (C) 2009 by Chris Parker *
3 * chrsprkr3@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the Python License version 2.5 or later. *
7 * *
8 * This program is distributed in the hope that it will be useful, *
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
11 ***************************************************************************/
14 $URL$
15 $Author$
16 $Date$
17 $Rev$
20 #include <X11/extensions/XTest.h>
21 #include <regex.h>
23 #include "xaut.h"
25 BOOL activate_window(Window win) {
26 char *event_name = "_NET_ACTIVE_WINDOW";
27 if (!_check_init() || win < 1) {
28 return FALSE;
30 if (!_is_supported_feature("_NET_ACTIVE_WINDOW")) {
31 fprintf(stderr, "Cannot use '_NET_ACTIVE_WINDOW', "
32 "so it is impossible to activate the window "
33 "using this function. Try alt-tabbing to it instead.");
35 long win_desk = window_desktop(win);
36 if (win_desk < 0) {
37 return FALSE;
39 long current_desktop = get_current_desktop();
40 if (win_desk != current_desktop) {
41 BOOL switched = set_current_desktop(win_desk);
42 if (!switched) {
43 return FALSE;
46 XEvent event;
47 memset(&event, 0, sizeof(XEvent));
48 event.xclient.display = defaults->display;
49 event.xclient.window = win;
50 event.xclient.format = 32;
52 //Toggling _NET_ACTIVE_WINDOW (event_name) with no other changes activates
53 event.xclient.data.l[0] = 2L; //We want to toggle the setting
54 event.xclient.data.l[1] = CurrentTime; //Now
55 event.xclient.data.l[2] = 0L; //These two flags are redundantly
56 event.xclient.data.l[3] = 0L; //saying "no other changes"
57 event.xclient.message_type =
58 XInternAtom(defaults->display, event_name, FALSE);
60 event.type = ClientMessage;
61 event.xclient.display = defaults->display;
62 event.xclient.window = win;
63 XWindowAttributes wattr;
64 XGetWindowAttributes(defaults->display, win, &wattr );
65 long mask = SubstructureNotifyMask | SubstructureRedirectMask;
66 Status status =
67 XSendEvent(defaults->display, wattr.screen->root , FALSE, mask, &event);
68 XFlush(defaults->display);
69 return (status != 0);
72 Window active_window() {
73 if (!_check_init()) {
74 return 0;
76 Window win = 0;
77 int focus_state_ignored = 0;
78 int success = XGetInputFocus(defaults->display, &win, &focus_state_ignored);
79 Window ret = 0;
80 if (success) {
81 ret = win;
83 return ret;
86 int _is_not_valid_error_handler(Display *dsp, XErrorEvent *err) {
87 return 0;
90 BOOL is_valid(Window win) {
91 _check_init();
92 XSetErrorHandler(_is_not_valid_error_handler);
93 XWindowAttributes attribs;
94 Status status = XGetWindowAttributes( defaults->display, win, &attribs);
95 XSetErrorHandler(NULL);
96 return status ? TRUE : FALSE;
99 Window find_outer_parent(Window win) {
100 Window root_return;
101 Window parent_return;
102 Window *children_return_ignored;
103 unsigned int num_children_return_ignored;
105 Status status = XQueryTree(
106 defaults->display,
107 win,
108 &root_return,
109 &parent_return,
110 &children_return_ignored,
111 &num_children_return_ignored
113 if(!status) {
114 fprintf(stderr, "Something went wrong trying to find parent\n");
115 return 0;
117 if(root_return == parent_return) {
118 return win;
119 } else if(parent_return > root_return) {
120 return find_outer_parent(parent_return);
121 } else {
122 fprintf(stderr, "Somehow missed the parent, returning null\n");
123 return 0;
127 Window find_window(char *title) {
128 if(! _check_init()) {
129 fprintf(stderr, "Failure to initialize");
130 return 0;
132 regex_t *regx = calloc(1, sizeof(regex_t));
133 if (!regx) {
134 fprintf(stderr, "Unable to allocate space for a regular expression");
135 return 0;
137 if (!_prepare_regex(title, &regx)) {
138 return 0;
140 unsigned long count;
141 Atom type_ret;
142 long offset = 0L;
143 long length = (~0L);
144 BOOL delete = FALSE;
145 int format_ret;
146 Window bytes_after;
147 unsigned char *results;
149 int prop_ret_val = XGetWindowProperty(
150 defaults->display,
151 XDefaultRootWindow(defaults->display),
152 XInternAtom(defaults->display, "_NET_CLIENT_LIST", FALSE),
153 offset,
154 length,
155 delete,
156 XA_WINDOW,
157 &type_ret,
158 &format_ret,
159 &count,
160 &bytes_after,
161 &results
163 if(prop_ret_val != Success) {
164 XFree(results);
165 fprintf(stderr, "XGetWindowProperty returned %d", prop_ret_val);
166 return 0;
168 unsigned long i;
169 Window *windows = (Window *)results;
170 Window *match_buffer = calloc(count, sizeof(Window)); //A safe size...
171 if(!match_buffer) {
172 fprintf(stderr, "Unable to allocate space for a window buffer\n");
173 XFree(results);
174 return 0;
176 unsigned int found = 0;
177 for(i = 0; i < count; i++) {
178 char *win_title = window_name(windows[i]);
179 logit(LOG_LEVEL_EXTRA_VERBOSE, "Testing to see if '%s' matches '%s'\n",
180 title, win_title);
181 if (win_title && !regexec(regx, win_title, 0, NULL, 0)) {
182 logit(LOG_LEVEL_VERBOSE, "Adding '%s' as a match\n", win_title);
183 match_buffer[found] = windows[i];
184 found++;
186 free(win_title);
188 Window final_ret = 0;
189 if(found == 0) {
190 logit(LOG_LEVEL_VERBOSE, "No matches found for '%s'\n", title);
191 } else if(found == 1) {
192 logit(LOG_LEVEL_VERBOSE, "Only one match found for '%s'\n", title);
193 final_ret = match_buffer[0];
194 } else {
195 logit(LOG_LEVEL_VERBOSE, "%d matches found for '%s'\n", found, title);
196 qsort(match_buffer, found, sizeof(Window), _window_search_comparator);
197 final_ret = match_buffer[0];
199 regfree(regx);
200 free(regx);
201 XFree(results);
202 free(match_buffer);
203 return final_ret;
206 Window* search_for_window(char *title) {
207 if(! _check_init()) {
208 fprintf(stderr, "Failure to initialize");
209 return 0;
211 regex_t *regx = calloc(1, sizeof(regex_t));
212 if (!regx) {
213 fprintf(stderr, "Unable to allocate space for a regular expression");
214 return 0;
216 if (!_prepare_regex(title, &regx)) {
217 return 0;
219 _window_search *search = calloc(1, sizeof(_window_search));
220 if (!search) {
221 fprintf(stderr, "Unable to allocate space for a buffer");
222 return 0;
224 search->buffer = calloc(10, sizeof(Window));
225 if (!search->buffer) {
226 fprintf(stderr, "Unable to allocate space for a buffer");
227 return 0;
229 search->buffer_size = 10;
230 search->current = XDefaultRootWindow(defaults->display);
231 search->found = 0;
232 search->title = title;
233 search->regx = &regx;
234 XSetErrorHandler(_invalid_window_error_handler);
235 _recursive_window_search(search);
236 XSetErrorHandler(NULL);
237 if(search->found == 0) {
238 logit(LOG_LEVEL_VERBOSE, "No matches found for '%s'\n", title);
239 } else if(search->found == 1) {
240 logit(LOG_LEVEL_VERBOSE, "Only one match found for '%s'\n", title);
241 } else {
242 logit(LOG_LEVEL_EXTRA_VERBOSE, "%d matches found for '%s'\n",
243 search->found, title);
244 qsort(search->buffer, search->found, sizeof(Window),
245 _window_search_comparator);
247 Window* ret = calloc(search->found + 1, sizeof(Window));
248 if(ret == NULL) {
249 fprintf(stderr, "Unable to allocate space for the retured windows");
250 } else {
251 unsigned int i;
252 for(i = 0; i < search->found; i++) {
253 ret[i] = search->buffer[i];
255 ret[search->found] = 0;
257 regfree(regx);
258 free(regx);
259 free(search->buffer);
260 free(search);
261 return ret;
264 BOOL move_window(Window win, int x, int y, long desktop) {
265 if(is_valid(win) == FALSE) {
266 fprintf(stderr, "Window %lu is invalid\n", win);
267 return FALSE;
269 if ((x < 0) && (y < 0) && (desktop < 0)) {
270 //Why am I being called?
271 fprintf(stderr, "All movement parameters were -1\nNothing to do\n");
272 return TRUE;
274 BOOL moved = _move_window_to_desktop(win, desktop);
275 if(moved == FALSE) {
276 fprintf(stderr, "Unable to move window %lu to desktop %lu\n",
277 win, desktop);
279 if((x < 0) && (y < 0)) {
280 logit(LOG_LEVEL_VERBOSE, "%s",
281 "Leaving window at it's current x y coordinates\n");
282 return TRUE;
283 } else if(x < 0) {
284 logit(LOG_LEVEL_EXTRA_VERBOSE, "%s",
285 "Using current window x coordinate as its destination\n");
286 x = window_x(win);
287 } else if(y < 0) {
288 logit(LOG_LEVEL_EXTRA_VERBOSE, "%s",
289 "Using current window y coordinate as its destination\n");
290 y = window_y(win);
292 logit(LOG_LEVEL_VERBOSE, "Moving window %lu to %d X %d\n", win, x, y);
293 XMoveWindow(defaults->display, win, x, y);
294 XFlush(defaults->display);
295 return TRUE;
298 BOOL iconify_window(Window win, BOOL tf) {
299 if(!_check_init() || win < 1) {
300 return FALSE;
302 if(is_valid(win) == FALSE) {
303 fprintf(stderr, "Window %lu is invalid\n", win);
304 return FALSE;
306 if(!_is_supported_feature("_NET_WM_ACTION_MINIMIZE")) {
307 fprintf(stderr, "Apparently that window cannot be minimized\n");
308 return FALSE;
311 Status status;
312 XSetErrorHandler(_invalid_window_error_handler);
313 XWindowAttributes attribs;
314 status = XGetWindowAttributes(
315 defaults->display,
316 win,
317 &attribs);
318 if(!status) {
319 fprintf(stderr, "%lu is not a valid window handle", win);
320 return FALSE;
322 if(tf) {
323 int screen = XScreenNumberOfScreen(attribs.screen);
324 status = XIconifyWindow(defaults->display, win, screen);
325 } else {
326 XMapWindow(defaults->display, win);
328 XFlush(defaults->display);
330 XSetErrorHandler(NULL);
331 return (status != 0);
334 BOOL minimize_window(Window win, BOOL tf) {
335 return iconify_window(win, tf);
338 BOOL maximize_window(Window win, BOOL tf) {
339 return(maximize_window_horz(win, tf) &&
340 maximize_window_vert(win, tf));
343 BOOL maximize_window_horz(Window win, BOOL tf) {
344 if(is_valid(win) == FALSE) {
345 fprintf(stderr, "Window %lu is invalid\n", win);
346 return FALSE;
348 char *horz = "_NET_WM_STATE_MAXIMIZED_HORZ";
349 if(!_check_init() || win < 1) {
350 return FALSE;
352 if(!_is_supported_feature(horz)) {
353 fprintf(stderr, "Apparently that window can't be"
354 " maximized horizontally" );
355 return FALSE;
357 Atom datal1 = XInternAtom(defaults->display, horz, FALSE);
358 Atom datal2 = 0;
359 long action = (tf) ? 1 : 0; //1 means "set", 0 means "clear" flag
360 return _alter_window_state(win, action, datal1, datal2);
363 BOOL maximize_window_vert(Window win, BOOL tf) {
364 if(is_valid(win) == FALSE) {
365 fprintf(stderr, "Window %lu is invalid\n", win);
366 return FALSE;
368 char *vert = "_NET_WM_STATE_MAXIMIZED_VERT";
369 if(!_check_init() || win < 1) {
370 return FALSE;
372 if (!_is_supported_feature(vert)) {
373 fprintf(stderr, "Apparently that window can't be"
374 " maximized vertically" );
375 return FALSE;
377 Atom datal1 = XInternAtom(defaults->display, vert, FALSE);
378 Atom datal2 = 0;
379 long action = (tf) ? 1 : 0; //1 means "set", 0 means "clear" flag
380 return _alter_window_state(win, action, datal1, datal2);
383 BOOL full_screen_window(Window win, BOOL tf) {
384 if(is_valid(win) == FALSE) {
385 fprintf(stderr, "Window %lu is invalid\n", win);
386 return FALSE;
388 char *full = "_NET_WM_STATE_FULLSCREEN";
389 if(!_check_init() || win < 1) {
390 return FALSE;
392 if(!_is_supported_feature(full)) {
393 fprintf(stderr, "Apparently that window can't be made full screen" );
395 Atom datal1 = XInternAtom(defaults->display, full, FALSE);
396 long action = (tf) ? 1 : 0; //1 means "set", 0 means "clear" flag
397 return _alter_window_state(win, action, datal1, 0);
400 BOOL shade_window(Window win, BOOL tf) {
401 if(is_valid(win) == FALSE) {
402 fprintf(stderr, "Window %lu is invalid\n", win);
403 return FALSE;
405 char *shade = "_NET_WM_STATE_SHADED";
406 if(!_check_init() || win < 1) {
407 return FALSE;
409 if(!_is_supported_feature(shade)) {
410 fprintf(stderr, "Apparently that window can't be shaded" );
412 Atom datal1 = XInternAtom(defaults->display, shade, FALSE);
413 long action = (tf) ? 1 : 0; //1 means "set", 0 means "clear" flag
414 return _alter_window_state(win, action, datal1, 0);
417 BOOL restore_window(Window win) {
418 if(is_valid(win) == FALSE) {
419 fprintf(stderr, "Window %lu is invalid\n", win);
420 return FALSE;
422 char *vert = "_NET_WM_STATE_MAXIMIZED_VERT";
423 char *horz = "_NET_WM_STATE_MAXIMIZED_HORZ";
424 char *shade = "_NET_WM_STATE_SHADED";
425 char *full = "_NET_WM_STATE_FULLSCREEN";
426 if(!_check_init() || win < 1) {
427 return FALSE;
429 BOOL ret = 0;
430 long action = 0; //Remove the bit
431 if(_is_supported_feature(shade)) {
432 Atom datal1 = XInternAtom(defaults->display, shade, FALSE);
433 ret |= _alter_window_state(win, action, datal1, 0);
435 if(_is_supported_feature(vert)) {
436 Atom datal1 = XInternAtom(defaults->display, vert, FALSE);
437 ret |= _alter_window_state(win, action, datal1, 0);
439 if(_is_supported_feature(horz)) {
440 Atom datal1 = XInternAtom(defaults->display, horz, FALSE);
441 ret |= _alter_window_state(win, action, datal1, 0);
443 if(_is_supported_feature(full)) {
444 Atom datal1 = XInternAtom(defaults->display, full, FALSE);
445 ret |= _alter_window_state(win, action, datal1, 0);
447 XMapWindow(defaults->display, win);
448 XFlush(defaults->display);
449 return ret;
452 int window_x(Window win) {
453 if (!_check_init()) {
454 return INT_MIN;
456 if(is_valid(win) == FALSE) {
457 fprintf(stderr, "Window %lu is invalid\n", win);
458 return INT_MIN;
460 Window parent = find_outer_parent(win);
461 if(!parent) {
462 return INT_MIN;
464 XWindowAttributes attribs;
465 int status = XGetWindowAttributes(defaults->display, parent, &attribs);
466 int ret = -1;
467 if (status) {
468 int junk_y = 0; //Y coordinate not used here
469 Window junk_win;
470 (void) XTranslateCoordinates(
471 defaults->display,
472 parent,
473 attribs.root,
474 -attribs.border_width,
475 -attribs.border_width,
476 &ret,
477 &junk_y,
478 &junk_win);
479 } else {
480 fprintf(stderr,"Unable to retrieve x attribute for %lu\n", win);
482 return ret;
485 int window_y(Window win) {
486 if (!_check_init()) {
487 return INT_MIN;
489 if(is_valid(win) == FALSE) {
490 fprintf(stderr, "Window %lu is invalid\n", win);
491 return INT_MIN;
493 Window parent = find_outer_parent(win);
494 if(!parent) {
495 return INT_MIN;
497 XWindowAttributes attribs;
498 int status = XGetWindowAttributes(defaults->display, parent, &attribs);
499 int ret = -1;
500 if (status) {
501 int junk_x = 0; //X coordinate not used here
502 Window junk_win;
503 (void) XTranslateCoordinates(
504 defaults->display,
505 parent,
506 attribs.root,
507 -attribs.border_width,
508 -attribs.border_width,
509 &junk_x,
510 &ret,
511 &junk_win);
512 } else {
513 fprintf(stderr,"Unable to retrieve y attribute for %lu\n", win);
515 return ret;
518 int window_w(Window win) {
519 if (!_check_init()) {
520 return INT_MIN;
522 if(is_valid(win) == FALSE) {
523 fprintf(stderr, "Window %lu is invalid\n", win);
524 return INT_MIN;
526 Window parent = find_outer_parent(win);
527 if(!parent) {
528 return INT_MIN;
530 XWindowAttributes attribs;
531 int status = XGetWindowAttributes(defaults->display, parent, &attribs);
532 int ret = -1;
533 if (status) {
534 ret = attribs.width;
535 } else {
536 fprintf(stderr,"Unable to retrieve width attribute for %lu\n", win);
538 return ret;
541 int window_h(Window win) {
542 if (!_check_init()) {
543 return -1;
545 if(is_valid(win) == FALSE) {
546 fprintf(stderr, "Window %lu is invalid\n", win);
547 return INT_MIN;
549 Window parent = find_outer_parent(win);
550 if(!parent) {
551 return INT_MIN;
553 XWindowAttributes attribs;
554 int status = XGetWindowAttributes(defaults->display, parent, &attribs);
555 int ret = -1;
556 if (status) {
557 ret = attribs.height;
558 } else {
559 fprintf(stderr,"Unable to retrieve height attribute for %lu\n", win);
561 return ret;
564 char *window_name(Window win) {
565 if (!_check_init()) {
566 return NULL;
568 if(is_valid(win) == FALSE) {
569 fprintf(stderr, "Window %lu is invalid\n", win);
570 return NULL;
572 //I don't know if it will cause problems freeing this outside X -
573 //so I'll make a copy and return that.
574 char *xname = "";
575 XFetchName(defaults->display, win, &xname);
576 if(xname == NULL) {
577 return NULL;
579 char *name;
580 name = calloc(strlen(xname) + 1, sizeof(char));
581 if(name == NULL) {
582 fprintf(stderr, "Unable to allocate space for a window name");
583 } else {
584 strncpy(name, xname, strlen(xname));
586 XFree(xname);
587 return name;
590 long window_desktop(Window win) {
591 if (!_check_init()) {
592 return LONG_MIN;
594 if(is_valid(win) == FALSE) {
595 fprintf(stderr, "Window %lu is invalid\n", win);
596 return LONG_MIN;
599 if (!_is_supported_feature("_NET_WM_DESKTOP")) {
600 fprintf(stderr,
601 "Apparently your window manager doesn't support "
602 "_NET_CURRENT_DESKTOP so I'm returning 1.\n");
603 return 1;
606 Atom type;
607 int size = 0;
608 long item_count = 0;
609 Atom request = XInternAtom(defaults->display, "_NET_WM_DESKTOP", FALSE);
611 unsigned char *window_desktop = _window_property((Window) win, request,
612 &item_count, &type, &size);
614 long desktop = 0;
615 if (item_count > 0) {
616 desktop = *((long*) window_desktop);
617 } else {
618 desktop = -2;
620 if(desktop == -1) {
621 logit(LOG_LEVEL_VERBOSE, "The window %lu is currently on all desktops\n", win);
622 } else {
623 logit(LOG_LEVEL_VERBOSE, "The window %lu is currently on desktop %lu\n",
624 win, (desktop + 1));
626 if(window_desktop) {
627 XFree(window_desktop);
629 desktop++; //Force desktop to be one based rather than zero based
630 return desktop;
633 BOOL _alter_window_state(Window win, long action, long datal1, long datal2) {
634 if(is_valid(win) == FALSE) {
635 fprintf(stderr, "Window %lu is invalid\n", win);
636 return FALSE;
638 long mask = SubstructureRedirectMask | SubstructureNotifyMask;
639 XEvent event;
640 Atom message_type = XInternAtom(defaults->display, "_NET_WM_STATE", FALSE);
641 event.xclient.type = ClientMessage;
642 event.xclient.serial = 0;
643 event.xclient.send_event = TRUE;
644 event.xclient.message_type = message_type;
645 event.xclient.window = win;
646 event.xclient.format = 32;
647 event.xclient.data.l[0] = action;
648 event.xclient.data.l[1] = datal1;
649 event.xclient.data.l[2] = datal2;
650 event.xclient.data.l[3] = 0;
651 event.xclient.data.l[4] = 0;
652 Status s = XSendEvent(
653 defaults->display,
654 DefaultRootWindow(defaults->display),
655 FALSE,
656 mask,
657 &event);
658 XFlush(defaults->display);
659 return (s != 0);
663 BOOL _ensure_window_buffer_size(_window_search *search) {
664 if (search->buffer_size == search->found) {
665 logit(LOG_LEVEL_EXTRA_VERBOSE,
666 "Growing window search results buffer from %d ",
667 search->buffer_size);
668 search->buffer_size += 20;
669 logit(LOG_LEVEL_EXTRA_VERBOSE, "to %d elements\n",
670 search->buffer_size);
671 search->buffer = realloc(search->buffer, search->buffer_size
672 * sizeof(Window));
673 if (search->buffer) {
674 return TRUE;
675 } else {
676 return FALSE;
678 } else {
679 return TRUE;
683 BOOL _move_window_to_desktop(Window win, long desktop) {
684 logit(LOG_LEVEL_EXTRA_VERBOSE,
685 "Received desktop value %ld for window %lu\n", desktop, win);
686 char *event_name = "_NET_WM_DESKTOP";
687 if (desktop < 0) {
688 logit(LOG_LEVEL_EXTRA_VERBOSE,
689 "Desktop %ld means 'leave it where it is'\n", desktop);
690 return TRUE;
691 } else if(desktop == 0) {
692 logit(LOG_LEVEL_EXTRA_VERBOSE, "%s", "Desktop 0 means 'put it on all desktops'\n");
693 } else {
694 logit(LOG_LEVEL_EXTRA_VERBOSE,
695 "Moving window %lu to desktop %ld\n",
696 win, desktop);
698 if (!_check_init()) {
699 return FALSE;
701 if(is_valid(win) == FALSE) {
702 fprintf(stderr, "Window %lu is invalid\n", win);
703 return FALSE;
706 if (!_is_supported_feature("_NET_WM_DESKTOP")) {
707 fprintf(stderr,
708 "Apparently your window manager doesn't support "
709 "_NET_CURRENT_DESKTOP so I'm leaving the window "
710 "where it is.\n");
711 return FALSE;
713 if (desktop == window_desktop(win)) {
714 logit(LOG_LEVEL_VERBOSE, "Window is already on the target desktop\n");
715 return TRUE;
717 desktop--; //Force desktop to be one based rather than zero based
718 logit(LOG_LEVEL_VERBOSE,
719 "*Actual* final destination desktop of window %lu is %ld\n",
720 win, desktop);
721 XEvent event;
722 memset(&event, 0, sizeof(event));
723 event.xclient.format = 32;
724 event.xclient.data.l[0] = desktop;
725 event.xclient.data.l[1] = CurrentTime;
726 event.type = ClientMessage;
727 event.xclient.display = defaults->display;
728 event.xclient.window = win;
729 event.xclient.message_type =
730 XInternAtom(defaults->display, event_name, FALSE);
731 XWindowAttributes wattr;
732 XGetWindowAttributes(defaults->display, win, &wattr );
733 long mask = SubstructureNotifyMask | SubstructureRedirectMask;
734 Status status =
735 XSendEvent(defaults->display, wattr.screen->root , FALSE, mask, &event);
736 XFlush(defaults->display);
737 return (status != 0);
740 BOOL _prepare_regex(char *search, regex_t **regx) {
741 if (regcomp(*regx, search, 0)) {
742 fprintf(stderr, "Unable to compile title regex %s", search);
743 return FALSE;
745 return TRUE;
748 void _recursive_window_search(_window_search *search) {
749 unsigned long desk_count = desktop_count();
750 Window root_return_ignored = 0;
751 Window parent_return_ignored = 0;
752 Window *children;
753 unsigned int count = 0;
754 Status status = XQueryTree(defaults->display, search->current,
755 &root_return_ignored, &parent_return_ignored, &children, &count);
756 if (count == 0 || !status) {
757 return;
759 unsigned int i;
760 for (i = 0; i < count; i++) {
761 if (!children[i]) {
762 return;
764 char *title = window_name(children[i]);
765 if (title) {
766 logit(LOG_LEVEL_EXTRA_VERBOSE,
767 "Testing to see if '%s' matches '%s'\n",
768 search->title, title);
769 if (!regexec(*search->regx, title, 0, NULL, 0)) {
770 unsigned long win_desk = window_desktop(children[i]);
771 if(win_desk > desk_count){
772 logit(LOG_LEVEL_VERBOSE,
773 "Skipping %lu because its hidden\n",
774 children[i]);
776 logit(LOG_LEVEL_VERBOSE, "Adding '%s' as a match\n", title);
777 if (_ensure_window_buffer_size(search)) {
778 Window res = children[i];
779 search->buffer[search->found] = res;
780 search->found++;
781 } else {
782 fprintf(stderr,
783 "Unable to allocate space for a window buffer");
786 free(title);
788 if (children[i]) {
789 search->current = children[i];
790 _recursive_window_search(search);
793 XFree(children);
796 int _window_search_comparator(const void *l, const void *r) {
797 //First sort is desktop - closest wins
798 Window winL = *((Window*) l);
799 Window winR = *((Window*) r);
800 long ldesk = window_desktop(winL);
801 long rdesk = window_desktop(winR);
802 if (ldesk != rdesk) {
803 long curr = get_current_desktop();
804 long difL = fabs(curr - ldesk);
805 long difR = fabs(curr - rdesk);
806 if (difL < difR) {
807 char *msg = "'%s' comes before '%s' because its"
808 " desktop %ld is closer to %ld than %l\n";
809 logit(LOG_LEVEL_EXTRA_VERBOSE, msg,
810 window_name(winL),
811 window_name(winR),
812 ldesk,
813 curr,
814 rdesk);
815 return -1;
816 } else if (difL > difR) {
817 char *msg = "'%s' comes before '%s' because its"
818 " desktop %ld is closer to %ld than %l\n";
819 logit(LOG_LEVEL_EXTRA_VERBOSE, msg,
820 window_name(winR),
821 window_name(winL),
822 rdesk,
823 curr,
824 ldesk);
825 return 1;
829 //If we're here, we sort by id
830 if (winL < winR) {
831 char *msg = "'%s' comes before '%s' because its"
832 " id %ld is lower than %ld\n";
833 logit(LOG_LEVEL_EXTRA_VERBOSE, msg,
834 window_name(winL),
835 window_name(winR),
836 winL,
837 winR);
838 return -1;
839 } else if (winR < winL) {
840 char *msg = "'%s' comes before '%s' because its"
841 " id %ld is lower than %ld\n";
842 logit(LOG_LEVEL_EXTRA_VERBOSE, msg,
843 window_name(winR),
844 window_name(winL),
845 winR,
846 winL);
847 return 1;
848 } else {
849 return 0;
853 int _invalid_window_property_error_handler(Display *dsp, XErrorEvent *err) {
854 return BadWindow;
856 unsigned char * _window_property(
857 Window win,
858 Atom property,
859 long *item_count_ret,
860 Atom *type,
861 int *size) {
862 long offset = 0L;
863 long length = (~0L);
864 BOOL delete = FALSE;
865 Atom type_ret;
866 int format_ret;
867 Window items_found;
868 Window bytes_after; /* unused */
869 int status;
870 unsigned char *x_prop;
872 XSetErrorHandler(_invalid_window_property_error_handler);
873 status = XGetWindowProperty(
874 defaults->display,
875 win, property, offset,
876 length, delete, AnyPropertyType, &type_ret, &format_ret,
877 &items_found, &bytes_after, &x_prop);
880 if (status == BadWindow) {
881 fprintf(stderr, "%ld is a bad window handle - returning null\n", win);
882 return NULL;
884 if (status != Success) {
885 fprintf(stderr, "XGetWindowProperty failed - returning null\n");
886 return NULL;
889 *item_count_ret = items_found;
890 *type = type_ret;
891 *size = format_ret;
892 return x_prop;