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