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;
122 GdkRoundTripCallback callback;
127 callback_idle (gpointer data)
129 SendEventState *state = (SendEventState *)data;
131 state->callback (state->window, !state->have_error, state->data);
139 send_event_handler (Display *dpy,
145 SendEventState *state = (SendEventState *)data;
147 if (dpy->last_request_read == state->send_event_req)
149 if (rep->generic.type == X_Error &&
150 rep->error.errorCode == BadWindow)
152 state->have_error = TRUE;
156 else if (dpy->last_request_read == state->get_input_focus_req)
158 xGetInputFocusReply replbuf;
159 xGetInputFocusReply *repl;
161 if (rep->generic.type != X_Error)
163 /* Actually does nothing, since there are no additional bytes
164 * to read, but maintain good form.
166 repl = (xGetInputFocusReply *)
167 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
168 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
173 gdk_threads_add_idle (callback_idle, state);
175 DeqAsyncHandler(state->dpy, &state->async);
177 return (rep->generic.type != X_Error);
184 client_message_to_wire (XClientMessageEvent *ev,
188 event->u.clientMessage.window = ev->window;
189 event->u.u.type = ev->type;
190 event->u.u.detail = ev->format;
194 event->u.clientMessage.u.b.type = ev->message_type;
195 for (i = 0; i < 20; i++)
196 event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
199 event->u.clientMessage.u.s.type = ev->message_type;
200 event->u.clientMessage.u.s.shorts0 = ev->data.s[0];
201 event->u.clientMessage.u.s.shorts1 = ev->data.s[1];
202 event->u.clientMessage.u.s.shorts2 = ev->data.s[2];
203 event->u.clientMessage.u.s.shorts3 = ev->data.s[3];
204 event->u.clientMessage.u.s.shorts4 = ev->data.s[4];
205 event->u.clientMessage.u.s.shorts5 = ev->data.s[5];
206 event->u.clientMessage.u.s.shorts6 = ev->data.s[6];
207 event->u.clientMessage.u.s.shorts7 = ev->data.s[7];
208 event->u.clientMessage.u.s.shorts8 = ev->data.s[8];
209 event->u.clientMessage.u.s.shorts9 = ev->data.s[9];
212 event->u.clientMessage.u.l.type = ev->message_type;
213 event->u.clientMessage.u.l.longs0 = ev->data.l[0];
214 event->u.clientMessage.u.l.longs1 = ev->data.l[1];
215 event->u.clientMessage.u.l.longs2 = ev->data.l[2];
216 event->u.clientMessage.u.l.longs3 = ev->data.l[3];
217 event->u.clientMessage.u.l.longs4 = ev->data.l[4];
220 /* client passing bogus data, let server complain */
226 _gdk_x11_send_client_message_async (GdkDisplay *display,
230 XClientMessageEvent *event_send,
231 GdkSendXEventCallback callback,
235 SendEventState *state;
237 dpy = GDK_DISPLAY_XDISPLAY (display);
239 state = g_new (SendEventState, 1);
242 state->window = window;
243 state->callback = callback;
245 state->have_error = FALSE;
249 state->async.next = dpy->async_handlers;
250 state->async.handler = send_event_handler;
251 state->async.data = (XPointer) state;
252 dpy->async_handlers = &state->async;
255 register xSendEventReq *req;
258 client_message_to_wire (event_send, &ev);
260 GetReq(SendEvent, req);
261 req->destination = window;
262 req->propagate = propagate;
263 req->eventMask = event_mask;
264 /* gross, matches Xproto.h */
266 memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
268 memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
271 state->send_event_req = dpy->request;
280 GetEmptyReq(GetInputFocus, req);
281 state->get_input_focus_req = dpy->request;
289 set_input_focus_handler (Display *dpy,
295 SetInputFocusState *state = (SetInputFocusState *)data;
297 if (dpy->last_request_read == state->set_input_focus_req)
299 if (rep->generic.type == X_Error &&
300 rep->error.errorCode == BadMatch)
302 /* Consume BadMatch errors, since we have no control
309 if (dpy->last_request_read == state->get_input_focus_req)
311 xGetInputFocusReply replbuf;
312 xGetInputFocusReply *repl;
314 if (rep->generic.type != X_Error)
316 /* Actually does nothing, since there are no additional bytes
317 * to read, but maintain good form.
319 repl = (xGetInputFocusReply *)
320 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
321 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
325 DeqAsyncHandler(state->dpy, &state->async);
329 return (rep->generic.type != X_Error);
336 _gdk_x11_set_input_focus_safe (GdkDisplay *display,
342 SetInputFocusState *state;
344 dpy = GDK_DISPLAY_XDISPLAY (display);
346 state = g_new (SetInputFocusState, 1);
352 state->async.next = dpy->async_handlers;
353 state->async.handler = set_input_focus_handler;
354 state->async.data = (XPointer) state;
355 dpy->async_handlers = &state->async;
358 xSetInputFocusReq *req;
360 GetReq(SetInputFocus, req);
362 req->revertTo = revert_to;
364 state->set_input_focus_req = dpy->request;
373 GetEmptyReq(GetInputFocus, req);
374 state->get_input_focus_req = dpy->request;
382 list_children_handler (Display *dpy,
388 ListChildrenState *state = (ListChildrenState *)data;
390 if (dpy->last_request_read != state->get_property_req)
393 if (rep->generic.type == X_Error)
395 state->have_error = TRUE;
400 xGetPropertyReply replbuf;
401 xGetPropertyReply *repl;
403 repl = (xGetPropertyReply *)
404 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
405 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
408 state->has_wm_state = repl->propertyType != None;
409 /* Since we called GetProperty with longLength of 0, we don't
410 * have to worry about consuming the property data that would
411 * normally follow after the reply
419 list_children_and_wm_state (Display *dpy,
422 gboolean *has_wm_state,
424 unsigned int *nchildren)
426 ListChildrenState state;
427 _XAsyncHandler async;
430 register xResourceReq *req;
431 xGetPropertyReq *prop_req;
437 *has_wm_state = FALSE;
439 state.have_error = FALSE;
440 state.has_wm_state = FALSE;
444 async.next = dpy->async_handlers;
445 async.handler = list_children_handler;
446 async.data = (XPointer) &state;
447 dpy->async_handlers = &async;
449 GetReq (GetProperty, prop_req);
450 prop_req->window = w;
451 prop_req->property = wm_state_atom;
452 prop_req->type = AnyPropertyType;
453 prop_req->delete = False;
454 prop_req->longOffset = 0;
455 prop_req->longLength = 0;
457 state.get_property_req = dpy->request;
460 GetResReq(QueryTree, w, req);
461 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
463 state.have_error = TRUE;
467 if (rep.nChildren != 0)
469 nbytes = rep.nChildren << 2;
470 if (state.have_error)
472 _XEatData(dpy, (unsigned long) nbytes);
475 *children = g_new (Window, rep.nChildren);
476 _XRead32 (dpy, (long *) *children, nbytes);
479 *nchildren = rep.nChildren;
480 *has_wm_state = state.has_wm_state;
484 DeqAsyncHandler(dpy, &async);
488 return !state.have_error;
492 handle_get_wa_reply (Display *dpy,
493 ChildInfoState *state,
494 xGetWindowAttributesReply *repl)
496 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
497 child->is_mapped = repl->mapState != IsUnmapped;
498 child->window_class = repl->class;
502 handle_get_geometry_reply (Display *dpy,
503 ChildInfoState *state,
504 xGetGeometryReply *repl)
506 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
508 child->x = cvtINT16toInt (repl->x);
509 child->y = cvtINT16toInt (repl->y);
510 child->width = repl->width;
511 child->height = repl->height;
515 handle_get_property_reply (Display *dpy,
516 ChildInfoState *state,
517 xGetPropertyReply *repl)
519 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
520 child->has_wm_state = repl->propertyType != None;
522 /* Since we called GetProperty with longLength of 0, we don't
523 * have to worry about consuming the property data that would
524 * normally follow after the reply
529 next_child (ChildInfoState *state)
531 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
533 if (!state->have_error && !state->child_has_error)
535 state->child_info[state->n_children_found].window = state->children[state->current_child];
536 state->n_children_found++;
538 state->current_child++;
539 if (state->get_wm_state)
540 state->current_request = CHILD_INFO_GET_PROPERTY;
542 state->current_request = CHILD_INFO_GET_WA;
543 state->child_has_error = FALSE;
544 state->have_error = FALSE;
547 state->current_request++;
551 get_child_info_handler (Display *dpy,
559 ChildInfoState *state = (ChildInfoState *)data;
561 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
564 if (rep->generic.type == X_Error)
566 state->child_has_error = TRUE;
567 if (rep->error.errorCode != BadDrawable ||
568 rep->error.errorCode != BadWindow)
570 state->have_error = TRUE;
576 switch (state->current_request)
578 case CHILD_INFO_GET_PROPERTY:
580 xGetPropertyReply replbuf;
581 xGetPropertyReply *repl;
583 repl = (xGetPropertyReply *)
584 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
585 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
588 handle_get_property_reply (dpy, state, repl);
591 case CHILD_INFO_GET_WA:
593 xGetWindowAttributesReply replbuf;
594 xGetWindowAttributesReply *repl;
596 repl = (xGetWindowAttributesReply *)
597 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
598 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
601 handle_get_wa_reply (dpy, state, repl);
604 case CHILD_INFO_GET_GEOMETRY:
606 xGetGeometryReply replbuf;
607 xGetGeometryReply *repl;
609 repl = (xGetGeometryReply *)
610 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
611 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
614 handle_get_geometry_reply (dpy, state, repl);
626 _gdk_x11_get_window_child_info (GdkDisplay *display,
628 gboolean get_wm_state,
629 gboolean *win_has_wm_state,
630 GdkChildInfoX11 **children,
634 _XAsyncHandler async;
635 ChildInfoState state;
637 gboolean has_wm_state;
644 dpy = GDK_DISPLAY_XDISPLAY (display);
646 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
648 wm_state_atom = None;
650 state.children = NULL;
653 gdk_error_trap_push ();
654 result = list_children_and_wm_state (dpy, window,
655 win_has_wm_state ? wm_state_atom : None,
657 &state.children, &state.nchildren);
658 gdk_error_trap_pop ();
661 g_free (state.children);
667 if (win_has_wm_state)
668 *win_has_wm_state = TRUE;
669 g_free (state.children);
674 if (win_has_wm_state)
675 *win_has_wm_state = FALSE;
678 state.get_wm_state = get_wm_state;
679 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
680 state.child_states = g_new (ChildInfoChildState, state.nchildren);
681 state.current_child = 0;
682 state.n_children_found = 0;
684 state.current_request = CHILD_INFO_GET_PROPERTY;
686 state.current_request = CHILD_INFO_GET_WA;
687 state.have_error = FALSE;
688 state.child_has_error = FALSE;
692 async.next = dpy->async_handlers;
693 async.handler = get_child_info_handler;
694 async.data = (XPointer) &state;
695 dpy->async_handlers = &async;
697 for (i = 0; i < state.nchildren; i++)
699 xResourceReq *resource_req;
700 xGetPropertyReq *prop_req;
701 Window window = state.children[i];
705 GetReq (GetProperty, prop_req);
706 prop_req->window = window;
707 prop_req->property = wm_state_atom;
708 prop_req->type = AnyPropertyType;
709 prop_req->delete = False;
710 prop_req->longOffset = 0;
711 prop_req->longLength = 0;
713 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
716 GetResReq(GetWindowAttributes, window, resource_req);
717 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
719 GetResReq(GetGeometry, window, resource_req);
720 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
725 /* Wait for the last reply
727 xGetGeometryReply rep;
729 /* On error, our async handler will get called
731 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
732 handle_get_geometry_reply (dpy, &state, &rep);
737 if (!state.have_error)
739 *children = state.child_info;
740 *nchildren = state.n_children_found;
744 g_free (state.child_info);
747 g_free (state.children);
748 g_free (state.child_states);
750 DeqAsyncHandler(dpy, &async);
754 return !state.have_error;
758 roundtrip_callback_idle (gpointer data)
760 RoundtripState *state = (RoundtripState *)data;
762 state->callback (state->display, state->data, state->get_input_focus_req);
770 roundtrip_handler (Display *dpy,
776 RoundtripState *state = (RoundtripState *)data;
778 if (dpy->last_request_read == state->get_input_focus_req)
780 xGetInputFocusReply replbuf;
781 xGetInputFocusReply *repl;
783 if (rep->generic.type != X_Error)
785 /* Actually does nothing, since there are no additional bytes
786 * to read, but maintain good form.
788 repl = (xGetInputFocusReply *)
789 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
790 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
796 gdk_threads_add_idle (roundtrip_callback_idle, state);
798 DeqAsyncHandler(state->dpy, &state->async);
800 return (rep->generic.type != X_Error);
807 _gdk_x11_roundtrip_async (GdkDisplay *display,
808 GdkRoundTripCallback callback,
812 RoundtripState *state;
814 dpy = GDK_DISPLAY_XDISPLAY (display);
816 state = g_new (RoundtripState, 1);
818 state->display = display;
820 state->callback = callback;
825 state->async.next = dpy->async_handlers;
826 state->async.handler = roundtrip_handler;
827 state->async.data = (XPointer) state;
828 dpy->async_handlers = &state->async;
836 GetEmptyReq(GetInputFocus, req);
837 state->get_input_focus_req = dpy->request;
844 #define __GDK_ASYNC_C__
845 #include "gdkaliasdef.c"