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