1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
31 #include "gdkdisplay-x11.h"
32 #include "gdkinternals.h"
33 #include "gdkprivate-x11.h"
35 #include "gdkdeviceprivate.h"
37 #include <glib/gprintf.h>
44 #include <X11/Xatom.h>
46 #include <X11/Xutil.h>
49 #include <X11/XKBlib.h>
53 typedef struct _GdkPredicate GdkPredicate;
54 typedef struct _GdkGlobalErrorTrap GdkGlobalErrorTrap;
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;
68 struct _GdkGlobalErrorTrap
74 * Private function declarations
77 #ifndef HAVE_XCONVERTCASE
78 static void gdkx_XConvertCase (KeySym symbol,
81 #define XConvertCase gdkx_XConvertCase
84 static int gdk_x_error (Display *display,
86 static int gdk_x_io_error (Display *display);
88 /* Private variable declarations
90 static GQueue gdk_error_traps;
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 },
99 _gdk_windowing_init (void)
101 _gdk_x11_initialize_locale ();
103 g_queue_init (&gdk_error_traps);
104 XSetErrorHandler (gdk_x_error);
105 XSetIOErrorHandler (gdk_x_io_error);
107 _gdk_selection_property = gdk_atom_intern_static_string ("GDK_SELECTION");
111 _gdk_x11_convert_grab_status (gint status)
116 return GDK_GRAB_SUCCESS;
118 return GDK_GRAB_ALREADY_GRABBED;
119 case GrabInvalidTime:
120 return GDK_GRAB_INVALID_TIME;
121 case GrabNotViewable:
122 return GDK_GRAB_NOT_VIEWABLE;
124 return GDK_GRAB_FROZEN;
127 g_assert_not_reached();
133 has_pointer_grab_callback (GdkDisplay *display,
137 GdkDevice *device = data;
139 _gdk_display_device_grab_update (display, device, serial);
143 _gdk_windowing_device_grab (GdkDevice *device,
146 gboolean owner_events,
147 GdkEventMask event_mask,
148 GdkWindow *confine_to,
153 GdkGrabStatus status = GDK_GRAB_SUCCESS;
155 if (!window || GDK_WINDOW_DESTROYED (window))
156 return GDK_GRAB_NOT_VIEWABLE;
158 display = gdk_device_get_display (device);
160 #ifdef G_ENABLE_DEBUG
161 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
162 status = GrabSuccess;
165 status = GDK_DEVICE_GET_CLASS (device)->grab (device,
172 if (status == GDK_GRAB_SUCCESS)
173 _gdk_x11_roundtrip_async (display,
174 has_pointer_grab_callback,
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.)
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.
190 _gdk_xgrab_check_unmap (GdkWindow *window,
193 GdkDisplay *display = gdk_window_get_display (window);
194 GdkDeviceManager *device_manager;
197 device_manager = gdk_display_get_device_manager (display);
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));
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);
208 g_list_free (devices);
212 * _gdk_xgrab_check_destroy:
213 * @window: a #GdkWindow
215 * Checks to see if window is the current grab window, and if
216 * so, clear the current grab window.
219 _gdk_xgrab_check_destroy (GdkWindow *window)
221 GdkDisplay *display = gdk_window_get_display (window);
222 GdkDeviceManager *device_manager;
223 GdkDeviceGrabInfo *grab;
226 device_manager = gdk_display_get_device_manager (display);
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));
233 for (d = devices; d; d = d->next)
235 /* Make sure there is no lasting grab in this native window */
236 grab = _gdk_display_get_last_device_grab (display, d->data);
238 if (grab && grab->native_window == window)
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;
250 g_list_free (devices);
254 _gdk_windowing_display_set_sm_client_id (GdkDisplay *display,
255 const gchar *sm_client_id)
257 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
262 if (sm_client_id && strcmp (sm_client_id, ""))
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));
270 XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
271 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
274 /* Close all open displays
277 _gdk_windowing_exit (void)
279 GSList *tmp_list = _gdk_displays;
283 XCloseDisplay (GDK_DISPLAY_XDISPLAY (tmp_list->data));
285 tmp_list = tmp_list->next;
290 *--------------------------------------------------------------
293 * The X I/O error handling routine.
296 * "display" is the X display the error orignated from.
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.
305 *--------------------------------------------------------------
309 gdk_x_io_error (Display *display)
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
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",
323 display ? DisplayString (display) : gdk_get_display_arg_name ());
327 g_warning ("%s: Fatal IO error %d (%s) on X server %s.\n",
329 errno, g_strerror (errno),
330 display ? DisplayString (display) : gdk_get_display_arg_name ());
336 /* X error handler. Keep the name the same because people are used to
337 * breaking on it in the debugger.
340 gdk_x_error (Display *xdisplay,
343 if (error->error_code)
345 GdkDisplay *error_display;
346 GdkDisplayManager *manager;
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)
355 GdkDisplayX11 *gdk_display = displays->data;
357 if (xdisplay == gdk_display->xdisplay)
359 error_display = GDK_DISPLAY_OBJECT (gdk_display);
360 g_slist_free (displays);
365 displays = g_slist_delete_link (displays, displays);
369 if (error_display == NULL)
371 /* Error on an X display not opened by GDK. Ignore. */
377 _gdk_x11_display_error_event (error_display, error);
385 _gdk_x11_error_handler_push (void)
387 GdkXErrorHandler previous;
389 previous = XSetErrorHandler (gdk_x_error);
391 if (_gdk_error_handler_push_count > 0)
393 if (previous != gdk_x_error)
394 g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
398 _gdk_old_error_handler = previous;
401 _gdk_error_handler_push_count += 1;
405 _gdk_x11_error_handler_pop (void)
407 g_return_if_fail (_gdk_error_handler_push_count > 0);
409 _gdk_error_handler_push_count -= 1;
411 if (_gdk_error_handler_push_count == 0)
413 XSetErrorHandler (_gdk_old_error_handler);
414 _gdk_old_error_handler = NULL;
419 * gdk_error_trap_push:
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.
430 * This API exists on all platforms but only does anything on X.
432 * You can use gdk_x11_display_error_trap_push() to ignore errors
433 * on only a single display.
436 * <title>Trapping an X error</title>
438 * gdk_error_trap_push (<!-- -->);
440 * // ... Call the X function which may cause an error here ...
443 * if (gdk_error_trap_pop (<!-- -->))
445 * // ... Handle the error here ...
452 gdk_error_trap_push (void)
454 GdkGlobalErrorTrap *trap;
455 GdkDisplayManager *manager;
458 trap = g_slice_new (GdkGlobalErrorTrap);
459 manager = gdk_display_manager_get ();
460 trap->displays = gdk_display_manager_list_displays (manager);
462 g_slist_foreach (trap->displays, (GFunc) g_object_ref, NULL);
463 for (tmp_list = trap->displays;
465 tmp_list = tmp_list->next)
467 gdk_x11_display_error_trap_push (tmp_list->data);
470 g_queue_push_head (&gdk_error_traps, trap);
474 gdk_error_trap_pop_internal (gboolean need_code)
476 GdkGlobalErrorTrap *trap;
480 trap = g_queue_pop_head (&gdk_error_traps);
482 g_return_val_if_fail (trap != NULL, Success);
485 for (tmp_list = trap->displays;
487 tmp_list = tmp_list->next)
492 code = gdk_x11_display_error_trap_pop (tmp_list->data);
494 gdk_x11_display_error_trap_pop_ignored (tmp_list->data);
496 /* we use the error on the last display listed, why not. */
501 g_slist_foreach (trap->displays, (GFunc) g_object_unref, NULL);
502 g_slist_free (trap->displays);
504 g_slice_free (GdkGlobalErrorTrap, trap);
510 * gdk_error_trap_pop_ignored:
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.
520 gdk_error_trap_pop_ignored (void)
522 gdk_error_trap_pop_internal (FALSE);
526 * gdk_error_trap_pop:
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().
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.
540 * Return value: X error code or 0 on success
543 gdk_error_trap_pop (void)
545 return gdk_error_trap_pop_internal (TRUE);
549 gdk_get_display (void)
551 return g_strdup (gdk_display_get_name (gdk_display_get_default ()));
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
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
564 * Send an event, like XSendEvent(), but trap errors and check
567 * Return value: %TRUE if sending the event succeeded.
570 _gdk_send_xevent (GdkDisplay *display,
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);
586 if (gdk_error_trap_pop ())
593 _gdk_region_get_xrectangles (const cairo_region_t *region,
599 XRectangle *rectangles;
600 cairo_rectangle_int_t box;
603 n = cairo_region_num_rectangles (region);
604 rectangles = g_new (XRectangle, n);
606 for (i = 0; i < n; i++)
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);
620 * gdk_x11_grab_server:
622 * Call gdk_x11_display_grab() on the default display.
623 * To ungrab the server again, use gdk_x11_ungrab_server().
625 * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
628 gdk_x11_grab_server (void)
630 gdk_x11_display_grab (gdk_display_get_default ());
634 * gdk_x11_ungrab_server:
636 * Ungrab the default display after it has been grabbed with
637 * gdk_x11_grab_server().
640 gdk_x11_ungrab_server (void)
642 gdk_x11_display_ungrab (gdk_display_get_default ());
646 * gdk_x11_get_default_screen:
648 * Gets the default GTK+ screen number.
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().
655 gdk_x11_get_default_screen (void)
657 return gdk_screen_get_number (gdk_screen_get_default ());
661 * gdk_x11_get_default_root_xwindow:
663 * Gets the root window of the default screen
664 * (see gdk_x11_get_default_screen()).
666 * Return value: an Xlib <type>Window</type>.
669 gdk_x11_get_default_root_xwindow (void)
671 return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
675 * gdk_x11_get_default_xdisplay:
677 * Gets the default GTK+ display.
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.
684 gdk_x11_get_default_xdisplay (void)
686 return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
690 _gdk_windowing_event_data_copy (const GdkEvent *src,
696 _gdk_windowing_event_data_free (GdkEvent *event)