]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkmain-x11.c
41b1b0a14ee32772b43c26abe04d268355ac0acc
[~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   gdk_window_add_filter (NULL,
121                          _gdk_wm_protocols_filter,
122                          NULL);
123   gdk_window_add_filter (NULL,
124                          _gdk_x11_dnd_filter,
125                          NULL);
126 }
127
128 GdkGrabStatus
129 _gdk_x11_convert_grab_status (gint status)
130 {
131   switch (status)
132     {
133     case GrabSuccess:
134       return GDK_GRAB_SUCCESS;
135     case AlreadyGrabbed:
136       return GDK_GRAB_ALREADY_GRABBED;
137     case GrabInvalidTime:
138       return GDK_GRAB_INVALID_TIME;
139     case GrabNotViewable:
140       return GDK_GRAB_NOT_VIEWABLE;
141     case GrabFrozen:
142       return GDK_GRAB_FROZEN;
143     }
144
145   g_assert_not_reached();
146
147   return 0;
148 }
149
150 /*
151  * _gdk_x11_window_grab_check_unmap:
152  * @window: a #GdkWindow
153  * @serial: serial from Unmap event (or from NextRequest(display)
154  *   if the unmap is being done by this client.)
155  *
156  * Checks to see if an unmap request or event causes the current
157  * grab window to become not viewable, and if so, clear the
158  * the pointer we keep to it.
159  **/
160 void
161 _gdk_x11_window_grab_check_unmap (GdkWindow *window,
162                                   gulong     serial)
163 {
164   GdkDisplay *display = gdk_window_get_display (window);
165   GdkDeviceManager *device_manager;
166   GList *devices, *d;
167
168   device_manager = gdk_display_get_device_manager (display);
169
170   /* Get all devices */
171   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
172   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
173   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
174
175   /* End all grabs on the newly hidden window */
176   for (d = devices; d; d = d->next)
177     _gdk_display_end_device_grab (display, d->data, serial, window, TRUE);
178
179   g_list_free (devices);
180 }
181
182 /*
183  * _gdk_x11_window_grab_check_destroy:
184  * @window: a #GdkWindow
185  * 
186  * Checks to see if window is the current grab window, and if
187  * so, clear the current grab window.
188  **/
189 void
190 _gdk_x11_window_grab_check_destroy (GdkWindow *window)
191 {
192   GdkDisplay *display = gdk_window_get_display (window);
193   GdkDeviceManager *device_manager;
194   GdkDeviceGrabInfo *grab;
195   GList *devices, *d;
196
197   device_manager = gdk_display_get_device_manager (display);
198
199   /* Get all devices */
200   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
201   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
202   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
203
204   for (d = devices; d; d = d->next)
205     {
206       /* Make sure there is no lasting grab in this native window */
207       grab = _gdk_display_get_last_device_grab (display, d->data);
208
209       if (grab && grab->native_window == window)
210         {
211           /* We don't know the actual serial to end, but it
212              doesn't really matter as this only happens
213              after we get told of the destroy from the
214              server so we know its ended in the server,
215              just make sure its ended. */
216           grab->serial_end = grab->serial_start;
217           grab->implicit_ungrab = TRUE;
218         }
219     }
220
221   g_list_free (devices);
222 }
223
224 /*
225  *--------------------------------------------------------------
226  * gdk_x_io_error
227  *
228  *   The X I/O error handling routine.
229  *
230  * Arguments:
231  *   "display" is the X display the error orignated from.
232  *
233  * Results:
234  *   An X I/O error basically means we lost our connection
235  *   to the X server. There is not much we can do to
236  *   continue, so simply print an error message and exit.
237  *
238  * Side effects:
239  *
240  *--------------------------------------------------------------
241  */
242
243 static int
244 gdk_x_io_error (Display *display)
245 {
246   /* This is basically modelled after the code in XLib. We need
247    * an explicit error handler here, so we can disable our atexit()
248    * which would otherwise cause a nice segfault.
249    * We fprintf(stderr, instead of g_warning() because g_warning()
250    * could possibly be redirected to a dialog
251    */
252   if (errno == EPIPE)
253     {
254       g_warning ("The application '%s' lost its connection to the display %s;\n"
255                  "most likely the X server was shut down or you killed/destroyed\n"
256                  "the application.\n",
257                  g_get_prgname (),
258                  display ? DisplayString (display) : gdk_get_display_arg_name ());
259     }
260   else
261     {
262       g_warning ("%s: Fatal IO error %d (%s) on X server %s.\n",
263                  g_get_prgname (),
264                  errno, g_strerror (errno),
265                  display ? DisplayString (display) : gdk_get_display_arg_name ());
266     }
267
268   _exit (1);
269 }
270
271 /* X error handler. Keep the name the same because people are used to
272  * breaking on it in the debugger.
273  */
274 static int
275 gdk_x_error (Display     *xdisplay,
276              XErrorEvent *error)
277 {
278   if (error->error_code)
279     {
280       GdkDisplay *error_display;
281       GdkDisplayManager *manager;
282       GSList *displays;
283
284       /* Figure out which GdkDisplay if any got the error. */
285       error_display = NULL;
286       manager = gdk_display_manager_get ();
287       displays = gdk_display_manager_list_displays (manager);
288       while (displays != NULL)
289         {
290           GdkX11Display *gdk_display = displays->data;
291
292           if (xdisplay == gdk_display->xdisplay)
293             {
294               error_display = GDK_DISPLAY (gdk_display);
295               g_slist_free (displays);
296               displays = NULL;
297             }
298           else
299             {
300               displays = g_slist_delete_link (displays, displays);
301             }
302         }
303
304       if (error_display == NULL)
305         {
306           /* Error on an X display not opened by GDK. Ignore. */
307
308           return 0;
309         }
310       else
311         {
312           _gdk_x11_display_error_event (error_display, error);
313         }
314     }
315
316   return 0;
317 }
318
319 void
320 _gdk_x11_error_handler_push (void)
321 {
322   GdkXErrorHandler previous;
323
324   previous = XSetErrorHandler (gdk_x_error);
325
326   if (_gdk_error_handler_push_count > 0)
327     {
328       if (previous != gdk_x_error)
329         g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
330     }
331   else
332     {
333       _gdk_old_error_handler = previous;
334     }
335
336   _gdk_error_handler_push_count += 1;
337 }
338
339 void
340 _gdk_x11_error_handler_pop  (void)
341 {
342   g_return_if_fail (_gdk_error_handler_push_count > 0);
343
344   _gdk_error_handler_push_count -= 1;
345
346   if (_gdk_error_handler_push_count == 0)
347     {
348       XSetErrorHandler (_gdk_old_error_handler);
349       _gdk_old_error_handler = NULL;
350     }
351 }
352
353 gint
354 _gdk_x11_display_send_xevent (GdkDisplay *display,
355                               Window      window,
356                               gboolean    propagate,
357                               glong       event_mask,
358                               XEvent     *event_send)
359 {
360   gboolean result;
361
362   if (gdk_display_is_closed (display))
363     return FALSE;
364
365   gdk_x11_display_error_trap_push (display);
366   result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window,
367                        propagate, event_mask, event_send);
368   XSync (GDK_DISPLAY_XDISPLAY (display), False);
369
370   if (gdk_x11_display_error_trap_pop (display))
371     return FALSE;
372
373   return result;
374 }
375
376 void
377 _gdk_x11_region_get_xrectangles (const cairo_region_t *region,
378                                  gint             x_offset,
379                                  gint             y_offset,
380                                  XRectangle     **rects,
381                                  gint            *n_rects)
382 {
383   XRectangle *rectangles;
384   cairo_rectangle_int_t box;
385   gint i, n;
386   
387   n = cairo_region_num_rectangles (region);
388   rectangles = g_new (XRectangle, n);
389
390   for (i = 0; i < n; i++)
391     {
392       cairo_region_get_rectangle (region, i, &box);
393       rectangles[i].x = CLAMP (box.x + x_offset, G_MINSHORT, G_MAXSHORT);
394       rectangles[i].y = CLAMP (box.y + y_offset, G_MINSHORT, G_MAXSHORT);
395       rectangles[i].width = CLAMP (box.width, G_MINSHORT, G_MAXSHORT);
396       rectangles[i].height = CLAMP (box.height, G_MINSHORT, G_MAXSHORT);
397     }
398
399   *n_rects = n;
400   *rects = rectangles;
401 }
402
403 /**
404  * gdk_x11_grab_server:
405  * 
406  * Call gdk_x11_display_grab() on the default display. 
407  * To ungrab the server again, use gdk_x11_ungrab_server(). 
408  *
409  * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
410  **/ 
411 void
412 gdk_x11_grab_server (void)
413 {
414   gdk_x11_display_grab (gdk_display_get_default ());
415 }
416
417 /**
418  * gdk_x11_ungrab_server:
419  *
420  * Ungrab the default display after it has been grabbed with 
421  * gdk_x11_grab_server(). 
422  **/
423 void
424 gdk_x11_ungrab_server (void)
425 {
426   gdk_x11_display_ungrab (gdk_display_get_default ());
427 }
428
429 /**
430  * gdk_x11_get_default_screen:
431  * 
432  * Gets the default GTK+ screen number.
433  * 
434  * Return value: returns the screen number specified by
435  *   the --display command line option or the DISPLAY environment
436  *   variable when gdk_init() calls XOpenDisplay().
437  **/
438 gint
439 gdk_x11_get_default_screen (void)
440 {
441   return gdk_screen_get_number (gdk_screen_get_default ());
442 }
443
444 /**
445  * gdk_x11_get_default_root_xwindow:
446  * 
447  * Gets the root window of the default screen 
448  * (see gdk_x11_get_default_screen()).  
449  * 
450  * Return value: an Xlib <type>Window</type>.
451  **/
452 Window
453 gdk_x11_get_default_root_xwindow (void)
454 {
455   return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
456 }
457
458 /**
459  * gdk_x11_get_default_xdisplay:
460  * 
461  * Gets the default GTK+ display.
462  * 
463  * Return value: (transfer none): the Xlib <type>Display*</type> for
464  * the display specified in the <option>--display</option> command
465  * line option or the <envar>DISPLAY</envar> environment variable.
466  **/
467 Display *
468 gdk_x11_get_default_xdisplay (void)
469 {
470   return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
471 }