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();
141 struct XPointerGrabInfo {
144 GdkWindow *native_window;
145 gboolean owner_events;
152 has_pointer_grab_callback (gpointer _data)
154 struct XPointerGrabInfo *data = _data;
156 _gdk_display_set_has_pointer_grab (data->display,
165 g_object_unref (data->window);
166 g_object_unref (data->native_window);
171 *--------------------------------------------------------------
174 * Grabs the pointer to a specific window
177 * "window" is the window which will receive the grab
178 * "owner_events" specifies whether events will be reported as is,
179 * or relative to "window"
180 * "event_mask" masks only interesting events
181 * "confine_to" limits the cursor movement to the specified window
182 * "cursor" changes the cursor for the duration of the grab
183 * "time" specifies the time
188 * requires a corresponding call to gdk_pointer_ungrab
190 *--------------------------------------------------------------
194 gdk_pointer_grab (GdkWindow * window,
195 gboolean owner_events,
196 GdkEventMask event_mask,
197 GdkWindow * confine_to,
202 GdkCursorPrivate *cursor_private;
204 GdkDisplayX11 *display_x11;
209 unsigned long serial;
212 g_return_val_if_fail (window != NULL, 0);
213 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
214 g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
216 native = gdk_window_get_toplevel (window);
218 /* TODO: What do we do for offscreens and their children? We need to proxy the grab somehow */
219 if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl))
220 return GDK_GRAB_SUCCESS;
223 confine_to = _gdk_window_get_impl_window (confine_to);
225 display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native));
227 cursor_private = (GdkCursorPrivate*) cursor;
229 xwindow = GDK_WINDOW_XID (native);
230 serial = NextRequest (GDK_WINDOW_XDISPLAY (native));
232 if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
235 xconfine_to = GDK_WINDOW_XID (confine_to);
241 _gdk_x11_cursor_update_theme (cursor);
242 xcursor = cursor_private->xcursor;
246 for (i = 0; i < _gdk_nenvent_masks; i++)
248 if (event_mask & (1 << (i + 1)))
249 xevent_mask |= _gdk_event_mask_table[i];
252 /* We don't want to set a native motion hint mask, as we're emulating motion
253 * hints. If we set a native one we just wouldn't get any events.
255 xevent_mask &= ~PointerMotionHintMask;
257 return_val = _gdk_input_grab_pointer (native,
263 if (return_val == GrabSuccess ||
264 G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed))
266 if (!GDK_WINDOW_DESTROYED (native))
268 #ifdef G_ENABLE_DEBUG
269 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
270 return_val = GrabSuccess;
273 return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (native),
277 GrabModeAsync, GrabModeAsync,
283 return_val = AlreadyGrabbed;
286 if (return_val == GrabSuccess)
288 struct XPointerGrabInfo *data;
290 data = g_new (struct XPointerGrabInfo, 1);
292 data->display = GDK_DISPLAY_OBJECT (display_x11);
293 data->window = g_object_ref (window);
294 data->native_window = g_object_ref (native);
295 data->owner_events = owner_events;
296 data->event_mask = event_mask;
297 data->serial = serial;
300 _gdk_x11_roundtrip_async (data->display,
301 has_pointer_grab_callback,
305 return gdk_x11_convert_grab_status (return_val);
309 *--------------------------------------------------------------
312 * Grabs the keyboard to a specific window
315 * "window" is the window which will receive the grab
316 * "owner_events" specifies whether events will be reported as is,
317 * or relative to "window"
318 * "time" specifies the time
323 * requires a corresponding call to gdk_keyboard_ungrab
325 *--------------------------------------------------------------
329 gdk_keyboard_grab (GdkWindow * window,
330 gboolean owner_events,
334 unsigned long serial;
336 GdkDisplayX11 *display_x11;
339 g_return_val_if_fail (window != NULL, 0);
340 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
342 native = gdk_window_get_toplevel (window);
344 /* TODO: What do we do for offscreens and children? We need to proxy the grab somehow */
345 if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl))
346 return GDK_GRAB_SUCCESS;
348 display = GDK_WINDOW_DISPLAY (native);
349 display_x11 = GDK_DISPLAY_X11 (display);
351 serial = NextRequest (GDK_WINDOW_XDISPLAY (native));
353 if (!GDK_WINDOW_DESTROYED (native))
355 #ifdef G_ENABLE_DEBUG
356 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
357 return_val = GrabSuccess;
360 return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (native),
361 GDK_WINDOW_XID (native),
363 GrabModeAsync, GrabModeAsync,
365 if (G_UNLIKELY (!display_x11->trusted_client &&
366 return_val == AlreadyGrabbed))
367 /* we can't grab the keyboard, but we can do a GTK-local grab */
368 return_val = GrabSuccess;
371 return_val = AlreadyGrabbed;
373 if (return_val == GrabSuccess)
374 _gdk_display_set_has_keyboard_grab (display,
379 return gdk_x11_convert_grab_status (return_val);
383 * _gdk_xgrab_check_unmap:
384 * @window: a #GdkWindow
385 * @serial: serial from Unmap event (or from NextRequest(display)
386 * if the unmap is being done by this client.)
388 * Checks to see if an unmap request or event causes the current
389 * grab window to become not viewable, and if so, clear the
390 * the pointer we keep to it.
393 _gdk_xgrab_check_unmap (GdkWindow *window,
396 GdkDisplay *display = gdk_drawable_get_display (window);
398 if (display->pointer_grab.window &&
399 serial >= display->pointer_grab.serial)
401 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
402 GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->pointer_grab.native_window);
404 while (tmp && tmp != private)
408 _gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME);
411 if (display->keyboard_grab.window &&
412 serial >= display->keyboard_grab.serial)
414 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
415 GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->keyboard_grab.window);
417 while (tmp && tmp != private)
421 _gdk_display_unset_has_keyboard_grab (display, TRUE);
426 * _gdk_xgrab_check_destroy:
427 * @window: a #GdkWindow
429 * Checks to see if window is the current grab window, and if
430 * so, clear the current grab window.
433 _gdk_xgrab_check_destroy (GdkWindow *window)
435 GdkDisplay *display = gdk_drawable_get_display (window);
437 if (window == display->pointer_grab.native_window &&
438 display->pointer_grab.window != NULL)
439 _gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME);
441 if (window == display->keyboard_grab.native_window &&
442 display->keyboard_grab.window != NULL)
443 _gdk_display_unset_has_keyboard_grab (display, TRUE);
446 #define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
453 * _gdk_xgrab_check_button_event:
454 * @window: a #GdkWindow
455 * @event: an XEvent of type ButtonPress or ButtonRelease
457 * Checks to see if a button event starts or ends an implicit grab.
460 _gdk_xgrab_check_button_event (GdkWindow *window,
463 GdkDisplay *display = gdk_drawable_get_display (window);
465 /* track implicit grabs for button presses */
466 switch (xevent->type)
469 if (!display->pointer_grab.window)
471 _gdk_display_set_has_pointer_grab (display,
475 gdk_window_get_events (window),
477 xevent->xbutton.time,
482 if (display->pointer_grab.window &&
483 display->pointer_grab.implicit &&
484 (xevent->xbutton.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (xevent->xbutton.button - 1))) == 0)
486 _gdk_display_unset_has_pointer_grab (display, TRUE, TRUE,
487 xevent->xbutton.time);
491 g_assert_not_reached ();
496 _gdk_windowing_display_set_sm_client_id (GdkDisplay *display,
497 const gchar *sm_client_id)
499 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
504 if (sm_client_id && strcmp (sm_client_id, ""))
506 XChangeProperty (display_x11->xdisplay, display_x11->leader_window,
507 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"),
508 XA_STRING, 8, PropModeReplace, (guchar *)sm_client_id,
509 strlen (sm_client_id));
512 XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
513 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
516 /* Close all open displays
519 _gdk_windowing_exit (void)
521 GSList *tmp_list = _gdk_displays;
525 XCloseDisplay (GDK_DISPLAY_XDISPLAY (tmp_list->data));
527 tmp_list = tmp_list->next;
532 *--------------------------------------------------------------
535 * The X error handling routine.
538 * "display" is the X display the error orignated from.
539 * "error" is the XErrorEvent that we are handling.
542 * Either we were expecting some sort of error to occur,
543 * in which case we set the "_gdk_error_code" flag, or this
544 * error was unexpected, in which case we will print an
545 * error message and exit. (Since trying to continue will
546 * most likely simply lead to more errors).
550 *--------------------------------------------------------------
554 gdk_x_error (Display *display,
557 if (error->error_code)
559 if (_gdk_error_warnings)
564 XGetErrorText (display, error->error_code, buf, 63);
567 g_strdup_printf ("The program '%s' received an X Window System error.\n"
568 "This probably reflects a bug in the program.\n"
569 "The error was '%s'.\n"
570 " (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
571 " (Note to programmers: normally, X errors are reported asynchronously;\n"
572 " that is, you will receive the error a while after causing it.\n"
573 " To debug your program, run it with the --sync command line\n"
574 " option to change this behavior. You can then get a meaningful\n"
575 " backtrace from your debugger if you break on the gdk_x_error() function.)",
583 #ifdef G_ENABLE_DEBUG
585 #else /* !G_ENABLE_DEBUG */
586 g_fprintf (stderr, "%s\n", msg);
589 #endif /* G_ENABLE_DEBUG */
591 _gdk_error_code = error->error_code;
598 *--------------------------------------------------------------
601 * The X I/O error handling routine.
604 * "display" is the X display the error orignated from.
607 * An X I/O error basically means we lost our connection
608 * to the X server. There is not much we can do to
609 * continue, so simply print an error message and exit.
613 *--------------------------------------------------------------
617 gdk_x_io_error (Display *display)
619 /* This is basically modelled after the code in XLib. We need
620 * an explicit error handler here, so we can disable our atexit()
621 * which would otherwise cause a nice segfault.
622 * We fprintf(stderr, instead of g_warning() because g_warning()
623 * could possibly be redirected to a dialog
628 "The application '%s' lost its connection to the display %s;\n"
629 "most likely the X server was shut down or you killed/destroyed\n"
630 "the application.\n",
632 display ? DisplayString (display) : gdk_get_display_arg_name ());
636 g_fprintf (stderr, "%s: Fatal IO error %d (%s) on X server %s.\n",
638 errno, g_strerror (errno),
639 display ? DisplayString (display) : gdk_get_display_arg_name ());
645 /*************************************************************
646 * gdk_error_trap_push:
647 * Push an error trap. X errors will be trapped until
648 * the corresponding gdk_error_pop(), which will return
649 * the error code, if any.
653 *************************************************************/
656 gdk_error_trap_push (void)
661 if (gdk_error_trap_free_list)
663 node = gdk_error_trap_free_list;
664 gdk_error_trap_free_list = gdk_error_trap_free_list->next;
668 node = g_slist_alloc ();
669 node->data = g_new (GdkErrorTrap, 1);
672 node->next = gdk_error_traps;
673 gdk_error_traps = node;
676 trap->old_handler = XSetErrorHandler (gdk_x_error);
677 trap->error_code = _gdk_error_code;
678 trap->error_warnings = _gdk_error_warnings;
681 _gdk_error_warnings = 0;
684 /*************************************************************
685 * gdk_error_trap_pop:
686 * Pop an error trap added with gdk_error_push()
690 * 0, if no error occured, otherwise the error code.
691 *************************************************************/
694 gdk_error_trap_pop (void)
700 g_return_val_if_fail (gdk_error_traps != NULL, 0);
702 node = gdk_error_traps;
703 gdk_error_traps = gdk_error_traps->next;
705 node->next = gdk_error_trap_free_list;
706 gdk_error_trap_free_list = node;
708 result = _gdk_error_code;
711 _gdk_error_code = trap->error_code;
712 _gdk_error_warnings = trap->error_warnings;
713 XSetErrorHandler (trap->old_handler);
719 gdk_get_display (void)
721 return g_strdup (gdk_display_get_name (gdk_display_get_default ()));
726 * @display: #GdkDisplay which @window is on
727 * @window: window ID to which to send the event
728 * @propagate: %TRUE if the event should be propagated if the target window
730 * @event_mask: event mask to match against, or 0 to send it to @window
731 * without regard to event masks.
732 * @event_send: #XEvent to send
734 * Send an event, like XSendEvent(), but trap errors and check
737 * Return value: %TRUE if sending the event succeeded.
740 _gdk_send_xevent (GdkDisplay *display,
751 gdk_error_trap_push ();
752 result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window,
753 propagate, event_mask, event_send);
754 XSync (GDK_DISPLAY_XDISPLAY (display), False);
756 if (gdk_error_trap_pop ())
763 _gdk_region_get_xrectangles (const GdkRegion *region,
769 XRectangle *rectangles = g_new (XRectangle, region->numRects);
770 GdkRegionBox *boxes = region->rects;
773 for (i = 0; i < region->numRects; i++)
775 rectangles[i].x = CLAMP (boxes[i].x1 + x_offset, G_MINSHORT, G_MAXSHORT);
776 rectangles[i].y = CLAMP (boxes[i].y1 + y_offset, G_MINSHORT, G_MAXSHORT);
777 rectangles[i].width = CLAMP (boxes[i].x2 + x_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].x;
778 rectangles[i].height = CLAMP (boxes[i].y2 + y_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].y;
782 *n_rects = region->numRects;
786 * gdk_x11_grab_server:
788 * Call gdk_x11_display_grab() on the default display.
789 * To ungrab the server again, use gdk_x11_ungrab_server().
791 * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
794 gdk_x11_grab_server (void)
796 gdk_x11_display_grab (gdk_display_get_default ());
800 * gdk_x11_ungrab_server:
802 * Ungrab the default display after it has been grabbed with
803 * gdk_x11_grab_server().
806 gdk_x11_ungrab_server (void)
808 gdk_x11_display_ungrab (gdk_display_get_default ());
812 * gdk_x11_get_default_screen:
814 * Gets the default GTK+ screen number.
816 * Return value: returns the screen number specified by
817 * the --display command line option or the DISPLAY environment
818 * variable when gdk_init() calls XOpenDisplay().
821 gdk_x11_get_default_screen (void)
823 return gdk_screen_get_number (gdk_screen_get_default ());
827 * gdk_x11_get_default_root_xwindow:
829 * Gets the root window of the default screen
830 * (see gdk_x11_get_default_screen()).
832 * Return value: an Xlib <type>Window</type>.
835 gdk_x11_get_default_root_xwindow (void)
837 return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
841 * gdk_x11_get_default_xdisplay:
843 * Gets the default GTK+ display.
845 * Return value: the Xlib <type>Display*</type> for the display
846 * specified in the <option>--display</option> command line option
847 * or the <envar>DISPLAY</envar> environment variable.
850 gdk_x11_get_default_xdisplay (void)
852 return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
855 #define __GDK_MAIN_X11_C__
856 #include "gdkaliasdef.c"