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.
51 #ifdef NEED_XIPROTO_H_FOR_XREPLY
52 #include <X11/extensions/XIproto.h>
55 #include <X11/Xlibint.h>
58 typedef struct _ChildInfoChildState ChildInfoChildState;
59 typedef struct _ChildInfoState ChildInfoState;
60 typedef struct _ListChildrenState ListChildrenState;
61 typedef struct _SendEventState SendEventState;
62 typedef struct _SetInputFocusState SetInputFocusState;
63 typedef struct _RoundtripState RoundtripState;
66 CHILD_INFO_GET_PROPERTY,
68 CHILD_INFO_GET_GEOMETRY
71 struct _ChildInfoChildState
76 struct _ChildInfoState
78 gboolean get_wm_state;
81 GdkChildInfoX11 *child_info;
82 ChildInfoChildState *child_states;
85 guint n_children_found;
88 gboolean child_has_error;
91 struct _ListChildrenState
94 gulong get_property_req;
96 gboolean has_wm_state;
99 struct _SendEventState
103 _XAsyncHandler async;
104 gulong send_event_req;
105 gulong get_input_focus_req;
107 GdkSendXEventCallback callback;
111 struct _SetInputFocusState
114 _XAsyncHandler async;
115 gulong set_input_focus_req;
116 gulong get_input_focus_req;
119 struct _RoundtripState
122 _XAsyncHandler async;
123 gulong get_input_focus_req;
125 GdkRoundTripCallback callback;
130 callback_idle (gpointer data)
132 SendEventState *state = (SendEventState *)data;
134 state->callback (state->window, !state->have_error, state->data);
142 send_event_handler (Display *dpy,
148 SendEventState *state = (SendEventState *)data;
150 if (dpy->last_request_read == state->send_event_req)
152 if (rep->generic.type == X_Error &&
153 rep->error.errorCode == BadWindow)
155 state->have_error = TRUE;
159 else if (dpy->last_request_read == state->get_input_focus_req)
161 xGetInputFocusReply replbuf;
162 xGetInputFocusReply *repl;
164 if (rep->generic.type != X_Error)
166 /* Actually does nothing, since there are no additional bytes
167 * to read, but maintain good form.
169 repl = (xGetInputFocusReply *)
170 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
171 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
176 gdk_threads_add_idle (callback_idle, state);
178 DeqAsyncHandler(state->dpy, &state->async);
180 return (rep->generic.type != X_Error);
187 client_message_to_wire (XClientMessageEvent *ev,
191 event->u.clientMessage.window = ev->window;
192 event->u.u.type = ev->type;
193 event->u.u.detail = ev->format;
197 event->u.clientMessage.u.b.type = ev->message_type;
198 for (i = 0; i < 20; i++)
199 event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
202 event->u.clientMessage.u.s.type = ev->message_type;
203 event->u.clientMessage.u.s.shorts0 = ev->data.s[0];
204 event->u.clientMessage.u.s.shorts1 = ev->data.s[1];
205 event->u.clientMessage.u.s.shorts2 = ev->data.s[2];
206 event->u.clientMessage.u.s.shorts3 = ev->data.s[3];
207 event->u.clientMessage.u.s.shorts4 = ev->data.s[4];
208 event->u.clientMessage.u.s.shorts5 = ev->data.s[5];
209 event->u.clientMessage.u.s.shorts6 = ev->data.s[6];
210 event->u.clientMessage.u.s.shorts7 = ev->data.s[7];
211 event->u.clientMessage.u.s.shorts8 = ev->data.s[8];
212 event->u.clientMessage.u.s.shorts9 = ev->data.s[9];
215 event->u.clientMessage.u.l.type = ev->message_type;
216 event->u.clientMessage.u.l.longs0 = ev->data.l[0];
217 event->u.clientMessage.u.l.longs1 = ev->data.l[1];
218 event->u.clientMessage.u.l.longs2 = ev->data.l[2];
219 event->u.clientMessage.u.l.longs3 = ev->data.l[3];
220 event->u.clientMessage.u.l.longs4 = ev->data.l[4];
223 /* client passing bogus data, let server complain */
229 _gdk_x11_send_client_message_async (GdkDisplay *display,
233 XClientMessageEvent *event_send,
234 GdkSendXEventCallback callback,
238 SendEventState *state;
240 dpy = GDK_DISPLAY_XDISPLAY (display);
242 state = g_new (SendEventState, 1);
245 state->window = window;
246 state->callback = callback;
248 state->have_error = FALSE;
252 state->async.next = dpy->async_handlers;
253 state->async.handler = send_event_handler;
254 state->async.data = (XPointer) state;
255 dpy->async_handlers = &state->async;
258 register xSendEventReq *req;
261 client_message_to_wire (event_send, &ev);
263 GetReq(SendEvent, req);
264 req->destination = window;
265 req->propagate = propagate;
266 req->eventMask = event_mask;
267 /* gross, matches Xproto.h */
269 memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
271 memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
274 state->send_event_req = dpy->request;
283 GetEmptyReq(GetInputFocus, req);
284 state->get_input_focus_req = dpy->request;
292 set_input_focus_handler (Display *dpy,
298 SetInputFocusState *state = (SetInputFocusState *)data;
300 if (dpy->last_request_read == state->set_input_focus_req)
302 if (rep->generic.type == X_Error &&
303 rep->error.errorCode == BadMatch)
305 /* Consume BadMatch errors, since we have no control
312 if (dpy->last_request_read == state->get_input_focus_req)
314 xGetInputFocusReply replbuf;
315 xGetInputFocusReply *repl;
317 if (rep->generic.type != X_Error)
319 /* Actually does nothing, since there are no additional bytes
320 * to read, but maintain good form.
322 repl = (xGetInputFocusReply *)
323 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
324 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
328 DeqAsyncHandler(state->dpy, &state->async);
332 return (rep->generic.type != X_Error);
339 _gdk_x11_set_input_focus_safe (GdkDisplay *display,
345 SetInputFocusState *state;
347 dpy = GDK_DISPLAY_XDISPLAY (display);
349 state = g_new (SetInputFocusState, 1);
355 state->async.next = dpy->async_handlers;
356 state->async.handler = set_input_focus_handler;
357 state->async.data = (XPointer) state;
358 dpy->async_handlers = &state->async;
361 xSetInputFocusReq *req;
363 GetReq(SetInputFocus, req);
365 req->revertTo = revert_to;
367 state->set_input_focus_req = dpy->request;
376 GetEmptyReq(GetInputFocus, req);
377 state->get_input_focus_req = dpy->request;
385 list_children_handler (Display *dpy,
391 ListChildrenState *state = (ListChildrenState *)data;
393 if (dpy->last_request_read != state->get_property_req)
396 if (rep->generic.type == X_Error)
398 state->have_error = TRUE;
403 xGetPropertyReply replbuf;
404 xGetPropertyReply *repl;
406 repl = (xGetPropertyReply *)
407 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
408 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
411 state->has_wm_state = repl->propertyType != None;
412 /* Since we called GetProperty with longLength of 0, we don't
413 * have to worry about consuming the property data that would
414 * normally follow after the reply
422 list_children_and_wm_state (Display *dpy,
425 gboolean *has_wm_state,
427 unsigned int *nchildren)
429 ListChildrenState state;
430 _XAsyncHandler async;
433 register xResourceReq *req;
434 xGetPropertyReq *prop_req;
440 *has_wm_state = FALSE;
442 state.have_error = FALSE;
443 state.has_wm_state = FALSE;
447 async.next = dpy->async_handlers;
448 async.handler = list_children_handler;
449 async.data = (XPointer) &state;
450 dpy->async_handlers = &async;
452 GetReq (GetProperty, prop_req);
453 prop_req->window = w;
454 prop_req->property = wm_state_atom;
455 prop_req->type = AnyPropertyType;
456 prop_req->delete = False;
457 prop_req->longOffset = 0;
458 prop_req->longLength = 0;
460 state.get_property_req = dpy->request;
463 GetResReq(QueryTree, w, req);
464 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
466 state.have_error = TRUE;
470 if (rep.nChildren != 0)
472 nbytes = rep.nChildren << 2;
473 if (state.have_error)
475 _XEatData(dpy, (unsigned long) nbytes);
478 *children = g_new (Window, rep.nChildren);
479 _XRead32 (dpy, (long *) *children, nbytes);
482 *nchildren = rep.nChildren;
483 *has_wm_state = state.has_wm_state;
487 DeqAsyncHandler(dpy, &async);
491 return !state.have_error;
495 handle_get_wa_reply (Display *dpy,
496 ChildInfoState *state,
497 xGetWindowAttributesReply *repl)
499 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
500 child->is_mapped = repl->mapState != IsUnmapped;
501 child->window_class = repl->class;
505 handle_get_geometry_reply (Display *dpy,
506 ChildInfoState *state,
507 xGetGeometryReply *repl)
509 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
511 child->x = cvtINT16toInt (repl->x);
512 child->y = cvtINT16toInt (repl->y);
513 child->width = repl->width;
514 child->height = repl->height;
518 handle_get_property_reply (Display *dpy,
519 ChildInfoState *state,
520 xGetPropertyReply *repl)
522 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
523 child->has_wm_state = repl->propertyType != None;
525 /* Since we called GetProperty with longLength of 0, we don't
526 * have to worry about consuming the property data that would
527 * normally follow after the reply
532 next_child (ChildInfoState *state)
534 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
536 if (!state->have_error && !state->child_has_error)
538 state->child_info[state->n_children_found].window = state->children[state->current_child];
539 state->n_children_found++;
541 state->current_child++;
542 if (state->get_wm_state)
543 state->current_request = CHILD_INFO_GET_PROPERTY;
545 state->current_request = CHILD_INFO_GET_WA;
546 state->child_has_error = FALSE;
547 state->have_error = FALSE;
550 state->current_request++;
554 get_child_info_handler (Display *dpy,
562 ChildInfoState *state = (ChildInfoState *)data;
564 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
567 if (rep->generic.type == X_Error)
569 state->child_has_error = TRUE;
570 if (rep->error.errorCode != BadDrawable ||
571 rep->error.errorCode != BadWindow)
573 state->have_error = TRUE;
579 switch (state->current_request)
581 case CHILD_INFO_GET_PROPERTY:
583 xGetPropertyReply replbuf;
584 xGetPropertyReply *repl;
586 repl = (xGetPropertyReply *)
587 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
588 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
591 handle_get_property_reply (dpy, state, repl);
594 case CHILD_INFO_GET_WA:
596 xGetWindowAttributesReply replbuf;
597 xGetWindowAttributesReply *repl;
599 repl = (xGetWindowAttributesReply *)
600 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
601 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
604 handle_get_wa_reply (dpy, state, repl);
607 case CHILD_INFO_GET_GEOMETRY:
609 xGetGeometryReply replbuf;
610 xGetGeometryReply *repl;
612 repl = (xGetGeometryReply *)
613 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
614 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
617 handle_get_geometry_reply (dpy, state, repl);
629 _gdk_x11_get_window_child_info (GdkDisplay *display,
631 gboolean get_wm_state,
632 gboolean *win_has_wm_state,
633 GdkChildInfoX11 **children,
637 _XAsyncHandler async;
638 ChildInfoState state;
640 gboolean has_wm_state;
647 dpy = GDK_DISPLAY_XDISPLAY (display);
649 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
651 wm_state_atom = None;
653 state.children = NULL;
656 gdk_x11_display_error_trap_push (display);
657 result = list_children_and_wm_state (dpy, window,
658 win_has_wm_state ? wm_state_atom : None,
660 &state.children, &state.nchildren);
661 gdk_x11_display_error_trap_pop_ignored (display);
664 g_free (state.children);
670 if (win_has_wm_state)
671 *win_has_wm_state = TRUE;
672 g_free (state.children);
677 if (win_has_wm_state)
678 *win_has_wm_state = FALSE;
681 state.get_wm_state = get_wm_state;
682 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
683 state.child_states = g_new (ChildInfoChildState, state.nchildren);
684 state.current_child = 0;
685 state.n_children_found = 0;
687 state.current_request = CHILD_INFO_GET_PROPERTY;
689 state.current_request = CHILD_INFO_GET_WA;
690 state.have_error = FALSE;
691 state.child_has_error = FALSE;
695 async.next = dpy->async_handlers;
696 async.handler = get_child_info_handler;
697 async.data = (XPointer) &state;
698 dpy->async_handlers = &async;
700 for (i = 0; i < state.nchildren; i++)
702 xResourceReq *resource_req;
703 xGetPropertyReq *prop_req;
704 Window window = state.children[i];
708 GetReq (GetProperty, prop_req);
709 prop_req->window = window;
710 prop_req->property = wm_state_atom;
711 prop_req->type = AnyPropertyType;
712 prop_req->delete = False;
713 prop_req->longOffset = 0;
714 prop_req->longLength = 0;
716 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
719 GetResReq(GetWindowAttributes, window, resource_req);
720 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
722 GetResReq(GetGeometry, window, resource_req);
723 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
728 /* Wait for the last reply
730 xGetGeometryReply rep;
732 /* On error, our async handler will get called
734 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
735 handle_get_geometry_reply (dpy, &state, &rep);
740 if (!state.have_error)
742 *children = state.child_info;
743 *nchildren = state.n_children_found;
747 g_free (state.child_info);
750 g_free (state.children);
751 g_free (state.child_states);
753 DeqAsyncHandler(dpy, &async);
757 return !state.have_error;
761 roundtrip_callback_idle (gpointer data)
763 RoundtripState *state = (RoundtripState *)data;
765 state->callback (state->display, state->data, state->get_input_focus_req);
773 roundtrip_handler (Display *dpy,
779 RoundtripState *state = (RoundtripState *)data;
781 if (dpy->last_request_read == state->get_input_focus_req)
783 xGetInputFocusReply replbuf;
784 xGetInputFocusReply *repl;
786 if (rep->generic.type != X_Error)
788 /* Actually does nothing, since there are no additional bytes
789 * to read, but maintain good form.
791 repl = (xGetInputFocusReply *)
792 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
793 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
799 gdk_threads_add_idle (roundtrip_callback_idle, state);
801 DeqAsyncHandler(state->dpy, &state->async);
803 return (rep->generic.type != X_Error);
810 _gdk_x11_roundtrip_async (GdkDisplay *display,
811 GdkRoundTripCallback callback,
815 RoundtripState *state;
817 dpy = GDK_DISPLAY_XDISPLAY (display);
819 state = g_new (RoundtripState, 1);
821 state->display = display;
823 state->callback = callback;
828 state->async.next = dpy->async_handlers;
829 state->async.handler = roundtrip_handler;
830 state->async.data = (XPointer) state;
831 dpy->async_handlers = &state->async;
839 GetEmptyReq(GetInputFocus, req);
840 state->get_input_focus_req = dpy->request;