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 callback_idle (gpointer data)
118 SendEventState *state = (SendEventState *)data;
120 state->callback (state->window, !state->have_error, state->data);
128 send_event_handler (Display *dpy,
134 SendEventState *state = (SendEventState *)data;
136 if (dpy->last_request_read == state->send_event_req)
138 if (rep->generic.type == X_Error &&
139 rep->error.errorCode == BadWindow)
141 state->have_error = TRUE;
145 else if (dpy->last_request_read == state->get_input_focus_req)
147 xGetInputFocusReply replbuf;
148 xGetInputFocusReply *repl;
150 if (rep->generic.type != X_Error)
152 /* Actually does nothing, since there are no additional bytes
153 * to read, but maintain good form.
155 repl = (xGetInputFocusReply *)
156 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
157 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
162 gdk_threads_add_idle (callback_idle, state);
164 DeqAsyncHandler(state->dpy, &state->async);
166 return (rep->generic.type != X_Error);
173 client_message_to_wire (XClientMessageEvent *ev,
177 event->u.clientMessage.window = ev->window;
178 event->u.u.type = ev->type;
179 event->u.u.detail = ev->format;
183 event->u.clientMessage.u.b.type = ev->message_type;
184 for (i = 0; i < 20; i++)
185 event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
188 event->u.clientMessage.u.s.type = ev->message_type;
189 event->u.clientMessage.u.s.shorts0 = ev->data.s[0];
190 event->u.clientMessage.u.s.shorts1 = ev->data.s[1];
191 event->u.clientMessage.u.s.shorts2 = ev->data.s[2];
192 event->u.clientMessage.u.s.shorts3 = ev->data.s[3];
193 event->u.clientMessage.u.s.shorts4 = ev->data.s[4];
194 event->u.clientMessage.u.s.shorts5 = ev->data.s[5];
195 event->u.clientMessage.u.s.shorts6 = ev->data.s[6];
196 event->u.clientMessage.u.s.shorts7 = ev->data.s[7];
197 event->u.clientMessage.u.s.shorts8 = ev->data.s[8];
198 event->u.clientMessage.u.s.shorts9 = ev->data.s[9];
201 event->u.clientMessage.u.l.type = ev->message_type;
202 event->u.clientMessage.u.l.longs0 = ev->data.l[0];
203 event->u.clientMessage.u.l.longs1 = ev->data.l[1];
204 event->u.clientMessage.u.l.longs2 = ev->data.l[2];
205 event->u.clientMessage.u.l.longs3 = ev->data.l[3];
206 event->u.clientMessage.u.l.longs4 = ev->data.l[4];
209 /* client passing bogus data, let server complain */
215 _gdk_x11_send_client_message_async (GdkDisplay *display,
219 XClientMessageEvent *event_send,
220 GdkSendXEventCallback callback,
224 SendEventState *state;
226 dpy = GDK_DISPLAY_XDISPLAY (display);
228 state = g_new (SendEventState, 1);
231 state->window = window;
232 state->callback = callback;
234 state->have_error = FALSE;
238 state->async.next = dpy->async_handlers;
239 state->async.handler = send_event_handler;
240 state->async.data = (XPointer) state;
241 dpy->async_handlers = &state->async;
244 register xSendEventReq *req;
247 client_message_to_wire (event_send, &ev);
249 GetReq(SendEvent, req);
250 req->destination = window;
251 req->propagate = propagate;
252 req->eventMask = event_mask;
253 /* gross, matches Xproto.h */
255 memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
257 memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
260 state->send_event_req = dpy->request;
269 GetEmptyReq(GetInputFocus, req);
270 state->get_input_focus_req = dpy->request;
278 set_input_focus_handler (Display *dpy,
284 SetInputFocusState *state = (SetInputFocusState *)data;
286 if (dpy->last_request_read == state->set_input_focus_req)
288 if (rep->generic.type == X_Error &&
289 rep->error.errorCode == BadMatch)
291 /* Consume BadMatch errors, since we have no control
298 if (dpy->last_request_read == state->get_input_focus_req)
300 xGetInputFocusReply replbuf;
301 xGetInputFocusReply *repl;
303 if (rep->generic.type != X_Error)
305 /* Actually does nothing, since there are no additional bytes
306 * to read, but maintain good form.
308 repl = (xGetInputFocusReply *)
309 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
310 (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
314 DeqAsyncHandler(state->dpy, &state->async);
318 return (rep->generic.type != X_Error);
325 _gdk_x11_set_input_focus_safe (GdkDisplay *display,
331 SetInputFocusState *state;
333 dpy = GDK_DISPLAY_XDISPLAY (display);
335 state = g_new (SetInputFocusState, 1);
341 state->async.next = dpy->async_handlers;
342 state->async.handler = set_input_focus_handler;
343 state->async.data = (XPointer) state;
344 dpy->async_handlers = &state->async;
347 xSetInputFocusReq *req;
349 GetReq(SetInputFocus, req);
351 req->revertTo = revert_to;
353 state->set_input_focus_req = dpy->request;
362 GetEmptyReq(GetInputFocus, req);
363 state->get_input_focus_req = dpy->request;
371 list_children_handler (Display *dpy,
377 ListChildrenState *state = (ListChildrenState *)data;
379 if (dpy->last_request_read != state->get_property_req)
382 if (rep->generic.type == X_Error)
384 state->have_error = TRUE;
389 xGetPropertyReply replbuf;
390 xGetPropertyReply *repl;
392 repl = (xGetPropertyReply *)
393 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
394 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
397 state->has_wm_state = repl->propertyType != None;
398 /* Since we called GetProperty with longLength of 0, we don't
399 * have to worry about consuming the property data that would
400 * normally follow after the reply
408 list_children_and_wm_state (Display *dpy,
411 gboolean *has_wm_state,
413 unsigned int *nchildren)
415 ListChildrenState state;
416 _XAsyncHandler async;
419 register xResourceReq *req;
420 xGetPropertyReq *prop_req;
426 *has_wm_state = FALSE;
428 state.have_error = FALSE;
429 state.has_wm_state = FALSE;
433 async.next = dpy->async_handlers;
434 async.handler = list_children_handler;
435 async.data = (XPointer) &state;
436 dpy->async_handlers = &async;
438 GetReq (GetProperty, prop_req);
439 prop_req->window = w;
440 prop_req->property = wm_state_atom;
441 prop_req->type = AnyPropertyType;
442 prop_req->delete = False;
443 prop_req->longOffset = 0;
444 prop_req->longLength = 0;
446 state.get_property_req = dpy->request;
449 GetResReq(QueryTree, w, req);
450 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
452 state.have_error = TRUE;
456 if (rep.nChildren != 0)
458 nbytes = rep.nChildren << 2;
459 if (state.have_error)
461 _XEatData(dpy, (unsigned long) nbytes);
464 *children = g_new (Window, rep.nChildren);
465 _XRead32 (dpy, (long *) *children, nbytes);
468 *nchildren = rep.nChildren;
469 *has_wm_state = state.has_wm_state;
473 DeqAsyncHandler(dpy, &async);
477 return !state.have_error;
481 handle_get_wa_reply (Display *dpy,
482 ChildInfoState *state,
483 xGetWindowAttributesReply *repl)
485 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
486 child->is_mapped = repl->mapState != IsUnmapped;
487 child->window_class = repl->class;
491 handle_get_geometry_reply (Display *dpy,
492 ChildInfoState *state,
493 xGetGeometryReply *repl)
495 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
497 child->x = cvtINT16toInt (repl->x);
498 child->y = cvtINT16toInt (repl->y);
499 child->width = repl->width;
500 child->height = repl->height;
504 handle_get_property_reply (Display *dpy,
505 ChildInfoState *state,
506 xGetPropertyReply *repl)
508 GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
509 child->has_wm_state = repl->propertyType != None;
511 /* Since we called GetProperty with longLength of 0, we don't
512 * have to worry about consuming the property data that would
513 * normally follow after the reply
518 next_child (ChildInfoState *state)
520 if (state->current_request == CHILD_INFO_GET_GEOMETRY)
522 if (!state->have_error && !state->child_has_error)
524 state->child_info[state->n_children_found].window = state->children[state->current_child];
525 state->n_children_found++;
527 state->current_child++;
528 if (state->get_wm_state)
529 state->current_request = CHILD_INFO_GET_PROPERTY;
531 state->current_request = CHILD_INFO_GET_WA;
532 state->child_has_error = FALSE;
533 state->have_error = FALSE;
536 state->current_request++;
540 get_child_info_handler (Display *dpy,
548 ChildInfoState *state = (ChildInfoState *)data;
550 if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
553 if (rep->generic.type == X_Error)
555 state->child_has_error = TRUE;
556 if (rep->error.errorCode != BadDrawable ||
557 rep->error.errorCode != BadWindow)
559 state->have_error = TRUE;
565 switch (state->current_request)
567 case CHILD_INFO_GET_PROPERTY:
569 xGetPropertyReply replbuf;
570 xGetPropertyReply *repl;
572 repl = (xGetPropertyReply *)
573 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
574 (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
577 handle_get_property_reply (dpy, state, repl);
580 case CHILD_INFO_GET_WA:
582 xGetWindowAttributesReply replbuf;
583 xGetWindowAttributesReply *repl;
585 repl = (xGetWindowAttributesReply *)
586 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
587 (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
590 handle_get_wa_reply (dpy, state, repl);
593 case CHILD_INFO_GET_GEOMETRY:
595 xGetGeometryReply replbuf;
596 xGetGeometryReply *repl;
598 repl = (xGetGeometryReply *)
599 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
600 (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
603 handle_get_geometry_reply (dpy, state, repl);
615 _gdk_x11_get_window_child_info (GdkDisplay *display,
617 gboolean get_wm_state,
618 gboolean *win_has_wm_state,
619 GdkChildInfoX11 **children,
623 _XAsyncHandler async;
624 ChildInfoState state;
626 gboolean has_wm_state;
633 dpy = GDK_DISPLAY_XDISPLAY (display);
635 wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
637 wm_state_atom = None;
639 state.children = NULL;
642 gdk_error_trap_push ();
643 result = list_children_and_wm_state (dpy, window,
644 win_has_wm_state ? wm_state_atom : None,
646 &state.children, &state.nchildren);
647 gdk_error_trap_pop ();
650 g_free (state.children);
656 if (win_has_wm_state)
657 *win_has_wm_state = TRUE;
658 g_free (state.children);
663 if (win_has_wm_state)
664 *win_has_wm_state = FALSE;
667 state.get_wm_state = get_wm_state;
668 state.child_info = g_new (GdkChildInfoX11, state.nchildren);
669 state.child_states = g_new (ChildInfoChildState, state.nchildren);
670 state.current_child = 0;
671 state.n_children_found = 0;
673 state.current_request = CHILD_INFO_GET_PROPERTY;
675 state.current_request = CHILD_INFO_GET_WA;
676 state.have_error = FALSE;
677 state.child_has_error = FALSE;
681 async.next = dpy->async_handlers;
682 async.handler = get_child_info_handler;
683 async.data = (XPointer) &state;
684 dpy->async_handlers = &async;
686 for (i = 0; i < state.nchildren; i++)
688 xResourceReq *resource_req;
689 xGetPropertyReq *prop_req;
690 Window window = state.children[i];
694 GetReq (GetProperty, prop_req);
695 prop_req->window = window;
696 prop_req->property = wm_state_atom;
697 prop_req->type = AnyPropertyType;
698 prop_req->delete = False;
699 prop_req->longOffset = 0;
700 prop_req->longLength = 0;
702 state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
705 GetResReq(GetWindowAttributes, window, resource_req);
706 state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
708 GetResReq(GetGeometry, window, resource_req);
709 state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
714 /* Wait for the last reply
716 xGetGeometryReply rep;
718 /* On error, our async handler will get called
720 if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
721 handle_get_geometry_reply (dpy, &state, &rep);
726 if (!state.have_error)
728 *children = state.child_info;
729 *nchildren = state.n_children_found;
733 g_free (state.child_info);
736 g_free (state.children);
737 g_free (state.child_states);
739 DeqAsyncHandler(dpy, &async);
743 return !state.have_error;
746 #define __GDK_ASYNC_C__
747 #include "gdkaliasdef.c"