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.
49 #include "gdkprivate-x11.h"
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 G_GNUC_UNUSED;
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 list_children_handler (Display *dpy,
298 ListChildrenState *state = (ListChildrenState *)data;
300 if (dpy->last_request_read != state->get_property_req)
303 if (rep->generic.type == X_Error)
305 state->have_error = TRUE;
310 xGetPropertyReply replbuf;
311 xGetPropertyReply *repl;
313 repl = (xGetPropertyReply *)
314 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
315 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
318 state->has_wm_state = repl->propertyType != None;
319 /* Since we called GetProperty with longLength of 0, we don't
320 * have to worry about consuming the property data that would
321 * normally follow after the reply
329 list_children_and_wm_state (Display *dpy,
332 gboolean *has_wm_state,
334 unsigned int *nchildren)
336 ListChildrenState state;
337 _XAsyncHandler async;
340 register xResourceReq *req;
341 xGetPropertyReq *prop_req;
347 *has_wm_state = FALSE;
349 state.have_error = FALSE;
350 state.has_wm_state = FALSE;
354 async.next = dpy->async_handlers;
355 async.handler = list_children_handler;
356 async.data = (XPointer) &state;
357 dpy->async_handlers = &async;
359 GetReq (GetProperty, prop_req);
360 prop_req->window = w;
361 prop_req->property = wm_state_atom;
362 prop_req->type = AnyPropertyType;
363 prop_req->delete = False;
364 prop_req->longOffset = 0;
365 prop_req->longLength = 0;
367 state.get_property_req = dpy->request;
370 GetResReq(QueryTree, w, req);
371 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
373 state.have_error = TRUE;
377 if (rep.nChildren != 0)
379 nbytes = rep.nChildren << 2;
380 if (state.have_error)
382 _XEatData(dpy, (unsigned long) nbytes);
385 *children = g_new (Window, rep.nChildren);
386 _XRead32 (dpy, (long *) *children, nbytes);
389 *nchildren = rep.nChildren;
390 *has_wm_state = state.has_wm_state;
394 DeqAsyncHandler(dpy, &async);
398 return !state.have_error;
402 handle_get_wa_reply (Display *dpy,
403 ChildInfoState *state,
404 xGetWindowAttributesReply *repl)
406 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
407 child->is_mapped = repl->mapState != IsUnmapped;
408 child->window_class = repl->class;
412 handle_get_geometry_reply (Display *dpy,
413 ChildInfoState *state,
414 xGetGeometryReply *repl)
416 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
418 child->x = cvtINT16toInt (repl->x);
419 child->y = cvtINT16toInt (repl->y);
420 child->width = repl->width;
421 child->height = repl->height;
425 handle_get_property_reply (Display *dpy,
426 ChildInfoState *state,
427 xGetPropertyReply *repl)
429 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
430 child->has_wm_state = repl->propertyType != None;
432 /* Since we called GetProperty with longLength of 0, we don't
433 * have to worry about consuming the property data that would
434 * normally follow after the reply
439 next_child (ChildInfoState *state)
441 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
443 if (!state->have_error && !state->child_has_error)
445 state->child_info[state->n_children_found].window = state->children[state->current_child];
446 state->n_children_found++;
448 state->current_child++;
449 if (state->get_wm_state)
450 state->current_request = CHILD_INFO_GET_PROPERTY;
452 state->current_request = CHILD_INFO_GET_WA;
453 state->child_has_error = FALSE;
454 state->have_error = FALSE;
457 state->current_request++;
461 get_child_info_handler (Display *dpy,
469 ChildInfoState *state = (ChildInfoState *)data;
471 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
474 if (rep->generic.type == X_Error)
476 state->child_has_error = TRUE;
477 if (rep->error.errorCode != BadDrawable ||
478 rep->error.errorCode != BadWindow)
480 state->have_error = TRUE;
486 switch (state->current_request)
488 case CHILD_INFO_GET_PROPERTY:
490 xGetPropertyReply replbuf;
491 xGetPropertyReply *repl;
493 repl = (xGetPropertyReply *)
494 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
495 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
498 handle_get_property_reply (dpy, state, repl);
501 case CHILD_INFO_GET_WA:
503 xGetWindowAttributesReply replbuf;
504 xGetWindowAttributesReply *repl;
506 repl = (xGetWindowAttributesReply *)
507 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
508 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
511 handle_get_wa_reply (dpy, state, repl);
514 case CHILD_INFO_GET_GEOMETRY:
516 xGetGeometryReply replbuf;
517 xGetGeometryReply *repl;
519 repl = (xGetGeometryReply *)
520 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
521 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
524 handle_get_geometry_reply (dpy, state, repl);
536 _gdk_x11_get_window_child_info (GdkDisplay *display,
538 gboolean get_wm_state,
539 gboolean *win_has_wm_state,
540 GdkChildInfoX11 **children,
544 _XAsyncHandler async;
545 ChildInfoState state;
547 gboolean has_wm_state;
554 dpy = GDK_DISPLAY_XDISPLAY (display);
556 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
558 wm_state_atom = None;
560 state.children = NULL;
563 gdk_x11_display_error_trap_push (display);
564 result = list_children_and_wm_state (dpy, window,
565 win_has_wm_state ? wm_state_atom : None,
567 &state.children, &state.nchildren);
568 gdk_x11_display_error_trap_pop_ignored (display);
571 g_free (state.children);
577 if (win_has_wm_state)
578 *win_has_wm_state = TRUE;
579 g_free (state.children);
584 if (win_has_wm_state)
585 *win_has_wm_state = FALSE;
588 state.get_wm_state = get_wm_state;
589 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
590 state.child_states = g_new (ChildInfoChildState, state.nchildren);
591 state.current_child = 0;
592 state.n_children_found = 0;
594 state.current_request = CHILD_INFO_GET_PROPERTY;
596 state.current_request = CHILD_INFO_GET_WA;
597 state.have_error = FALSE;
598 state.child_has_error = FALSE;
602 async.next = dpy->async_handlers;
603 async.handler = get_child_info_handler;
604 async.data = (XPointer) &state;
605 dpy->async_handlers = &async;
607 for (i = 0; i < state.nchildren; i++)
609 xResourceReq *resource_req;
610 xGetPropertyReq *prop_req;
611 Window window = state.children[i];
615 GetReq (GetProperty, prop_req);
616 prop_req->window = window;
617 prop_req->property = wm_state_atom;
618 prop_req->type = AnyPropertyType;
619 prop_req->delete = False;
620 prop_req->longOffset = 0;
621 prop_req->longLength = 0;
623 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
626 GetResReq(GetWindowAttributes, window, resource_req);
627 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
629 GetResReq(GetGeometry, window, resource_req);
630 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
635 /* Wait for the last reply
637 xGetGeometryReply rep;
639 /* On error, our async handler will get called
641 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
642 handle_get_geometry_reply (dpy, &state, &rep);
647 if (!state.have_error)
649 *children = state.child_info;
650 *nchildren = state.n_children_found;
654 g_free (state.child_info);
657 g_free (state.children);
658 g_free (state.child_states);
660 DeqAsyncHandler(dpy, &async);
664 return !state.have_error;
668 roundtrip_callback_idle (gpointer data)
670 RoundtripState *state = (RoundtripState *)data;
672 state->callback (state->display, state->data, state->get_input_focus_req);
680 roundtrip_handler (Display *dpy,
686 RoundtripState *state = (RoundtripState *)data;
688 if (dpy->last_request_read == state->get_input_focus_req)
690 xGetInputFocusReply replbuf;
691 xGetInputFocusReply *repl G_GNUC_UNUSED;
693 if (rep->generic.type != X_Error)
695 /* Actually does nothing, since there are no additional bytes
696 * to read, but maintain good form.
698 repl = (xGetInputFocusReply *)
699 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
700 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
706 gdk_threads_add_idle (roundtrip_callback_idle, state);
708 DeqAsyncHandler(state->dpy, &state->async);
710 return (rep->generic.type != X_Error);
717 _gdk_x11_roundtrip_async (GdkDisplay *display,
718 GdkRoundTripCallback callback,
722 RoundtripState *state;
724 dpy = GDK_DISPLAY_XDISPLAY (display);
726 state = g_new (RoundtripState, 1);
728 state->display = display;
730 state->callback = callback;
735 state->async.next = dpy->async_handlers;
736 state->async.handler = roundtrip_handler;
737 state->async.data = (XPointer) state;
738 dpy->async_handlers = &state->async;
746 GetEmptyReq(GetInputFocus, req);
747 state->get_input_focus_req = dpy->request;