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, see <http://www.gnu.org/licenses/>.
18 /* Portions of code in this file are based on code from Xlib
21 Copyright 1986, 1998 The Open Group
23 Permission to use, copy, modify, distribute, and sell this software and its
24 documentation for any purpose is hereby granted without fee, provided that
25 the above copyright notice appear in all copies and that both that
26 copyright notice and this permission notice appear in supporting
29 The above copyright notice and this permission notice shall be included in
30 all copies or substantial portions of the Software.
32 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
36 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
37 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 Except as contained in this notice, the name of The Open Group shall not be
40 used in advertising or otherwise to promote the sale, use or other dealings
41 in this Software without prior written authorization from The Open Group.
47 #include "gdkprivate-x11.h"
49 #ifdef NEED_XIPROTO_H_FOR_XREPLY
50 #include <X11/extensions/XIproto.h>
53 #include <X11/Xlibint.h>
56 typedef struct _ChildInfoChildState ChildInfoChildState;
57 typedef struct _ChildInfoState ChildInfoState;
58 typedef struct _ListChildrenState ListChildrenState;
59 typedef struct _SendEventState SendEventState;
60 typedef struct _SetInputFocusState SetInputFocusState;
61 typedef struct _RoundtripState RoundtripState;
64 CHILD_INFO_GET_PROPERTY,
66 CHILD_INFO_GET_GEOMETRY
69 struct _ChildInfoChildState
74 struct _ChildInfoState
76 gboolean get_wm_state;
79 GdkChildInfoX11 *child_info;
80 ChildInfoChildState *child_states;
83 guint n_children_found;
86 gboolean child_has_error;
89 struct _ListChildrenState
92 gulong get_property_req;
94 gboolean has_wm_state;
97 struct _SendEventState
101 _XAsyncHandler async;
102 gulong send_event_req;
103 gulong get_input_focus_req;
105 GdkSendXEventCallback callback;
109 struct _SetInputFocusState
112 _XAsyncHandler async;
113 gulong set_input_focus_req;
114 gulong get_input_focus_req;
117 struct _RoundtripState
120 _XAsyncHandler async;
121 gulong get_input_focus_req;
123 GdkRoundTripCallback callback;
128 callback_idle (gpointer data)
130 SendEventState *state = (SendEventState *)data;
132 state->callback (state->window, !state->have_error, state->data);
140 send_event_handler (Display *dpy,
146 SendEventState *state = (SendEventState *)data;
148 if (dpy->last_request_read == state->send_event_req)
150 if (rep->generic.type == X_Error &&
151 rep->error.errorCode == BadWindow)
153 state->have_error = TRUE;
157 else if (dpy->last_request_read == state->get_input_focus_req)
159 xGetInputFocusReply replbuf;
160 xGetInputFocusReply *repl G_GNUC_UNUSED;
162 if (rep->generic.type != X_Error)
164 /* Actually does nothing, since there are no additional bytes
165 * to read, but maintain good form.
167 repl = (xGetInputFocusReply *)
168 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
169 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
174 gdk_threads_add_idle (callback_idle, state);
176 DeqAsyncHandler(state->dpy, &state->async);
178 return (rep->generic.type != X_Error);
185 client_message_to_wire (XClientMessageEvent *ev,
189 event->u.clientMessage.window = ev->window;
190 event->u.u.type = ev->type;
191 event->u.u.detail = ev->format;
195 event->u.clientMessage.u.b.type = ev->message_type;
196 for (i = 0; i < 20; i++)
197 event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
200 event->u.clientMessage.u.s.type = ev->message_type;
201 event->u.clientMessage.u.s.shorts0 = ev->data.s[0];
202 event->u.clientMessage.u.s.shorts1 = ev->data.s[1];
203 event->u.clientMessage.u.s.shorts2 = ev->data.s[2];
204 event->u.clientMessage.u.s.shorts3 = ev->data.s[3];
205 event->u.clientMessage.u.s.shorts4 = ev->data.s[4];
206 event->u.clientMessage.u.s.shorts5 = ev->data.s[5];
207 event->u.clientMessage.u.s.shorts6 = ev->data.s[6];
208 event->u.clientMessage.u.s.shorts7 = ev->data.s[7];
209 event->u.clientMessage.u.s.shorts8 = ev->data.s[8];
210 event->u.clientMessage.u.s.shorts9 = ev->data.s[9];
213 event->u.clientMessage.u.l.type = ev->message_type;
214 event->u.clientMessage.u.l.longs0 = ev->data.l[0];
215 event->u.clientMessage.u.l.longs1 = ev->data.l[1];
216 event->u.clientMessage.u.l.longs2 = ev->data.l[2];
217 event->u.clientMessage.u.l.longs3 = ev->data.l[3];
218 event->u.clientMessage.u.l.longs4 = ev->data.l[4];
221 /* client passing bogus data, let server complain */
227 _gdk_x11_send_client_message_async (GdkDisplay *display,
231 XClientMessageEvent *event_send,
232 GdkSendXEventCallback callback,
236 SendEventState *state;
238 dpy = GDK_DISPLAY_XDISPLAY (display);
240 state = g_new (SendEventState, 1);
243 state->window = window;
244 state->callback = callback;
246 state->have_error = FALSE;
250 state->async.next = dpy->async_handlers;
251 state->async.handler = send_event_handler;
252 state->async.data = (XPointer) state;
253 dpy->async_handlers = &state->async;
256 register xSendEventReq *req;
259 client_message_to_wire (event_send, &ev);
261 GetReq(SendEvent, req);
262 req->destination = window;
263 req->propagate = propagate;
264 req->eventMask = event_mask;
265 /* gross, matches Xproto.h */
267 memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
269 memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
272 state->send_event_req = dpy->request;
279 G_GNUC_UNUSED xReq *req;
281 GetEmptyReq(GetInputFocus, req);
282 state->get_input_focus_req = dpy->request;
290 list_children_handler (Display *dpy,
296 ListChildrenState *state = (ListChildrenState *)data;
298 if (dpy->last_request_read != state->get_property_req)
301 if (rep->generic.type == X_Error)
303 state->have_error = TRUE;
308 xGetPropertyReply replbuf;
309 xGetPropertyReply *repl;
311 repl = (xGetPropertyReply *)
312 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
313 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
316 state->has_wm_state = repl->propertyType != None;
317 /* Since we called GetProperty with longLength of 0, we don't
318 * have to worry about consuming the property data that would
319 * normally follow after the reply
327 list_children_and_wm_state (Display *dpy,
330 gboolean *has_wm_state,
332 unsigned int *nchildren)
334 ListChildrenState state;
335 _XAsyncHandler async;
338 register xResourceReq *req;
339 xGetPropertyReq *prop_req;
345 *has_wm_state = FALSE;
347 state.have_error = FALSE;
348 state.has_wm_state = FALSE;
352 async.next = dpy->async_handlers;
353 async.handler = list_children_handler;
354 async.data = (XPointer) &state;
355 dpy->async_handlers = &async;
357 GetReq (GetProperty, prop_req);
358 prop_req->window = w;
359 prop_req->property = wm_state_atom;
360 prop_req->type = AnyPropertyType;
361 prop_req->delete = False;
362 prop_req->longOffset = 0;
363 prop_req->longLength = 0;
365 state.get_property_req = dpy->request;
368 GetResReq(QueryTree, w, req);
369 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
371 state.have_error = TRUE;
375 if (rep.nChildren != 0)
377 nbytes = rep.nChildren << 2;
378 if (state.have_error)
380 _XEatData(dpy, (unsigned long) nbytes);
383 *children = g_new (Window, rep.nChildren);
384 _XRead32 (dpy, (long *) *children, nbytes);
387 *nchildren = rep.nChildren;
388 *has_wm_state = state.has_wm_state;
392 DeqAsyncHandler(dpy, &async);
396 return !state.have_error;
400 handle_get_wa_reply (Display *dpy,
401 ChildInfoState *state,
402 xGetWindowAttributesReply *repl)
404 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
405 child->is_mapped = repl->mapState != IsUnmapped;
406 child->window_class = repl->class;
410 handle_get_geometry_reply (Display *dpy,
411 ChildInfoState *state,
412 xGetGeometryReply *repl)
414 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
416 child->x = cvtINT16toInt (repl->x);
417 child->y = cvtINT16toInt (repl->y);
418 child->width = repl->width;
419 child->height = repl->height;
423 handle_get_property_reply (Display *dpy,
424 ChildInfoState *state,
425 xGetPropertyReply *repl)
427 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
428 child->has_wm_state = repl->propertyType != None;
430 /* Since we called GetProperty with longLength of 0, we don't
431 * have to worry about consuming the property data that would
432 * normally follow after the reply
437 next_child (ChildInfoState *state)
439 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
441 if (!state->have_error && !state->child_has_error)
443 state->child_info[state->n_children_found].window = state->children[state->current_child];
444 state->n_children_found++;
446 state->current_child++;
447 if (state->get_wm_state)
448 state->current_request = CHILD_INFO_GET_PROPERTY;
450 state->current_request = CHILD_INFO_GET_WA;
451 state->child_has_error = FALSE;
452 state->have_error = FALSE;
455 state->current_request++;
459 get_child_info_handler (Display *dpy,
467 ChildInfoState *state = (ChildInfoState *)data;
469 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
472 if (rep->generic.type == X_Error)
474 state->child_has_error = TRUE;
475 if (rep->error.errorCode != BadDrawable ||
476 rep->error.errorCode != BadWindow)
478 state->have_error = TRUE;
484 switch (state->current_request)
486 case CHILD_INFO_GET_PROPERTY:
488 xGetPropertyReply replbuf;
489 xGetPropertyReply *repl;
491 repl = (xGetPropertyReply *)
492 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
493 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
496 handle_get_property_reply (dpy, state, repl);
499 case CHILD_INFO_GET_WA:
501 xGetWindowAttributesReply replbuf;
502 xGetWindowAttributesReply *repl;
504 repl = (xGetWindowAttributesReply *)
505 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
506 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
509 handle_get_wa_reply (dpy, state, repl);
512 case CHILD_INFO_GET_GEOMETRY:
514 xGetGeometryReply replbuf;
515 xGetGeometryReply *repl;
517 repl = (xGetGeometryReply *)
518 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
519 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
522 handle_get_geometry_reply (dpy, state, repl);
534 _gdk_x11_get_window_child_info (GdkDisplay *display,
536 gboolean get_wm_state,
537 gboolean *win_has_wm_state,
538 GdkChildInfoX11 **children,
542 _XAsyncHandler async;
543 ChildInfoState state;
545 gboolean has_wm_state;
552 dpy = GDK_DISPLAY_XDISPLAY (display);
554 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
556 wm_state_atom = None;
558 state.children = NULL;
561 gdk_x11_display_error_trap_push (display);
562 result = list_children_and_wm_state (dpy, window,
563 win_has_wm_state ? wm_state_atom : None,
565 &state.children, &state.nchildren);
566 gdk_x11_display_error_trap_pop_ignored (display);
569 g_free (state.children);
575 if (win_has_wm_state)
576 *win_has_wm_state = TRUE;
577 g_free (state.children);
582 if (win_has_wm_state)
583 *win_has_wm_state = FALSE;
586 state.get_wm_state = get_wm_state;
587 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
588 state.child_states = g_new (ChildInfoChildState, state.nchildren);
589 state.current_child = 0;
590 state.n_children_found = 0;
592 state.current_request = CHILD_INFO_GET_PROPERTY;
594 state.current_request = CHILD_INFO_GET_WA;
595 state.have_error = FALSE;
596 state.child_has_error = FALSE;
600 async.next = dpy->async_handlers;
601 async.handler = get_child_info_handler;
602 async.data = (XPointer) &state;
603 dpy->async_handlers = &async;
605 for (i = 0; i < state.nchildren; i++)
607 xResourceReq *resource_req;
608 xGetPropertyReq *prop_req;
609 Window window = state.children[i];
613 GetReq (GetProperty, prop_req);
614 prop_req->window = window;
615 prop_req->property = wm_state_atom;
616 prop_req->type = AnyPropertyType;
617 prop_req->delete = False;
618 prop_req->longOffset = 0;
619 prop_req->longLength = 0;
621 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
624 GetResReq(GetWindowAttributes, window, resource_req);
625 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
627 GetResReq(GetGeometry, window, resource_req);
628 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
633 /* Wait for the last reply
635 xGetGeometryReply rep;
637 /* On error, our async handler will get called
639 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
640 handle_get_geometry_reply (dpy, &state, &rep);
645 if (!state.have_error)
647 *children = state.child_info;
648 *nchildren = state.n_children_found;
652 g_free (state.child_info);
655 g_free (state.children);
656 g_free (state.child_states);
658 DeqAsyncHandler(dpy, &async);
662 return !state.have_error;
666 roundtrip_callback_idle (gpointer data)
668 RoundtripState *state = (RoundtripState *)data;
670 state->callback (state->display, state->data, state->get_input_focus_req);
678 roundtrip_handler (Display *dpy,
684 RoundtripState *state = (RoundtripState *)data;
686 if (dpy->last_request_read == state->get_input_focus_req)
688 xGetInputFocusReply replbuf;
689 xGetInputFocusReply *repl G_GNUC_UNUSED;
691 if (rep->generic.type != X_Error)
693 /* Actually does nothing, since there are no additional bytes
694 * to read, but maintain good form.
696 repl = (xGetInputFocusReply *)
697 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
698 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
704 gdk_threads_add_idle (roundtrip_callback_idle, state);
706 DeqAsyncHandler(state->dpy, &state->async);
708 return (rep->generic.type != X_Error);
715 _gdk_x11_roundtrip_async (GdkDisplay *display,
716 GdkRoundTripCallback callback,
720 RoundtripState *state;
722 dpy = GDK_DISPLAY_XDISPLAY (display);
724 state = g_new (RoundtripState, 1);
726 state->display = display;
728 state->callback = callback;
733 state->async.next = dpy->async_handlers;
734 state->async.handler = roundtrip_handler;
735 state->async.data = (XPointer) state;
736 dpy->async_handlers = &state->async;
742 G_GNUC_UNUSED xReq *req;
744 GetEmptyReq(GetInputFocus, req);
745 state->get_input_focus_req = dpy->request;