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, see <http://www.gnu.org/licenses/>.
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #include "gdkdeviceprivate.h"
28 #include "gdkinternals.h"
31 #include "gdkdisplay-x11.h"
32 #include "gdkprivate-x11.h"
34 #include <glib/gprintf.h>
41 #include <X11/Xatom.h>
43 #include <X11/Xutil.h>
46 #include <X11/XKBlib.h>
50 * SECTION:x_interaction
51 * @Short_description: X backend-specific functions
52 * @Title: X Window System Interaction
54 * The functions in this section are specific to the GDK X11 backend.
55 * To use them, you need to include the <literal><gdk/gdkx.h></literal>
56 * header and use the X11-specific pkg-config files to build your
57 * application (either <literal>gdk-x11-3.0</literal> or
58 * <literal>gtk+-x11-3.0</literal>).
60 * To make your code compile with other GDK backends, guard backend-specific
61 * calls by an ifdef as follows. Since GDK may be built with multiple
62 * backends, you should also check for the backend that is in use (e.g. by
63 * using the GDK_IS_X11_DISPLAY() macro).
65 * #ifdef GDK_WINDOWING_X11
66 * if (GDK_IS_X11_DISPLAY (display))
68 * /* make X11-specific calls here */
72 * #ifdef GDK_WINDOWING_QUARTZ
73 * if (GDK_IS_QUARTZ_DISPLAY (display))
75 * /* make Quartz-specific calls here &ast/
79 * g_error ("Unsupported GDK backend");
83 typedef struct _GdkPredicate GdkPredicate;
91 /* non-GDK previous error handler */
92 typedef int (*GdkXErrorHandler) (Display *, XErrorEvent *);
93 static GdkXErrorHandler _gdk_old_error_handler;
94 /* number of times we've pushed the GDK error handler */
95 static int _gdk_error_handler_push_count = 0;
98 * Private function declarations
101 static int gdk_x_error (Display *display,
103 static int gdk_x_io_error (Display *display);
106 _gdk_x11_windowing_init (void)
108 XSetErrorHandler (gdk_x_error);
109 XSetIOErrorHandler (gdk_x_io_error);
111 gdk_window_add_filter (NULL,
112 _gdk_wm_protocols_filter,
114 gdk_window_add_filter (NULL,
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();
142 * _gdk_x11_window_grab_check_unmap:
143 * @window: a #GdkWindow
144 * @serial: serial from Unmap event (or from NextRequest(display)
145 * if the unmap is being done by this client.)
147 * Checks to see if an unmap request or event causes the current
148 * grab window to become not viewable, and if so, clear the
149 * the pointer we keep to it.
152 _gdk_x11_window_grab_check_unmap (GdkWindow *window,
155 GdkDisplay *display = gdk_window_get_display (window);
156 GdkDeviceManager *device_manager;
159 device_manager = gdk_display_get_device_manager (display);
161 /* Get all devices */
162 devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
163 devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
164 devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
166 /* End all grabs on the newly hidden window */
167 for (d = devices; d; d = d->next)
168 _gdk_display_end_device_grab (display, d->data, serial, window, TRUE);
170 g_list_free (devices);
174 * _gdk_x11_window_grab_check_destroy:
175 * @window: a #GdkWindow
177 * Checks to see if window is the current grab window, and if
178 * so, clear the current grab window.
181 _gdk_x11_window_grab_check_destroy (GdkWindow *window)
183 GdkDisplay *display = gdk_window_get_display (window);
184 GdkDeviceManager *device_manager;
185 GdkDeviceGrabInfo *grab;
188 device_manager = gdk_display_get_device_manager (display);
190 /* Get all devices */
191 devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
192 devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
193 devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
195 for (d = devices; d; d = d->next)
197 /* Make sure there is no lasting grab in this native window */
198 grab = _gdk_display_get_last_device_grab (display, d->data);
200 if (grab && grab->native_window == window)
202 /* We don't know the actual serial to end, but it
203 doesn't really matter as this only happens
204 after we get told of the destroy from the
205 server so we know its ended in the server,
206 just make sure its ended. */
207 grab->serial_end = grab->serial_start;
208 grab->implicit_ungrab = TRUE;
212 g_list_free (devices);
216 *--------------------------------------------------------------
219 * The X I/O error handling routine.
222 * "display" is the X display the error orignated from.
225 * An X I/O error basically means we lost our connection
226 * to the X server. There is not much we can do to
227 * continue, so simply print an error message and exit.
231 *--------------------------------------------------------------
235 gdk_x_io_error (Display *display)
237 /* This is basically modelled after the code in XLib. We need
238 * an explicit error handler here, so we can disable our atexit()
239 * which would otherwise cause a nice segfault.
240 * We fprintf(stderr, instead of g_warning() because g_warning()
241 * could possibly be redirected to a dialog
245 g_warning ("The application '%s' lost its connection to the display %s;\n"
246 "most likely the X server was shut down or you killed/destroyed\n"
247 "the application.\n",
249 display ? DisplayString (display) : gdk_get_display_arg_name ());
253 g_warning ("%s: Fatal IO error %d (%s) on X server %s.\n",
255 errno, g_strerror (errno),
256 display ? DisplayString (display) : gdk_get_display_arg_name ());
262 /* X error handler. Keep the name the same because people are used to
263 * breaking on it in the debugger.
266 gdk_x_error (Display *xdisplay,
269 if (error->error_code)
271 GdkDisplay *error_display;
272 GdkDisplayManager *manager;
275 /* Figure out which GdkDisplay if any got the error. */
276 error_display = NULL;
277 manager = gdk_display_manager_get ();
278 displays = gdk_display_manager_list_displays (manager);
279 while (displays != NULL)
281 GdkX11Display *gdk_display = displays->data;
283 if (xdisplay == gdk_display->xdisplay)
285 error_display = GDK_DISPLAY (gdk_display);
286 g_slist_free (displays);
291 displays = g_slist_delete_link (displays, displays);
295 if (error_display == NULL)
297 /* Error on an X display not opened by GDK. Ignore. */
303 _gdk_x11_display_error_event (error_display, error);
311 _gdk_x11_error_handler_push (void)
313 GdkXErrorHandler previous;
315 previous = XSetErrorHandler (gdk_x_error);
317 if (_gdk_error_handler_push_count > 0)
319 if (previous != gdk_x_error)
320 g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
324 _gdk_old_error_handler = previous;
327 _gdk_error_handler_push_count += 1;
331 _gdk_x11_error_handler_pop (void)
333 g_return_if_fail (_gdk_error_handler_push_count > 0);
335 _gdk_error_handler_push_count -= 1;
337 if (_gdk_error_handler_push_count == 0)
339 XSetErrorHandler (_gdk_old_error_handler);
340 _gdk_old_error_handler = NULL;
345 _gdk_x11_display_send_xevent (GdkDisplay *display,
353 if (gdk_display_is_closed (display))
356 gdk_x11_display_error_trap_push (display);
357 result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window,
358 propagate, event_mask, event_send);
359 XSync (GDK_DISPLAY_XDISPLAY (display), False);
361 if (gdk_x11_display_error_trap_pop (display))
368 _gdk_x11_region_get_xrectangles (const cairo_region_t *region,
374 XRectangle *rectangles;
375 cairo_rectangle_int_t box;
378 n = cairo_region_num_rectangles (region);
379 rectangles = g_new (XRectangle, n);
381 for (i = 0; i < n; i++)
383 cairo_region_get_rectangle (region, i, &box);
384 rectangles[i].x = CLAMP (box.x + x_offset, G_MINSHORT, G_MAXSHORT);
385 rectangles[i].y = CLAMP (box.y + y_offset, G_MINSHORT, G_MAXSHORT);
386 rectangles[i].width = CLAMP (box.width, G_MINSHORT, G_MAXSHORT);
387 rectangles[i].height = CLAMP (box.height, G_MINSHORT, G_MAXSHORT);
395 * gdk_x11_grab_server:
397 * Call gdk_x11_display_grab() on the default display.
398 * To ungrab the server again, use gdk_x11_ungrab_server().
400 * gdk_x11_grab_server()/gdk_x11_ungrab_server() calls can be nested.
403 gdk_x11_grab_server (void)
405 gdk_x11_display_grab (gdk_display_get_default ());
409 * gdk_x11_ungrab_server:
411 * Ungrab the default display after it has been grabbed with
412 * gdk_x11_grab_server().
415 gdk_x11_ungrab_server (void)
417 gdk_x11_display_ungrab (gdk_display_get_default ());
421 * gdk_x11_get_default_screen:
423 * Gets the default GTK+ screen number.
425 * Return value: returns the screen number specified by
426 * the --display command line option or the DISPLAY environment
427 * variable when gdk_init() calls XOpenDisplay().
430 gdk_x11_get_default_screen (void)
432 return gdk_screen_get_number (gdk_screen_get_default ());
436 * gdk_x11_get_default_root_xwindow:
438 * Gets the root window of the default screen
439 * (see gdk_x11_get_default_screen()).
441 * Return value: an Xlib <type>Window</type>.
444 gdk_x11_get_default_root_xwindow (void)
446 return GDK_SCREEN_XROOTWIN (gdk_screen_get_default ());
450 * gdk_x11_get_default_xdisplay:
452 * Gets the default GTK+ display.
454 * Return value: (transfer none): the Xlib <type>Display*</type> for
455 * the display specified in the <option>--display</option> command
456 * line option or the <envar>DISPLAY</envar> environment variable.
459 gdk_x11_get_default_xdisplay (void)
461 return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());