]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkasync.c
Fix warning due to typo
[~andy/gtk] / gdk / x11 / gdkasync.c
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   GdkRoundTripCallback callback;
122   gpointer data;
123 };
124
125 static gboolean
126 callback_idle (gpointer data)
127 {
128   SendEventState *state = (SendEventState *)data;  
129   
130   state->callback (state->window, !state->have_error, state->data);
131
132   g_free (state);
133
134   return FALSE;
135 }
136
137 static Bool
138 send_event_handler (Display *dpy,
139                     xReply  *rep,
140                     char    *buf,
141                     int      len,
142                     XPointer data)
143 {
144   SendEventState *state = (SendEventState *)data;  
145
146   if (dpy->last_request_read == state->send_event_req)
147     {
148       if (rep->generic.type == X_Error &&
149           rep->error.errorCode == BadWindow)
150         {
151           state->have_error = TRUE;
152           return True;
153         }
154     }
155   else if (dpy->last_request_read == state->get_input_focus_req)
156     {
157       xGetInputFocusReply replbuf;
158       xGetInputFocusReply *repl;
159       
160       if (rep->generic.type != X_Error)
161         {
162           /* Actually does nothing, since there are no additional bytes
163            * to read, but maintain good form.
164            */
165           repl = (xGetInputFocusReply *)
166             _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
167                             (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
168                             True);
169         }
170
171       if (state->callback)
172         gdk_threads_add_idle (callback_idle, state);
173
174       DeqAsyncHandler(state->dpy, &state->async);
175
176       return (rep->generic.type != X_Error);
177     }
178
179   return False;
180 }
181
182 static void
183 client_message_to_wire (XClientMessageEvent *ev,
184                         xEvent              *event)
185 {
186   int i;
187   event->u.clientMessage.window = ev->window;
188   event->u.u.type = ev->type;
189   event->u.u.detail = ev->format;
190   switch (ev->format)
191     {
192     case 8:     
193       event->u.clientMessage.u.b.type   = ev->message_type;
194       for (i = 0; i < 20; i++)
195         event->u.clientMessage.u.b.bytes[i] = ev->data.b[i];
196       break;
197     case 16:
198       event->u.clientMessage.u.s.type   = ev->message_type;
199       event->u.clientMessage.u.s.shorts0   = ev->data.s[0];
200       event->u.clientMessage.u.s.shorts1   = ev->data.s[1];
201       event->u.clientMessage.u.s.shorts2   = ev->data.s[2];
202       event->u.clientMessage.u.s.shorts3   = ev->data.s[3];
203       event->u.clientMessage.u.s.shorts4   = ev->data.s[4];
204       event->u.clientMessage.u.s.shorts5   = ev->data.s[5];
205       event->u.clientMessage.u.s.shorts6   = ev->data.s[6];
206       event->u.clientMessage.u.s.shorts7   = ev->data.s[7];
207       event->u.clientMessage.u.s.shorts8   = ev->data.s[8];
208       event->u.clientMessage.u.s.shorts9   = ev->data.s[9];
209       break;
210     case 32:
211       event->u.clientMessage.u.l.type   = ev->message_type;
212       event->u.clientMessage.u.l.longs0   = ev->data.l[0];
213       event->u.clientMessage.u.l.longs1   = ev->data.l[1];
214       event->u.clientMessage.u.l.longs2   = ev->data.l[2];
215       event->u.clientMessage.u.l.longs3   = ev->data.l[3];
216       event->u.clientMessage.u.l.longs4   = ev->data.l[4];
217       break;
218     default:
219       /* client passing bogus data, let server complain */
220       break;
221     }
222 }
223
224 void
225 _gdk_x11_send_client_message_async (GdkDisplay           *display, 
226                                     Window                window, 
227                                     gboolean              propagate,
228                                     glong                 event_mask,
229                                     XClientMessageEvent  *event_send,
230                                     GdkSendXEventCallback callback,
231                                     gpointer              data)
232 {
233   Display *dpy;
234   SendEventState *state;
235   
236   dpy = GDK_DISPLAY_XDISPLAY (display);
237
238   state = g_new (SendEventState, 1);
239
240   state->dpy = dpy;
241   state->window = window;
242   state->callback = callback;
243   state->data = data;
244   state->have_error = FALSE;
245   
246   LockDisplay(dpy);
247
248   state->async.next = dpy->async_handlers;
249   state->async.handler = send_event_handler;
250   state->async.data = (XPointer) state;
251   dpy->async_handlers = &state->async;
252
253   {
254     register xSendEventReq *req;
255     xEvent ev;
256     
257     client_message_to_wire (event_send, &ev);
258       
259     GetReq(SendEvent, req);
260     req->destination = window;
261     req->propagate = propagate;
262     req->eventMask = event_mask;
263     /* gross, matches Xproto.h */
264 #ifdef WORD64                   
265     memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
266 #else    
267     memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
268 #endif
269     
270     state->send_event_req = dpy->request;
271   }
272
273   /*
274    * XSync (dpy, 0)
275    */
276   {
277     xReq *req;
278     
279     GetEmptyReq(GetInputFocus, req);
280     state->get_input_focus_req = dpy->request;
281   }
282   
283   UnlockDisplay(dpy);
284   SyncHandle();
285 }
286
287 static Bool
288 set_input_focus_handler (Display *dpy,
289                          xReply  *rep,
290                          char    *buf,
291                          int      len,
292                          XPointer data)
293 {
294   SetInputFocusState *state = (SetInputFocusState *)data;  
295
296   if (dpy->last_request_read == state->set_input_focus_req)
297     {
298       if (rep->generic.type == X_Error &&
299           rep->error.errorCode == BadMatch)
300         {
301           /* Consume BadMatch errors, since we have no control
302            * over them.
303            */
304           return True;
305         }
306     }
307   
308   if (dpy->last_request_read == state->get_input_focus_req)
309     {
310       xGetInputFocusReply replbuf;
311       xGetInputFocusReply *repl;
312       
313       if (rep->generic.type != X_Error)
314         {
315           /* Actually does nothing, since there are no additional bytes
316            * to read, but maintain good form.
317            */
318           repl = (xGetInputFocusReply *)
319             _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
320                             (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
321                             True);
322         }
323
324       DeqAsyncHandler(state->dpy, &state->async);
325
326       g_free (state);
327       
328       return (rep->generic.type != X_Error);
329     }
330
331   return False;
332 }
333
334 void
335 _gdk_x11_set_input_focus_safe (GdkDisplay             *display,
336                                Window                  window,
337                                int                     revert_to,
338                                Time                    time)
339 {
340   Display *dpy;
341   SetInputFocusState *state;
342   
343   dpy = GDK_DISPLAY_XDISPLAY (display);
344
345   state = g_new (SetInputFocusState, 1);
346
347   state->dpy = dpy;
348   
349   LockDisplay(dpy);
350
351   state->async.next = dpy->async_handlers;
352   state->async.handler = set_input_focus_handler;
353   state->async.data = (XPointer) state;
354   dpy->async_handlers = &state->async;
355
356   {
357     xSetInputFocusReq *req;
358     
359     GetReq(SetInputFocus, req);
360     req->focus = window;
361     req->revertTo = revert_to;
362     req->time = time;
363     state->set_input_focus_req = dpy->request;
364   }
365
366   /*
367    * XSync (dpy, 0)
368    */
369   {
370     xReq *req;
371     
372     GetEmptyReq(GetInputFocus, req);
373     state->get_input_focus_req = dpy->request;
374   }
375   
376   UnlockDisplay(dpy);
377   SyncHandle();
378 }
379
380 static Bool
381 list_children_handler (Display *dpy,
382                        xReply  *rep,
383                        char    *buf,
384                        int      len,
385                        XPointer data)
386 {
387   ListChildrenState *state = (ListChildrenState *)data;
388
389   if (dpy->last_request_read != state->get_property_req)
390     return False;
391   
392   if (rep->generic.type == X_Error)
393     {
394       state->have_error = TRUE;
395       return False;
396     }
397   else
398     {
399       xGetPropertyReply replbuf;
400       xGetPropertyReply *repl;
401             
402       repl = (xGetPropertyReply *)
403         _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
404                         (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
405                         True);
406
407       state->has_wm_state = repl->propertyType != None;
408       /* Since we called GetProperty with longLength of 0, we don't
409        * have to worry about consuming the property data that would
410        * normally follow after the reply
411        */
412
413       return True;
414     }
415 }
416
417 static gboolean
418 list_children_and_wm_state (Display      *dpy,
419                             Window        w,
420                             Atom          wm_state_atom,
421                             gboolean     *has_wm_state,
422                             Window      **children,
423                             unsigned int *nchildren)
424 {
425   ListChildrenState state;
426   _XAsyncHandler async;
427   long nbytes;
428   xQueryTreeReply rep;
429   register xResourceReq *req;
430   xGetPropertyReq *prop_req;
431
432   LockDisplay(dpy);
433
434   *children = NULL;
435   *nchildren = 0;
436   *has_wm_state = FALSE;
437   
438   state.have_error = FALSE;
439   state.has_wm_state = FALSE;
440
441   if (wm_state_atom)
442     {
443       async.next = dpy->async_handlers;
444       async.handler = list_children_handler;
445       async.data = (XPointer) &state;
446       dpy->async_handlers = &async;
447
448       GetReq (GetProperty, prop_req);
449       prop_req->window = w;
450       prop_req->property = wm_state_atom;
451       prop_req->type = AnyPropertyType;
452       prop_req->delete = False;
453       prop_req->longOffset = 0;
454       prop_req->longLength = 0;
455       
456       state.get_property_req = dpy->request;
457     }
458   
459   GetResReq(QueryTree, w, req);
460   if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
461     {
462       state.have_error = TRUE;
463       goto out;
464     }
465
466   if (rep.nChildren != 0)
467     {
468       nbytes = rep.nChildren << 2;
469       if (state.have_error)
470         {
471           _XEatData(dpy, (unsigned long) nbytes);
472           goto out;
473         }
474       *children = g_new (Window, rep.nChildren);
475       _XRead32 (dpy, (long *) *children, nbytes);
476     }
477
478   *nchildren = rep.nChildren;
479   *has_wm_state = state.has_wm_state;
480
481  out:
482   if (wm_state_atom)
483     DeqAsyncHandler(dpy, &async);
484   UnlockDisplay(dpy);
485   SyncHandle();
486   
487   return !state.have_error;
488 }
489
490 static void
491 handle_get_wa_reply (Display                   *dpy,
492                      ChildInfoState            *state,
493                      xGetWindowAttributesReply *repl)
494 {
495   GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
496   child->is_mapped = repl->mapState != IsUnmapped;
497   child->window_class = repl->class;
498 }
499
500 static void
501 handle_get_geometry_reply (Display           *dpy,
502                            ChildInfoState    *state,
503                            xGetGeometryReply *repl)
504 {
505   GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
506   
507   child->x = cvtINT16toInt (repl->x);
508   child->y = cvtINT16toInt (repl->y);
509   child->width = repl->width;
510   child->height = repl->height;
511 }
512
513 static void
514 handle_get_property_reply (Display           *dpy,
515                            ChildInfoState    *state,
516                            xGetPropertyReply *repl)
517 {
518   GdkChildInfoX11 *child = &state->child_info[state->n_children_found];
519   child->has_wm_state = repl->propertyType != None;
520
521   /* Since we called GetProperty with longLength of 0, we don't
522    * have to worry about consuming the property data that would
523    * normally follow after the reply
524    */
525 }
526
527 static void
528 next_child (ChildInfoState *state)
529 {
530   if (state->current_request == CHILD_INFO_GET_GEOMETRY)
531     {
532       if (!state->have_error && !state->child_has_error)
533         {
534           state->child_info[state->n_children_found].window = state->children[state->current_child];
535           state->n_children_found++;
536         }
537       state->current_child++;
538       if (state->get_wm_state)
539         state->current_request = CHILD_INFO_GET_PROPERTY;
540       else
541         state->current_request = CHILD_INFO_GET_WA;
542       state->child_has_error = FALSE;
543       state->have_error = FALSE;
544     }
545   else
546     state->current_request++;
547 }
548
549 static Bool
550 get_child_info_handler (Display *dpy,
551                         xReply  *rep,
552                         char    *buf,
553                         int      len,
554                         XPointer data)
555 {
556   Bool result = True;
557   
558   ChildInfoState *state = (ChildInfoState *)data;
559
560   if (dpy->last_request_read != state->child_states[state->current_child].seq[state->current_request])
561     return False;
562   
563   if (rep->generic.type == X_Error)
564     {
565       state->child_has_error = TRUE;
566       if (rep->error.errorCode != BadDrawable ||
567           rep->error.errorCode != BadWindow)
568         {
569           state->have_error = TRUE;
570           result = False;
571         }
572     }
573   else
574     {
575       switch (state->current_request)
576         {
577         case CHILD_INFO_GET_PROPERTY:
578           {
579             xGetPropertyReply replbuf;
580             xGetPropertyReply *repl;
581             
582             repl = (xGetPropertyReply *)
583               _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
584                               (sizeof(xGetPropertyReply) - sizeof(xReply)) >> 2,
585                               True);
586             
587             handle_get_property_reply (dpy, state, repl);
588           }
589           break;
590         case CHILD_INFO_GET_WA:
591           {
592             xGetWindowAttributesReply replbuf;
593             xGetWindowAttributesReply *repl;
594             
595             repl = (xGetWindowAttributesReply *)
596               _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
597                               (sizeof(xGetWindowAttributesReply) - sizeof(xReply)) >> 2,
598                               True);
599             
600             handle_get_wa_reply (dpy, state, repl);
601           }
602           break;
603         case CHILD_INFO_GET_GEOMETRY:
604           {
605             xGetGeometryReply replbuf;
606             xGetGeometryReply *repl;
607             
608             repl = (xGetGeometryReply *)
609               _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
610                               (sizeof(xGetGeometryReply) - sizeof(xReply)) >> 2,
611                               True);
612             
613             handle_get_geometry_reply (dpy, state, repl);
614           }
615           break;
616         }
617     }
618
619   next_child (state);
620
621   return result;
622 }
623
624 gboolean
625 _gdk_x11_get_window_child_info (GdkDisplay       *display,
626                                 Window            window,
627                                 gboolean          get_wm_state,
628                                 gboolean         *win_has_wm_state,
629                                 GdkChildInfoX11 **children,
630                                 guint            *nchildren)
631 {
632   Display *dpy;
633   _XAsyncHandler async;
634   ChildInfoState state;
635   Atom wm_state_atom;
636   gboolean has_wm_state;
637   Bool result;
638   guint i;
639
640   *children = NULL;
641   *nchildren = 0;
642   
643   dpy = GDK_DISPLAY_XDISPLAY (display);
644   if (get_wm_state)
645     wm_state_atom = gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE");
646   else
647     wm_state_atom = None;
648
649   state.children = NULL;
650   state.nchildren = 0;
651
652   gdk_error_trap_push ();
653   result = list_children_and_wm_state (dpy, window,
654                                        win_has_wm_state ? wm_state_atom : None,
655                                        &has_wm_state,
656                                        &state.children, &state.nchildren);
657   gdk_error_trap_pop ();
658   if (!result)
659     {
660       g_free (state.children);
661       return FALSE;
662     }
663
664   if (has_wm_state)
665     {
666       if (win_has_wm_state)
667         *win_has_wm_state = TRUE;
668       g_free (state.children);
669       return TRUE;
670     }
671   else
672     {
673       if (win_has_wm_state)
674         *win_has_wm_state = FALSE;
675     }
676
677   state.get_wm_state = get_wm_state;
678   state.child_info = g_new (GdkChildInfoX11, state.nchildren);
679   state.child_states = g_new (ChildInfoChildState, state.nchildren);
680   state.current_child = 0;
681   state.n_children_found = 0;
682   if (get_wm_state)
683     state.current_request = CHILD_INFO_GET_PROPERTY;
684   else
685     state.current_request = CHILD_INFO_GET_WA;
686   state.have_error = FALSE;
687   state.child_has_error = FALSE;
688
689   LockDisplay(dpy);
690
691   async.next = dpy->async_handlers;
692   async.handler = get_child_info_handler;
693   async.data = (XPointer) &state;
694   dpy->async_handlers = &async;
695   
696   for (i = 0; i < state.nchildren; i++)
697     {
698       xResourceReq *resource_req;
699       xGetPropertyReq *prop_req;
700       Window window = state.children[i];
701       
702       if (get_wm_state)
703         {
704           GetReq (GetProperty, prop_req);
705           prop_req->window = window;
706           prop_req->property = wm_state_atom;
707           prop_req->type = AnyPropertyType;
708           prop_req->delete = False;
709           prop_req->longOffset = 0;
710           prop_req->longLength = 0;
711
712           state.child_states[i].seq[CHILD_INFO_GET_PROPERTY] = dpy->request;
713         }
714       
715       GetResReq(GetWindowAttributes, window, resource_req);
716       state.child_states[i].seq[CHILD_INFO_GET_WA] = dpy->request;
717       
718       GetResReq(GetGeometry, window, resource_req);
719       state.child_states[i].seq[CHILD_INFO_GET_GEOMETRY] = dpy->request;
720     }
721
722   if (i != 0)
723     {
724       /* Wait for the last reply
725        */
726       xGetGeometryReply rep;
727
728       /* On error, our async handler will get called
729        */
730       if (_XReply (dpy, (xReply *)&rep, 0, xTrue))
731         handle_get_geometry_reply (dpy, &state, &rep);
732
733       next_child (&state);
734     }
735
736   if (!state.have_error)
737     {
738       *children = state.child_info;
739       *nchildren = state.n_children_found;
740     }
741   else
742     {
743       g_free (state.child_info);
744     }
745
746   g_free (state.children);
747   g_free (state.child_states);
748   
749   DeqAsyncHandler(dpy, &async);
750   UnlockDisplay(dpy);
751   SyncHandle();
752
753   return !state.have_error;
754 }
755
756 static gboolean
757 roundtrip_callback_idle (gpointer data)
758 {
759   RoundtripState *state = (RoundtripState *)data;  
760   
761   state->callback (state->data);
762
763   g_free (state);
764
765   return FALSE;
766 }
767
768 static Bool
769 roundtrip_handler (Display *dpy,
770                    xReply  *rep,
771                    char    *buf,
772                    int      len,
773                    XPointer data)
774 {
775   RoundtripState *state = (RoundtripState *)data;  
776   
777   if (dpy->last_request_read == state->get_input_focus_req)
778     {
779       xGetInputFocusReply replbuf;
780       xGetInputFocusReply *repl;
781       
782       if (rep->generic.type != X_Error)
783         {
784           /* Actually does nothing, since there are no additional bytes
785            * to read, but maintain good form.
786            */
787           repl = (xGetInputFocusReply *)
788             _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
789                             (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
790                             True);
791         }
792
793       if (state->callback)
794         gdk_threads_add_idle (roundtrip_callback_idle, state);
795
796       DeqAsyncHandler(state->dpy, &state->async);
797
798       return (rep->generic.type != X_Error);
799     }
800
801   return False;
802 }
803
804 void
805 _gdk_x11_roundtrip_async (GdkDisplay           *display, 
806                           GdkRoundTripCallback callback,
807                           gpointer              data)
808 {
809   Display *dpy;
810   RoundtripState *state;
811   
812   dpy = GDK_DISPLAY_XDISPLAY (display);
813
814   state = g_new (RoundtripState, 1);
815
816   state->dpy = dpy;
817   state->callback = callback;
818   state->data = data;
819   
820   LockDisplay(dpy);
821
822   state->async.next = dpy->async_handlers;
823   state->async.handler = roundtrip_handler;
824   state->async.data = (XPointer) state;
825   dpy->async_handlers = &state->async;
826
827   /*
828    * XSync (dpy, 0)
829    */
830   {
831     xReq *req;
832     
833     GetEmptyReq(GetInputFocus, req);
834     state->get_input_focus_req = dpy->request;
835   }
836   
837   UnlockDisplay(dpy);
838   SyncHandle();
839 }
840
841 #define __GDK_ASYNC_C__
842 #include "gdkaliasdef.c"