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/.
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 int gdk_initialized = 0; /* 1 if the library is initialized,
90 static GSList *gdk_error_traps = NULL; /* List of error traps */
91 static GSList *gdk_error_trap_free_list = NULL; /* Free list */
93 GdkArgDesc _gdk_windowing_args[] = {
94 { "sync", GDK_ARG_BOOL, &_gdk_synchronize, (GdkArgFunc)NULL },
99 _gdk_windowing_init (gint *argc,
102 _gdk_x11_initialize_locale ();
104 XSetErrorHandler (gdk_x_error);
105 XSetIOErrorHandler (gdk_x_io_error);
107 _gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE);
111 _gdk_windowing_set_default_display (GdkDisplay *display)
113 gdk_display = GDK_DISPLAY_XDISPLAY (display);
117 gdk_set_use_xshm (gboolean use_xshm)
122 gdk_get_use_xshm (void)
124 return GDK_DISPLAY_X11 (gdk_display_get_default ())->use_xshm;
128 gdk_x11_convert_grab_status (gint status)
133 return GDK_GRAB_SUCCESS;
135 return GDK_GRAB_ALREADY_GRABBED;
136 case GrabInvalidTime:
137 return GDK_GRAB_INVALID_TIME;
138 case GrabNotViewable:
139 return GDK_GRAB_NOT_VIEWABLE;
141 return GDK_GRAB_FROZEN;
144 g_assert_not_reached();
150 *--------------------------------------------------------------
153 * Grabs the pointer to a specific window
156 * "window" is the window which will receive the grab
157 * "owner_events" specifies whether events will be reported as is,
158 * or relative to "window"
159 * "event_mask" masks only interesting events
160 * "confine_to" limits the cursor movement to the specified window
161 * "cursor" changes the cursor for the duration of the grab
162 * "time" specifies the time
167 * requires a corresponding call to gdk_pointer_ungrab
169 *--------------------------------------------------------------
173 gdk_pointer_grab (GdkWindow * window,
174 gboolean owner_events,
175 GdkEventMask event_mask,
176 GdkWindow * confine_to,
181 GdkCursorPrivate *cursor_private;
186 unsigned long serial;
189 g_return_val_if_fail (window != NULL, 0);
190 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
191 g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
193 cursor_private = (GdkCursorPrivate*) cursor;
195 xwindow = GDK_WINDOW_XID (window);
196 serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
198 if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
201 xconfine_to = GDK_WINDOW_XID (confine_to);
206 xcursor = cursor_private->xcursor;
210 for (i = 0; i < _gdk_nenvent_masks; i++)
212 if (event_mask & (1 << (i + 1)))
213 xevent_mask |= _gdk_event_mask_table[i];
216 return_val = _gdk_input_grab_pointer (window,
222 if (return_val == GrabSuccess)
224 if (!GDK_WINDOW_DESTROYED (window))
226 #ifdef G_ENABLE_DEBUG
227 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
228 return_val = GrabSuccess;
231 return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (window),
235 GrabModeAsync, GrabModeAsync,
241 return_val = AlreadyGrabbed;
244 if (return_val == GrabSuccess)
246 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
247 display_x11->pointer_xgrab_window = (GdkWindowObject *)window;
248 display_x11->pointer_xgrab_serial = serial;
249 display_x11->pointer_xgrab_owner_events = owner_events;
252 return gdk_x11_convert_grab_status (return_val);
256 * gdk_pointer_grab_info_libgtk_only:
257 * @display: the #GdkDisplay for which to get the grab information
258 * @grab_window: location to store current grab window
259 * @owner_events: location to store boolean indicating whether
260 * the @owner_events flag to gdk_pointer_grab() was %TRUE.
262 * Determines information about the current pointer grab.
263 * This is not public API and must not be used by applications.
265 * Return value: %TRUE if this application currently has the
269 gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
270 GdkWindow **grab_window,
271 gboolean *owner_events)
273 GdkDisplayX11 *display_x11;
275 g_return_val_if_fail (GDK_IS_DISPLAY (display), False);
277 display_x11 = GDK_DISPLAY_X11 (display);
279 if (display_x11->pointer_xgrab_window)
282 *grab_window = (GdkWindow *)display_x11->pointer_xgrab_window;
284 *owner_events = display_x11->pointer_xgrab_owner_events;
293 *--------------------------------------------------------------
296 * Grabs the keyboard to a specific window
299 * "window" is the window which will receive the grab
300 * "owner_events" specifies whether events will be reported as is,
301 * or relative to "window"
302 * "time" specifies the time
307 * requires a corresponding call to gdk_keyboard_ungrab
309 *--------------------------------------------------------------
313 gdk_keyboard_grab (GdkWindow * window,
314 gboolean owner_events,
318 unsigned long serial;
320 g_return_val_if_fail (window != NULL, 0);
321 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
323 serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
325 if (!GDK_WINDOW_DESTROYED (window))
327 #ifdef G_ENABLE_DEBUG
328 if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
329 return_val = GrabSuccess;
332 return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (window),
333 GDK_WINDOW_XID (window),
335 GrabModeAsync, GrabModeAsync,
339 return_val = AlreadyGrabbed;
341 if (return_val == GrabSuccess)
343 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
344 display_x11->keyboard_xgrab_window = (GdkWindowObject *)window;
345 display_x11->keyboard_xgrab_serial = serial;
346 display_x11->keyboard_xgrab_owner_events = owner_events;
349 return gdk_x11_convert_grab_status (return_val);
353 * gdk_keyboard_grab_info_libgtk_only:
354 * @display: the display for which to get the grab information
355 * @grab_window: location to store current grab window
356 * @owner_events: location to store boolean indicating whether
357 * the @owner_events flag to gdk_keyboard_grab() was %TRUE.
359 * Determines information about the current keyboard grab.
360 * This is not public API and must not be used by applications.
362 * Return value: %TRUE if this application currently has the
366 gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
367 GdkWindow **grab_window,
368 gboolean *owner_events)
370 GdkDisplayX11 *display_x11;
372 g_return_val_if_fail (GDK_IS_DISPLAY (display), False);
374 display_x11 = GDK_DISPLAY_X11 (display);
376 if (display_x11->keyboard_xgrab_window)
379 *grab_window = (GdkWindow *)display_x11->keyboard_xgrab_window;
381 *owner_events = display_x11->keyboard_xgrab_owner_events;
390 * _gdk_xgrab_check_unmap:
391 * @window: a #GdkWindow
392 * @serial: serial from Unmap event (or from NextRequest(display)
393 * if the unmap is being done by this client.)
395 * Checks to see if an unmap request or event causes the current
396 * grab window to become not viewable, and if so, clear the
397 * the pointer we keep to it.
400 _gdk_xgrab_check_unmap (GdkWindow *window,
403 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
405 if (display_x11->pointer_xgrab_window &&
406 serial >= display_x11->pointer_xgrab_serial)
408 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
409 GdkWindowObject *tmp = display_x11->pointer_xgrab_window;
411 while (tmp && tmp != private)
415 display_x11->pointer_xgrab_window = NULL;
418 if (display_x11->keyboard_xgrab_window &&
419 serial >= display_x11->keyboard_xgrab_serial)
421 GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
422 GdkWindowObject *tmp = display_x11->keyboard_xgrab_window;
425 while (tmp && tmp != private)
429 display_x11->keyboard_xgrab_window = NULL;
434 * _gdk_xgrab_check_destroy:
435 * @window: a #GdkWindow
437 * Checks to see if window is the current grab window, and if
438 * so, clear the current grab window.
441 _gdk_xgrab_check_destroy (GdkWindow *window)
443 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (gdk_drawable_get_display (window));
445 if ((GdkWindowObject *)window == display_x11->pointer_xgrab_window)
446 display_x11->pointer_xgrab_window = NULL;
448 if ((GdkWindowObject *)window == display_x11->keyboard_xgrab_window)
449 display_x11->keyboard_xgrab_window = NULL;
453 * gdk_display_set_sm_client_id:
454 * @display: a #GdkDisplay
455 * @sm_client_id: the client id assigned by the session manager when the
456 * connection was opened, or %NULL to remove the property.
458 * Sets the <literal>SM_CLIENT_ID</literal> property on the application's leader window
459 * so that the window manager can save the application's state using the X11R6 ICCCM
460 * session management protocol.
462 * See the X Session Management Library documentation for more information on
463 * session management and the Inter-Client Communication Conventions Manual
464 * (ICCCM) for information on the <literal>WM_CLIENT_LEADER</literal> property.
465 * (Both documents are part of the X Window System distribution.)
468 gdk_display_set_sm_client_id (GdkDisplay *display,
469 const gchar *sm_client_id)
471 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
476 if (sm_client_id && strcmp (sm_client_id, ""))
478 XChangeProperty (display_x11->xdisplay, display_x11->leader_window,
479 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"),
480 XA_STRING, 8, PropModeReplace, sm_client_id,
481 strlen (sm_client_id));
484 XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
485 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
488 /* Close all open displays
491 _gdk_windowing_exit (void)
493 GSList *tmp_list = _gdk_displays;
497 pango_x_shutdown_display (GDK_DISPLAY_XDISPLAY (tmp_list->data));
498 XCloseDisplay (GDK_DISPLAY_XDISPLAY (tmp_list->data));
500 tmp_list = tmp_list->next;
505 *--------------------------------------------------------------
508 * The X error handling routine.
511 * "display" is the X display the error orignated from.
512 * "error" is the XErrorEvent that we are handling.
515 * Either we were expecting some sort of error to occur,
516 * in which case we set the "_gdk_error_code" flag, or this
517 * error was unexpected, in which case we will print an
518 * error message and exit. (Since trying to continue will
519 * most likely simply lead to more errors).
523 *--------------------------------------------------------------
527 gdk_x_error (Display *display,
530 if (error->error_code)
532 if (_gdk_error_warnings)
537 XGetErrorText (display, error->error_code, buf, 63);
540 g_strdup_printf ("The program '%s' received an X Window System error.\n"
541 "This probably reflects a bug in the program.\n"
542 "The error was '%s'.\n"
543 " (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
544 " (Note to programmers: normally, X errors are reported asynchronously;\n"
545 " that is, you will receive the error a while after causing it.\n"
546 " To debug your program, run it with the --sync command line\n"
547 " option to change this behavior. You can then get a meaningful\n"
548 " backtrace from your debugger if you break on the gdk_x_error() function.)",
556 #ifdef G_ENABLE_DEBUG
558 #else /* !G_ENABLE_DEBUG */
559 fprintf (stderr, "%s\n", msg);
562 #endif /* G_ENABLE_DEBUG */
564 _gdk_error_code = error->error_code;
571 *--------------------------------------------------------------
574 * The X I/O error handling routine.
577 * "display" is the X display the error orignated from.
580 * An X I/O error basically means we lost our connection
581 * to the X server. There is not much we can do to
582 * continue, so simply print an error message and exit.
586 *--------------------------------------------------------------
590 gdk_x_io_error (Display *display)
592 /* This is basically modelled after the code in XLib. We need
593 * an explicit error handler here, so we can disable our atexit()
594 * which would otherwise cause a nice segfault.
595 * We fprintf(stderr, instead of g_warning() because g_warning()
596 * could possibly be redirected to a dialog
601 "The application '%s' lost its connection to the display %s;\n"
602 "most likely the X server was shut down or you killed/destroyed\n"
603 "the application.\n",
605 display ? DisplayString (display) : gdk_get_display_arg_name ());
609 fprintf (stderr, "%s: Fatal IO error %d (%s) on X server %s.\n",
611 errno, g_strerror (errno),
612 display ? DisplayString (display) : gdk_get_display_arg_name ());
615 /* Disable the atexit shutdown for GDK */
621 /*************************************************************
622 * gdk_error_trap_push:
623 * Push an error trap. X errors will be trapped until
624 * the corresponding gdk_error_pop(), which will return
625 * the error code, if any.
629 *************************************************************/
632 gdk_error_trap_push (void)
637 if (gdk_error_trap_free_list)
639 node = gdk_error_trap_free_list;
640 gdk_error_trap_free_list = gdk_error_trap_free_list->next;
644 node = g_slist_alloc ();
645 node->data = g_new (GdkErrorTrap, 1);
648 node->next = gdk_error_traps;
649 gdk_error_traps = node;
652 trap->old_handler = XSetErrorHandler (gdk_x_error);
653 trap->error_code = _gdk_error_code;
654 trap->error_warnings = _gdk_error_warnings;
657 _gdk_error_warnings = 0;
660 /*************************************************************
661 * gdk_error_trap_pop:
662 * Pop an error trap added with gdk_error_push()
666 * 0, if no error occured, otherwise the error code.
667 *************************************************************/
670 gdk_error_trap_pop (void)
676 g_return_val_if_fail (gdk_error_traps != NULL, 0);
678 node = gdk_error_traps;
679 gdk_error_traps = gdk_error_traps->next;
681 node->next = gdk_error_trap_free_list;
682 gdk_error_trap_free_list = node;
684 result = _gdk_error_code;
687 _gdk_error_code = trap->error_code;
688 _gdk_error_warnings = trap->error_warnings;
689 XSetErrorHandler (trap->old_handler);
695 gdk_get_display (void)
697 return g_strdup (gdk_display_get_name (gdk_display_get_default ()));
702 * @display: #GdkDisplay which @window is on
703 * @window: window ID to which to send the event
704 * @propagate: %TRUE if the event should be propagated if the target window
706 * @event_mask: event mask to match against, or 0 to send it to @window
707 * without regard to event masks.
708 * @event_send: #XEvent to send
710 * Send an event, like XSendEvent(), but trap errors and check
713 * Return value: %TRUE if sending the event succeeded.
716 _gdk_send_xevent (GdkDisplay *display,
727 gdk_error_trap_push ();
728 result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window,
729 propagate, event_mask, event_send);
730 XSync (GDK_DISPLAY_XDISPLAY (display), False);
732 return result && gdk_error_trap_pop() == Success;
736 _gdk_region_get_xrectangles (GdkRegion *region,
742 XRectangle *rectangles = g_new (XRectangle, region->numRects);
743 GdkRegionBox *boxes = region->rects;
746 for (i = 0; i < region->numRects; i++)
748 rectangles[i].x = CLAMP (boxes[i].x1 + x_offset, G_MINSHORT, G_MAXSHORT);
749 rectangles[i].y = CLAMP (boxes[i].y1 + y_offset, G_MINSHORT, G_MAXSHORT);
750 rectangles[i].width = CLAMP (boxes[i].x2 + x_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].x;
751 rectangles[i].height = CLAMP (boxes[i].y2 + y_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].y;
755 *n_rects = region->numRects;
759 gdk_x11_grab_server ()
761 gdk_x11_display_grab (gdk_display_get_default ());
765 gdk_x11_ungrab_server ()
767 gdk_x11_display_ungrab (gdk_display_get_default ());
771 * gdk_x11_get_default_screen:
773 * Gets the default GTK+ screen number.
775 * Return value: returns the screen number specified by
776 * the --display command line option or the DISPLAY environment
777 * variable when gdk_init() calls XOpenDisplay().
780 gdk_x11_get_default_screen (void)
782 return gdk_screen_get_number (gdk_screen_get_default ());
786 gdk_x11_get_default_root_xwindow (void)
788 return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
792 gdk_x11_get_default_xdisplay (void)
794 return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());