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.
46 #include <X11/Xlibint.h>
50 typedef struct _ChildInfoChildState ChildInfoChildState;
51 typedef struct _ChildInfoState ChildInfoState;
52 typedef struct _ListChildrenState ListChildrenState;
53 typedef struct _SendEventState SendEventState;
54 typedef struct _SetInputFocusState SetInputFocusState;
57 CHILD_INFO_GET_PROPERTY,
59 CHILD_INFO_GET_GEOMETRY
62 struct _ChildInfoChildState
67 struct _ChildInfoState
69 gboolean get_wm_state;
72 GdkChildInfoX11 *child_info;
73 ChildInfoChildState *child_states;
76 guint n_children_found;
79 gboolean child_has_error;
82 struct _ListChildrenState
85 gulong get_property_req;
87 gboolean has_wm_state;
90 struct _SendEventState
95 gulong send_event_req;
96 gulong get_input_focus_req;
98 GdkSendXEventCallback callback;
102 struct _SetInputFocusState
105 _XAsyncHandler async;
106 gulong set_input_focus_req;
107 gulong get_input_focus_req;
111 send_event_handler (Display *dpy,
117 SendEventState *state = (SendEventState *)data;
119 if (dpy->last_request_read == state->send_event_req)
121 if (rep->generic.type == X_Error &&
122 rep->error.errorCode == BadWindow)
124 state->have_error = TRUE;
128 else if (dpy->last_request_read == state->get_input_focus_req)
130 xGetInputFocusReply replbuf;
131 xGetInputFocusReply *repl;
133 if (rep->generic.type != X_Error)
135 /* Actually does nothing, since there are no additional bytes
136 * to read, but maintain good form.
138 repl = (xGetInputFocusReply *)
139 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
140 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
145 state->callback (state->window, !state->have_error, state->data);
147 DeqAsyncHandler(state->dpy, &state->async);
149 return (rep->generic.type != X_Error);
156 client_message_to_wire (XClientMessageEvent *ev,
160 event->u.clientMessage.window = ev->window;
161 event->u.u.type = ev->type;
162 event->u.u.detail = ev->format;
166 event->u.clientMessage.u.b.type = ev->message_type;
167 for (i = 0; i < 20; i++)
168 event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
171 event->u.clientMessage.u.s.type = ev->message_type;
172 event->u.clientMessage.u.s.shorts0 = ev->data.s[0];
173 event->u.clientMessage.u.s.shorts1 = ev->data.s[1];
174 event->u.clientMessage.u.s.shorts2 = ev->data.s[2];
175 event->u.clientMessage.u.s.shorts3 = ev->data.s[3];
176 event->u.clientMessage.u.s.shorts4 = ev->data.s[4];
177 event->u.clientMessage.u.s.shorts5 = ev->data.s[5];
178 event->u.clientMessage.u.s.shorts6 = ev->data.s[6];
179 event->u.clientMessage.u.s.shorts7 = ev->data.s[7];
180 event->u.clientMessage.u.s.shorts8 = ev->data.s[8];
181 event->u.clientMessage.u.s.shorts9 = ev->data.s[9];
184 event->u.clientMessage.u.l.type = ev->message_type;
185 event->u.clientMessage.u.l.longs0 = ev->data.l[0];
186 event->u.clientMessage.u.l.longs1 = ev->data.l[1];
187 event->u.clientMessage.u.l.longs2 = ev->data.l[2];
188 event->u.clientMessage.u.l.longs3 = ev->data.l[3];
189 event->u.clientMessage.u.l.longs4 = ev->data.l[4];
192 /* client passing bogus data, let server complain */
198 _gdk_x11_send_client_message_async (GdkDisplay *display,
202 XClientMessageEvent *event_send,
203 GdkSendXEventCallback callback,
207 SendEventState *state;
209 dpy = GDK_DISPLAY_XDISPLAY (display);
211 state = g_new (SendEventState, 1);
214 state->window = window;
215 state->callback = callback;
217 state->have_error = FALSE;
221 state->async.next = dpy->async_handlers;
222 state->async.handler = send_event_handler;
223 state->async.data = (XPointer) state;
224 dpy->async_handlers = &state->async;
227 register xSendEventReq *req;
230 client_message_to_wire (event_send, &ev);
232 GetReq(SendEvent, req);
233 req->destination = window;
234 req->propagate = propagate;
235 req->eventMask = event_mask;
236 /* gross, matches Xproto.h */
238 memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
240 memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
243 state->send_event_req = dpy->request;
252 GetEmptyReq(GetInputFocus, req);
253 state->get_input_focus_req = dpy->request;
261 set_input_focus_handler (Display *dpy,
267 SetInputFocusState *state = (SetInputFocusState *)data;
269 if (dpy->last_request_read == state->set_input_focus_req)
271 if (rep->generic.type == X_Error &&
272 rep->error.errorCode == BadMatch)
274 /* Consume BadMatch errors, since we have no control
281 if (dpy->last_request_read == state->get_input_focus_req)
283 xGetInputFocusReply replbuf;
284 xGetInputFocusReply *repl;
286 if (rep->generic.type != X_Error)
288 /* Actually does nothing, since there are no additional bytes
289 * to read, but maintain good form.
291 repl = (xGetInputFocusReply *)
292 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
293 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
297 DeqAsyncHandler(state->dpy, &state->async);
301 return (rep->generic.type != X_Error);
308 _gdk_x11_set_input_focus_safe (GdkDisplay *display,
314 SetInputFocusState *state;
316 dpy = GDK_DISPLAY_XDISPLAY (display);
318 state = g_new (SetInputFocusState, 1);
324 state->async.next = dpy->async_handlers;
325 state->async.handler = set_input_focus_handler;
326 state->async.data = (XPointer) state;
327 dpy->async_handlers = &state->async;
330 xSetInputFocusReq *req;
332 GetReq(SetInputFocus, req);
334 req->revertTo = revert_to;
336 state->set_input_focus_req = dpy->request;
345 GetEmptyReq(GetInputFocus, req);
346 state->get_input_focus_req = dpy->request;
354 list_children_handler (Display *dpy,
360 ListChildrenState *state = (ListChildrenState *)data;
362 if (dpy->last_request_read != state->get_property_req)
365 if (rep->generic.type == X_Error)
367 state->have_error = TRUE;
372 xGetPropertyReply replbuf;
373 xGetPropertyReply *repl;
375 repl = (xGetPropertyReply *)
376 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
377 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
380 state->has_wm_state = repl->propertyType != None;
381 /* Since we called GetProperty with longLength of 0, we don't
382 * have to worry about consuming the property data that would
383 * normally follow after the reply
391 list_children_and_wm_state (Display *dpy,
394 gboolean *has_wm_state,
396 unsigned int *nchildren)
398 ListChildrenState state;
399 _XAsyncHandler async;
402 register xResourceReq *req;
403 xGetPropertyReq *prop_req;
409 *has_wm_state = FALSE;
411 state.have_error = FALSE;
412 state.has_wm_state = FALSE;
416 async.next = dpy->async_handlers;
417 async.handler = list_children_handler;
418 async.data = (XPointer) &state;
419 dpy->async_handlers = &async;
421 GetReq (GetProperty, prop_req);
422 prop_req->window = w;
423 prop_req->property = wm_state_atom;
424 prop_req->type = AnyPropertyType;
425 prop_req->delete = False;
426 prop_req->longOffset = 0;
427 prop_req->longLength = 0;
429 state.get_property_req = dpy->request;
432 GetResReq(QueryTree, w, req);
433 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
435 state.have_error = TRUE;
439 if (rep.nChildren != 0)
441 nbytes = rep.nChildren << 2;
442 if (state.have_error)
444 _XEatData(dpy, (unsigned long) nbytes);
447 *children = g_new (Window, rep.nChildren);
448 _XRead32 (dpy, (long *) *children, nbytes);
451 *nchildren = rep.nChildren;
452 *has_wm_state = state.has_wm_state;
456 DeqAsyncHandler(dpy, &async);
460 return !state.have_error;
464 handle_get_wa_reply (Display *dpy,
465 ChildInfoState *state,
466 xGetWindowAttributesReply *repl)
468 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
469 child->is_mapped = repl->mapState != IsUnmapped;
470 child->window_class = repl->class;
474 handle_get_geometry_reply (Display *dpy,
475 ChildInfoState *state,
476 xGetGeometryReply *repl)
478 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
480 child->x = cvtINT16toInt (repl->x);
481 child->y = cvtINT16toInt (repl->y);
482 child->width = repl->width;
483 child->height = repl->height;
487 handle_get_property_reply (Display *dpy,
488 ChildInfoState *state,
489 xGetPropertyReply *repl)
491 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
492 child->has_wm_state = repl->propertyType != None;
494 /* Since we called GetProperty with longLength of 0, we don't
495 * have to worry about consuming the property data that would
496 * normally follow after the reply
501 next_child (ChildInfoState *state)
503 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
505 if (!state->have_error && !state->child_has_error)
507 state->child_info[state->n_children_found].window = state->children[state->current_child];
508 state->n_children_found++;
510 state->current_child++;
511 if (state->get_wm_state)
512 state->current_request = CHILD_INFO_GET_PROPERTY;
514 state->current_request = CHILD_INFO_GET_WA;
515 state->child_has_error = FALSE;
516 state->have_error = FALSE;
519 state->current_request++;
523 get_child_info_handler (Display *dpy,
531 ChildInfoState *state = (ChildInfoState *)data;
533 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
536 if (rep->generic.type == X_Error)
538 state->child_has_error = TRUE;
539 if (rep->error.errorCode != BadDrawable ||
540 rep->error.errorCode != BadWindow)
542 state->have_error = TRUE;
548 switch (state->current_request)
550 case CHILD_INFO_GET_PROPERTY:
552 xGetPropertyReply replbuf;
553 xGetPropertyReply *repl;
555 repl = (xGetPropertyReply *)
556 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
557 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
560 handle_get_property_reply (dpy, state, repl);
563 case CHILD_INFO_GET_WA:
565 xGetWindowAttributesReply replbuf;
566 xGetWindowAttributesReply *repl;
568 repl = (xGetWindowAttributesReply *)
569 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
570 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
573 handle_get_wa_reply (dpy, state, repl);
576 case CHILD_INFO_GET_GEOMETRY:
578 xGetGeometryReply replbuf;
579 xGetGeometryReply *repl;
581 repl = (xGetGeometryReply *)
582 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
583 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
586 handle_get_geometry_reply (dpy, state, repl);
598 _gdk_x11_get_window_child_info (GdkDisplay *display,
600 gboolean get_wm_state,
601 gboolean *win_has_wm_state,
602 GdkChildInfoX11 **children,
606 _XAsyncHandler async;
607 ChildInfoState state;
609 gboolean has_wm_state;
616 dpy = GDK_DISPLAY_XDISPLAY (display);
618 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
620 wm_state_atom = None;
622 gdk_error_trap_push ();
623 result = list_children_and_wm_state (dpy, window,
624 win_has_wm_state ? wm_state_atom : None,
626 &state.children, &state.nchildren);
627 gdk_error_trap_pop ();
633 if (win_has_wm_state)
634 *win_has_wm_state = TRUE;
639 if (win_has_wm_state)
640 *win_has_wm_state = FALSE;
643 state.get_wm_state = get_wm_state;
644 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
645 state.child_states = g_new (ChildInfoChildState, state.nchildren);
646 state.current_child = 0;
647 state.n_children_found = 0;
649 state.current_request = CHILD_INFO_GET_PROPERTY;
651 state.current_request = CHILD_INFO_GET_WA;
652 state.have_error = FALSE;
653 state.child_has_error = FALSE;
657 async.next = dpy->async_handlers;
658 async.handler = get_child_info_handler;
659 async.data = (XPointer) &state;
660 dpy->async_handlers = &async;
662 for (i = 0; i < state.nchildren; i++)
664 xResourceReq *resource_req;
665 xGetPropertyReq *prop_req;
666 Window window = state.children[i];
670 GetReq (GetProperty, prop_req);
671 prop_req->window = window;
672 prop_req->property = wm_state_atom;
673 prop_req->type = AnyPropertyType;
674 prop_req->delete = False;
675 prop_req->longOffset = 0;
676 prop_req->longLength = 0;
678 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
681 GetResReq(GetWindowAttributes, window, resource_req);
682 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
684 GetResReq(GetGeometry, window, resource_req);
685 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
690 /* Wait for the last reply
692 xGetGeometryReply rep;
694 /* On error, our async handler will get called
696 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
697 handle_get_geometry_reply (dpy, &state, &rep);
702 if (!state.have_error)
704 *children = state.child_info;
705 *nchildren = state.n_children_found;
709 g_free (state.child_info);
712 g_free (state.children);
713 g_free (state.child_states);
715 DeqAsyncHandler(dpy, &async);
719 return !state.have_error;