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;
60 typedef struct _RoundtripState RoundtripState;
63 CHILD_INFO_GET_PROPERTY,
65 CHILD_INFO_GET_GEOMETRY
68 struct _ChildInfoChildState
73 struct _ChildInfoState
75 gboolean get_wm_state;
78 GdkChildInfoX11 *child_info;
79 ChildInfoChildState *child_states;
82 guint n_children_found;
85 gboolean child_has_error;
88 struct _ListChildrenState
91 gulong get_property_req;
93 gboolean has_wm_state;
96 struct _SendEventState
100 _XAsyncHandler async;
101 gulong send_event_req;
102 gulong get_input_focus_req;
104 GdkSendXEventCallback callback;
108 struct _SetInputFocusState
111 _XAsyncHandler async;
112 gulong set_input_focus_req;
113 gulong get_input_focus_req;
116 struct _RoundtripState
119 _XAsyncHandler async;
120 gulong get_input_focus_req;
121 GdkRoundTripCallback callback;
126 callback_idle (gpointer data)
128 SendEventState *state = (SendEventState *)data;
130 state->callback (state->window, !state->have_error, state->data);
138 send_event_handler (Display *dpy,
144 SendEventState *state = (SendEventState *)data;
146 if (dpy->last_request_read == state->send_event_req)
148 if (rep->generic.type == X_Error &&
149 rep->error.errorCode == BadWindow)
151 state->have_error = TRUE;
155 else if (dpy->last_request_read == state->get_input_focus_req)
157 xGetInputFocusReply replbuf;
158 xGetInputFocusReply *repl;
160 if (rep->generic.type != X_Error)
162 /* Actually does nothing, since there are no additional bytes
163 * to read, but maintain good form.
165 repl = (xGetInputFocusReply *)
166 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
167 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
172 gdk_threads_add_idle (callback_idle, state);
174 DeqAsyncHandler(state->dpy, &state->async);
176 return (rep->generic.type != X_Error);
183 client_message_to_wire (XClientMessageEvent *ev,
187 event->u.clientMessage.window = ev->window;
188 event->u.u.type = ev->type;
189 event->u.u.detail = ev->format;
193 event->u.clientMessage.u.b.type = ev->message_type;
194 for (i = 0; i < 20; i++)
195 event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
198 event->u.clientMessage.u.s.type = ev->message_type;
199 event->u.clientMessage.u.s.shorts0 = ev->data.s[0];
200 event->u.clientMessage.u.s.shorts1 = ev->data.s[1];
201 event->u.clientMessage.u.s.shorts2 = ev->data.s[2];
202 event->u.clientMessage.u.s.shorts3 = ev->data.s[3];
203 event->u.clientMessage.u.s.shorts4 = ev->data.s[4];
204 event->u.clientMessage.u.s.shorts5 = ev->data.s[5];
205 event->u.clientMessage.u.s.shorts6 = ev->data.s[6];
206 event->u.clientMessage.u.s.shorts7 = ev->data.s[7];
207 event->u.clientMessage.u.s.shorts8 = ev->data.s[8];
208 event->u.clientMessage.u.s.shorts9 = ev->data.s[9];
211 event->u.clientMessage.u.l.type = ev->message_type;
212 event->u.clientMessage.u.l.longs0 = ev->data.l[0];
213 event->u.clientMessage.u.l.longs1 = ev->data.l[1];
214 event->u.clientMessage.u.l.longs2 = ev->data.l[2];
215 event->u.clientMessage.u.l.longs3 = ev->data.l[3];
216 event->u.clientMessage.u.l.longs4 = ev->data.l[4];
219 /* client passing bogus data, let server complain */
225 _gdk_x11_send_client_message_async (GdkDisplay *display,
229 XClientMessageEvent *event_send,
230 GdkSendXEventCallback callback,
234 SendEventState *state;
236 dpy = GDK_DISPLAY_XDISPLAY (display);
238 state = g_new (SendEventState, 1);
241 state->window = window;
242 state->callback = callback;
244 state->have_error = FALSE;
248 state->async.next = dpy->async_handlers;
249 state->async.handler = send_event_handler;
250 state->async.data = (XPointer) state;
251 dpy->async_handlers = &state->async;
254 register xSendEventReq *req;
257 client_message_to_wire (event_send, &ev);
259 GetReq(SendEvent, req);
260 req->destination = window;
261 req->propagate = propagate;
262 req->eventMask = event_mask;
263 /* gross, matches Xproto.h */
265 memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
267 memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
270 state->send_event_req = dpy->request;
279 GetEmptyReq(GetInputFocus, req);
280 state->get_input_focus_req = dpy->request;
288 set_input_focus_handler (Display *dpy,
294 SetInputFocusState *state = (SetInputFocusState *)data;
296 if (dpy->last_request_read == state->set_input_focus_req)
298 if (rep->generic.type == X_Error &&
299 rep->error.errorCode == BadMatch)
301 /* Consume BadMatch errors, since we have no control
308 if (dpy->last_request_read == state->get_input_focus_req)
310 xGetInputFocusReply replbuf;
311 xGetInputFocusReply *repl;
313 if (rep->generic.type != X_Error)
315 /* Actually does nothing, since there are no additional bytes
316 * to read, but maintain good form.
318 repl = (xGetInputFocusReply *)
319 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
320 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
324 DeqAsyncHandler(state->dpy, &state->async);
328 return (rep->generic.type != X_Error);
335 _gdk_x11_set_input_focus_safe (GdkDisplay *display,
341 SetInputFocusState *state;
343 dpy = GDK_DISPLAY_XDISPLAY (display);
345 state = g_new (SetInputFocusState, 1);
351 state->async.next = dpy->async_handlers;
352 state->async.handler = set_input_focus_handler;
353 state->async.data = (XPointer) state;
354 dpy->async_handlers = &state->async;
357 xSetInputFocusReq *req;
359 GetReq(SetInputFocus, req);
361 req->revertTo = revert_to;
363 state->set_input_focus_req = dpy->request;
372 GetEmptyReq(GetInputFocus, req);
373 state->get_input_focus_req = dpy->request;
381 list_children_handler (Display *dpy,
387 ListChildrenState *state = (ListChildrenState *)data;
389 if (dpy->last_request_read != state->get_property_req)
392 if (rep->generic.type == X_Error)
394 state->have_error = TRUE;
399 xGetPropertyReply replbuf;
400 xGetPropertyReply *repl;
402 repl = (xGetPropertyReply *)
403 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
404 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
407 state->has_wm_state = repl->propertyType != None;
408 /* Since we called GetProperty with longLength of 0, we don't
409 * have to worry about consuming the property data that would
410 * normally follow after the reply
418 list_children_and_wm_state (Display *dpy,
421 gboolean *has_wm_state,
423 unsigned int *nchildren)
425 ListChildrenState state;
426 _XAsyncHandler async;
429 register xResourceReq *req;
430 xGetPropertyReq *prop_req;
436 *has_wm_state = FALSE;
438 state.have_error = FALSE;
439 state.has_wm_state = FALSE;
443 async.next = dpy->async_handlers;
444 async.handler = list_children_handler;
445 async.data = (XPointer) &state;
446 dpy->async_handlers = &async;
448 GetReq (GetProperty, prop_req);
449 prop_req->window = w;
450 prop_req->property = wm_state_atom;
451 prop_req->type = AnyPropertyType;
452 prop_req->delete = False;
453 prop_req->longOffset = 0;
454 prop_req->longLength = 0;
456 state.get_property_req = dpy->request;
459 GetResReq(QueryTree, w, req);
460 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
462 state.have_error = TRUE;
466 if (rep.nChildren != 0)
468 nbytes = rep.nChildren << 2;
469 if (state.have_error)
471 _XEatData(dpy, (unsigned long) nbytes);
474 *children = g_new (Window, rep.nChildren);
475 _XRead32 (dpy, (long *) *children, nbytes);
478 *nchildren = rep.nChildren;
479 *has_wm_state = state.has_wm_state;
483 DeqAsyncHandler(dpy, &async);
487 return !state.have_error;
491 handle_get_wa_reply (Display *dpy,
492 ChildInfoState *state,
493 xGetWindowAttributesReply *repl)
495 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
496 child->is_mapped = repl->mapState != IsUnmapped;
497 child->window_class = repl->class;
501 handle_get_geometry_reply (Display *dpy,
502 ChildInfoState *state,
503 xGetGeometryReply *repl)
505 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
507 child->x = cvtINT16toInt (repl->x);
508 child->y = cvtINT16toInt (repl->y);
509 child->width = repl->width;
510 child->height = repl->height;
514 handle_get_property_reply (Display *dpy,
515 ChildInfoState *state,
516 xGetPropertyReply *repl)
518 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
519 child->has_wm_state = repl->propertyType != None;
521 /* Since we called GetProperty with longLength of 0, we don't
522 * have to worry about consuming the property data that would
523 * normally follow after the reply
528 next_child (ChildInfoState *state)
530 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
532 if (!state->have_error && !state->child_has_error)
534 state->child_info[state->n_children_found].window = state->children[state->current_child];
535 state->n_children_found++;
537 state->current_child++;
538 if (state->get_wm_state)
539 state->current_request = CHILD_INFO_GET_PROPERTY;
541 state->current_request = CHILD_INFO_GET_WA;
542 state->child_has_error = FALSE;
543 state->have_error = FALSE;
546 state->current_request++;
550 get_child_info_handler (Display *dpy,
558 ChildInfoState *state = (ChildInfoState *)data;
560 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
563 if (rep->generic.type == X_Error)
565 state->child_has_error = TRUE;
566 if (rep->error.errorCode != BadDrawable ||
567 rep->error.errorCode != BadWindow)
569 state->have_error = TRUE;
575 switch (state->current_request)
577 case CHILD_INFO_GET_PROPERTY:
579 xGetPropertyReply replbuf;
580 xGetPropertyReply *repl;
582 repl = (xGetPropertyReply *)
583 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
584 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
587 handle_get_property_reply (dpy, state, repl);
590 case CHILD_INFO_GET_WA:
592 xGetWindowAttributesReply replbuf;
593 xGetWindowAttributesReply *repl;
595 repl = (xGetWindowAttributesReply *)
596 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
597 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
600 handle_get_wa_reply (dpy, state, repl);
603 case CHILD_INFO_GET_GEOMETRY:
605 xGetGeometryReply replbuf;
606 xGetGeometryReply *repl;
608 repl = (xGetGeometryReply *)
609 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
610 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
613 handle_get_geometry_reply (dpy, state, repl);
625 _gdk_x11_get_window_child_info (GdkDisplay *display,
627 gboolean get_wm_state,
628 gboolean *win_has_wm_state,
629 GdkChildInfoX11 **children,
633 _XAsyncHandler async;
634 ChildInfoState state;
636 gboolean has_wm_state;
643 dpy = GDK_DISPLAY_XDISPLAY (display);
645 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
647 wm_state_atom = None;
649 state.children = NULL;
652 gdk_error_trap_push ();
653 result = list_children_and_wm_state (dpy, window,
654 win_has_wm_state ? wm_state_atom : None,
656 &state.children, &state.nchildren);
657 gdk_error_trap_pop ();
660 g_free (state.children);
666 if (win_has_wm_state)
667 *win_has_wm_state = TRUE;
668 g_free (state.children);
673 if (win_has_wm_state)
674 *win_has_wm_state = FALSE;
677 state.get_wm_state = get_wm_state;
678 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
679 state.child_states = g_new (ChildInfoChildState, state.nchildren);
680 state.current_child = 0;
681 state.n_children_found = 0;
683 state.current_request = CHILD_INFO_GET_PROPERTY;
685 state.current_request = CHILD_INFO_GET_WA;
686 state.have_error = FALSE;
687 state.child_has_error = FALSE;
691 async.next = dpy->async_handlers;
692 async.handler = get_child_info_handler;
693 async.data = (XPointer) &state;
694 dpy->async_handlers = &async;
696 for (i = 0; i < state.nchildren; i++)
698 xResourceReq *resource_req;
699 xGetPropertyReq *prop_req;
700 Window window = state.children[i];
704 GetReq (GetProperty, prop_req);
705 prop_req->window = window;
706 prop_req->property = wm_state_atom;
707 prop_req->type = AnyPropertyType;
708 prop_req->delete = False;
709 prop_req->longOffset = 0;
710 prop_req->longLength = 0;
712 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
715 GetResReq(GetWindowAttributes, window, resource_req);
716 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
718 GetResReq(GetGeometry, window, resource_req);
719 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
724 /* Wait for the last reply
726 xGetGeometryReply rep;
728 /* On error, our async handler will get called
730 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
731 handle_get_geometry_reply (dpy, &state, &rep);
736 if (!state.have_error)
738 *children = state.child_info;
739 *nchildren = state.n_children_found;
743 g_free (state.child_info);
746 g_free (state.children);
747 g_free (state.child_states);
749 DeqAsyncHandler(dpy, &async);
753 return !state.have_error;
757 roundtrip_callback_idle (gpointer data)
759 RoundtripState *state = (RoundtripState *)data;
761 state->callback (state->data);
769 roundtrip_handler (Display *dpy,
775 RoundtripState *state = (RoundtripState *)data;
777 if (dpy->last_request_read == state->get_input_focus_req)
779 xGetInputFocusReply replbuf;
780 xGetInputFocusReply *repl;
782 if (rep->generic.type != X_Error)
784 /* Actually does nothing, since there are no additional bytes
785 * to read, but maintain good form.
787 repl = (xGetInputFocusReply *)
788 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
789 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
794 gdk_threads_add_idle (roundtrip_callback_idle, state);
796 DeqAsyncHandler(state->dpy, &state->async);
798 return (rep->generic.type != X_Error);
805 _gdk_x11_roundtrip_async (GdkDisplay *display,
806 GdkRoundTripCallback callback,
810 RoundtripState *state;
812 dpy = GDK_DISPLAY_XDISPLAY (display);
814 state = g_new (RoundtripState, 1);
817 state->callback = callback;
822 state->async.next = dpy->async_handlers;
823 state->async.handler = roundtrip_handler;
824 state->async.data = (XPointer) state;
825 dpy->async_handlers = &state->async;
833 GetEmptyReq(GetInputFocus, req);
834 state->get_input_focus_req = dpy->request;
841 #define __GDK_ASYNC_C__
842 #include "gdkaliasdef.c"