]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkmain-x11.c
Mark api with xlib types as skipped
[~andy/gtk] / gdk / x11 / gdkmain-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include "gdkdeviceprivate.h"
30 #include "gdkinternals.h"
31 #include "gdkintl.h"
32 #include "gdkasync.h"
33 #include "gdkdisplay-x11.h"
34 #include "gdkprivate-x11.h"
35
36 #include <glib/gprintf.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <limits.h>
41 #include <errno.h>
42
43 #include <X11/Xatom.h>
44 #include <X11/Xlib.h>
45 #include <X11/Xutil.h>
46
47 #ifdef HAVE_XKB
48 #include <X11/XKBlib.h>
49 #endif
50
51 /**
52  * SECTION:x_interaction
53  * @Short_description: X backend-specific functions
54  * @Title: X Window System Interaction
55  *
56  * The functions in this section are specific to the GDK X11 backend.
57  * To use them, you need to include the <literal>&lt;gdk/gdkx.h&gt;</literal>
58  * header and use the X11-specific pkg-config files to build your
59  * application (either <literal>gdk-x11-3.0</literal> or
60  * <literal>gtk+-x11-3.0</literal>).
61  *
62  * To make your code compile with other GDK backends, guard backend-specific
63  * calls by an ifdef as follows. Since GDK may be built with multiple
64  * backends, you should also check for the backend that is in use (e.g. by
65  * using the GDK_IS_X11_DISPLAY() macro).
66  * |[
67  * #ifdef GDK_WINDOWING_X11
68  *   if (GDK_IS_X11_DISPLAY (display))
69  *     {
70  *       /&ast; make X11-specific calls here &ast;/
71  *     }
72  *   else
73  * #endif
74  * #ifdef GDK_WINDOWING_QUARTZ
75  *   if (GDK_IS_QUARTZ_DISPLAY (display))
76  *     {
77  *       /&ast; make Quartz-specific calls here &ast/
78  *     }
79  *   else
80  * #endif
81  *   g_error ("Unsupported GDK backend");
82  * ]|
83  */
84
85 typedef struct _GdkPredicate GdkPredicate;
86
87 struct _GdkPredicate
88 {
89   GdkEventFunc func;
90   gpointer data;
91 };
92
93 /* non-GDK previous error handler */
94 typedef int (*GdkXErrorHandler) (Display *, XErrorEvent *);
95 static GdkXErrorHandler _gdk_old_error_handler;
96 /* number of times we've pushed the GDK error handler */
97 static int _gdk_error_handler_push_count = 0;
98
99 /*
100  * Private function declarations
101  */
102
103 #ifndef HAVE_XCONVERTCASE
104 static void      gdkx_XConvertCase      (KeySym        symbol,
105                                          KeySym       *lower,
106                                          KeySym       *upper);
107 #define XConvertCase gdkx_XConvertCase
108 #endif
109
110 static int          gdk_x_error                  (Display     *display, 
111                                                   XErrorEvent *error);
112 static int          gdk_x_io_error               (Display     *display);
113
114 void
115 _gdk_x11_windowing_init (void)
116 {
117   XSetErrorHandler (gdk_x_error);
118   XSetIOErrorHandler (gdk_x_io_error);
119 }
120
121 GdkGrabStatus
122 _gdk_x11_convert_grab_status (gint status)
123 {
124   switch (status)
125     {
126     case GrabSuccess:
127       return GDK_GRAB_SUCCESS;
128     case AlreadyGrabbed:
129       return GDK_GRAB_ALREADY_GRABBED;
130     case GrabInvalidTime:
131       return GDK_GRAB_INVALID_TIME;
132     case GrabNotViewable:
133       return GDK_GRAB_NOT_VIEWABLE;
134     case GrabFrozen:
135       return GDK_GRAB_FROZEN;
136     }
137
138   g_assert_not_reached();
139
140   return 0;
141 }
142
143 /*
144  * _gdk_x11_window_grab_check_unmap:
145  * @window: a #GdkWindow
146  * @serial: serial from Unmap event (or from NextRequest(display)
147  *   if the unmap is being done by this client.)
148  *
149  * Checks to see if an unmap request or event causes the current
150  * grab window to become not viewable, and if so, clear the
151  * the pointer we keep to it.
152  **/
153 void
154 _gdk_x11_window_grab_check_unmap (GdkWindow *window,
155                                   gulong     serial)
156 {
157   GdkDisplay *display = gdk_window_get_display (window);
158   GdkDeviceManager *device_manager;
159   GList *devices, *d;
160
161   device_manager = gdk_display_get_device_manager (display);
162
163   /* Get all devices */
164   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
165   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
166   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
167
168   /* End all grabs on the newly hidden window */
169   for (d = devices; d; d = d->next)
170     _gdk_display_end_device_grab (display, d->data, serial, window, TRUE);
171
172   g_list_free (devices);
173 }
174
175 /*
176  * _gdk_x11_window_grab_check_destroy:
177  * @window: a #GdkWindow
178  * 
179  * Checks to see if window is the current grab window, and if
180  * so, clear the current grab window.
181  **/
182 void
183 _gdk_x11_window_grab_check_destroy (GdkWindow *window)
184 {
185   GdkDisplay *display = gdk_window_get_display (window);
186   GdkDeviceManager *device_manager;
187   GdkDeviceGrabInfo *grab;
188   GList *devices, *d;
189
190   device_manager = gdk_display_get_device_manager (display);
191
192   /* Get all devices */
193   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
194   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
195   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
196
197   for (d = devices; d; d = d->next)
198     {
199       /* Make sure there is no lasting grab in this native window */
200       grab = _gdk_display_get_last_device_grab (display, d->data);
201
202       if (grab && grab->native_window == window)
203         {
204           /* We don't know the actual serial to end, but it
205              doesn't really matter as this only happens
206              after we get told of the destroy from the
207              server so we know its ended in the server,
208              just make sure its ended. */
209           grab->serial_end = grab->serial_start;
210           grab->implicit_ungrab = TRUE;
211         }
212     }
213
214   g_list_free (devices);
215 }
216
217 /*
218  *--------------------------------------------------------------
219  * gdk_x_io_error
220  *
221  *   The X I/O error handling routine.
222  *
223  * Arguments:
224  *   "display" is the X display the error orignated from.
225  *
226  * Results:
227  *   An X I/O error basically means we lost our connection
228  *   to the X server. There is not much we can do to
229  *   continue, so simply print an error message and exit.
230  *
231  * Side effects:
232  *
233  *--------------------------------------------------------------
234  */
235
236 static int
237 gdk_x_io_error (Display *display)
238 {
239   /* This is basically modelled after the code in XLib. We need
240    * an explicit error handler here, so we can disable our atexit()
241    * which would otherwise cause a nice segfault.
242    * We fprintf(stderr, instead of g_warning() because g_warning()
243    * could possibly be redirected to a dialog
244    */
245   if (errno == EPIPE)
246     {
247       g_warning ("The application '%s' lost its connection to the display %s;\n"
248                  "most likely the X server was shut down or you killed/destroyed\n"
249                  "the application.\n",
250                  g_get_prgname (),
251                  display ? DisplayString (display) : gdk_get_display_arg_name ());
252     }
253   else
254     {
255       g_warning ("%s: Fatal IO error %d (%s) on X server %s.\n",
256                  g_get_prgname (),
257                  errno, g_strerror (errno),
258                  display ? DisplayString (display) : gdk_get_display_arg_name ());
259     }
260
261   exit(1);
262 }
263
264 /* X error handler. Keep the name the same because people are used to
265  * breaking on it in the debugger.
266  */
267 static int
268 gdk_x_error (Display     *xdisplay,
269              XErrorEvent *error)
270 {
271   if (error->error_code)
272     {
273       GdkDisplay *error_display;
274       GdkDisplayManager *manager;
275       GSList *displays;
276
277       /* Figure out which GdkDisplay if any got the error. */
278       error_display = NULL;
279       manager = gdk_display_manager_get ();
280       displays = gdk_display_manager_list_displays (manager);
281       while (displays != NULL)
282         {
283           GdkX11Display *gdk_display = displays->data;
284
285           if (xdisplay == gdk_display->xdisplay)
286             {
287               error_display = GDK_DISPLAY (gdk_display);
288               g_slist_free (displays);
289               displays = NULL;
290             }
291           else
292             {
293               displays = g_slist_delete_link (displays, displays);
294             }
295         }
296
297       if (error_display == NULL)
298         {
299           /* Error on an X display not opened by GDK. Ignore. */
300
301           return 0;
302         }
303       else
304         {
305           _gdk_x11_display_error_event (error_display, error);
306         }
307     }
308
309   return 0;
310 }
311
312 void
313 _gdk_x11_error_handler_push (void)
314 {
315   GdkXErrorHandler previous;
316
317   previous = XSetErrorHandler (gdk_x_error);
318
319   if (_gdk_error_handler_push_count > 0)
320     {
321       if (previous != gdk_x_error)
322         g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
323     }
324   else
325     {
326       _gdk_old_error_handler = previous;
327     }
328
329   _gdk_error_handler_push_count += 1;
330 }
331
332 void
333 _gdk_x11_error_handler_pop  (void)
334 {
335   g_return_if_fail (_gdk_error_handler_push_count > 0);
336
337   _gdk_error_handler_push_count -= 1;
338
339   if (_gdk_error_handler_push_count == 0)
340     {
341       XSetErrorHandler (_gdk_old_error_handler);
342       _gdk_old_error_handler = NULL;
343     }
344 }
345
346 gint
347 _gdk_x11_display_send_xevent (GdkDisplay *display,
348                               Window      window,
349                               gboolean    propagate,
350                               glong       event_mask,
351                               XEvent     *event_send)
352 {
353   gboolean result;
354
355   if (gdk_display_is_closed (display))
356     return FALSE;
357
358   gdk_x11_display_error_trap_push (display);
359   result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window,
360                        propagate, event_mask, event_send);
361   XSync (GDK_DISPLAY_XDISPLAY (display), False);
362
363   if (gdk_x11_display_error_trap_pop (display))
364     return FALSE;
365
366   return result;
367 }
368
369 void
370 _gdk_x11_region_get_xrectangles (const cairo_region_t *region,
371                                  gint             x_offset,
372                                  gint             y_offset,
373                                  XRectangle     **rects,
374                                  gint            *n_rects)
375 {
376   XRectangle *rectangles;
377   cairo_rectangle_int_t box;
378   gint i, n;
379   
380   n = cairo_region_num_rectangles (region);
381   rectangles = g_new (XRectangle, n);
382
383   for (i = 0; i < n; i++)
384     {
385       cairo_region_get_rectangle (region, i, &box);
386       rectangles[i].x = CLAMP (box.x + x_offset, G_MINSHORT, G_MAXSHORT);
387       rectangles[i].y = CLAMP (box.y + y_offset, G_MINSHORT, G_MAXSHORT);
388       rectangles[i].width = CLAMP (box.width, G_MINSHORT, G_MAXSHORT);
389       rectangles[i].height = CLAMP (box.height, G_MINSHORT, G_MAXSHORT);
390     }
391
392   *n_rects = n;
393   *rects = rectangles;
394 }
395
396 /**
397  * gdk_x11_grab_server:
398  * 
399  * Call gdk_x11_display_grab() on the default display. 
400  * To ungrab the server again, use gdk_x11_ungrab_server(). 
401  *
402  * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
403  **/ 
404 void
405 gdk_x11_grab_server (void)
406 {
407   gdk_x11_display_grab (gdk_display_get_default ());
408 }
409
410 /**
411  * gdk_x11_ungrab_server:
412  *
413  * Ungrab the default display after it has been grabbed with 
414  * gdk_x11_grab_server(). 
415  **/
416 void
417 gdk_x11_ungrab_server (void)
418 {
419   gdk_x11_display_ungrab (gdk_display_get_default ());
420 }
421
422 /**
423  * gdk_x11_get_default_screen:
424  * 
425  * Gets the default GTK+ screen number.
426  * 
427  * Return value: returns the screen number specified by
428  *   the --display command line option or the DISPLAY environment
429  *   variable when gdk_init() calls XOpenDisplay().
430  **/
431 gint
432 gdk_x11_get_default_screen (void)
433 {
434   return gdk_screen_get_number (gdk_screen_get_default ());
435 }
436
437 /**
438  * gdk_x11_get_default_root_xwindow: (skip)
439  * 
440  * Gets the root window of the default screen 
441  * (see gdk_x11_get_default_screen()).  
442  * 
443  * Return value: an Xlib <type>Window</type>.
444  **/
445 Window
446 gdk_x11_get_default_root_xwindow (void)
447 {
448   return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
449 }
450
451 /**
452  * gdk_x11_get_default_xdisplay: (skip)
453  * 
454  * Gets the default GTK+ display.
455  * 
456  * Return value: the Xlib <type>Display*</type> for the display
457  * specified in the <option>--display</option> command line option 
458  * or the <envar>DISPLAY</envar> environment variable.
459  **/
460 Display *
461 gdk_x11_get_default_xdisplay (void)
462 {
463   return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
464 }