1 /* GTK - The GIMP Toolkit
2  * gdkasync.c: Utility functions using the Xlib asynchronous interfaces
3  * Copyright (C) 2003, Red Hat, Inc.
4  *
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.
9  *
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.
14  *
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.
19  */
20 /* Portions of code in this file are based on code from Xlib
21  */
22 /*
23 Copyright 1986, 1998  The Open Group
24 
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
29 documentation.
30 
31 The above copyright notice and this permission notice shall be included in
32 all copies or substantial portions of the Software.
33 
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.
40 
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.
44 
45 */
46 #include "config.h"
47 #ifdef NEED_XIPROTO_H_FOR_XREPLY
48 #include <X11/extensions/XIproto.h>
49 #endif
50 #include <X11/Xlibint.h>
51 #include "gdkasync.h"
52 #include "gdkx.h"
53 #include "gdkalias.h"
54 
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;
61 
62 typedef enum {
63   CHILD_INFO_GET_PROPERTY,
64   CHILD_INFO_GET_WA,
65   CHILD_INFO_GET_GEOMETRY
66 } ChildInfoReq;
67 
68 struct _ChildInfoChildState
69 {
70   gulong seq[3];
71 };
72 
73 struct _ChildInfoState
74 {
75   gboolean get_wm_state;
76   Window *children;
77   guint nchildren;
78   GdkChildInfoX11 *child_info;
79   ChildInfoChildState *child_states;
80 
81   guint current_child;
82   guint n_children_found;
83   gint current_request;
84   gboolean have_error;
85   gboolean child_has_error;
86 };
87 
88 struct _ListChildrenState
89 {
90   Display *dpy;
91   gulong get_property_req;
92   gboolean have_error;
93   gboolean has_wm_state;
94 };
95 
96 struct _SendEventState
97 {
98   Display *dpy;
99   Window window;
100   _XAsyncHandler async;
101   gulong send_event_req;
102   gulong get_input_focus_req;
103   gboolean have_error;
104   GdkSendXEventCallback callback;
105   gpointer data;
106 };
107 
108 struct _SetInputFocusState
109 {
110   Display *dpy;
111   _XAsyncHandler async;
112   gulong set_input_focus_req;
113   gulong get_input_focus_req;
114 };
115 
116 struct _RoundtripState
117 {
118   Display *dpy;
119   _XAsyncHandler async;
120   gulong get_input_focus_req;
121   GdkDisplay *display;
122   GdkRoundTripCallback callback;
123   gpointer data;
124 };
125 
126 static gboolean
callback_idle(gpointer data)127 callback_idle (gpointer data)
128 {
129   SendEventState *state = (SendEventState *)data;
130 
131   state->callback (state->window, !state->have_error, state->data);
132 
133   g_free (state);
134 
135   return FALSE;
136 }
137 
138 static Bool
send_event_handler(Display * dpy,xReply * rep,char * buf,int len,XPointer data)139 send_event_handler (Display *dpy,
140 		    xReply  *rep,
141 		    char    *buf,
142 		    int      len,
143 		    XPointer data)
144 {
145   SendEventState *state = (SendEventState *)data;
146 
147   if (dpy->last_request_read == state->send_event_req)
148     {
149       if (rep->generic.type == X_Error &&
150 	  rep->error.errorCode == BadWindow)
151 	{
152 	  state->have_error = TRUE;
153 	  return True;
154 	}
155     }
156   else if (dpy->last_request_read == state->get_input_focus_req)
157     {
158       xGetInputFocusReply replbuf;
159       xGetInputFocusReply *repl;
160 
161       if (rep->generic.type != X_Error)
162 	{
163 	  /* Actually does nothing, since there are no additional bytes
164 	   * to read, but maintain good form.
165 	   */
166 	  repl = (xGetInputFocusReply *)
167 	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
168 			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
169 			    True);
170 	}
171 
172       if (state->callback)
173         gdk_threads_add_idle (callback_idle, state);
174 
175       DeqAsyncHandler(state->dpy, &state->async);
176 
177       return (rep->generic.type != X_Error);
178     }
179 
180   return False;
181 }
182 
183 static void
client_message_to_wire(XClientMessageEvent * ev,xEvent * event)184 client_message_to_wire (XClientMessageEvent *ev,
185 			xEvent              *event)
186 {
187   int i;
188   event->u.clientMessage.window = ev->window;
189   event->u.u.type = ev->type;
190   event->u.u.detail = ev->format;
191   switch (ev->format)
192     {
193     case 8:
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];
197       break;
198     case 16:
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];
210       break;
211     case 32:
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];
218       break;
219     default:
220       /* client passing bogus data, let server complain */
221       break;
222     }
223 }
224 
225 void
_gdk_x11_send_client_message_async(GdkDisplay * display,Window window,gboolean propagate,glong event_mask,XClientMessageEvent * event_send,GdkSendXEventCallback callback,gpointer data)226 _gdk_x11_send_client_message_async (GdkDisplay           *display,
227 				    Window                window,
228 				    gboolean              propagate,
229 				    glong                 event_mask,
230 				    XClientMessageEvent  *event_send,
231 				    GdkSendXEventCallback callback,
232 				    gpointer              data)
233 {
234   Display *dpy;
235   SendEventState *state;
236 
237   dpy = GDK_DISPLAY_XDISPLAY (display);
238 
239   state = g_new (SendEventState, 1);
240 
241   state->dpy = dpy;
242   state->window = window;
243   state->callback = callback;
244   state->data = data;
245   state->have_error = FALSE;
246 
247   LockDisplay(dpy);
248 
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;
253 
254   {
255     register xSendEventReq *req;
256     xEvent ev;
257 
258     client_message_to_wire (event_send, &ev);
259 
260     GetReq(SendEvent, req);
261     req->destination = window;
262     req->propagate = propagate;
263     req->eventMask = event_mask;
264     /* gross, matches Xproto.h */
265 #ifdef WORD64
266     memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
267 #else
268     memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
269 #endif
270 
271     state->send_event_req = dpy->request;
272   }
273 
274   /*
275    * XSync (dpy, 0)
276    */
277   {
278     xReq *req;
279 
280     GetEmptyReq(GetInputFocus, req);
281     state->get_input_focus_req = dpy->request;
282   }
283 
284   UnlockDisplay(dpy);
285   SyncHandle();
286 }
287 
288 static Bool
set_input_focus_handler(Display * dpy,xReply * rep,char * buf,int len,XPointer data)289 set_input_focus_handler (Display *dpy,
290 			 xReply  *rep,
291 			 char    *buf,
292 			 int      len,
293 			 XPointer data)
294 {
295   SetInputFocusState *state = (SetInputFocusState *)data;
296 
297   if (dpy->last_request_read == state->set_input_focus_req)
298     {
299       if (rep->generic.type == X_Error &&
300 	  rep->error.errorCode == BadMatch)
301 	{
302 	  /* Consume BadMatch errors, since we have no control
303 	   * over them.
304 	   */
305 	  return True;
306 	}
307     }
308 
309   if (dpy->last_request_read == state->get_input_focus_req)
310     {
311       xGetInputFocusReply replbuf;
312       xGetInputFocusReply *repl;
313 
314       if (rep->generic.type != X_Error)
315 	{
316 	  /* Actually does nothing, since there are no additional bytes
317 	   * to read, but maintain good form.
318 	   */
319 	  repl = (xGetInputFocusReply *)
320 	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
321 			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
322 			    True);
323 	}
324 
325       DeqAsyncHandler(state->dpy, &state->async);
326 
327       g_free (state);
328 
329       return (rep->generic.type != X_Error);
330     }
331 
332   return False;
333 }
334 
335 void
_gdk_x11_set_input_focus_safe(GdkDisplay * display,Window window,int revert_to,Time time)336 _gdk_x11_set_input_focus_safe (GdkDisplay             *display,
337 			       Window                  window,
338 			       int                     revert_to,
339 			       Time                    time)
340 {
341   Display *dpy;
342   SetInputFocusState *state;
343 
344   dpy = GDK_DISPLAY_XDISPLAY (display);
345 
346   state = g_new (SetInputFocusState, 1);
347 
348   state->dpy = dpy;
349 
350   LockDisplay(dpy);
351 
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;
356 
357   {
358     xSetInputFocusReq *req;
359 
360     GetReq(SetInputFocus, req);
361     req->focus = window;
362     req->revertTo = revert_to;
363     req->time = time;
364     state->set_input_focus_req = dpy->request;
365   }
366 
367   /*
368    * XSync (dpy, 0)
369    */
370   {
371     xReq *req;
372 
373     GetEmptyReq(GetInputFocus, req);
374     state->get_input_focus_req = dpy->request;
375   }
376 
377   UnlockDisplay(dpy);
378   SyncHandle();
379 }
380 
381 static Bool
list_children_handler(Display * dpy,xReply * rep,char * buf,int len,XPointer data)382 list_children_handler (Display *dpy,
383 		       xReply  *rep,
384 		       char    *buf,
385 		       int      len,
386 		       XPointer data)
387 {
388   ListChildrenState *state = (ListChildrenState *)data;
389 
390   if (dpy->last_request_read != state->get_property_req)
391     return False;
392 
393   if (rep->generic.type == X_Error)
394     {
395       state->have_error = TRUE;
396       return False;
397     }
398   else
399     {
400       xGetPropertyReply replbuf;
401       xGetPropertyReply *repl;
402 
403       repl = (xGetPropertyReply *)
404 	_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
405 			(sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
406 			True);
407 
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
412        */
413 
414       return True;
415     }
416 }
417 
418 static gboolean
list_children_and_wm_state(Display * dpy,Window w,Atom wm_state_atom,gboolean * has_wm_state,Window ** children,unsigned int * nchildren)419 list_children_and_wm_state (Display      *dpy,
420 			    Window        w,
421 			    Atom          wm_state_atom,
422 			    gboolean     *has_wm_state,
423 			    Window      **children,
424 			    unsigned int *nchildren)
425 {
426   ListChildrenState state;
427   _XAsyncHandler async;
428   long nbytes;
429   xQueryTreeReply rep;
430   register xResourceReq *req;
431   xGetPropertyReq *prop_req;
432 
433   LockDisplay(dpy);
434 
435   *children = NULL;
436   *nchildren = 0;
437   *has_wm_state = FALSE;
438 
439   state.have_error = FALSE;
440   state.has_wm_state = FALSE;
441 
442   if (wm_state_atom)
443     {
444       async.next = dpy->async_handlers;
445       async.handler = list_children_handler;
446       async.data = (XPointer) &state;
447       dpy->async_handlers = &async;
448 
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;
456 
457       state.get_property_req = dpy->request;
458     }
459 
460   GetResReq(QueryTree, w, req);
461   if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
462     {
463       state.have_error = TRUE;
464       goto out;
465     }
466 
467   if (rep.nChildren != 0)
468     {
469       nbytes = rep.nChildren << 2;
470       if (state.have_error)
471 	{
472 	  _XEatData(dpy, (unsigned long) nbytes);
473 	  goto out;
474 	}
475       *children = g_new (Window, rep.nChildren);
476       _XRead32 (dpy, (long *) *children, nbytes);
477     }
478 
479   *nchildren = rep.nChildren;
480   *has_wm_state = state.has_wm_state;
481 
482  out:
483   if (wm_state_atom)
484     DeqAsyncHandler(dpy, &async);
485   UnlockDisplay(dpy);
486   SyncHandle();
487 
488   return !state.have_error;
489 }
490 
491 static void
handle_get_wa_reply(Display * dpy,ChildInfoState * state,xGetWindowAttributesReply * repl)492 handle_get_wa_reply (Display                   *dpy,
493 		     ChildInfoState            *state,
494 		     xGetWindowAttributesReply *repl)
495 {
496   GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
497   child->is_mapped = repl->mapState != IsUnmapped;
498   child->window_class = repl->class;
499 }
500 
501 static void
handle_get_geometry_reply(Display * dpy,ChildInfoState * state,xGetGeometryReply * repl)502 handle_get_geometry_reply (Display           *dpy,
503 			   ChildInfoState    *state,
504 			   xGetGeometryReply *repl)
505 {
506   GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
507 
508   child->x = cvtINT16toInt (repl->x);
509   child->y = cvtINT16toInt (repl->y);
510   child->width = repl->width;
511   child->height = repl->height;
512 }
513 
514 static void
handle_get_property_reply(Display * dpy,ChildInfoState * state,xGetPropertyReply * repl)515 handle_get_property_reply (Display           *dpy,
516 			   ChildInfoState    *state,
517 			   xGetPropertyReply *repl)
518 {
519   GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
520   child->has_wm_state = repl->propertyType != None;
521 
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
525    */
526 }
527 
528 static void
next_child(ChildInfoState * state)529 next_child (ChildInfoState *state)
530 {
531   if (state->current_request == CHILD_INFO_GET_GEOMETRY)
532     {
533       if (!state->have_error && !state->child_has_error)
534 	{
535 	  state->child_info[state->n_children_found].window = state->children[state->current_child];
536 	  state->n_children_found++;
537 	}
538       state->current_child++;
539       if (state->get_wm_state)
540 	state->current_request = CHILD_INFO_GET_PROPERTY;
541       else
542 	state->current_request = CHILD_INFO_GET_WA;
543       state->child_has_error = FALSE;
544       state->have_error = FALSE;
545     }
546   else
547     state->current_request++;
548 }
549 
550 static Bool
get_child_info_handler(Display * dpy,xReply * rep,char * buf,int len,XPointer data)551 get_child_info_handler (Display *dpy,
552 			xReply  *rep,
553 			char    *buf,
554 			int      len,
555 			XPointer data)
556 {
557   Bool result = True;
558 
559   ChildInfoState *state = (ChildInfoState *)data;
560 
561   if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
562     return False;
563 
564   if (rep->generic.type == X_Error)
565     {
566       state->child_has_error = TRUE;
567       if (rep->error.errorCode != BadDrawable ||
568 	  rep->error.errorCode != BadWindow)
569 	{
570 	  state->have_error = TRUE;
571 	  result = False;
572 	}
573     }
574   else
575     {
576       switch (state->current_request)
577 	{
578 	case CHILD_INFO_GET_PROPERTY:
579 	  {
580 	    xGetPropertyReply replbuf;
581 	    xGetPropertyReply *repl;
582 
583 	    repl = (xGetPropertyReply *)
584 	      _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
585 			      (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
586 			      True);
587 
588 	    handle_get_property_reply (dpy, state, repl);
589 	  }
590 	  break;
591 	case CHILD_INFO_GET_WA:
592 	  {
593 	    xGetWindowAttributesReply replbuf;
594 	    xGetWindowAttributesReply *repl;
595 
596 	    repl = (xGetWindowAttributesReply *)
597 	      _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
598 			      (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
599 			      True);
600 
601 	    handle_get_wa_reply (dpy, state, repl);
602 	  }
603 	  break;
604 	case CHILD_INFO_GET_GEOMETRY:
605 	  {
606 	    xGetGeometryReply replbuf;
607 	    xGetGeometryReply *repl;
608 
609 	    repl = (xGetGeometryReply *)
610 	      _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
611 			      (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
612 			      True);
613 
614 	    handle_get_geometry_reply (dpy, state, repl);
615 	  }
616 	  break;
617 	}
618     }
619 
620   next_child (state);
621 
622   return result;
623 }
624 
625 gboolean
_gdk_x11_get_window_child_info(GdkDisplay * display,Window window,gboolean get_wm_state,gboolean * win_has_wm_state,GdkChildInfoX11 ** children,guint * nchildren)626 _gdk_x11_get_window_child_info (GdkDisplay       *display,
627 				Window            window,
628 				gboolean          get_wm_state,
629 				gboolean         *win_has_wm_state,
630 				GdkChildInfoX11 **children,
631 				guint            *nchildren)
632 {
633   Display *dpy;
634   _XAsyncHandler async;
635   ChildInfoState state;
636   Atom wm_state_atom;
637   gboolean has_wm_state;
638   Bool result;
639   guint i;
640 
641   *children = NULL;
642   *nchildren = 0;
643 
644   dpy = GDK_DISPLAY_XDISPLAY (display);
645   if (get_wm_state)
646     wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
647   else
648     wm_state_atom = None;
649 
650   state.children = NULL;
651   state.nchildren = 0;
652 
653   gdk_error_trap_push ();
654   result = list_children_and_wm_state (dpy, window,
655 				       win_has_wm_state ? wm_state_atom : None,
656 				       &has_wm_state,
657 				       &state.children, &state.nchildren);
658   gdk_error_trap_pop ();
659   if (!result)
660     {
661       g_free (state.children);
662       return FALSE;
663     }
664 
665   if (has_wm_state)
666     {
667       if (win_has_wm_state)
668 	*win_has_wm_state = TRUE;
669       g_free (state.children);
670       return TRUE;
671     }
672   else
673     {
674       if (win_has_wm_state)
675 	*win_has_wm_state = FALSE;
676     }
677 
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;
683   if (get_wm_state)
684     state.current_request = CHILD_INFO_GET_PROPERTY;
685   else
686     state.current_request = CHILD_INFO_GET_WA;
687   state.have_error = FALSE;
688   state.child_has_error = FALSE;
689 
690   LockDisplay(dpy);
691 
692   async.next = dpy->async_handlers;
693   async.handler = get_child_info_handler;
694   async.data = (XPointer) &state;
695   dpy->async_handlers = &async;
696 
697   for (i = 0; i < state.nchildren; i++)
698     {
699       xResourceReq *resource_req;
700       xGetPropertyReq *prop_req;
701       Window window = state.children[i];
702 
703       if (get_wm_state)
704 	{
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;
712 
713 	  state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
714 	}
715 
716       GetResReq(GetWindowAttributes, window, resource_req);
717       state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
718 
719       GetResReq(GetGeometry, window, resource_req);
720       state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
721     }
722 
723   if (i != 0)
724     {
725       /* Wait for the last reply
726        */
727       xGetGeometryReply rep;
728 
729       /* On error, our async handler will get called
730        */
731       if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
732 	handle_get_geometry_reply (dpy, &state, &rep);
733 
734       next_child (&state);
735     }
736 
737   if (!state.have_error)
738     {
739       *children = state.child_info;
740       *nchildren = state.n_children_found;
741     }
742   else
743     {
744       g_free (state.child_info);
745     }
746 
747   g_free (state.children);
748   g_free (state.child_states);
749 
750   DeqAsyncHandler(dpy, &async);
751   UnlockDisplay(dpy);
752   SyncHandle();
753 
754   return !state.have_error;
755 }
756 
757 static gboolean
roundtrip_callback_idle(gpointer data)758 roundtrip_callback_idle (gpointer data)
759 {
760   RoundtripState *state = (RoundtripState *)data;
761 
762   state->callback (state->display, state->data, state->get_input_focus_req);
763 
764   g_free (state);
765 
766   return FALSE;
767 }
768 
769 static Bool
roundtrip_handler(Display * dpy,xReply * rep,char * buf,int len,XPointer data)770 roundtrip_handler (Display *dpy,
771 		   xReply  *rep,
772 		   char    *buf,
773 		   int      len,
774 		   XPointer data)
775 {
776   RoundtripState *state = (RoundtripState *)data;
777 
778   if (dpy->last_request_read == state->get_input_focus_req)
779     {
780       xGetInputFocusReply replbuf;
781       xGetInputFocusReply *repl;
782 
783       if (rep->generic.type != X_Error)
784 	{
785 	  /* Actually does nothing, since there are no additional bytes
786 	   * to read, but maintain good form.
787 	   */
788 	  repl = (xGetInputFocusReply *)
789 	    _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
790 			    (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
791 			    True);
792 	}
793 
794 
795       if (state->callback)
796         gdk_threads_add_idle (roundtrip_callback_idle, state);
797 
798       DeqAsyncHandler(state->dpy, &state->async);
799 
800       return (rep->generic.type != X_Error);
801     }
802 
803   return False;
804 }
805 
806 void
_gdk_x11_roundtrip_async(GdkDisplay * display,GdkRoundTripCallback callback,gpointer data)807 _gdk_x11_roundtrip_async (GdkDisplay           *display,
808 			  GdkRoundTripCallback callback,
809 			  gpointer              data)
810 {
811   Display *dpy;
812   RoundtripState *state;
813 
814   dpy = GDK_DISPLAY_XDISPLAY (display);
815 
816   state = g_new (RoundtripState, 1);
817 
818   state->display = display;
819   state->dpy = dpy;
820   state->callback = callback;
821   state->data = data;
822 
823   LockDisplay(dpy);
824 
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;
829 
830   /*
831    * XSync (dpy, 0)
832    */
833   {
834     xReq *req;
835 
836     GetEmptyReq(GetInputFocus, req);
837     state->get_input_focus_req = dpy->request;
838   }
839 
840   UnlockDisplay(dpy);
841   SyncHandle();
842 }
843 
844 #define __GDK_ASYNC_C__
845 #include "gdkaliasdef.c"
846