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 #include <X11/Xlibint.h>
51 typedef struct _ChildInfoChildState ChildInfoChildState;
52 typedef struct _ChildInfoState ChildInfoState;
53 typedef struct _ListChildrenState ListChildrenState;
54 typedef struct _SendEventState SendEventState;
55 typedef struct _SetInputFocusState SetInputFocusState;
58 CHILD_INFO_GET_PROPERTY,
60 CHILD_INFO_GET_GEOMETRY
63 struct _ChildInfoChildState
68 struct _ChildInfoState
70 gboolean get_wm_state;
73 GdkChildInfoX11 *child_info;
74 ChildInfoChildState *child_states;
77 guint n_children_found;
80 gboolean child_has_error;
83 struct _ListChildrenState
86 gulong get_property_req;
88 gboolean has_wm_state;
91 struct _SendEventState
96 gulong send_event_req;
97 gulong get_input_focus_req;
99 GdkSendXEventCallback callback;
103 struct _SetInputFocusState
106 _XAsyncHandler async;
107 gulong set_input_focus_req;
108 gulong get_input_focus_req;
112 send_event_handler (Display *dpy,
118 SendEventState *state = (SendEventState *)data;
120 if (dpy->last_request_read == state->send_event_req)
122 if (rep->generic.type == X_Error &&
123 rep->error.errorCode == BadWindow)
125 state->have_error = TRUE;
129 else if (dpy->last_request_read == state->get_input_focus_req)
131 xGetInputFocusReply replbuf;
132 xGetInputFocusReply *repl;
134 if (rep->generic.type != X_Error)
136 /* Actually does nothing, since there are no additional bytes
137 * to read, but maintain good form.
139 repl = (xGetInputFocusReply *)
140 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
141 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
146 state->callback (state->window, !state->have_error, state->data);
148 DeqAsyncHandler(state->dpy, &state->async);
150 return (rep->generic.type != X_Error);
157 client_message_to_wire (XClientMessageEvent *ev,
161 event->u.clientMessage.window = ev->window;
162 event->u.u.type = ev->type;
163 event->u.u.detail = ev->format;
167 event->u.clientMessage.u.b.type = ev->message_type;
168 for (i = 0; i < 20; i++)
169 event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
172 event->u.clientMessage.u.s.type = ev->message_type;
173 event->u.clientMessage.u.s.shorts0 = ev->data.s[0];
174 event->u.clientMessage.u.s.shorts1 = ev->data.s[1];
175 event->u.clientMessage.u.s.shorts2 = ev->data.s[2];
176 event->u.clientMessage.u.s.shorts3 = ev->data.s[3];
177 event->u.clientMessage.u.s.shorts4 = ev->data.s[4];
178 event->u.clientMessage.u.s.shorts5 = ev->data.s[5];
179 event->u.clientMessage.u.s.shorts6 = ev->data.s[6];
180 event->u.clientMessage.u.s.shorts7 = ev->data.s[7];
181 event->u.clientMessage.u.s.shorts8 = ev->data.s[8];
182 event->u.clientMessage.u.s.shorts9 = ev->data.s[9];
185 event->u.clientMessage.u.l.type = ev->message_type;
186 event->u.clientMessage.u.l.longs0 = ev->data.l[0];
187 event->u.clientMessage.u.l.longs1 = ev->data.l[1];
188 event->u.clientMessage.u.l.longs2 = ev->data.l[2];
189 event->u.clientMessage.u.l.longs3 = ev->data.l[3];
190 event->u.clientMessage.u.l.longs4 = ev->data.l[4];
193 /* client passing bogus data, let server complain */
199 _gdk_x11_send_client_message_async (GdkDisplay *display,
203 XClientMessageEvent *event_send,
204 GdkSendXEventCallback callback,
208 SendEventState *state;
210 dpy = GDK_DISPLAY_XDISPLAY (display);
212 state = g_new (SendEventState, 1);
215 state->window = window;
216 state->callback = callback;
218 state->have_error = FALSE;
222 state->async.next = dpy->async_handlers;
223 state->async.handler = send_event_handler;
224 state->async.data = (XPointer) state;
225 dpy->async_handlers = &state->async;
228 register xSendEventReq *req;
231 client_message_to_wire (event_send, &ev);
233 GetReq(SendEvent, req);
234 req->destination = window;
235 req->propagate = propagate;
236 req->eventMask = event_mask;
237 /* gross, matches Xproto.h */
239 memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
241 memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
244 state->send_event_req = dpy->request;
253 GetEmptyReq(GetInputFocus, req);
254 state->get_input_focus_req = dpy->request;
262 set_input_focus_handler (Display *dpy,
268 SetInputFocusState *state = (SetInputFocusState *)data;
270 if (dpy->last_request_read == state->set_input_focus_req)
272 if (rep->generic.type == X_Error &&
273 rep->error.errorCode == BadMatch)
275 /* Consume BadMatch errors, since we have no control
282 if (dpy->last_request_read == state->get_input_focus_req)
284 xGetInputFocusReply replbuf;
285 xGetInputFocusReply *repl;
287 if (rep->generic.type != X_Error)
289 /* Actually does nothing, since there are no additional bytes
290 * to read, but maintain good form.
292 repl = (xGetInputFocusReply *)
293 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
294 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
298 DeqAsyncHandler(state->dpy, &state->async);
302 return (rep->generic.type != X_Error);
309 _gdk_x11_set_input_focus_safe (GdkDisplay *display,
315 SetInputFocusState *state;
317 dpy = GDK_DISPLAY_XDISPLAY (display);
319 state = g_new (SetInputFocusState, 1);
325 state->async.next = dpy->async_handlers;
326 state->async.handler = set_input_focus_handler;
327 state->async.data = (XPointer) state;
328 dpy->async_handlers = &state->async;
331 xSetInputFocusReq *req;
333 GetReq(SetInputFocus, req);
335 req->revertTo = revert_to;
337 state->set_input_focus_req = dpy->request;
346 GetEmptyReq(GetInputFocus, req);
347 state->get_input_focus_req = dpy->request;
355 list_children_handler (Display *dpy,
361 ListChildrenState *state = (ListChildrenState *)data;
363 if (dpy->last_request_read != state->get_property_req)
366 if (rep->generic.type == X_Error)
368 state->have_error = TRUE;
373 xGetPropertyReply replbuf;
374 xGetPropertyReply *repl;
376 repl = (xGetPropertyReply *)
377 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
378 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
381 state->has_wm_state = repl->propertyType != None;
382 /* Since we called GetProperty with longLength of 0, we don't
383 * have to worry about consuming the property data that would
384 * normally follow after the reply
392 list_children_and_wm_state (Display *dpy,
395 gboolean *has_wm_state,
397 unsigned int *nchildren)
399 ListChildrenState state;
400 _XAsyncHandler async;
403 register xResourceReq *req;
404 xGetPropertyReq *prop_req;
410 *has_wm_state = FALSE;
412 state.have_error = FALSE;
413 state.has_wm_state = FALSE;
417 async.next = dpy->async_handlers;
418 async.handler = list_children_handler;
419 async.data = (XPointer) &state;
420 dpy->async_handlers = &async;
422 GetReq (GetProperty, prop_req);
423 prop_req->window = w;
424 prop_req->property = wm_state_atom;
425 prop_req->type = AnyPropertyType;
426 prop_req->delete = False;
427 prop_req->longOffset = 0;
428 prop_req->longLength = 0;
430 state.get_property_req = dpy->request;
433 GetResReq(QueryTree, w, req);
434 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
436 state.have_error = TRUE;
440 if (rep.nChildren != 0)
442 nbytes = rep.nChildren << 2;
443 if (state.have_error)
445 _XEatData(dpy, (unsigned long) nbytes);
448 *children = g_new (Window, rep.nChildren);
449 _XRead32 (dpy, (long *) *children, nbytes);
452 *nchildren = rep.nChildren;
453 *has_wm_state = state.has_wm_state;
457 DeqAsyncHandler(dpy, &async);
461 return !state.have_error;
465 handle_get_wa_reply (Display *dpy,
466 ChildInfoState *state,
467 xGetWindowAttributesReply *repl)
469 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
470 child->is_mapped = repl->mapState != IsUnmapped;
471 child->window_class = repl->class;
475 handle_get_geometry_reply (Display *dpy,
476 ChildInfoState *state,
477 xGetGeometryReply *repl)
479 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
481 child->x = cvtINT16toInt (repl->x);
482 child->y = cvtINT16toInt (repl->y);
483 child->width = repl->width;
484 child->height = repl->height;
488 handle_get_property_reply (Display *dpy,
489 ChildInfoState *state,
490 xGetPropertyReply *repl)
492 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
493 child->has_wm_state = repl->propertyType != None;
495 /* Since we called GetProperty with longLength of 0, we don't
496 * have to worry about consuming the property data that would
497 * normally follow after the reply
502 next_child (ChildInfoState *state)
504 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
506 if (!state->have_error && !state->child_has_error)
508 state->child_info[state->n_children_found].window = state->children[state->current_child];
509 state->n_children_found++;
511 state->current_child++;
512 if (state->get_wm_state)
513 state->current_request = CHILD_INFO_GET_PROPERTY;
515 state->current_request = CHILD_INFO_GET_WA;
516 state->child_has_error = FALSE;
517 state->have_error = FALSE;
520 state->current_request++;
524 get_child_info_handler (Display *dpy,
532 ChildInfoState *state = (ChildInfoState *)data;
534 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
537 if (rep->generic.type == X_Error)
539 state->child_has_error = TRUE;
540 if (rep->error.errorCode != BadDrawable ||
541 rep->error.errorCode != BadWindow)
543 state->have_error = TRUE;
549 switch (state->current_request)
551 case CHILD_INFO_GET_PROPERTY:
553 xGetPropertyReply replbuf;
554 xGetPropertyReply *repl;
556 repl = (xGetPropertyReply *)
557 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
558 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
561 handle_get_property_reply (dpy, state, repl);
564 case CHILD_INFO_GET_WA:
566 xGetWindowAttributesReply replbuf;
567 xGetWindowAttributesReply *repl;
569 repl = (xGetWindowAttributesReply *)
570 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
571 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
574 handle_get_wa_reply (dpy, state, repl);
577 case CHILD_INFO_GET_GEOMETRY:
579 xGetGeometryReply replbuf;
580 xGetGeometryReply *repl;
582 repl = (xGetGeometryReply *)
583 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
584 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
587 handle_get_geometry_reply (dpy, state, repl);
599 _gdk_x11_get_window_child_info (GdkDisplay *display,
601 gboolean get_wm_state,
602 gboolean *win_has_wm_state,
603 GdkChildInfoX11 **children,
607 _XAsyncHandler async;
608 ChildInfoState state;
610 gboolean has_wm_state;
617 dpy = GDK_DISPLAY_XDISPLAY (display);
619 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
621 wm_state_atom = None;
623 gdk_error_trap_push ();
624 result = list_children_and_wm_state (dpy, window,
625 win_has_wm_state ? wm_state_atom : None,
627 &state.children, &state.nchildren);
628 gdk_error_trap_pop ();
634 if (win_has_wm_state)
635 *win_has_wm_state = TRUE;
640 if (win_has_wm_state)
641 *win_has_wm_state = FALSE;
644 state.get_wm_state = get_wm_state;
645 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
646 state.child_states = g_new (ChildInfoChildState, state.nchildren);
647 state.current_child = 0;
648 state.n_children_found = 0;
650 state.current_request = CHILD_INFO_GET_PROPERTY;
652 state.current_request = CHILD_INFO_GET_WA;
653 state.have_error = FALSE;
654 state.child_has_error = FALSE;
658 async.next = dpy->async_handlers;
659 async.handler = get_child_info_handler;
660 async.data = (XPointer) &state;
661 dpy->async_handlers = &async;
663 for (i = 0; i < state.nchildren; i++)
665 xResourceReq *resource_req;
666 xGetPropertyReq *prop_req;
667 Window window = state.children[i];
671 GetReq (GetProperty, prop_req);
672 prop_req->window = window;
673 prop_req->property = wm_state_atom;
674 prop_req->type = AnyPropertyType;
675 prop_req->delete = False;
676 prop_req->longOffset = 0;
677 prop_req->longLength = 0;
679 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
682 GetResReq(GetWindowAttributes, window, resource_req);
683 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
685 GetResReq(GetGeometry, window, resource_req);
686 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
691 /* Wait for the last reply
693 xGetGeometryReply rep;
695 /* On error, our async handler will get called
697 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
698 handle_get_geometry_reply (dpy, &state, &rep);
703 if (!state.have_error)
705 *children = state.child_info;
706 *nchildren = state.n_children_found;
710 g_free (state.child_info);
713 g_free (state.children);
714 g_free (state.child_states);
716 DeqAsyncHandler(dpy, &async);
720 return !state.have_error;