1 /* GTK - The GIMP Toolkit
2 * gdkasync.c: Utility functions using the Xlib asynchronous interfaces
3 * Copyright (C) 2003, Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 /* Portions of code in this file are based on code from Xlib
23 Copyright 1986, 1998 The Open Group
25 Permission to use, copy, modify, distribute, and sell this software and its
26 documentation for any purpose is hereby granted without fee, provided that
27 the above copyright notice appear in all copies and that both that
28 copyright notice and this permission notice appear in supporting
31 The above copyright notice and this permission notice shall be included in
32 all copies or substantial portions of the Software.
34 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
38 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 Except as contained in this notice, the name of The Open Group shall not be
42 used in advertising or otherwise to promote the sale, use or other dealings
43 in this Software without prior written authorization from The Open Group.
47 #ifdef NEED_XIPROTO_H_FOR_XREPLY
48 #include <X11/extensions/XIproto.h>
50 #include <X11/Xlibint.h>
55 typedef struct _ChildInfoChildState ChildInfoChildState;
56 typedef struct _ChildInfoState ChildInfoState;
57 typedef struct _ListChildrenState ListChildrenState;
58 typedef struct _SendEventState SendEventState;
59 typedef struct _SetInputFocusState SetInputFocusState;
62 CHILD_INFO_GET_PROPERTY,
64 CHILD_INFO_GET_GEOMETRY
67 struct _ChildInfoChildState
72 struct _ChildInfoState
74 gboolean get_wm_state;
77 GdkChildInfoX11 *child_info;
78 ChildInfoChildState *child_states;
81 guint n_children_found;
84 gboolean child_has_error;
87 struct _ListChildrenState
90 gulong get_property_req;
92 gboolean has_wm_state;
95 struct _SendEventState
100 gulong send_event_req;
101 gulong get_input_focus_req;
103 GdkSendXEventCallback callback;
107 struct _SetInputFocusState
110 _XAsyncHandler async;
111 gulong set_input_focus_req;
112 gulong get_input_focus_req;
116 send_event_handler (Display *dpy,
122 SendEventState *state = (SendEventState *)data;
124 if (dpy->last_request_read == state->send_event_req)
126 if (rep->generic.type == X_Error &&
127 rep->error.errorCode == BadWindow)
129 state->have_error = TRUE;
133 else if (dpy->last_request_read == state->get_input_focus_req)
135 xGetInputFocusReply replbuf;
136 xGetInputFocusReply *repl;
138 if (rep->generic.type != X_Error)
140 /* Actually does nothing, since there are no additional bytes
141 * to read, but maintain good form.
143 repl = (xGetInputFocusReply *)
144 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
145 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
150 state->callback (state->window, !state->have_error, state->data);
152 DeqAsyncHandler(state->dpy, &state->async);
156 return (rep->generic.type != X_Error);
163 client_message_to_wire (XClientMessageEvent *ev,
167 event->u.clientMessage.window = ev->window;
168 event->u.u.type = ev->type;
169 event->u.u.detail = ev->format;
173 event->u.clientMessage.u.b.type = ev->message_type;
174 for (i = 0; i < 20; i++)
175 event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
178 event->u.clientMessage.u.s.type = ev->message_type;
179 event->u.clientMessage.u.s.shorts0 = ev->data.s[0];
180 event->u.clientMessage.u.s.shorts1 = ev->data.s[1];
181 event->u.clientMessage.u.s.shorts2 = ev->data.s[2];
182 event->u.clientMessage.u.s.shorts3 = ev->data.s[3];
183 event->u.clientMessage.u.s.shorts4 = ev->data.s[4];
184 event->u.clientMessage.u.s.shorts5 = ev->data.s[5];
185 event->u.clientMessage.u.s.shorts6 = ev->data.s[6];
186 event->u.clientMessage.u.s.shorts7 = ev->data.s[7];
187 event->u.clientMessage.u.s.shorts8 = ev->data.s[8];
188 event->u.clientMessage.u.s.shorts9 = ev->data.s[9];
191 event->u.clientMessage.u.l.type = ev->message_type;
192 event->u.clientMessage.u.l.longs0 = ev->data.l[0];
193 event->u.clientMessage.u.l.longs1 = ev->data.l[1];
194 event->u.clientMessage.u.l.longs2 = ev->data.l[2];
195 event->u.clientMessage.u.l.longs3 = ev->data.l[3];
196 event->u.clientMessage.u.l.longs4 = ev->data.l[4];
199 /* client passing bogus data, let server complain */
205 _gdk_x11_send_client_message_async (GdkDisplay *display,
209 XClientMessageEvent *event_send,
210 GdkSendXEventCallback callback,
214 SendEventState *state;
216 dpy = GDK_DISPLAY_XDISPLAY (display);
218 state = g_new (SendEventState, 1);
221 state->window = window;
222 state->callback = callback;
224 state->have_error = FALSE;
228 state->async.next = dpy->async_handlers;
229 state->async.handler = send_event_handler;
230 state->async.data = (XPointer) state;
231 dpy->async_handlers = &state->async;
234 register xSendEventReq *req;
237 client_message_to_wire (event_send, &ev);
239 GetReq(SendEvent, req);
240 req->destination = window;
241 req->propagate = propagate;
242 req->eventMask = event_mask;
243 /* gross, matches Xproto.h */
245 memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
247 memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
250 state->send_event_req = dpy->request;
259 GetEmptyReq(GetInputFocus, req);
260 state->get_input_focus_req = dpy->request;
268 set_input_focus_handler (Display *dpy,
274 SetInputFocusState *state = (SetInputFocusState *)data;
276 if (dpy->last_request_read == state->set_input_focus_req)
278 if (rep->generic.type == X_Error &&
279 rep->error.errorCode == BadMatch)
281 /* Consume BadMatch errors, since we have no control
288 if (dpy->last_request_read == state->get_input_focus_req)
290 xGetInputFocusReply replbuf;
291 xGetInputFocusReply *repl;
293 if (rep->generic.type != X_Error)
295 /* Actually does nothing, since there are no additional bytes
296 * to read, but maintain good form.
298 repl = (xGetInputFocusReply *)
299 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
300 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
304 DeqAsyncHandler(state->dpy, &state->async);
308 return (rep->generic.type != X_Error);
315 _gdk_x11_set_input_focus_safe (GdkDisplay *display,
321 SetInputFocusState *state;
323 dpy = GDK_DISPLAY_XDISPLAY (display);
325 state = g_new (SetInputFocusState, 1);
331 state->async.next = dpy->async_handlers;
332 state->async.handler = set_input_focus_handler;
333 state->async.data = (XPointer) state;
334 dpy->async_handlers = &state->async;
337 xSetInputFocusReq *req;
339 GetReq(SetInputFocus, req);
341 req->revertTo = revert_to;
343 state->set_input_focus_req = dpy->request;
352 GetEmptyReq(GetInputFocus, req);
353 state->get_input_focus_req = dpy->request;
361 list_children_handler (Display *dpy,
367 ListChildrenState *state = (ListChildrenState *)data;
369 if (dpy->last_request_read != state->get_property_req)
372 if (rep->generic.type == X_Error)
374 state->have_error = TRUE;
379 xGetPropertyReply replbuf;
380 xGetPropertyReply *repl;
382 repl = (xGetPropertyReply *)
383 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
384 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
387 state->has_wm_state = repl->propertyType != None;
388 /* Since we called GetProperty with longLength of 0, we don't
389 * have to worry about consuming the property data that would
390 * normally follow after the reply
398 list_children_and_wm_state (Display *dpy,
401 gboolean *has_wm_state,
403 unsigned int *nchildren)
405 ListChildrenState state;
406 _XAsyncHandler async;
409 register xResourceReq *req;
410 xGetPropertyReq *prop_req;
416 *has_wm_state = FALSE;
418 state.have_error = FALSE;
419 state.has_wm_state = FALSE;
423 async.next = dpy->async_handlers;
424 async.handler = list_children_handler;
425 async.data = (XPointer) &state;
426 dpy->async_handlers = &async;
428 GetReq (GetProperty, prop_req);
429 prop_req->window = w;
430 prop_req->property = wm_state_atom;
431 prop_req->type = AnyPropertyType;
432 prop_req->delete = False;
433 prop_req->longOffset = 0;
434 prop_req->longLength = 0;
436 state.get_property_req = dpy->request;
439 GetResReq(QueryTree, w, req);
440 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
442 state.have_error = TRUE;
446 if (rep.nChildren != 0)
448 nbytes = rep.nChildren << 2;
449 if (state.have_error)
451 _XEatData(dpy, (unsigned long) nbytes);
454 *children = g_new (Window, rep.nChildren);
455 _XRead32 (dpy, (long *) *children, nbytes);
458 *nchildren = rep.nChildren;
459 *has_wm_state = state.has_wm_state;
463 DeqAsyncHandler(dpy, &async);
467 return !state.have_error;
471 handle_get_wa_reply (Display *dpy,
472 ChildInfoState *state,
473 xGetWindowAttributesReply *repl)
475 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
476 child->is_mapped = repl->mapState != IsUnmapped;
477 child->window_class = repl->class;
481 handle_get_geometry_reply (Display *dpy,
482 ChildInfoState *state,
483 xGetGeometryReply *repl)
485 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
487 child->x = cvtINT16toInt (repl->x);
488 child->y = cvtINT16toInt (repl->y);
489 child->width = repl->width;
490 child->height = repl->height;
494 handle_get_property_reply (Display *dpy,
495 ChildInfoState *state,
496 xGetPropertyReply *repl)
498 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
499 child->has_wm_state = repl->propertyType != None;
501 /* Since we called GetProperty with longLength of 0, we don't
502 * have to worry about consuming the property data that would
503 * normally follow after the reply
508 next_child (ChildInfoState *state)
510 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
512 if (!state->have_error && !state->child_has_error)
514 state->child_info[state->n_children_found].window = state->children[state->current_child];
515 state->n_children_found++;
517 state->current_child++;
518 if (state->get_wm_state)
519 state->current_request = CHILD_INFO_GET_PROPERTY;
521 state->current_request = CHILD_INFO_GET_WA;
522 state->child_has_error = FALSE;
523 state->have_error = FALSE;
526 state->current_request++;
530 get_child_info_handler (Display *dpy,
538 ChildInfoState *state = (ChildInfoState *)data;
540 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
543 if (rep->generic.type == X_Error)
545 state->child_has_error = TRUE;
546 if (rep->error.errorCode != BadDrawable ||
547 rep->error.errorCode != BadWindow)
549 state->have_error = TRUE;
555 switch (state->current_request)
557 case CHILD_INFO_GET_PROPERTY:
559 xGetPropertyReply replbuf;
560 xGetPropertyReply *repl;
562 repl = (xGetPropertyReply *)
563 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
564 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
567 handle_get_property_reply (dpy, state, repl);
570 case CHILD_INFO_GET_WA:
572 xGetWindowAttributesReply replbuf;
573 xGetWindowAttributesReply *repl;
575 repl = (xGetWindowAttributesReply *)
576 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
577 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
580 handle_get_wa_reply (dpy, state, repl);
583 case CHILD_INFO_GET_GEOMETRY:
585 xGetGeometryReply replbuf;
586 xGetGeometryReply *repl;
588 repl = (xGetGeometryReply *)
589 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
590 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
593 handle_get_geometry_reply (dpy, state, repl);
605 _gdk_x11_get_window_child_info (GdkDisplay *display,
607 gboolean get_wm_state,
608 gboolean *win_has_wm_state,
609 GdkChildInfoX11 **children,
613 _XAsyncHandler async;
614 ChildInfoState state;
616 gboolean has_wm_state;
623 dpy = GDK_DISPLAY_XDISPLAY (display);
625 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
627 wm_state_atom = None;
629 gdk_error_trap_push ();
630 result = list_children_and_wm_state (dpy, window,
631 win_has_wm_state ? wm_state_atom : None,
633 &state.children, &state.nchildren);
634 gdk_error_trap_pop ();
640 if (win_has_wm_state)
641 *win_has_wm_state = TRUE;
646 if (win_has_wm_state)
647 *win_has_wm_state = FALSE;
650 state.get_wm_state = get_wm_state;
651 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
652 state.child_states = g_new (ChildInfoChildState, state.nchildren);
653 state.current_child = 0;
654 state.n_children_found = 0;
656 state.current_request = CHILD_INFO_GET_PROPERTY;
658 state.current_request = CHILD_INFO_GET_WA;
659 state.have_error = FALSE;
660 state.child_has_error = FALSE;
664 async.next = dpy->async_handlers;
665 async.handler = get_child_info_handler;
666 async.data = (XPointer) &state;
667 dpy->async_handlers = &async;
669 for (i = 0; i < state.nchildren; i++)
671 xResourceReq *resource_req;
672 xGetPropertyReq *prop_req;
673 Window window = state.children[i];
677 GetReq (GetProperty, prop_req);
678 prop_req->window = window;
679 prop_req->property = wm_state_atom;
680 prop_req->type = AnyPropertyType;
681 prop_req->delete = False;
682 prop_req->longOffset = 0;
683 prop_req->longLength = 0;
685 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
688 GetResReq(GetWindowAttributes, window, resource_req);
689 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
691 GetResReq(GetGeometry, window, resource_req);
692 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
697 /* Wait for the last reply
699 xGetGeometryReply rep;
701 /* On error, our async handler will get called
703 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
704 handle_get_geometry_reply (dpy, &state, &rep);
709 if (!state.have_error)
711 *children = state.child_info;
712 *nchildren = state.n_children_found;
716 g_free (state.child_info);
719 g_free (state.children);
720 g_free (state.child_states);
722 DeqAsyncHandler(dpy, &async);
726 return !state.have_error;
729 #define __GDK_ASYNC_C__
730 #include "gdkaliasdef.c"