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;
62 CHILD_INFO_GET_PROPERTY,
64 CHILD_INFO_GET_GEOMETRY
67 struct _ChildInfoChildState
72 struct _ChildInfoState
74 gboolean get_wm_state;
77 GdkChildInfoX11 *child_info;
78 ChildInfoChildState *child_states;
81 guint n_children_found;
84 gboolean child_has_error;
87 struct _ListChildrenState
90 gulong get_property_req;
92 gboolean has_wm_state;
95 struct _SendEventState
100 gulong send_event_req;
101 gulong get_input_focus_req;
103 GdkSendXEventCallback callback;
107 struct _SetInputFocusState
110 _XAsyncHandler async;
111 gulong set_input_focus_req;
112 gulong get_input_focus_req;
116 send_event_handler (Display *dpy,
122 SendEventState *state = (SendEventState *)data;
124 if (dpy->last_request_read == state->send_event_req)
126 if (rep->generic.type == X_Error &&
127 rep->error.errorCode == BadWindow)
129 state->have_error = TRUE;
133 else if (dpy->last_request_read == state->get_input_focus_req)
135 xGetInputFocusReply replbuf;
136 xGetInputFocusReply *repl;
138 if (rep->generic.type != X_Error)
140 /* Actually does nothing, since there are no additional bytes
141 * to read, but maintain good form.
143 repl = (xGetInputFocusReply *)
144 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
145 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
150 state->callback (state->window, !state->have_error, state->data);
152 DeqAsyncHandler(state->dpy, &state->async);
154 return (rep->generic.type != X_Error);
161 client_message_to_wire (XClientMessageEvent *ev,
165 event->u.clientMessage.window = ev->window;
166 event->u.u.type = ev->type;
167 event->u.u.detail = ev->format;
171 event->u.clientMessage.u.b.type = ev->message_type;
172 for (i = 0; i < 20; i++)
173 event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
176 event->u.clientMessage.u.s.type = ev->message_type;
177 event->u.clientMessage.u.s.shorts0 = ev->data.s[0];
178 event->u.clientMessage.u.s.shorts1 = ev->data.s[1];
179 event->u.clientMessage.u.s.shorts2 = ev->data.s[2];
180 event->u.clientMessage.u.s.shorts3 = ev->data.s[3];
181 event->u.clientMessage.u.s.shorts4 = ev->data.s[4];
182 event->u.clientMessage.u.s.shorts5 = ev->data.s[5];
183 event->u.clientMessage.u.s.shorts6 = ev->data.s[6];
184 event->u.clientMessage.u.s.shorts7 = ev->data.s[7];
185 event->u.clientMessage.u.s.shorts8 = ev->data.s[8];
186 event->u.clientMessage.u.s.shorts9 = ev->data.s[9];
189 event->u.clientMessage.u.l.type = ev->message_type;
190 event->u.clientMessage.u.l.longs0 = ev->data.l[0];
191 event->u.clientMessage.u.l.longs1 = ev->data.l[1];
192 event->u.clientMessage.u.l.longs2 = ev->data.l[2];
193 event->u.clientMessage.u.l.longs3 = ev->data.l[3];
194 event->u.clientMessage.u.l.longs4 = ev->data.l[4];
197 /* client passing bogus data, let server complain */
203 _gdk_x11_send_client_message_async (GdkDisplay *display,
207 XClientMessageEvent *event_send,
208 GdkSendXEventCallback callback,
212 SendEventState *state;
214 dpy = GDK_DISPLAY_XDISPLAY (display);
216 state = g_new (SendEventState, 1);
219 state->window = window;
220 state->callback = callback;
222 state->have_error = FALSE;
226 state->async.next = dpy->async_handlers;
227 state->async.handler = send_event_handler;
228 state->async.data = (XPointer) state;
229 dpy->async_handlers = &state->async;
232 register xSendEventReq *req;
235 client_message_to_wire (event_send, &ev);
237 GetReq(SendEvent, req);
238 req->destination = window;
239 req->propagate = propagate;
240 req->eventMask = event_mask;
241 /* gross, matches Xproto.h */
243 memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
245 memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
248 state->send_event_req = dpy->request;
257 GetEmptyReq(GetInputFocus, req);
258 state->get_input_focus_req = dpy->request;
266 set_input_focus_handler (Display *dpy,
272 SetInputFocusState *state = (SetInputFocusState *)data;
274 if (dpy->last_request_read == state->set_input_focus_req)
276 if (rep->generic.type == X_Error &&
277 rep->error.errorCode == BadMatch)
279 /* Consume BadMatch errors, since we have no control
286 if (dpy->last_request_read == state->get_input_focus_req)
288 xGetInputFocusReply replbuf;
289 xGetInputFocusReply *repl;
291 if (rep->generic.type != X_Error)
293 /* Actually does nothing, since there are no additional bytes
294 * to read, but maintain good form.
296 repl = (xGetInputFocusReply *)
297 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
298 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
302 DeqAsyncHandler(state->dpy, &state->async);
306 return (rep->generic.type != X_Error);
313 _gdk_x11_set_input_focus_safe (GdkDisplay *display,
319 SetInputFocusState *state;
321 dpy = GDK_DISPLAY_XDISPLAY (display);
323 state = g_new (SetInputFocusState, 1);
329 state->async.next = dpy->async_handlers;
330 state->async.handler = set_input_focus_handler;
331 state->async.data = (XPointer) state;
332 dpy->async_handlers = &state->async;
335 xSetInputFocusReq *req;
337 GetReq(SetInputFocus, req);
339 req->revertTo = revert_to;
341 state->set_input_focus_req = dpy->request;
350 GetEmptyReq(GetInputFocus, req);
351 state->get_input_focus_req = dpy->request;
359 list_children_handler (Display *dpy,
365 ListChildrenState *state = (ListChildrenState *)data;
367 if (dpy->last_request_read != state->get_property_req)
370 if (rep->generic.type == X_Error)
372 state->have_error = TRUE;
377 xGetPropertyReply replbuf;
378 xGetPropertyReply *repl;
380 repl = (xGetPropertyReply *)
381 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
382 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
385 state->has_wm_state = repl->propertyType != None;
386 /* Since we called GetProperty with longLength of 0, we don't
387 * have to worry about consuming the property data that would
388 * normally follow after the reply
396 list_children_and_wm_state (Display *dpy,
399 gboolean *has_wm_state,
401 unsigned int *nchildren)
403 ListChildrenState state;
404 _XAsyncHandler async;
407 register xResourceReq *req;
408 xGetPropertyReq *prop_req;
414 *has_wm_state = FALSE;
416 state.have_error = FALSE;
417 state.has_wm_state = FALSE;
421 async.next = dpy->async_handlers;
422 async.handler = list_children_handler;
423 async.data = (XPointer) &state;
424 dpy->async_handlers = &async;
426 GetReq (GetProperty, prop_req);
427 prop_req->window = w;
428 prop_req->property = wm_state_atom;
429 prop_req->type = AnyPropertyType;
430 prop_req->delete = False;
431 prop_req->longOffset = 0;
432 prop_req->longLength = 0;
434 state.get_property_req = dpy->request;
437 GetResReq(QueryTree, w, req);
438 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
440 state.have_error = TRUE;
444 if (rep.nChildren != 0)
446 nbytes = rep.nChildren << 2;
447 if (state.have_error)
449 _XEatData(dpy, (unsigned long) nbytes);
452 *children = g_new (Window, rep.nChildren);
453 _XRead32 (dpy, (long *) *children, nbytes);
456 *nchildren = rep.nChildren;
457 *has_wm_state = state.has_wm_state;
461 DeqAsyncHandler(dpy, &async);
465 return !state.have_error;
469 handle_get_wa_reply (Display *dpy,
470 ChildInfoState *state,
471 xGetWindowAttributesReply *repl)
473 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
474 child->is_mapped = repl->mapState != IsUnmapped;
475 child->window_class = repl->class;
479 handle_get_geometry_reply (Display *dpy,
480 ChildInfoState *state,
481 xGetGeometryReply *repl)
483 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
485 child->x = cvtINT16toInt (repl->x);
486 child->y = cvtINT16toInt (repl->y);
487 child->width = repl->width;
488 child->height = repl->height;
492 handle_get_property_reply (Display *dpy,
493 ChildInfoState *state,
494 xGetPropertyReply *repl)
496 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
497 child->has_wm_state = repl->propertyType != None;
499 /* Since we called GetProperty with longLength of 0, we don't
500 * have to worry about consuming the property data that would
501 * normally follow after the reply
506 next_child (ChildInfoState *state)
508 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
510 if (!state->have_error && !state->child_has_error)
512 state->child_info[state->n_children_found].window = state->children[state->current_child];
513 state->n_children_found++;
515 state->current_child++;
516 if (state->get_wm_state)
517 state->current_request = CHILD_INFO_GET_PROPERTY;
519 state->current_request = CHILD_INFO_GET_WA;
520 state->child_has_error = FALSE;
521 state->have_error = FALSE;
524 state->current_request++;
528 get_child_info_handler (Display *dpy,
536 ChildInfoState *state = (ChildInfoState *)data;
538 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
541 if (rep->generic.type == X_Error)
543 state->child_has_error = TRUE;
544 if (rep->error.errorCode != BadDrawable ||
545 rep->error.errorCode != BadWindow)
547 state->have_error = TRUE;
553 switch (state->current_request)
555 case CHILD_INFO_GET_PROPERTY:
557 xGetPropertyReply replbuf;
558 xGetPropertyReply *repl;
560 repl = (xGetPropertyReply *)
561 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
562 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
565 handle_get_property_reply (dpy, state, repl);
568 case CHILD_INFO_GET_WA:
570 xGetWindowAttributesReply replbuf;
571 xGetWindowAttributesReply *repl;
573 repl = (xGetWindowAttributesReply *)
574 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
575 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
578 handle_get_wa_reply (dpy, state, repl);
581 case CHILD_INFO_GET_GEOMETRY:
583 xGetGeometryReply replbuf;
584 xGetGeometryReply *repl;
586 repl = (xGetGeometryReply *)
587 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
588 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
591 handle_get_geometry_reply (dpy, state, repl);
603 _gdk_x11_get_window_child_info (GdkDisplay *display,
605 gboolean get_wm_state,
606 gboolean *win_has_wm_state,
607 GdkChildInfoX11 **children,
611 _XAsyncHandler async;
612 ChildInfoState state;
614 gboolean has_wm_state;
621 dpy = GDK_DISPLAY_XDISPLAY (display);
623 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
625 wm_state_atom = None;
627 gdk_error_trap_push ();
628 result = list_children_and_wm_state (dpy, window,
629 win_has_wm_state ? wm_state_atom : None,
631 &state.children, &state.nchildren);
632 gdk_error_trap_pop ();
638 if (win_has_wm_state)
639 *win_has_wm_state = TRUE;
644 if (win_has_wm_state)
645 *win_has_wm_state = FALSE;
648 state.get_wm_state = get_wm_state;
649 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
650 state.child_states = g_new (ChildInfoChildState, state.nchildren);
651 state.current_child = 0;
652 state.n_children_found = 0;
654 state.current_request = CHILD_INFO_GET_PROPERTY;
656 state.current_request = CHILD_INFO_GET_WA;
657 state.have_error = FALSE;
658 state.child_has_error = FALSE;
662 async.next = dpy->async_handlers;
663 async.handler = get_child_info_handler;
664 async.data = (XPointer) &state;
665 dpy->async_handlers = &async;
667 for (i = 0; i < state.nchildren; i++)
669 xResourceReq *resource_req;
670 xGetPropertyReq *prop_req;
671 Window window = state.children[i];
675 GetReq (GetProperty, prop_req);
676 prop_req->window = window;
677 prop_req->property = wm_state_atom;
678 prop_req->type = AnyPropertyType;
679 prop_req->delete = False;
680 prop_req->longOffset = 0;
681 prop_req->longLength = 0;
683 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
686 GetResReq(GetWindowAttributes, window, resource_req);
687 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
689 GetResReq(GetGeometry, window, resource_req);
690 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
695 /* Wait for the last reply
697 xGetGeometryReply rep;
699 /* On error, our async handler will get called
701 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
702 handle_get_geometry_reply (dpy, &state, &rep);
707 if (!state.have_error)
709 *children = state.child_info;
710 *nchildren = state.n_children_found;
714 g_free (state.child_info);
717 g_free (state.children);
718 g_free (state.child_states);
720 DeqAsyncHandler(dpy, &async);
724 return !state.have_error;