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/.
37 #include <X11/Xatom.h>
39 #include <X11/Xutil.h>
42 #include <X11/XKBlib.h>
47 #include "gdkprivate-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;
70 * Private function declarations
73 #ifndef HAVE_XCONVERTCASE
74 static void gdkx_XConvertCase (KeySym symbol,
77 #define XConvertCase gdkx_XConvertCase
80 static int gdk_x_error (Display *display,
82 static int gdk_x_io_error (Display *display);
84 /* Private variable declarations
86 static int gdk_initialized = 0; /* 1 if the library is initialized,
90 static gint autorepeat;
91 static gboolean gdk_synchronize = FALSE;
94 static const GDebugKey gdk_debug_keys[] = {
95 {"events", GDK_DEBUG_EVENTS},
96 {"misc", GDK_DEBUG_MISC},
97 {"dnd", GDK_DEBUG_DND},
98 {"xim", GDK_DEBUG_XIM}
101 static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
103 #endif /* G_ENABLE_DEBUG */
105 GdkArgDesc _gdk_windowing_args[] = {
106 { "display", GDK_ARG_STRING, &gdk_display_name, (GdkArgFunc)NULL },
107 { "sync", GDK_ARG_BOOL, &gdk_synchronize, (GdkArgFunc)NULL },
108 { "no-xshm", GDK_ARG_NOBOOL, &gdk_use_xshm, (GdkArgFunc)NULL },
109 { "class", GDK_ARG_STRING, &gdk_progclass, (GdkArgFunc)NULL },
110 { "gxid-host", GDK_ARG_STRING, &gdk_input_gxid_host, (GdkArgFunc)NULL },
111 { "gxid-port", GDK_ARG_INT, &gdk_input_gxid_port, (GdkArgFunc)NULL },
116 _gdk_windowing_init_check (int argc, char **argv)
118 XKeyboardState keyboard_state;
119 XClassHint *class_hint;
122 XSetErrorHandler (gdk_x_error);
123 XSetIOErrorHandler (gdk_x_io_error);
125 gdk_display = XOpenDisplay (gdk_display_name);
130 XSynchronize (gdk_display, True);
132 gdk_screen = DefaultScreen (gdk_display);
133 gdk_root_window = RootWindow (gdk_display, gdk_screen);
135 gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window,
136 10, 10, 10, 10, 0, 0 , 0);
137 class_hint = XAllocClassHint();
138 class_hint->res_name = g_get_prgname ();
139 if (gdk_progclass == NULL)
141 gdk_progclass = g_strdup (g_get_prgname ());
142 gdk_progclass[0] = toupper (gdk_progclass[0]);
144 class_hint->res_class = gdk_progclass;
145 XmbSetWMProperties (gdk_display, gdk_leader_window,
146 NULL, NULL, argv, argc,
147 NULL, NULL, class_hint);
151 XChangeProperty (gdk_display, gdk_leader_window,
152 gdk_atom_intern ("_NET_WM_PID", FALSE),
157 gdk_wm_delete_window = gdk_atom_intern ("WM_DELETE_WINDOW", FALSE);
158 gdk_wm_take_focus = gdk_atom_intern ("WM_TAKE_FOCUS", FALSE);
159 gdk_wm_protocols = gdk_atom_intern ("WM_PROTOCOLS", FALSE);
160 gdk_wm_window_protocols[0] = gdk_wm_delete_window;
161 gdk_wm_window_protocols[1] = gdk_wm_take_focus;
162 gdk_wm_window_protocols[2] = gdk_atom_intern ("_NET_WM_PING", FALSE);
163 gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE);
165 XGetKeyboardControl (gdk_display, &keyboard_state);
166 autorepeat = keyboard_state.global_auto_repeat;
170 gint xkb_major = XkbMajorVersion;
171 gint xkb_minor = XkbMinorVersion;
172 if (XkbLibraryVersion (&xkb_major, &xkb_minor))
174 xkb_major = XkbMajorVersion;
175 xkb_minor = XkbMinorVersion;
177 if (XkbQueryExtension (gdk_display, NULL, &_gdk_xkb_event_type, NULL,
178 &xkb_major, &xkb_minor))
180 Bool detectable_autorepeat_supported;
184 XkbSelectEvents (gdk_display,
186 XkbMapNotifyMask | XkbStateNotifyMask,
187 XkbMapNotifyMask | XkbStateNotifyMask);
189 XkbSetDetectableAutoRepeat (gdk_display,
191 &detectable_autorepeat_supported);
193 GDK_NOTE (MISC, g_message ("Detectable autorepeat %s.",
194 detectable_autorepeat_supported ? "supported" : "not supported"));
196 _gdk_have_xkb_autorepeat = detectable_autorepeat_supported;
206 gdk_set_use_xshm (gboolean use_xshm)
208 gdk_use_xshm = use_xshm;
212 gdk_get_use_xshm (void)
218 gdk_x11_convert_grab_status (gint status)
223 return GDK_GRAB_SUCCESS;
225 return GDK_GRAB_ALREADY_GRABBED;
226 case GrabInvalidTime:
227 return GDK_GRAB_INVALID_TIME;
228 case GrabNotViewable:
229 return GDK_GRAB_NOT_VIEWABLE;
231 return GDK_GRAB_FROZEN;
234 g_assert_not_reached();
240 *--------------------------------------------------------------
243 * Grabs the pointer 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 * "event_mask" masks only interesting events
250 * "confine_to" limits the cursor movement to the specified window
251 * "cursor" changes the cursor for the duration of the grab
252 * "time" specifies the time
257 * requires a corresponding call to gdk_pointer_ungrab
259 *--------------------------------------------------------------
263 gdk_pointer_grab (GdkWindow * window,
264 gboolean owner_events,
265 GdkEventMask event_mask,
266 GdkWindow * confine_to,
271 GdkCursorPrivate *cursor_private;
278 g_return_val_if_fail (window != NULL, 0);
279 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
280 g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
282 cursor_private = (GdkCursorPrivate*) cursor;
284 xwindow = GDK_WINDOW_XID (window);
286 if (!confine_to || GDK_WINDOW_DESTROYED (confine_to))
289 xconfine_to = GDK_WINDOW_XID (confine_to);
294 xcursor = cursor_private->xcursor;
298 for (i = 0; i < gdk_nevent_masks; i++)
300 if (event_mask & (1 << (i + 1)))
301 xevent_mask |= gdk_event_mask_table[i];
304 return_val = _gdk_input_grab_pointer (window,
310 if (return_val == GrabSuccess)
312 if (!GDK_WINDOW_DESTROYED (window))
313 return_val = XGrabPointer (GDK_WINDOW_XDISPLAY (window),
317 GrabModeAsync, GrabModeAsync,
322 return_val = AlreadyGrabbed;
325 if (return_val == GrabSuccess)
326 gdk_xgrab_window = (GdkWindowObject *)window;
328 return gdk_x11_convert_grab_status (return_val);
332 *--------------------------------------------------------------
335 * Releases any pointer grab
343 *--------------------------------------------------------------
347 gdk_pointer_ungrab (guint32 time)
349 _gdk_input_ungrab_pointer (time);
351 XUngrabPointer (gdk_display, time);
352 gdk_xgrab_window = NULL;
356 *--------------------------------------------------------------
357 * gdk_pointer_is_grabbed
359 * Tell wether there is an active x pointer grab in effect
367 *--------------------------------------------------------------
371 gdk_pointer_is_grabbed (void)
373 return gdk_xgrab_window != NULL;
377 *--------------------------------------------------------------
380 * Grabs the keyboard to a specific window
383 * "window" is the window which will receive the grab
384 * "owner_events" specifies whether events will be reported as is,
385 * or relative to "window"
386 * "time" specifies the time
391 * requires a corresponding call to gdk_keyboard_ungrab
393 *--------------------------------------------------------------
397 gdk_keyboard_grab (GdkWindow * window,
398 gboolean owner_events,
403 g_return_val_if_fail (window != NULL, 0);
404 g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
406 if (!GDK_WINDOW_DESTROYED (window))
407 return_val = XGrabKeyboard (GDK_WINDOW_XDISPLAY (window),
408 GDK_WINDOW_XID (window),
410 GrabModeAsync, GrabModeAsync,
413 return_val = AlreadyGrabbed;
415 return gdk_x11_convert_grab_status (return_val);
419 *--------------------------------------------------------------
420 * gdk_keyboard_ungrab
422 * Releases any keyboard grab
430 *--------------------------------------------------------------
434 gdk_keyboard_ungrab (guint32 time)
436 XUngrabKeyboard (gdk_display, time);
440 *--------------------------------------------------------------
443 * Return the width of the screen.
451 *--------------------------------------------------------------
455 gdk_screen_width (void)
459 return_val = DisplayWidth (gdk_display, gdk_screen);
465 *--------------------------------------------------------------
468 * Return the height of the screen.
476 *--------------------------------------------------------------
480 gdk_screen_height (void)
484 return_val = DisplayHeight (gdk_display, gdk_screen);
490 *--------------------------------------------------------------
491 * gdk_screen_width_mm
493 * Return the width of the screen in millimeters.
501 *--------------------------------------------------------------
505 gdk_screen_width_mm (void)
509 return_val = DisplayWidthMM (gdk_display, gdk_screen);
515 *--------------------------------------------------------------
518 * Return the height of the screen in millimeters.
526 *--------------------------------------------------------------
530 gdk_screen_height_mm (void)
534 return_val = DisplayHeightMM (gdk_display, gdk_screen);
540 *--------------------------------------------------------------
541 * gdk_set_sm_client_id
543 * Set the SM_CLIENT_ID property on the WM_CLIENT_LEADER window
544 * so that the window manager can save our state using the
545 * X11R6 ICCCM session management protocol. A NULL value should
546 * be set following disconnection from the session manager to
547 * remove the SM_CLIENT_ID property.
551 * "sm_client_id" specifies the client id assigned to us by the
552 * session manager or NULL to remove the property.
558 *--------------------------------------------------------------
562 gdk_set_sm_client_id (const gchar* sm_client_id)
564 if (sm_client_id && strcmp (sm_client_id, ""))
566 XChangeProperty (gdk_display, gdk_leader_window,
567 gdk_atom_intern ("SM_CLIENT_ID", FALSE),
568 XA_STRING, 8, PropModeReplace,
569 sm_client_id, strlen(sm_client_id));
572 XDeleteProperty (gdk_display, gdk_leader_window,
573 gdk_atom_intern ("SM_CLIENT_ID", FALSE));
579 XBell(gdk_display, 0);
583 gdk_windowing_exit (void)
585 pango_x_shutdown_display (gdk_display);
587 XCloseDisplay (gdk_display);
591 *--------------------------------------------------------------
594 * The X error handling routine.
597 * "display" is the X display the error orignated from.
598 * "error" is the XErrorEvent that we are handling.
601 * Either we were expecting some sort of error to occur,
602 * in which case we set the "gdk_error_code" flag, or this
603 * error was unexpected, in which case we will print an
604 * error message and exit. (Since trying to continue will
605 * most likely simply lead to more errors).
609 *--------------------------------------------------------------
613 gdk_x_error (Display *display,
616 if (error->error_code)
618 if (gdk_error_warnings)
623 XGetErrorText (display, error->error_code, buf, 63);
626 g_strdup_printf ("The program '%s' received an X Window System error.\n"
627 "This probably reflects a bug in the program.\n"
628 "The error was '%s'.\n"
629 " (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
630 " (Note to programmers: normally, X errors are reported asynchronously;\n"
631 " that is, you will receive the error a while after causing it.\n"
632 " To debug your program, run it with the --sync command line\n"
633 " option to change this behavior. You can then get a meaningful\n"
634 " backtrace from your debugger if you break on the gdk_x_error() function.)",
642 #ifdef G_ENABLE_DEBUG
644 #else /* !G_ENABLE_DEBUG */
645 fprintf (stderr, "%s\n", msg);
648 #endif /* G_ENABLE_DEBUG */
650 gdk_error_code = error->error_code;
657 *--------------------------------------------------------------
660 * The X I/O error handling routine.
663 * "display" is the X display the error orignated from.
666 * An X I/O error basically means we lost our connection
667 * to the X server. There is not much we can do to
668 * continue, so simply print an error message and exit.
672 *--------------------------------------------------------------
676 gdk_x_io_error (Display *display)
678 /* This is basically modelled after the code in XLib. We need
679 * an explicit error handler here, so we can disable our atexit()
680 * which would otherwise cause a nice segfault.
681 * We fprintf(stderr, instead of g_warning() because g_warning()
682 * could possibly be redirected to a dialog
687 "The application '%s' lost its connection to the display %s;\n"
688 "most likely the X server was shut down or you killed/destroyed\n"
689 "the application.\n",
691 gdk_display ? DisplayString (gdk_display) : gdk_get_display());
695 fprintf (stderr, "%s: Fatal IO error %d (%s) on X server %s.\n",
697 errno, g_strerror (errno),
698 gdk_display ? DisplayString (gdk_display) : gdk_get_display());
701 /* Disable the atexit shutdown for GDK */
708 gdk_get_display (void)
710 return (gchar *)XDisplayName (gdk_display_name);
714 gdk_send_xevent (Window window, gboolean propagate, glong event_mask,
718 gint old_warnings = gdk_error_warnings;
722 gdk_error_warnings = 0;
723 result = XSendEvent (gdk_display, window, propagate, event_mask, event_send);
724 XSync (gdk_display, False);
725 gdk_error_warnings = old_warnings;
727 return result && !gdk_error_code;
731 _gdk_region_get_xrectangles (GdkRegion *region,
737 XRectangle *rectangles = g_new (XRectangle, region->numRects);
738 GdkRegionBox *boxes = region->rects;
741 for (i = 0; i < region->numRects; i++)
743 rectangles[i].x = CLAMP (boxes[i].x1 + x_offset, G_MINSHORT, G_MAXSHORT);
744 rectangles[i].y = CLAMP (boxes[i].y1 + y_offset, G_MINSHORT, G_MAXSHORT);
745 rectangles[i].width = CLAMP (boxes[i].x2 + x_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].x;
746 rectangles[i].height = CLAMP (boxes[i].y2 + y_offset, G_MINSHORT, G_MAXSHORT) - rectangles[i].y;
750 *n_rects = region->numRects;
753 /* FIXME put in GdkDisplay */
754 static gint grab_count = 0;
756 gdk_x11_grab_server (void)
759 XGrabServer (gdk_display);
764 gdk_x11_ungrab_server (void)
766 g_return_if_fail (grab_count > 0);
770 XUngrabServer (gdk_display);