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/.
29 #include <glib/gprintf.h>
36 #include <X11/Xatom.h>
38 #include <X11/Xutil.h>
41 #include <X11/XKBlib.h>
48 #include "gdkdisplay-x11.h"
49 #include "gdkinternals.h"
51 #include "gdkregion-generic.h"
52 #include "gdkinputprivate.h"
55 typedef struct _GdkPredicate GdkPredicate;
56 typedef struct _GdkErrorTrap GdkErrorTrap;
66 int (*old_handler) (Display *, XErrorEvent *);
72 * Private function declarations
75 #ifndef HAVE_XCONVERTCASE
76 static void gdkx_XConvertCase (KeySym symbol,
79 #define XConvertCase gdkx_XConvertCase
82 static int gdk_x_error (Display *display,
84 static int gdk_x_io_error (Display *display);
86 /* Private variable declarations
88 static GSList *gdk_error_traps = NULL; /* List of error traps */
89 static GSList *gdk_error_trap_free_list = NULL; /* Free list */
91 const GOptionEntry _gdk_windowing_args[] = {
92 { "sync", 0, 0, G_OPTION_ARG_NONE, &_gdk_synchronize,
93 /* Description of --sync in --help output */ N_("Make X calls synchronous"), NULL },
98 _gdk_windowing_init (void)
100 _gdk_x11_initialize_locale ();
102 XSetErrorHandler (gdk_x_error);
103 XSetIOErrorHandler (gdk_x_io_error);
105 _gdk_selection_property = gdk_atom_intern_static_string ("GDK_SELECTION");
109 gdk_set_use_xshm (gboolean use_xshm)
114 gdk_get_use_xshm (void)
116 return GDK_DISPLAY_X11 (gdk_display_get_default ())->use_xshm;
120 gdk_x11_convert_grab_status (gint status)
125 return GDK_GRAB_SUCCESS;
127 return GDK_GRAB_ALREADY_GRABBED;
128 case GrabInvalidTime:
129 return GDK_GRAB_INVALID_TIME;
130 case GrabNotViewable:
131 return GDK_GRAB_NOT_VIEWABLE;
133 return GDK_GRAB_FROZEN;
136 g_assert_not_reached();
142 has_pointer_grab_callback (GdkDisplay *display,
146 _gdk_display_pointer_grab_update (display, serial);
150 _gdk_windowing_pointer_grab (GdkWindow *window,
152 gboolean owner_events,
153 GdkEventMask event_mask,
154 GdkWindow *confine_to,
159 GdkCursorPrivate *cursor_private;
160 GdkDisplayX11 *display_x11;
168 confine_to = _gdk_window_get_impl_window (confine_to);
170 display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native));
172 cursor_private = (GdkCursorPrivate*) cursor;
174 xwindow = GDK_WINDOW_XID (native);
176 if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
179 xconfine_to = GDK_WINDOW_XID (confine_to);
185 _gdk_x11_cursor_update_theme (cursor);
186 xcursor = cursor_private->xcursor;
190 for (i = 0; i < _gdk_nenvent_masks; i++)
192 if (event_mask & (1 << (i + 1)))
193 xevent_mask |= _gdk_event_mask_table[i];
196 /* We don't want to set a native motion hint mask, as we're emulating motion
197 * hints. If we set a native one we just wouldn't get any events.
199 xevent_mask &= ~PointerMotionHintMask;
201 return_val = _gdk_input_grab_pointer (window,
208 if (return_val == GrabSuccess ||
209 G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed))
211 if (!GDK_WINDOW_DESTROYED (native))
213 #ifdef G_ENABLE_DEBUG
214 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
215 return_val = GrabSuccess;
218 return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (native),
222 GrabModeAsync, GrabModeAsync,
228 return_val = AlreadyGrabbed;
231 if (return_val == GrabSuccess)
232 _gdk_x11_roundtrip_async (GDK_DISPLAY_OBJECT (display_x11),
233 has_pointer_grab_callback,
236 return gdk_x11_convert_grab_status (return_val);
240 *--------------------------------------------------------------
243 * Grabs the keyboard to a specific window
246 * "window" is the window which will receive the grab
247 * "owner_events" specifies whether events will be reported as is,
248 * or relative to "window"
249 * "time" specifies the time
254 * requires a corresponding call to gdk_keyboard_ungrab
256 *--------------------------------------------------------------
260 gdk_keyboard_grab (GdkWindow * window,
261 gboolean owner_events,
265 unsigned long serial;
267 GdkDisplayX11 *display_x11;
270 g_return_val_if_fail (window != NULL, 0);
271 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
273 native = gdk_window_get_toplevel (window);
275 /* TODO: What do we do for offscreens and children? We need to proxy the grab somehow */
276 if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl))
277 return GDK_GRAB_SUCCESS;
279 display = GDK_WINDOW_DISPLAY (native);
280 display_x11 = GDK_DISPLAY_X11 (display);
282 serial = NextRequest (GDK_WINDOW_XDISPLAY (native));
284 if (!GDK_WINDOW_DESTROYED (native))
286 #ifdef G_ENABLE_DEBUG
287 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
288 return_val = GrabSuccess;
291 return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (native),
292 GDK_WINDOW_XID (native),
294 GrabModeAsync, GrabModeAsync,
296 if (G_UNLIKELY (!display_x11->trusted_client &&
297 return_val == AlreadyGrabbed))
298 /* we can't grab the keyboard, but we can do a GTK-local grab */
299 return_val = GrabSuccess;
302 return_val = AlreadyGrabbed;
304 if (return_val == GrabSuccess)
305 _gdk_display_set_has_keyboard_grab (display,
310 return gdk_x11_convert_grab_status (return_val);
314 * _gdk_xgrab_check_unmap:
315 * @window: a #GdkWindow
316 * @serial: serial from Unmap event (or from NextRequest(display)
317 * if the unmap is being done by this client.)
319 * Checks to see if an unmap request or event causes the current
320 * grab window to become not viewable, and if so, clear the
321 * the pointer we keep to it.
324 _gdk_xgrab_check_unmap (GdkWindow *window,
327 GdkDisplay *display = gdk_drawable_get_display (window);
329 _gdk_display_end_pointer_grab (display, serial, window, TRUE);
331 if (display->keyboard_grab.window &&
332 serial >= display->keyboard_grab.serial)
334 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
335 GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->keyboard_grab.window);
337 while (tmp && tmp != private)
341 _gdk_display_unset_has_keyboard_grab (display, TRUE);
346 * _gdk_xgrab_check_destroy:
347 * @window: a #GdkWindow
349 * Checks to see if window is the current grab window, and if
350 * so, clear the current grab window.
353 _gdk_xgrab_check_destroy (GdkWindow *window)
355 GdkDisplay *display = gdk_drawable_get_display (window);
356 GdkPointerGrabInfo *grab;
358 /* Make sure there is no lasting grab in this native
360 grab = _gdk_display_get_last_pointer_grab (display);
361 if (grab && grab->native_window == window)
363 /* We don't know the actual serial to end, but it
364 doesn't really matter as this only happens
365 after we get told of the destroy from the
366 server so we know its ended in the server,
367 just make sure its ended. */
368 grab->serial_end = grab->serial_start;
369 grab->implicit_ungrab = TRUE;
372 if (window == display->keyboard_grab.native_window &&
373 display->keyboard_grab.window != NULL)
374 _gdk_display_unset_has_keyboard_grab (display, TRUE);
378 _gdk_windowing_display_set_sm_client_id (GdkDisplay *display,
379 const gchar *sm_client_id)
381 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
386 if (sm_client_id && strcmp (sm_client_id, ""))
388 XChangeProperty (display_x11->xdisplay, display_x11->leader_window,
389 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"),
390 XA_STRING, 8, PropModeReplace, (guchar *)sm_client_id,
391 strlen (sm_client_id));
394 XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
395 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
398 /* Close all open displays
401 _gdk_windowing_exit (void)
403 GSList *tmp_list = _gdk_displays;
407 XCloseDisplay (GDK_DISPLAY_XDISPLAY (tmp_list->data));
409 tmp_list = tmp_list->next;
414 *--------------------------------------------------------------
417 * The X error handling routine.
420 * "display" is the X display the error orignated from.
421 * "error" is the XErrorEvent that we are handling.
424 * Either we were expecting some sort of error to occur,
425 * in which case we set the "_gdk_error_code" flag, or this
426 * error was unexpected, in which case we will print an
427 * error message and exit. (Since trying to continue will
428 * most likely simply lead to more errors).
432 *--------------------------------------------------------------
436 gdk_x_error (Display *display,
439 if (error->error_code)
441 if (_gdk_error_warnings)
446 XGetErrorText (display, error->error_code, buf, 63);
449 g_strdup_printf ("The program '%s' received an X Window System error.\n"
450 "This probably reflects a bug in the program.\n"
451 "The error was '%s'.\n"
452 " (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
453 " (Note to programmers: normally, X errors are reported asynchronously;\n"
454 " that is, you will receive the error a while after causing it.\n"
455 " To debug your program, run it with the --sync command line\n"
456 " option to change this behavior. You can then get a meaningful\n"
457 " backtrace from your debugger if you break on the gdk_x_error() function.)",
465 #ifdef G_ENABLE_DEBUG
467 #else /* !G_ENABLE_DEBUG */
468 g_fprintf (stderr, "%s\n", msg);
471 #endif /* G_ENABLE_DEBUG */
473 _gdk_error_code = error->error_code;
480 *--------------------------------------------------------------
483 * The X I/O error handling routine.
486 * "display" is the X display the error orignated from.
489 * An X I/O error basically means we lost our connection
490 * to the X server. There is not much we can do to
491 * continue, so simply print an error message and exit.
495 *--------------------------------------------------------------
499 gdk_x_io_error (Display *display)
501 /* This is basically modelled after the code in XLib. We need
502 * an explicit error handler here, so we can disable our atexit()
503 * which would otherwise cause a nice segfault.
504 * We fprintf(stderr, instead of g_warning() because g_warning()
505 * could possibly be redirected to a dialog
510 "The application '%s' lost its connection to the display %s;\n"
511 "most likely the X server was shut down or you killed/destroyed\n"
512 "the application.\n",
514 display ? DisplayString (display) : gdk_get_display_arg_name ());
518 g_fprintf (stderr, "%s: Fatal IO error %d (%s) on X server %s.\n",
520 errno, g_strerror (errno),
521 display ? DisplayString (display) : gdk_get_display_arg_name ());
527 /*************************************************************
528 * gdk_error_trap_push:
529 * Push an error trap. X errors will be trapped until
530 * the corresponding gdk_error_pop(), which will return
531 * the error code, if any.
535 *************************************************************/
538 gdk_error_trap_push (void)
543 if (gdk_error_trap_free_list)
545 node = gdk_error_trap_free_list;
546 gdk_error_trap_free_list = gdk_error_trap_free_list->next;
550 node = g_slist_alloc ();
551 node->data = g_new (GdkErrorTrap, 1);
554 node->next = gdk_error_traps;
555 gdk_error_traps = node;
558 trap->old_handler = XSetErrorHandler (gdk_x_error);
559 trap->error_code = _gdk_error_code;
560 trap->error_warnings = _gdk_error_warnings;
563 _gdk_error_warnings = 0;
566 /*************************************************************
567 * gdk_error_trap_pop:
568 * Pop an error trap added with gdk_error_push()
572 * 0, if no error occured, otherwise the error code.
573 *************************************************************/
576 gdk_error_trap_pop (void)
582 g_return_val_if_fail (gdk_error_traps != NULL, 0);
584 node = gdk_error_traps;
585 gdk_error_traps = gdk_error_traps->next;
587 node->next = gdk_error_trap_free_list;
588 gdk_error_trap_free_list = node;
590 result = _gdk_error_code;
593 _gdk_error_code = trap->error_code;
594 _gdk_error_warnings = trap->error_warnings;
595 XSetErrorHandler (trap->old_handler);
601 gdk_get_display (void)
603 return g_strdup (gdk_display_get_name (gdk_display_get_default ()));
608 * @display: #GdkDisplay which @window is on
609 * @window: window ID to which to send the event
610 * @propagate: %TRUE if the event should be propagated if the target window
612 * @event_mask: event mask to match against, or 0 to send it to @window
613 * without regard to event masks.
614 * @event_send: #XEvent to send
616 * Send an event, like XSendEvent(), but trap errors and check
619 * Return value: %TRUE if sending the event succeeded.
622 _gdk_send_xevent (GdkDisplay *display,
633 gdk_error_trap_push ();
634 result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window,
635 propagate, event_mask, event_send);
636 XSync (GDK_DISPLAY_XDISPLAY (display), False);
638 if (gdk_error_trap_pop ())
645 _gdk_region_get_xrectangles (const GdkRegion *region,
651 XRectangle *rectangles = g_new (XRectangle, region->numRects);
652 GdkRegionBox *boxes = region->rects;
655 for (i = 0; i < region->numRects; i++)
657 rectangles[i].x = CLAMP (boxes[i].x1 + x_offset, G_MINSHORT, G_MAXSHORT);
658 rectangles[i].y = CLAMP (boxes[i].y1 + y_offset, G_MINSHORT, G_MAXSHORT);
659 rectangles[i].width = CLAMP (boxes[i].x2 + x_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].x;
660 rectangles[i].height = CLAMP (boxes[i].y2 + y_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].y;
664 *n_rects = region->numRects;
668 * gdk_x11_grab_server:
670 * Call gdk_x11_display_grab() on the default display.
671 * To ungrab the server again, use gdk_x11_ungrab_server().
673 * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
676 gdk_x11_grab_server (void)
678 gdk_x11_display_grab (gdk_display_get_default ());
682 * gdk_x11_ungrab_server:
684 * Ungrab the default display after it has been grabbed with
685 * gdk_x11_grab_server().
688 gdk_x11_ungrab_server (void)
690 gdk_x11_display_ungrab (gdk_display_get_default ());
694 * gdk_x11_get_default_screen:
696 * Gets the default GTK+ screen number.
698 * Return value: returns the screen number specified by
699 * the --display command line option or the DISPLAY environment
700 * variable when gdk_init() calls XOpenDisplay().
703 gdk_x11_get_default_screen (void)
705 return gdk_screen_get_number (gdk_screen_get_default ());
709 * gdk_x11_get_default_root_xwindow:
711 * Gets the root window of the default screen
712 * (see gdk_x11_get_default_screen()).
714 * Return value: an Xlib <type>Window</type>.
717 gdk_x11_get_default_root_xwindow (void)
719 return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
723 * gdk_x11_get_default_xdisplay:
725 * Gets the default GTK+ display.
727 * Return value: the Xlib <type>Display*</type> for the display
728 * specified in the <option>--display</option> command line option
729 * or the <envar>DISPLAY</envar> environment variable.
732 gdk_x11_get_default_xdisplay (void)
734 return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
737 #define __GDK_MAIN_X11_C__
738 #include "gdkaliasdef.c"