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>
47 #include "gdkdisplay-x11.h"
48 #include "gdkinternals.h"
50 #include "gdkregion-generic.h"
51 #include "gdkinputprivate.h"
54 typedef struct _GdkPredicate GdkPredicate;
55 typedef struct _GdkErrorTrap GdkErrorTrap;
65 int (*old_handler) (Display *, XErrorEvent *);
71 * Private function declarations
74 #ifndef HAVE_XCONVERTCASE
75 static void gdkx_XConvertCase (KeySym symbol,
78 #define XConvertCase gdkx_XConvertCase
81 static int gdk_x_error (Display *display,
83 static int gdk_x_io_error (Display *display);
85 /* Private variable declarations
87 static GSList *gdk_error_traps = NULL; /* List of error traps */
88 static GSList *gdk_error_trap_free_list = NULL; /* Free list */
90 const GOptionEntry _gdk_windowing_args[] = {
91 { "sync", 0, 0, G_OPTION_ARG_NONE, &_gdk_synchronize,
92 /* Description of --sync in --help output */ N_("Make X calls synchronous"), NULL },
97 _gdk_windowing_init (void)
99 _gdk_x11_initialize_locale ();
101 XSetErrorHandler (gdk_x_error);
102 XSetIOErrorHandler (gdk_x_io_error);
104 _gdk_selection_property = gdk_atom_intern_static_string ("GDK_SELECTION");
108 gdk_set_use_xshm (gboolean use_xshm)
113 gdk_get_use_xshm (void)
115 return GDK_DISPLAY_X11 (gdk_display_get_default ())->use_xshm;
119 gdk_x11_convert_grab_status (gint status)
124 return GDK_GRAB_SUCCESS;
126 return GDK_GRAB_ALREADY_GRABBED;
127 case GrabInvalidTime:
128 return GDK_GRAB_INVALID_TIME;
129 case GrabNotViewable:
130 return GDK_GRAB_NOT_VIEWABLE;
132 return GDK_GRAB_FROZEN;
135 g_assert_not_reached();
141 generate_grab_broken_event (GdkWindow *window,
144 GdkWindow *grab_window)
146 g_return_if_fail (window != NULL);
148 if (!GDK_WINDOW_DESTROYED (window))
151 event.type = GDK_GRAB_BROKEN;
152 event.grab_broken.window = window;
153 event.grab_broken.send_event = 0;
154 event.grab_broken.keyboard = keyboard;
155 event.grab_broken.implicit = implicit;
156 event.grab_broken.grab_window = grab_window;
157 gdk_event_put (&event);
162 *--------------------------------------------------------------
165 * Grabs the pointer to a specific window
168 * "window" is the window which will receive the grab
169 * "owner_events" specifies whether events will be reported as is,
170 * or relative to "window"
171 * "event_mask" masks only interesting events
172 * "confine_to" limits the cursor movement to the specified window
173 * "cursor" changes the cursor for the duration of the grab
174 * "time" specifies the time
179 * requires a corresponding call to gdk_pointer_ungrab
181 *--------------------------------------------------------------
185 gdk_pointer_grab (GdkWindow * window,
186 gboolean owner_events,
187 GdkEventMask event_mask,
188 GdkWindow * confine_to,
193 GdkCursorPrivate *cursor_private;
195 GdkDisplayX11 *display_x11;
200 unsigned long serial;
203 g_return_val_if_fail (window != NULL, 0);
204 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
205 g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
207 native = _gdk_window_get_impl_window (window);
210 confine_to = _gdk_window_get_impl_window (confine_to);
212 display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native));
214 cursor_private = (GdkCursorPrivate*) cursor;
216 xwindow = GDK_WINDOW_XID (native);
217 serial = NextRequest (GDK_WINDOW_XDISPLAY (native));
219 if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
222 xconfine_to = GDK_WINDOW_XID (confine_to);
228 _gdk_x11_cursor_update_theme (cursor);
229 xcursor = cursor_private->xcursor;
233 for (i = 0; i < _gdk_nenvent_masks; i++)
235 if (event_mask & (1 << (i + 1)))
236 xevent_mask |= _gdk_event_mask_table[i];
239 return_val = _gdk_input_grab_pointer (native,
245 if (return_val == GrabSuccess ||
246 G_UNLIKELY (!display_x11->trusted_client && return_val == AlreadyGrabbed))
248 if (!GDK_WINDOW_DESTROYED (native))
250 #ifdef G_ENABLE_DEBUG
251 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
252 return_val = GrabSuccess;
255 return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (native),
259 GrabModeAsync, GrabModeAsync,
265 return_val = AlreadyGrabbed;
268 if (return_val == GrabSuccess)
270 _gdk_display_set_has_pointer_grab (GDK_DISPLAY_OBJECT (display_x11),
280 return gdk_x11_convert_grab_status (return_val);
284 *--------------------------------------------------------------
287 * Grabs the keyboard to a specific window
290 * "window" is the window which will receive the grab
291 * "owner_events" specifies whether events will be reported as is,
292 * or relative to "window"
293 * "time" specifies the time
298 * requires a corresponding call to gdk_keyboard_ungrab
300 *--------------------------------------------------------------
304 gdk_keyboard_grab (GdkWindow * window,
305 gboolean owner_events,
309 unsigned long serial;
310 GdkDisplayX11 *display_x11;
313 if (1) return 0; /* TODO: fix */
315 g_return_val_if_fail (window != NULL, 0);
316 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
318 native = _gdk_window_get_impl_window (window);
320 display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (native));
322 serial = NextRequest (GDK_WINDOW_XDISPLAY (native));
324 if (!GDK_WINDOW_DESTROYED (native))
326 #ifdef G_ENABLE_DEBUG
327 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
328 return_val = GrabSuccess;
331 return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (native),
332 GDK_WINDOW_XID (native),
334 GrabModeAsync, GrabModeAsync,
336 if (G_UNLIKELY (!display_x11->trusted_client &&
337 return_val == AlreadyGrabbed))
338 /* we can't grab the keyboard, but we can do a GTK-local grab */
339 return_val = GrabSuccess;
342 return_val = AlreadyGrabbed;
344 if (return_val == GrabSuccess)
346 if (display_x11->keyboard_xgrab_window != NULL &&
347 display_x11->keyboard_xgrab_window != (GdkWindowObject *)window)
348 generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window),
349 TRUE, FALSE, window);
351 display_x11->keyboard_xgrab_window = (GdkWindowObject *)window;
352 display_x11->keyboard_xgrab_native_window = (GdkWindowObject *)native;
353 display_x11->keyboard_xgrab_serial = serial;
354 display_x11->keyboard_xgrab_owner_events = owner_events;
355 display_x11->keyboard_xgrab_time = time;
358 return gdk_x11_convert_grab_status (return_val);
362 _gdk_windowing_grab_broken (GdkDisplay *display)
364 /* TODO: Move to common code */
366 GdkDisplayX11 *display_x11;
368 g_return_if_fail (display != NULL);
370 display_x11 = GDK_DISPLAY_X11 (display);
371 generate_grab_broken_event (GDK_WINDOW (display_x11->pointer_grab.window),
373 display_x11->pointer_grab.implicit,
375 display_x11->pointer_grab.window = NULL;
380 * gdk_keyboard_grab_info_libgtk_only:
381 * @display: the display for which to get the grab information
382 * @grab_window: location to store current grab window
383 * @owner_events: location to store boolean indicating whether
384 * the @owner_events flag to gdk_keyboard_grab() was %TRUE.
386 * Determines information about the current keyboard grab.
387 * This is not public API and must not be used by applications.
389 * Return value: %TRUE if this application currently has the
393 gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
394 GdkWindow **grab_window,
395 gboolean *owner_events)
397 GdkDisplayX11 *display_x11;
399 g_return_val_if_fail (GDK_IS_DISPLAY (display), False);
401 display_x11 = GDK_DISPLAY_X11 (display);
403 if (display_x11->keyboard_xgrab_window)
406 *grab_window = (GdkWindow *)display_x11->keyboard_xgrab_window;
408 *owner_events = display_x11->keyboard_xgrab_owner_events;
417 * _gdk_xgrab_check_unmap:
418 * @window: a #GdkWindow
419 * @serial: serial from Unmap event (or from NextRequest(display)
420 * if the unmap is being done by this client.)
422 * Checks to see if an unmap request or event causes the current
423 * grab window to become not viewable, and if so, clear the
424 * the pointer we keep to it.
427 _gdk_xgrab_check_unmap (GdkWindow *window,
430 GdkDisplay *display = gdk_drawable_get_display (window);
431 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
433 if (display->pointer_grab.window &&
434 serial >= display->pointer_grab.serial)
436 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
437 GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->pointer_grab.native_window);
439 while (tmp && tmp != private)
443 _gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME);
446 if (display_x11->keyboard_xgrab_window &&
447 serial >= display_x11->keyboard_xgrab_serial)
449 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
450 GdkWindowObject *tmp = display_x11->keyboard_xgrab_window;
453 while (tmp && tmp != private)
458 generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window),
460 display_x11->keyboard_xgrab_window = NULL;
466 * _gdk_xgrab_check_destroy:
467 * @window: a #GdkWindow
469 * Checks to see if window is the current grab window, and if
470 * so, clear the current grab window.
473 _gdk_xgrab_check_destroy (GdkWindow *window)
475 GdkDisplay *display = gdk_drawable_get_display (window);
476 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
478 if (window == display->pointer_grab.native_window &&
479 display->pointer_grab.window != NULL)
480 _gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME);
482 if ((GdkWindowObject *)window == display_x11->keyboard_xgrab_native_window &&
483 display_x11->keyboard_xgrab_window != NULL)
485 generate_grab_broken_event (GDK_WINDOW (display_x11->keyboard_xgrab_window),
487 display_x11->keyboard_xgrab_window = NULL;
491 #define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
498 * _gdk_xgrab_check_button_event:
499 * @window: a #GdkWindow
500 * @event: an XEvent of type ButtonPress or ButtonRelease
502 * Checks to see if a button event starts or ends an implicit grab.
505 _gdk_xgrab_check_button_event (GdkWindow *window,
508 GdkDisplay *display = gdk_drawable_get_display (window);
510 /* track implicit grabs for button presses */
511 switch (xevent->type)
514 if (!display->pointer_grab.window)
516 _gdk_display_set_has_pointer_grab (display,
520 gdk_window_get_events (window),
522 xevent->xbutton.time,
527 if (display->pointer_grab.window &&
528 display->pointer_grab.implicit &&
529 (xevent->xbutton.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (xevent->xbutton.button - 1))) == 0)
531 _gdk_display_unset_has_pointer_grab (display, TRUE, TRUE,
532 xevent->xbutton.time);
536 g_assert_not_reached ();
541 _gdk_windowing_display_set_sm_client_id (GdkDisplay *display,
542 const gchar *sm_client_id)
544 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
549 if (sm_client_id && strcmp (sm_client_id, ""))
551 XChangeProperty (display_x11->xdisplay, display_x11->leader_window,
552 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"),
553 XA_STRING, 8, PropModeReplace, (guchar *)sm_client_id,
554 strlen (sm_client_id));
557 XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
558 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
561 /* Close all open displays
564 _gdk_windowing_exit (void)
566 GSList *tmp_list = _gdk_displays;
570 XCloseDisplay (GDK_DISPLAY_XDISPLAY (tmp_list->data));
572 tmp_list = tmp_list->next;
577 *--------------------------------------------------------------
580 * The X error handling routine.
583 * "display" is the X display the error orignated from.
584 * "error" is the XErrorEvent that we are handling.
587 * Either we were expecting some sort of error to occur,
588 * in which case we set the "_gdk_error_code" flag, or this
589 * error was unexpected, in which case we will print an
590 * error message and exit. (Since trying to continue will
591 * most likely simply lead to more errors).
595 *--------------------------------------------------------------
599 gdk_x_error (Display *display,
602 if (error->error_code)
604 if (_gdk_error_warnings)
609 XGetErrorText (display, error->error_code, buf, 63);
612 g_strdup_printf ("The program '%s' received an X Window System error.\n"
613 "This probably reflects a bug in the program.\n"
614 "The error was '%s'.\n"
615 " (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
616 " (Note to programmers: normally, X errors are reported asynchronously;\n"
617 " that is, you will receive the error a while after causing it.\n"
618 " To debug your program, run it with the --sync command line\n"
619 " option to change this behavior. You can then get a meaningful\n"
620 " backtrace from your debugger if you break on the gdk_x_error() function.)",
628 #ifdef G_ENABLE_DEBUG
630 #else /* !G_ENABLE_DEBUG */
631 g_fprintf (stderr, "%s\n", msg);
634 #endif /* G_ENABLE_DEBUG */
636 _gdk_error_code = error->error_code;
643 *--------------------------------------------------------------
646 * The X I/O error handling routine.
649 * "display" is the X display the error orignated from.
652 * An X I/O error basically means we lost our connection
653 * to the X server. There is not much we can do to
654 * continue, so simply print an error message and exit.
658 *--------------------------------------------------------------
662 gdk_x_io_error (Display *display)
664 /* This is basically modelled after the code in XLib. We need
665 * an explicit error handler here, so we can disable our atexit()
666 * which would otherwise cause a nice segfault.
667 * We fprintf(stderr, instead of g_warning() because g_warning()
668 * could possibly be redirected to a dialog
673 "The application '%s' lost its connection to the display %s;\n"
674 "most likely the X server was shut down or you killed/destroyed\n"
675 "the application.\n",
677 display ? DisplayString (display) : gdk_get_display_arg_name ());
681 g_fprintf (stderr, "%s: Fatal IO error %d (%s) on X server %s.\n",
683 errno, g_strerror (errno),
684 display ? DisplayString (display) : gdk_get_display_arg_name ());
690 /*************************************************************
691 * gdk_error_trap_push:
692 * Push an error trap. X errors will be trapped until
693 * the corresponding gdk_error_pop(), which will return
694 * the error code, if any.
698 *************************************************************/
701 gdk_error_trap_push (void)
706 if (gdk_error_trap_free_list)
708 node = gdk_error_trap_free_list;
709 gdk_error_trap_free_list = gdk_error_trap_free_list->next;
713 node = g_slist_alloc ();
714 node->data = g_new (GdkErrorTrap, 1);
717 node->next = gdk_error_traps;
718 gdk_error_traps = node;
721 trap->old_handler = XSetErrorHandler (gdk_x_error);
722 trap->error_code = _gdk_error_code;
723 trap->error_warnings = _gdk_error_warnings;
726 _gdk_error_warnings = 0;
729 /*************************************************************
730 * gdk_error_trap_pop:
731 * Pop an error trap added with gdk_error_push()
735 * 0, if no error occured, otherwise the error code.
736 *************************************************************/
739 gdk_error_trap_pop (void)
745 g_return_val_if_fail (gdk_error_traps != NULL, 0);
747 node = gdk_error_traps;
748 gdk_error_traps = gdk_error_traps->next;
750 node->next = gdk_error_trap_free_list;
751 gdk_error_trap_free_list = node;
753 result = _gdk_error_code;
756 _gdk_error_code = trap->error_code;
757 _gdk_error_warnings = trap->error_warnings;
758 XSetErrorHandler (trap->old_handler);
764 gdk_get_display (void)
766 return g_strdup (gdk_display_get_name (gdk_display_get_default ()));
771 * @display: #GdkDisplay which @window is on
772 * @window: window ID to which to send the event
773 * @propagate: %TRUE if the event should be propagated if the target window
775 * @event_mask: event mask to match against, or 0 to send it to @window
776 * without regard to event masks.
777 * @event_send: #XEvent to send
779 * Send an event, like XSendEvent(), but trap errors and check
782 * Return value: %TRUE if sending the event succeeded.
785 _gdk_send_xevent (GdkDisplay *display,
796 gdk_error_trap_push ();
797 result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window,
798 propagate, event_mask, event_send);
799 XSync (GDK_DISPLAY_XDISPLAY (display), False);
801 if (gdk_error_trap_pop ())
808 _gdk_region_get_xrectangles (const GdkRegion *region,
814 XRectangle *rectangles = g_new (XRectangle, region->numRects);
815 GdkRegionBox *boxes = region->rects;
818 for (i = 0; i < region->numRects; i++)
820 rectangles[i].x = CLAMP (boxes[i].x1 + x_offset, G_MINSHORT, G_MAXSHORT);
821 rectangles[i].y = CLAMP (boxes[i].y1 + y_offset, G_MINSHORT, G_MAXSHORT);
822 rectangles[i].width = CLAMP (boxes[i].x2 + x_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].x;
823 rectangles[i].height = CLAMP (boxes[i].y2 + y_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].y;
827 *n_rects = region->numRects;
831 * gdk_x11_grab_server:
833 * Call gdk_x11_display_grab() on the default display.
834 * To ungrab the server again, use gdk_x11_ungrab_server().
836 * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
839 gdk_x11_grab_server (void)
841 gdk_x11_display_grab (gdk_display_get_default ());
845 * gdk_x11_ungrab_server:
847 * Ungrab the default display after it has been grabbed with
848 * gdk_x11_grab_server().
851 gdk_x11_ungrab_server (void)
853 gdk_x11_display_ungrab (gdk_display_get_default ());
857 * gdk_x11_get_default_screen:
859 * Gets the default GTK+ screen number.
861 * Return value: returns the screen number specified by
862 * the --display command line option or the DISPLAY environment
863 * variable when gdk_init() calls XOpenDisplay().
866 gdk_x11_get_default_screen (void)
868 return gdk_screen_get_number (gdk_screen_get_default ());
872 * gdk_x11_get_default_root_xwindow:
874 * Gets the root window of the default screen
875 * (see gdk_x11_get_default_screen()).
877 * Return value: an Xlib <type>Window</type>.
880 gdk_x11_get_default_root_xwindow (void)
882 return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
886 * gdk_x11_get_default_xdisplay:
888 * Gets the default GTK+ display.
890 * Return value: the Xlib <type>Display*</type> for the display
891 * specified in the <option>--display</option> command line option
892 * or the <envar>DISPLAY</envar> environment variable.
895 gdk_x11_get_default_xdisplay (void)
897 return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
900 #define __GDK_MAIN_X11_C__
901 #include "gdkaliasdef.c"