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