]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkasync.c
Add a function to XSendEvent() and call a calback on failure/success.
[~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 <X11/Xlibint.h>
47 #include "gdkasync.h"
48 #include "gdkx.h"
49
50 typedef struct _SendEventState SendEventState;
51 typedef struct _SetInputFocusState SetInputFocusState;
52
53 struct _SendEventState
54 {
55   Display *dpy;
56   Window window;
57   _XAsyncHandler async;
58   gulong send_event_req;
59   gulong get_input_focus_req;
60   gboolean have_error;
61   GdkSendXEventCallback callback;
62   gpointer data;
63 };
64
65 struct _SetInputFocusState
66 {
67   Display *dpy;
68   _XAsyncHandler async;
69   gulong set_input_focus_req;
70   gulong get_input_focus_req;
71 };
72
73 static Bool
74 send_event_handler (Display *dpy,
75                     xReply  *rep,
76                     char    *buf,
77                     int      len,
78                     XPointer data)
79 {
80   SendEventState *state = (SendEventState *)data;  
81
82   if (dpy->last_request_read == state->send_event_req)
83     {
84       if (rep->generic.type == X_Error)
85         {
86           if (rep->error.errorCode == BadWindow)
87             {
88               state->have_error = TRUE;
89               return True;
90             }
91         }
92     }
93   else if (dpy->last_request_read == state->get_input_focus_req)
94     {
95       xGetInputFocusReply replbuf;
96       xGetInputFocusReply *repl;
97       
98       if (rep->generic.type != X_Error)
99         {
100           repl = (xGetInputFocusReply *)
101             _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
102                             (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
103                             True);
104         }
105
106       if (state->callback)
107         state->callback (state->window, !state->have_error, state->data);
108
109       DeqAsyncHandler(state->dpy, &state->async);
110
111       g_free (state);
112       
113       return True;
114     }
115
116   return False;
117 }
118
119 void
120 _gdk_send_xevent_async (GdkDisplay           *display, 
121                         Window                window, 
122                         gboolean              propagate,
123                         glong                 event_mask,
124                         XEvent               *event_send,
125                         GdkSendXEventCallback callback,
126                         gpointer              data)
127 {
128   Display *dpy;
129   SendEventState *state;
130   Status status;
131   
132   dpy = GDK_DISPLAY_XDISPLAY (display);
133
134   state = g_new (SendEventState, 1);
135
136   state->dpy = dpy;
137   state->window = window;
138   state->callback = callback;
139   state->data = data;
140   state->have_error = FALSE;
141   
142   LockDisplay(dpy);
143
144   state->async.next = dpy->async_handlers;
145   state->async.handler = send_event_handler;
146   state->async.data = (XPointer) state;
147   dpy->async_handlers = &state->async;
148
149   {
150     register xSendEventReq *req;
151     xEvent ev;
152     register Status (**fp)();
153     
154     /* call through display to find proper conversion routine */
155     
156     fp = &dpy->wire_vec[event_send->type & 0177];
157     if (*fp == NULL) *fp = _XEventToWire;
158     status = (**fp)(dpy, event_send, &ev);
159     
160     if (!status)
161       {
162         g_warning ("Error converting event to wire");
163         DeqAsyncHandler(dpy, &state->async);
164         UnlockDisplay(dpy);
165         SyncHandle();
166         g_free (state);
167
168         return;
169       }
170       
171     GetReq(SendEvent, req);
172     req->destination = window;
173     req->propagate = propagate;
174     req->eventMask = event_mask;
175     /* gross, matches Xproto.h */
176 #ifdef WORD64                   
177     memcpy ((char *) req->eventdata, (char *) &ev, SIZEOF(xEvent));
178 #else    
179     memcpy ((char *) &req->event, (char *) &ev, SIZEOF(xEvent));
180 #endif
181     
182     state->send_event_req = dpy->request;
183   }
184
185   /*
186    * XSync (dpy, 0)
187    */
188   {
189     xReq *req;
190     
191     GetEmptyReq(GetInputFocus, req);
192     state->get_input_focus_req = dpy->request;
193   }
194   
195   UnlockDisplay(dpy);
196   SyncHandle();
197 }
198
199 static Bool
200 set_input_focus_handler (Display *dpy,
201                          xReply  *rep,
202                          char    *buf,
203                          int      len,
204                          XPointer data)
205 {
206   SetInputFocusState *state = (SetInputFocusState *)data;  
207
208   if (dpy->last_request_read == state->set_input_focus_req)
209     {
210       if (rep->generic.type == X_Error &&
211           rep->error.errorCode == BadMatch)
212         {
213           /* Consume BadMatch errors, since we have no control
214            * over them.
215            */
216           return True;
217         }
218     }
219   
220   if (dpy->last_request_read == state->get_input_focus_req)
221     {
222       xGetInputFocusReply replbuf;
223       xGetInputFocusReply *repl;
224       
225       if (rep->generic.type != X_Error)
226         {
227           /* Actually does nothing, since there are no additional bytes
228            * to read, but maintain good form.
229            */
230           repl = (xGetInputFocusReply *)
231             _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
232                             (sizeof(xGetInputFocusReply) - sizeof(xReply)) >> 2,
233                             True);
234         }
235
236       DeqAsyncHandler(state->dpy, &state->async);
237
238       g_free (state);
239       
240       return (rep->generic.type != X_Error);
241     }
242
243   return False;
244 }
245
246 void
247 _gdk_x11_set_input_focus_safe (GdkDisplay             *display,
248                                Window                  window,
249                                int                     revert_to,
250                                Time                    time)
251 {
252   Display *dpy;
253   SetInputFocusState *state;
254   
255   dpy = GDK_DISPLAY_XDISPLAY (display);
256
257   state = g_new (SetInputFocusState, 1);
258
259   state->dpy = dpy;
260   
261   LockDisplay(dpy);
262
263   state->async.next = dpy->async_handlers;
264   state->async.handler = set_input_focus_handler;
265   state->async.data = (XPointer) state;
266   dpy->async_handlers = &state->async;
267
268   {
269     xSetInputFocusReq *req;
270     
271     GetReq(SetInputFocus, req);
272     req->focus = window;
273     req->revertTo = revert_to;
274     req->time = time;
275     state->set_input_focus_req = dpy->request;
276   }
277
278   /*
279    * XSync (dpy, 0)
280    */
281   {
282     xReq *req;
283     
284     GetEmptyReq(GetInputFocus, req);
285     state->get_input_focus_req = dpy->request;
286   }
287   
288   UnlockDisplay(dpy);
289   SyncHandle();
290 }