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"
49 #include "gdkregion-generic.h"
50 #include "gdkinputprivate.h"
52 #include <pango/pangox.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 GdkArgDesc _gdk_windowing_args[] = {
91 { "sync", GDK_ARG_BOOL, &_gdk_synchronize, (GdkArgFunc)NULL },
96 _gdk_windowing_init (gint *argc,
99 _gdk_x11_initialize_locale ();
101 XSetErrorHandler (gdk_x_error);
102 XSetIOErrorHandler (gdk_x_io_error);
104 _gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE);
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 *--------------------------------------------------------------
144 * Grabs the pointer to a specific window
147 * "window" is the window which will receive the grab
148 * "owner_events" specifies whether events will be reported as is,
149 * or relative to "window"
150 * "event_mask" masks only interesting events
151 * "confine_to" limits the cursor movement to the specified window
152 * "cursor" changes the cursor for the duration of the grab
153 * "time" specifies the time
158 * requires a corresponding call to gdk_pointer_ungrab
160 *--------------------------------------------------------------
164 gdk_pointer_grab (GdkWindow * window,
165 gboolean owner_events,
166 GdkEventMask event_mask,
167 GdkWindow * confine_to,
172 GdkCursorPrivate *cursor_private;
177 unsigned long serial;
180 g_return_val_if_fail (window != NULL, 0);
181 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
182 g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
184 cursor_private = (GdkCursorPrivate*) cursor;
186 xwindow = GDK_WINDOW_XID (window);
187 serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
189 if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
192 xconfine_to = GDK_WINDOW_XID (confine_to);
197 xcursor = cursor_private->xcursor;
201 for (i = 0; i < _gdk_nenvent_masks; i++)
203 if (event_mask & (1 << (i + 1)))
204 xevent_mask |= _gdk_event_mask_table[i];
207 return_val = _gdk_input_grab_pointer (window,
213 if (return_val == GrabSuccess)
215 if (!GDK_WINDOW_DESTROYED (window))
217 #ifdef G_ENABLE_DEBUG
218 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
219 return_val = GrabSuccess;
222 return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (window),
226 GrabModeAsync, GrabModeAsync,
232 return_val = AlreadyGrabbed;
235 if (return_val == GrabSuccess)
237 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
238 display_x11->pointer_xgrab_window = (GdkWindowObject *)window;
239 display_x11->pointer_xgrab_serial = serial;
240 display_x11->pointer_xgrab_owner_events = owner_events;
243 return gdk_x11_convert_grab_status (return_val);
247 * gdk_pointer_grab_info_libgtk_only:
248 * @display: the #GdkDisplay for which to get the grab information
249 * @grab_window: location to store current grab window
250 * @owner_events: location to store boolean indicating whether
251 * the @owner_events flag to gdk_pointer_grab() was %TRUE.
253 * Determines information about the current pointer grab.
254 * This is not public API and must not be used by applications.
256 * Return value: %TRUE if this application currently has the
260 gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
261 GdkWindow **grab_window,
262 gboolean *owner_events)
264 GdkDisplayX11 *display_x11;
266 g_return_val_if_fail (GDK_IS_DISPLAY (display), False);
268 display_x11 = GDK_DISPLAY_X11 (display);
270 if (display_x11->pointer_xgrab_window)
273 *grab_window = (GdkWindow *)display_x11->pointer_xgrab_window;
275 *owner_events = display_x11->pointer_xgrab_owner_events;
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;
311 g_return_val_if_fail (window != NULL, 0);
312 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
314 serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
316 if (!GDK_WINDOW_DESTROYED (window))
318 #ifdef G_ENABLE_DEBUG
319 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
320 return_val = GrabSuccess;
323 return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (window),
324 GDK_WINDOW_XID (window),
326 GrabModeAsync, GrabModeAsync,
330 return_val = AlreadyGrabbed;
332 if (return_val == GrabSuccess)
334 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
335 display_x11->keyboard_xgrab_window = (GdkWindowObject *)window;
336 display_x11->keyboard_xgrab_serial = serial;
337 display_x11->keyboard_xgrab_owner_events = owner_events;
340 return gdk_x11_convert_grab_status (return_val);
344 * gdk_keyboard_grab_info_libgtk_only:
345 * @display: the display for which to get the grab information
346 * @grab_window: location to store current grab window
347 * @owner_events: location to store boolean indicating whether
348 * the @owner_events flag to gdk_keyboard_grab() was %TRUE.
350 * Determines information about the current keyboard grab.
351 * This is not public API and must not be used by applications.
353 * Return value: %TRUE if this application currently has the
357 gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
358 GdkWindow **grab_window,
359 gboolean *owner_events)
361 GdkDisplayX11 *display_x11;
363 g_return_val_if_fail (GDK_IS_DISPLAY (display), False);
365 display_x11 = GDK_DISPLAY_X11 (display);
367 if (display_x11->keyboard_xgrab_window)
370 *grab_window = (GdkWindow *)display_x11->keyboard_xgrab_window;
372 *owner_events = display_x11->keyboard_xgrab_owner_events;
381 * _gdk_xgrab_check_unmap:
382 * @window: a #GdkWindow
383 * @serial: serial from Unmap event (or from NextRequest(display)
384 * if the unmap is being done by this client.)
386 * Checks to see if an unmap request or event causes the current
387 * grab window to become not viewable, and if so, clear the
388 * the pointer we keep to it.
391 _gdk_xgrab_check_unmap (GdkWindow *window,
394 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
396 if (display_x11->pointer_xgrab_window &&
397 serial >= display_x11->pointer_xgrab_serial)
399 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
400 GdkWindowObject *tmp = display_x11->pointer_xgrab_window;
402 while (tmp && tmp != private)
406 display_x11->pointer_xgrab_window = NULL;
409 if (display_x11->keyboard_xgrab_window &&
410 serial >= display_x11->keyboard_xgrab_serial)
412 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
413 GdkWindowObject *tmp = display_x11->keyboard_xgrab_window;
416 while (tmp && tmp != private)
420 display_x11->keyboard_xgrab_window = NULL;
425 * _gdk_xgrab_check_destroy:
426 * @window: a #GdkWindow
428 * Checks to see if window is the current grab window, and if
429 * so, clear the current grab window.
432 _gdk_xgrab_check_destroy (GdkWindow *window)
434 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
436 if ((GdkWindowObject *)window == display_x11->pointer_xgrab_window)
437 display_x11->pointer_xgrab_window = NULL;
439 if ((GdkWindowObject *)window == display_x11->keyboard_xgrab_window)
440 display_x11->keyboard_xgrab_window = NULL;
444 _gdk_windowing_display_set_sm_client_id (GdkDisplay *display,
445 const gchar *sm_client_id)
447 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
452 if (sm_client_id && strcmp (sm_client_id, ""))
454 XChangeProperty (display_x11->xdisplay, display_x11->leader_window,
455 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"),
456 XA_STRING, 8, PropModeReplace, sm_client_id,
457 strlen (sm_client_id));
460 XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
461 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
464 /* Close all open displays
467 _gdk_windowing_exit (void)
469 GSList *tmp_list = _gdk_displays;
473 XCloseDisplay (GDK_DISPLAY_XDISPLAY (tmp_list->data));
475 tmp_list = tmp_list->next;
480 *--------------------------------------------------------------
483 * The X error handling routine.
486 * "display" is the X display the error orignated from.
487 * "error" is the XErrorEvent that we are handling.
490 * Either we were expecting some sort of error to occur,
491 * in which case we set the "_gdk_error_code" flag, or this
492 * error was unexpected, in which case we will print an
493 * error message and exit. (Since trying to continue will
494 * most likely simply lead to more errors).
498 *--------------------------------------------------------------
502 gdk_x_error (Display *display,
505 if (error->error_code)
507 if (_gdk_error_warnings)
512 XGetErrorText (display, error->error_code, buf, 63);
515 g_strdup_printf ("The program '%s' received an X Window System error.\n"
516 "This probably reflects a bug in the program.\n"
517 "The error was '%s'.\n"
518 " (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
519 " (Note to programmers: normally, X errors are reported asynchronously;\n"
520 " that is, you will receive the error a while after causing it.\n"
521 " To debug your program, run it with the --sync command line\n"
522 " option to change this behavior. You can then get a meaningful\n"
523 " backtrace from your debugger if you break on the gdk_x_error() function.)",
531 #ifdef G_ENABLE_DEBUG
533 #else /* !G_ENABLE_DEBUG */
534 g_fprintf (stderr, "%s\n", msg);
537 #endif /* G_ENABLE_DEBUG */
539 _gdk_error_code = error->error_code;
546 *--------------------------------------------------------------
549 * The X I/O error handling routine.
552 * "display" is the X display the error orignated from.
555 * An X I/O error basically means we lost our connection
556 * to the X server. There is not much we can do to
557 * continue, so simply print an error message and exit.
561 *--------------------------------------------------------------
565 gdk_x_io_error (Display *display)
567 /* This is basically modelled after the code in XLib. We need
568 * an explicit error handler here, so we can disable our atexit()
569 * which would otherwise cause a nice segfault.
570 * We fprintf(stderr, instead of g_warning() because g_warning()
571 * could possibly be redirected to a dialog
576 "The application '%s' lost its connection to the display %s;\n"
577 "most likely the X server was shut down or you killed/destroyed\n"
578 "the application.\n",
580 display ? DisplayString (display) : gdk_get_display_arg_name ());
584 g_fprintf (stderr, "%s: Fatal IO error %d (%s) on X server %s.\n",
586 errno, g_strerror (errno),
587 display ? DisplayString (display) : gdk_get_display_arg_name ());
593 /*************************************************************
594 * gdk_error_trap_push:
595 * Push an error trap. X errors will be trapped until
596 * the corresponding gdk_error_pop(), which will return
597 * the error code, if any.
601 *************************************************************/
604 gdk_error_trap_push (void)
609 if (gdk_error_trap_free_list)
611 node = gdk_error_trap_free_list;
612 gdk_error_trap_free_list = gdk_error_trap_free_list->next;
616 node = g_slist_alloc ();
617 node->data = g_new (GdkErrorTrap, 1);
620 node->next = gdk_error_traps;
621 gdk_error_traps = node;
624 trap->old_handler = XSetErrorHandler (gdk_x_error);
625 trap->error_code = _gdk_error_code;
626 trap->error_warnings = _gdk_error_warnings;
629 _gdk_error_warnings = 0;
632 /*************************************************************
633 * gdk_error_trap_pop:
634 * Pop an error trap added with gdk_error_push()
638 * 0, if no error occured, otherwise the error code.
639 *************************************************************/
642 gdk_error_trap_pop (void)
648 g_return_val_if_fail (gdk_error_traps != NULL, 0);
650 node = gdk_error_traps;
651 gdk_error_traps = gdk_error_traps->next;
653 node->next = gdk_error_trap_free_list;
654 gdk_error_trap_free_list = node;
656 result = _gdk_error_code;
659 _gdk_error_code = trap->error_code;
660 _gdk_error_warnings = trap->error_warnings;
661 XSetErrorHandler (trap->old_handler);
667 gdk_get_display (void)
669 return g_strdup (gdk_display_get_name (gdk_display_get_default ()));
674 * @display: #GdkDisplay which @window is on
675 * @window: window ID to which to send the event
676 * @propagate: %TRUE if the event should be propagated if the target window
678 * @event_mask: event mask to match against, or 0 to send it to @window
679 * without regard to event masks.
680 * @event_send: #XEvent to send
682 * Send an event, like XSendEvent(), but trap errors and check
685 * Return value: %TRUE if sending the event succeeded.
688 _gdk_send_xevent (GdkDisplay *display,
699 gdk_error_trap_push ();
700 result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window,
701 propagate, event_mask, event_send);
702 XSync (GDK_DISPLAY_XDISPLAY (display), False);
704 return result && gdk_error_trap_pop() == Success;
708 _gdk_region_get_xrectangles (GdkRegion *region,
714 XRectangle *rectangles = g_new (XRectangle, region->numRects);
715 GdkRegionBox *boxes = region->rects;
718 for (i = 0; i < region->numRects; i++)
720 rectangles[i].x = CLAMP (boxes[i].x1 + x_offset, G_MINSHORT, G_MAXSHORT);
721 rectangles[i].y = CLAMP (boxes[i].y1 + y_offset, G_MINSHORT, G_MAXSHORT);
722 rectangles[i].width = CLAMP (boxes[i].x2 + x_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].x;
723 rectangles[i].height = CLAMP (boxes[i].y2 + y_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].y;
727 *n_rects = region->numRects;
731 * gdk_x11_grab_server:
733 * Call gdk_x11_display_grab() on the default display.
734 * To ungrab the server again, use gdk_x11_ungrab_server().
736 * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
739 gdk_x11_grab_server ()
741 gdk_x11_display_grab (gdk_display_get_default ());
745 * gdk_x11_ungrab_server:
747 * Ungrab the default display after it has been grabbed with
748 * gdk_x11_grab_server().
751 gdk_x11_ungrab_server ()
753 gdk_x11_display_ungrab (gdk_display_get_default ());
757 * gdk_x11_get_default_screen:
759 * Gets the default GTK+ screen number.
761 * Return value: returns the screen number specified by
762 * the --display command line option or the DISPLAY environment
763 * variable when gdk_init() calls XOpenDisplay().
766 gdk_x11_get_default_screen (void)
768 return gdk_screen_get_number (gdk_screen_get_default ());
772 * gdk_x11_get_default_root_xwindow:
774 * Gets the root window of the default screen
775 * (see gdk_x11_get_default_screen()).
777 * Return value: an Xlib <type>Window</type>.
780 gdk_x11_get_default_root_xwindow (void)
782 return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
786 * gdk_x11_get_default_xdisplay:
788 * Gets the default GTK+ display.
790 * Return value: the Xlib <type>Display*</type> for the display
791 * specified in the <option>--display</option> command line option
792 * or the <envar>DISPLAY</envar> environment variable.
795 gdk_x11_get_default_xdisplay (void)
797 return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());