1 /***************************************************************************
2 * Copyright (C) 2009 by Chris Parker *
3 * chrsprkr3@gmail.com *
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. *
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 ***************************************************************************/
20 #include <X11/extensions/XTest.h>
25 BOOL
activate_window(Window win
) {
26 char *event_name
= "_NET_ACTIVE_WINDOW";
27 if (!_check_init() || win
< 1) {
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
);
39 long current_desktop
= get_current_desktop();
40 if (win_desk
!= current_desktop
) {
41 BOOL switched
= set_current_desktop(win_desk
);
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
;
67 XSendEvent(defaults
->display
, wattr
.screen
->root
, FALSE
, mask
, &event
);
68 XFlush(defaults
->display
);
72 Window
active_window() {
77 int focus_state_ignored
= 0;
78 int success
= XGetInputFocus(defaults
->display
, &win
, &focus_state_ignored
);
86 int _is_not_valid_error_handler(Display
*dsp
, XErrorEvent
*err
) {
90 BOOL
is_valid(Window win
) {
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
) {
101 Window parent_return
;
102 Window
*children_return_ignored
;
103 unsigned int num_children_return_ignored
;
105 Status status
= XQueryTree(
110 &children_return_ignored
,
111 &num_children_return_ignored
114 fprintf(stderr
, "Something went wrong trying to find parent\n");
117 if(root_return
== parent_return
) {
119 } else if(parent_return
> root_return
) {
120 return find_outer_parent(parent_return
);
122 fprintf(stderr
, "Somehow missed the parent, returning null\n");
127 Window
find_window(char *title
) {
128 if(! _check_init()) {
129 fprintf(stderr
, "Failure to initialize");
132 regex_t
*regx
= calloc(1, sizeof(regex_t
));
134 fprintf(stderr
, "Unable to allocate space for a regular expression");
137 if (!_prepare_regex(title
, ®x
)) {
147 unsigned char *results
;
149 int prop_ret_val
= XGetWindowProperty(
151 XDefaultRootWindow(defaults
->display
),
152 XInternAtom(defaults
->display
, "_NET_CLIENT_LIST", FALSE
),
163 if(prop_ret_val
!= Success
) {
165 fprintf(stderr
, "XGetWindowProperty returned %d", prop_ret_val
);
169 Window
*windows
= (Window
*)results
;
170 Window
*match_buffer
= calloc(count
, sizeof(Window
)); //A safe size...
172 fprintf(stderr
, "Unable to allocate space for a window buffer\n");
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",
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
];
188 Window final_ret
= 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];
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];
206 Window
* search_for_window(char *title
) {
207 if(! _check_init()) {
208 fprintf(stderr
, "Failure to initialize");
211 regex_t
*regx
= calloc(1, sizeof(regex_t
));
213 fprintf(stderr
, "Unable to allocate space for a regular expression");
216 if (!_prepare_regex(title
, ®x
)) {
219 _window_search
*search
= calloc(1, sizeof(_window_search
));
221 fprintf(stderr
, "Unable to allocate space for a buffer");
224 search
->buffer
= calloc(10, sizeof(Window
));
225 if (!search
->buffer
) {
226 fprintf(stderr
, "Unable to allocate space for a buffer");
229 search
->buffer_size
= 10;
230 search
->current
= XDefaultRootWindow(defaults
->display
);
232 search
->title
= title
;
233 search
->regx
= ®x
;
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
);
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
));
249 fprintf(stderr
, "Unable to allocate space for the retured windows");
252 for(i
= 0; i
< search
->found
; i
++) {
253 ret
[i
] = search
->buffer
[i
];
255 ret
[search
->found
] = 0;
259 free(search
->buffer
);
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
);
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");
274 BOOL moved
= _move_window_to_desktop(win
, desktop
);
276 fprintf(stderr
, "Unable to move window %lu to desktop %lu\n",
279 if((x
< 0) && (y
< 0)) {
280 logit(LOG_LEVEL_VERBOSE
, "%s",
281 "Leaving window at it's current x y coordinates\n");
284 logit(LOG_LEVEL_EXTRA_VERBOSE
, "%s",
285 "Using current window x coordinate as its destination\n");
288 logit(LOG_LEVEL_EXTRA_VERBOSE
, "%s",
289 "Using current window y coordinate as its destination\n");
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
);
298 BOOL
iconify_window(Window win
, BOOL tf
) {
299 if(!_check_init() || win
< 1) {
302 if(is_valid(win
) == FALSE
) {
303 fprintf(stderr
, "Window %lu is invalid\n", win
);
306 if(!_is_supported_feature("_NET_WM_ACTION_MINIMIZE")) {
307 fprintf(stderr
, "Apparently that window cannot be minimized\n");
312 XSetErrorHandler(_invalid_window_error_handler
);
313 XWindowAttributes attribs
;
314 status
= XGetWindowAttributes(
319 fprintf(stderr
, "%lu is not a valid window handle", win
);
323 int screen
= XScreenNumberOfScreen(attribs
.screen
);
324 status
= XIconifyWindow(defaults
->display
, win
, screen
);
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
);
348 char *horz
= "_NET_WM_STATE_MAXIMIZED_HORZ";
349 if(!_check_init() || win
< 1) {
352 if(!_is_supported_feature(horz
)) {
353 fprintf(stderr
, "Apparently that window can't be"
354 " maximized horizontally" );
357 Atom datal1
= XInternAtom(defaults
->display
, horz
, FALSE
);
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
);
368 char *vert
= "_NET_WM_STATE_MAXIMIZED_VERT";
369 if(!_check_init() || win
< 1) {
372 if (!_is_supported_feature(vert
)) {
373 fprintf(stderr
, "Apparently that window can't be"
374 " maximized vertically" );
377 Atom datal1
= XInternAtom(defaults
->display
, vert
, FALSE
);
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
);
388 char *full
= "_NET_WM_STATE_FULLSCREEN";
389 if(!_check_init() || win
< 1) {
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
);
405 char *shade
= "_NET_WM_STATE_SHADED";
406 if(!_check_init() || win
< 1) {
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
);
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) {
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
);
452 int window_x(Window win
) {
453 if (!_check_init()) {
456 if(is_valid(win
) == FALSE
) {
457 fprintf(stderr
, "Window %lu is invalid\n", win
);
460 Window parent
= find_outer_parent(win
);
464 XWindowAttributes attribs
;
465 int status
= XGetWindowAttributes(defaults
->display
, parent
, &attribs
);
468 int junk_y
= 0; //Y coordinate not used here
470 (void) XTranslateCoordinates(
474 -attribs
.border_width
,
475 -attribs
.border_width
,
480 fprintf(stderr
,"Unable to retrieve x attribute for %lu\n", win
);
485 int window_y(Window win
) {
486 if (!_check_init()) {
489 if(is_valid(win
) == FALSE
) {
490 fprintf(stderr
, "Window %lu is invalid\n", win
);
493 Window parent
= find_outer_parent(win
);
497 XWindowAttributes attribs
;
498 int status
= XGetWindowAttributes(defaults
->display
, parent
, &attribs
);
501 int junk_x
= 0; //X coordinate not used here
503 (void) XTranslateCoordinates(
507 -attribs
.border_width
,
508 -attribs
.border_width
,
513 fprintf(stderr
,"Unable to retrieve y attribute for %lu\n", win
);
518 int window_w(Window win
) {
519 if (!_check_init()) {
522 if(is_valid(win
) == FALSE
) {
523 fprintf(stderr
, "Window %lu is invalid\n", win
);
526 Window parent
= find_outer_parent(win
);
530 XWindowAttributes attribs
;
531 int status
= XGetWindowAttributes(defaults
->display
, parent
, &attribs
);
536 fprintf(stderr
,"Unable to retrieve width attribute for %lu\n", win
);
541 int window_h(Window win
) {
542 if (!_check_init()) {
545 if(is_valid(win
) == FALSE
) {
546 fprintf(stderr
, "Window %lu is invalid\n", win
);
549 Window parent
= find_outer_parent(win
);
553 XWindowAttributes attribs
;
554 int status
= XGetWindowAttributes(defaults
->display
, parent
, &attribs
);
557 ret
= attribs
.height
;
559 fprintf(stderr
,"Unable to retrieve height attribute for %lu\n", win
);
564 char *window_name(Window win
) {
565 if (!_check_init()) {
568 if(is_valid(win
) == FALSE
) {
569 fprintf(stderr
, "Window %lu is invalid\n", win
);
572 //I don't know if it will cause problems freeing this outside X -
573 //so I'll make a copy and return that.
575 XFetchName(defaults
->display
, win
, &xname
);
580 name
= calloc(strlen(xname
) + 1, sizeof(char));
582 fprintf(stderr
, "Unable to allocate space for a window name");
584 strncpy(name
, xname
, strlen(xname
));
590 long window_desktop(Window win
) {
591 if (!_check_init()) {
594 if(is_valid(win
) == FALSE
) {
595 fprintf(stderr
, "Window %lu is invalid\n", win
);
599 if (!_is_supported_feature("_NET_WM_DESKTOP")) {
601 "Apparently your window manager doesn't support "
602 "_NET_CURRENT_DESKTOP so I'm returning 1.\n");
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
);
615 if (item_count
> 0) {
616 desktop
= *((long*) window_desktop
);
621 logit(LOG_LEVEL_VERBOSE
, "The window %lu is currently on all desktops\n", win
);
623 logit(LOG_LEVEL_VERBOSE
, "The window %lu is currently on desktop %lu\n",
627 XFree(window_desktop
);
629 desktop
++; //Force desktop to be one based rather than zero based
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
);
638 long mask
= SubstructureRedirectMask
| SubstructureNotifyMask
;
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(
654 DefaultRootWindow(defaults
->display
),
658 XFlush(defaults
->display
);
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
673 if (search
->buffer
) {
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";
688 logit(LOG_LEVEL_EXTRA_VERBOSE
,
689 "Desktop %ld means 'leave it where it is'\n", desktop
);
691 } else if(desktop
== 0) {
692 logit(LOG_LEVEL_EXTRA_VERBOSE
, "%s", "Desktop 0 means 'put it on all desktops'\n");
694 logit(LOG_LEVEL_EXTRA_VERBOSE
,
695 "Moving window %lu to desktop %ld\n",
698 if (!_check_init()) {
701 if(is_valid(win
) == FALSE
) {
702 fprintf(stderr
, "Window %lu is invalid\n", win
);
706 if (!_is_supported_feature("_NET_WM_DESKTOP")) {
708 "Apparently your window manager doesn't support "
709 "_NET_CURRENT_DESKTOP so I'm leaving the window "
713 if (desktop
== window_desktop(win
)) {
714 logit(LOG_LEVEL_VERBOSE
, "Window is already on the target desktop\n");
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",
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
;
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
);
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;
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
) {
760 for (i
= 0; i
< count
; i
++) {
764 char *title
= window_name(children
[i
]);
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",
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
;
783 "Unable to allocate space for a window buffer");
789 search
->current
= children
[i
];
790 _recursive_window_search(search
);
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
);
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
,
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
,
829 //If we're here, we sort by id
831 char *msg
= "'%s' comes before '%s' because its"
832 " id %ld is lower than %ld\n";
833 logit(LOG_LEVEL_EXTRA_VERBOSE
, msg
,
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
,
853 int _invalid_window_property_error_handler(Display
*dsp
, XErrorEvent
*err
) {
856 unsigned char * _window_property(
859 long *item_count_ret
,
868 Window bytes_after
; /* unused */
870 unsigned char *x_prop
;
872 XSetErrorHandler(_invalid_window_property_error_handler
);
873 status
= XGetWindowProperty(
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
);
884 if (status
!= Success
) {
885 fprintf(stderr
, "XGetWindowProperty failed - returning null\n");
889 *item_count_ret
= items_found
;