]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkmain-x11.c
[introspection] add transfer none annotation to gdk_keyval_name return
[~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 "gdkx.h"
30 #include "gdkasync.h"
31 #include "gdkdisplay-x11.h"
32 #include "gdkinternals.h"
33 #include "gdkprivate-x11.h"
34 #include "gdkintl.h"
35 #include "gdkdeviceprivate.h"
36
37 #include <glib/gprintf.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <limits.h>
42 #include <errno.h>
43
44 #include <X11/Xatom.h>
45 #include <X11/Xlib.h>
46 #include <X11/Xutil.h>
47
48 #ifdef HAVE_XKB
49 #include <X11/XKBlib.h>
50 #endif
51
52
53 typedef struct _GdkPredicate        GdkPredicate;
54 typedef struct _GdkGlobalErrorTrap  GdkGlobalErrorTrap;
55
56 struct _GdkPredicate
57 {
58   GdkEventFunc func;
59   gpointer data;
60 };
61
62 /* non-GDK previous error handler */
63 typedef int (*GdkXErrorHandler) (Display *, XErrorEvent *);
64 static GdkXErrorHandler _gdk_old_error_handler;
65 /* number of times we've pushed the GDK error handler */
66 static int _gdk_error_handler_push_count = 0;
67
68 struct _GdkGlobalErrorTrap
69 {
70   GSList *displays;
71 };
72
73 /* 
74  * Private function declarations
75  */
76
77 #ifndef HAVE_XCONVERTCASE
78 static void      gdkx_XConvertCase      (KeySym        symbol,
79                                          KeySym       *lower,
80                                          KeySym       *upper);
81 #define XConvertCase gdkx_XConvertCase
82 #endif
83
84 static int          gdk_x_error                  (Display     *display, 
85                                                   XErrorEvent *error);
86 static int          gdk_x_io_error               (Display     *display);
87
88 /* Private variable declarations
89  */
90 static GQueue gdk_error_traps;
91
92 const GOptionEntry _gdk_windowing_args[] = {
93   { "sync", 0, 0, G_OPTION_ARG_NONE, &_gdk_synchronize, 
94     /* Description of --sync in --help output */ N_("Make X calls synchronous"), NULL },
95   { NULL }
96 };
97
98 void
99 _gdk_windowing_init (void)
100 {
101   _gdk_x11_initialize_locale ();
102
103   g_queue_init (&gdk_error_traps);
104   XSetErrorHandler (gdk_x_error);
105   XSetIOErrorHandler (gdk_x_io_error);
106
107   _gdk_selection_property = gdk_atom_intern_static_string ("GDK_SELECTION");
108 }
109
110 GdkGrabStatus
111 _gdk_x11_convert_grab_status (gint status)
112 {
113   switch (status)
114     {
115     case GrabSuccess:
116       return GDK_GRAB_SUCCESS;
117     case AlreadyGrabbed:
118       return GDK_GRAB_ALREADY_GRABBED;
119     case GrabInvalidTime:
120       return GDK_GRAB_INVALID_TIME;
121     case GrabNotViewable:
122       return GDK_GRAB_NOT_VIEWABLE;
123     case GrabFrozen:
124       return GDK_GRAB_FROZEN;
125     }
126
127   g_assert_not_reached();
128
129   return 0;
130 }
131
132 static void
133 has_pointer_grab_callback (GdkDisplay *display,
134                            gpointer data,
135                            gulong serial)
136 {
137   GdkDevice *device = data;
138
139   _gdk_display_device_grab_update (display, device, serial);
140 }
141
142 GdkGrabStatus
143 _gdk_windowing_device_grab (GdkDevice    *device,
144                             GdkWindow    *window,
145                             GdkWindow    *native,
146                             gboolean      owner_events,
147                             GdkEventMask  event_mask,
148                             GdkWindow    *confine_to,
149                             GdkCursor    *cursor,
150                             guint32       time)
151 {
152   GdkDisplay *display;
153   GdkGrabStatus status = GDK_GRAB_SUCCESS;
154
155   if (!window || GDK_WINDOW_DESTROYED (window))
156     return GDK_GRAB_NOT_VIEWABLE;
157
158   display = gdk_device_get_display (device);
159
160 #ifdef G_ENABLE_DEBUG
161   if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
162     status = GrabSuccess;
163   else
164 #endif
165     status = GDK_DEVICE_GET_CLASS (device)->grab (device,
166                                                   native,
167                                                   owner_events,
168                                                   event_mask,
169                                                   confine_to,
170                                                   cursor,
171                                                   time);
172   if (status == GDK_GRAB_SUCCESS)
173     _gdk_x11_roundtrip_async (display,
174                               has_pointer_grab_callback,
175                               device);
176   return status;
177 }
178
179 /**
180  * _gdk_xgrab_check_unmap:
181  * @window: a #GdkWindow
182  * @serial: serial from Unmap event (or from NextRequest(display)
183  *   if the unmap is being done by this client.)
184  * 
185  * Checks to see if an unmap request or event causes the current
186  * grab window to become not viewable, and if so, clear the
187  * the pointer we keep to it.
188  **/
189 void
190 _gdk_xgrab_check_unmap (GdkWindow *window,
191                         gulong     serial)
192 {
193   GdkDisplay *display = gdk_window_get_display (window);
194   GdkDeviceManager *device_manager;
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   /* End all grabs on the newly hidden window */
205   for (d = devices; d; d = d->next)
206     _gdk_display_end_device_grab (display, d->data, serial, window, TRUE);
207
208   g_list_free (devices);
209 }
210
211 /**
212  * _gdk_xgrab_check_destroy:
213  * @window: a #GdkWindow
214  * 
215  * Checks to see if window is the current grab window, and if
216  * so, clear the current grab window.
217  **/
218 void
219 _gdk_xgrab_check_destroy (GdkWindow *window)
220 {
221   GdkDisplay *display = gdk_window_get_display (window);
222   GdkDeviceManager *device_manager;
223   GdkDeviceGrabInfo *grab;
224   GList *devices, *d;
225
226   device_manager = gdk_display_get_device_manager (display);
227
228   /* Get all devices */
229   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
230   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
231   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
232
233   for (d = devices; d; d = d->next)
234     {
235       /* Make sure there is no lasting grab in this native window */
236       grab = _gdk_display_get_last_device_grab (display, d->data);
237
238       if (grab && grab->native_window == window)
239         {
240           /* We don't know the actual serial to end, but it
241              doesn't really matter as this only happens
242              after we get told of the destroy from the
243              server so we know its ended in the server,
244              just make sure its ended. */
245           grab->serial_end = grab->serial_start;
246           grab->implicit_ungrab = TRUE;
247         }
248     }
249
250   g_list_free (devices);
251 }
252
253 void
254 _gdk_windowing_display_set_sm_client_id (GdkDisplay  *display,
255                                          const gchar *sm_client_id)
256 {
257   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
258
259   if (display->closed)
260     return;
261
262   if (sm_client_id && strcmp (sm_client_id, ""))
263     {
264       XChangeProperty (display_x11->xdisplay, display_x11->leader_window,
265                        gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"),
266                        XA_STRING, 8, PropModeReplace, (guchar *)sm_client_id,
267                        strlen (sm_client_id));
268     }
269   else
270     XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
271                      gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
272 }
273
274 /* Close all open displays
275  */
276 void
277 _gdk_windowing_exit (void)
278 {
279   GSList *tmp_list = _gdk_displays;
280     
281   while (tmp_list)
282     {
283       XCloseDisplay (GDK_DISPLAY_XDISPLAY (tmp_list->data));
284       
285       tmp_list = tmp_list->next;
286   }
287 }
288
289 /*
290  *--------------------------------------------------------------
291  * gdk_x_io_error
292  *
293  *   The X I/O error handling routine.
294  *
295  * Arguments:
296  *   "display" is the X display the error orignated from.
297  *
298  * Results:
299  *   An X I/O error basically means we lost our connection
300  *   to the X server. There is not much we can do to
301  *   continue, so simply print an error message and exit.
302  *
303  * Side effects:
304  *
305  *--------------------------------------------------------------
306  */
307
308 static int
309 gdk_x_io_error (Display *display)
310 {
311   /* This is basically modelled after the code in XLib. We need
312    * an explicit error handler here, so we can disable our atexit()
313    * which would otherwise cause a nice segfault.
314    * We fprintf(stderr, instead of g_warning() because g_warning()
315    * could possibly be redirected to a dialog
316    */
317   if (errno == EPIPE)
318     {
319       g_warning ("The application '%s' lost its connection to the display %s;\n"
320                  "most likely the X server was shut down or you killed/destroyed\n"
321                  "the application.\n",
322                  g_get_prgname (),
323                  display ? DisplayString (display) : gdk_get_display_arg_name ());
324     }
325   else
326     {
327       g_warning ("%s: Fatal IO error %d (%s) on X server %s.\n",
328                  g_get_prgname (),
329                  errno, g_strerror (errno),
330                  display ? DisplayString (display) : gdk_get_display_arg_name ());
331     }
332
333   exit(1);
334 }
335
336 /* X error handler. Keep the name the same because people are used to
337  * breaking on it in the debugger.
338  */
339 static int
340 gdk_x_error (Display     *xdisplay,
341              XErrorEvent *error)
342 {
343   if (error->error_code)
344     {
345       GdkDisplay *error_display;
346       GdkDisplayManager *manager;
347       GSList *displays;
348
349       /* Figure out which GdkDisplay if any got the error. */
350       error_display = NULL;
351       manager = gdk_display_manager_get ();
352       displays = gdk_display_manager_list_displays (manager);
353       while (displays != NULL)
354         {
355           GdkDisplayX11 *gdk_display = displays->data;
356
357           if (xdisplay == gdk_display->xdisplay)
358             {
359               error_display = GDK_DISPLAY_OBJECT (gdk_display);
360               g_slist_free (displays);
361               displays = NULL;
362             }
363           else
364             {
365               displays = g_slist_delete_link (displays, displays);
366             }
367         }
368
369       if (error_display == NULL)
370         {
371           /* Error on an X display not opened by GDK. Ignore. */
372
373           return 0;
374         }
375       else
376         {
377           _gdk_x11_display_error_event (error_display, error);
378         }
379     }
380
381   return 0;
382 }
383
384 void
385 _gdk_x11_error_handler_push (void)
386 {
387   GdkXErrorHandler previous;
388
389   previous = XSetErrorHandler (gdk_x_error);
390
391   if (_gdk_error_handler_push_count > 0)
392     {
393       if (previous != gdk_x_error)
394         g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
395     }
396   else
397     {
398       _gdk_old_error_handler = previous;
399     }
400
401   _gdk_error_handler_push_count += 1;
402 }
403
404 void
405 _gdk_x11_error_handler_pop  (void)
406 {
407   g_return_if_fail (_gdk_error_handler_push_count > 0);
408
409   _gdk_error_handler_push_count -= 1;
410
411   if (_gdk_error_handler_push_count == 0)
412     {
413       XSetErrorHandler (_gdk_old_error_handler);
414       _gdk_old_error_handler = NULL;
415     }
416 }
417
418 /**
419  * gdk_error_trap_push:
420  *
421  * This function allows X errors to be trapped instead of the normal
422  * behavior of exiting the application. It should only be used if it
423  * is not possible to avoid the X error in any other way. Errors are
424  * ignored on all #GdkDisplay currently known to the
425  * #GdkDisplayManager. If you don't care which error happens and just
426  * want to ignore everything, pop with gdk_error_trap_pop_ignored().
427  * If you need the error code, use gdk_error_trap_pop() which may have
428  * to block and wait for the error to arrive from the X server.
429  *
430  * This API exists on all platforms but only does anything on X.
431  *
432  * You can use gdk_x11_display_error_trap_push() to ignore errors
433  * on only a single display.
434  *
435  * <example>
436  * <title>Trapping an X error</title>
437  * <programlisting>
438  * gdk_error_trap_push (<!-- -->);
439  *
440  *  // ... Call the X function which may cause an error here ...
441  *
442  *
443  * if (gdk_error_trap_pop (<!-- -->))
444  *  {
445  *    // ... Handle the error here ...
446  *  }
447  * </programlisting>
448  * </example>
449  *
450  */
451 void
452 gdk_error_trap_push (void)
453 {
454   GdkGlobalErrorTrap *trap;
455   GdkDisplayManager *manager;
456   GSList *tmp_list;
457
458   trap = g_slice_new (GdkGlobalErrorTrap);
459   manager = gdk_display_manager_get ();
460   trap->displays = gdk_display_manager_list_displays (manager);
461
462   g_slist_foreach (trap->displays, (GFunc) g_object_ref, NULL);
463   for (tmp_list = trap->displays;
464        tmp_list != NULL;
465        tmp_list = tmp_list->next)
466     {
467       gdk_x11_display_error_trap_push (tmp_list->data);
468     }
469
470   g_queue_push_head (&gdk_error_traps, trap);
471 }
472
473 static gint
474 gdk_error_trap_pop_internal (gboolean need_code)
475 {
476   GdkGlobalErrorTrap *trap;
477   gint result;
478   GSList *tmp_list;
479
480   trap = g_queue_pop_head (&gdk_error_traps);
481
482   g_return_val_if_fail (trap != NULL, Success);
483
484   result = Success;
485   for (tmp_list = trap->displays;
486        tmp_list != NULL;
487        tmp_list = tmp_list->next)
488     {
489       gint code = Success;
490
491       if (need_code)
492         code = gdk_x11_display_error_trap_pop (tmp_list->data);
493       else
494         gdk_x11_display_error_trap_pop_ignored (tmp_list->data);
495
496       /* we use the error on the last display listed, why not. */
497       if (code != Success)
498         result = code;
499     }
500
501   g_slist_foreach (trap->displays, (GFunc) g_object_unref, NULL);
502   g_slist_free (trap->displays);
503
504   g_slice_free (GdkGlobalErrorTrap, trap);
505
506   return result;
507 }
508
509 /**
510  * gdk_error_trap_pop_ignored:
511  *
512  * Removes an error trap pushed with gdk_error_trap_push(), but
513  * without bothering to wait and see whether an error occurred.  If an
514  * error arrives later asynchronously that was triggered while the
515  * trap was pushed, that error will be ignored.
516  *
517  * Since: 3.0
518  */
519 void
520 gdk_error_trap_pop_ignored (void)
521 {
522   gdk_error_trap_pop_internal (FALSE);
523 }
524
525 /**
526  * gdk_error_trap_pop:
527  *
528  * Removes an error trap pushed with gdk_error_trap_push().
529  * May block until an error has been definitively received
530  * or not received from the X server. gdk_error_trap_pop_ignored()
531  * is preferred if you don't need to know whether an error
532  * occurred, because it never has to block. If you don't
533  * need the return value of gdk_error_trap_pop(), use
534  * gdk_error_trap_pop_ignored().
535  *
536  * Prior to GDK 3.0, this function would not automatically
537  * sync for you, so you had to gdk_flush() if your last
538  * call to Xlib was not a blocking round trip.
539  *
540  * Return value: X error code or 0 on success
541  */
542 gint
543 gdk_error_trap_pop (void)
544 {
545   return gdk_error_trap_pop_internal (TRUE);
546 }
547
548 gchar *
549 gdk_get_display (void)
550 {
551   return g_strdup (gdk_display_get_name (gdk_display_get_default ()));
552 }
553
554 /**
555  * _gdk_send_xevent:
556  * @display: #GdkDisplay which @window is on
557  * @window: window ID to which to send the event
558  * @propagate: %TRUE if the event should be propagated if the target window
559  *             doesn't handle it.
560  * @event_mask: event mask to match against, or 0 to send it to @window
561  *              without regard to event masks.
562  * @event_send: #XEvent to send
563  * 
564  * Send an event, like XSendEvent(), but trap errors and check
565  * the result.
566  * 
567  * Return value: %TRUE if sending the event succeeded.
568  **/
569 gint 
570 _gdk_send_xevent (GdkDisplay *display,
571                   Window      window, 
572                   gboolean    propagate, 
573                   glong       event_mask,
574                   XEvent     *event_send)
575 {
576   gboolean result;
577
578   if (display->closed)
579     return FALSE;
580
581   gdk_error_trap_push ();
582   result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window, 
583                        propagate, event_mask, event_send);
584   XSync (GDK_DISPLAY_XDISPLAY (display), False);
585   
586   if (gdk_error_trap_pop ())
587     return FALSE;
588  
589   return result;
590 }
591
592 void
593 _gdk_region_get_xrectangles (const cairo_region_t *region,
594                              gint             x_offset,
595                              gint             y_offset,
596                              XRectangle     **rects,
597                              gint            *n_rects)
598 {
599   XRectangle *rectangles;
600   cairo_rectangle_int_t box;
601   gint i, n;
602   
603   n = cairo_region_num_rectangles (region);
604   rectangles = g_new (XRectangle, n);
605
606   for (i = 0; i < n; i++)
607     {
608       cairo_region_get_rectangle (region, i, &box);
609       rectangles[i].x = CLAMP (box.x + x_offset, G_MINSHORT, G_MAXSHORT);
610       rectangles[i].y = CLAMP (box.y + y_offset, G_MINSHORT, G_MAXSHORT);
611       rectangles[i].width = CLAMP (box.width, G_MINSHORT, G_MAXSHORT);
612       rectangles[i].height = CLAMP (box.height, G_MINSHORT, G_MAXSHORT);
613     }
614
615   *n_rects = n;
616   *rects = rectangles;
617 }
618
619 /**
620  * gdk_x11_grab_server:
621  * 
622  * Call gdk_x11_display_grab() on the default display. 
623  * To ungrab the server again, use gdk_x11_ungrab_server(). 
624  *
625  * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
626  **/ 
627 void
628 gdk_x11_grab_server (void)
629 {
630   gdk_x11_display_grab (gdk_display_get_default ());
631 }
632
633 /**
634  * gdk_x11_ungrab_server:
635  *
636  * Ungrab the default display after it has been grabbed with 
637  * gdk_x11_grab_server(). 
638  **/
639 void
640 gdk_x11_ungrab_server (void)
641 {
642   gdk_x11_display_ungrab (gdk_display_get_default ());
643 }
644
645 /**
646  * gdk_x11_get_default_screen:
647  * 
648  * Gets the default GTK+ screen number.
649  * 
650  * Return value: returns the screen number specified by
651  *   the --display command line option or the DISPLAY environment
652  *   variable when gdk_init() calls XOpenDisplay().
653  **/
654 gint
655 gdk_x11_get_default_screen (void)
656 {
657   return gdk_screen_get_number (gdk_screen_get_default ());
658 }
659
660 /**
661  * gdk_x11_get_default_root_xwindow:
662  * 
663  * Gets the root window of the default screen 
664  * (see gdk_x11_get_default_screen()).  
665  * 
666  * Return value: an Xlib <type>Window</type>.
667  **/
668 Window
669 gdk_x11_get_default_root_xwindow (void)
670 {
671   return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
672 }
673
674 /**
675  * gdk_x11_get_default_xdisplay:
676  * 
677  * Gets the default GTK+ display.
678  * 
679  * Return value: the Xlib <type>Display*</type> for the display
680  * specified in the <option>--display</option> command line option 
681  * or the <envar>DISPLAY</envar> environment variable.
682  **/
683 Display *
684 gdk_x11_get_default_xdisplay (void)
685 {
686   return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
687 }
688
689 void
690 _gdk_windowing_event_data_copy (const GdkEvent *src,
691                                 GdkEvent       *dst)
692 {
693 }
694
695 void
696 _gdk_windowing_event_data_free (GdkEvent *event)
697 {
698 }