1/* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
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.
8 *
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.
13 *
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/>.
16 */
17
18/*
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/.
23 */
24
25#include "config.h"
26
27#include "gdkdeviceprivate.h"
28#include "gdkintl.h"
29#include "gdkasync.h"
30#include "gdkdisplay-x11.h"
31#include "gdkprivate-x11.h"
32
33#include <glib/gprintf.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37#include <limits.h>
38#include <errno.h>
39
40#include <X11/Xatom.h>
41#include <X11/Xlib.h>
42#include <X11/Xutil.h>
43
44#ifdef HAVE_XKB
45#include <X11/XKBlib.h>
46#endif
47
48/* non-GDK previous error handler */
49typedef int (*GdkXErrorHandler) (Display *, XErrorEvent *);
50static GdkXErrorHandler _gdk_old_error_handler;
51/* number of times we've pushed the GDK error handler */
52static int _gdk_error_handler_push_count = 0;
53
54/*
55 * Private function declarations
56 */
57
58static int gdk_x_error (Display *display,
59 XErrorEvent *error);
60static int gdk_x_io_error (Display *display);
61
62void
63_gdk_x11_surfaceing_init (void)
64{
65 XSetErrorHandler (gdk_x_error);
66 XSetIOErrorHandler (gdk_x_io_error);
67}
68
69/*
70 * _gdk_x11_surface_grab_check_unmap:
71 * @surface: a `GdkSurface`
72 * @serial: serial from Unmap event (or from NextRequest(display)
73 * if the unmap is being done by this client.)
74 *
75 * Checks to see if an unmap request or event causes the current
76 * grab surface to become not viewable, and if so, clear the
77 * the pointer we keep to it.
78 **/
79void
80_gdk_x11_surface_grab_check_unmap (GdkSurface *surface,
81 gulong serial)
82{
83 GdkDisplay *display = gdk_surface_get_display (surface);
84 GdkSeat *seat;
85 GList *devices, *d;
86
87 seat = gdk_display_get_default_seat (display);
88
89 devices = gdk_seat_get_devices (seat, capabilities: GDK_SEAT_CAPABILITY_ALL);
90 devices = g_list_prepend (list: devices, data: gdk_seat_get_keyboard (seat));
91 devices = g_list_prepend (list: devices, data: gdk_seat_get_pointer (seat));
92
93 /* End all grabs on the newly hidden surface */
94 for (d = devices; d; d = d->next)
95 _gdk_display_end_device_grab (display, device: d->data, serial, if_child: surface, TRUE);
96
97 g_list_free (list: devices);
98}
99
100/*
101 * _gdk_x11_surface_grab_check_destroy:
102 * @surface: a `GdkSurface`
103 *
104 * Checks to see if surface is the current grab surface, and if
105 * so, clear the current grab surface.
106 **/
107void
108_gdk_x11_surface_grab_check_destroy (GdkSurface *surface)
109{
110 GdkDisplay *display = gdk_surface_get_display (surface);
111 GdkSeat *seat;
112 GdkDeviceGrabInfo *grab;
113 GList *devices, *d;
114
115 seat = gdk_display_get_default_seat (display);
116
117 devices = gdk_seat_get_devices (seat, capabilities: GDK_SEAT_CAPABILITY_ALL);
118 devices = g_list_prepend (list: devices, data: gdk_seat_get_keyboard (seat));
119 devices = g_list_prepend (list: devices, data: gdk_seat_get_pointer (seat));
120
121 for (d = devices; d; d = d->next)
122 {
123 /* Make sure there is no lasting grab in this native surface */
124 grab = _gdk_display_get_last_device_grab (display, device: d->data);
125
126 if (grab && grab->surface == surface)
127 {
128 /* We don't know the actual serial to end, but it
129 doesn't really matter as this only happens
130 after we get told of the destroy from the
131 server so we know its ended in the server,
132 just make sure its ended. */
133 grab->serial_end = grab->serial_start;
134 grab->implicit_ungrab = TRUE;
135 }
136 }
137
138 g_list_free (list: devices);
139}
140
141/*
142 *--------------------------------------------------------------
143 * gdk_x_io_error
144 *
145 * The X I/O error handling routine.
146 *
147 * Arguments:
148 * "display" is the X display the error originated from.
149 *
150 * Results:
151 * An X I/O error basically means we lost our connection
152 * to the X server. There is not much we can do to
153 * continue, so simply print an error message and exit.
154 *
155 * Side effects:
156 *
157 *--------------------------------------------------------------
158 */
159
160static int
161gdk_x_io_error (Display *display)
162{
163 /* This is basically modelled after the code in XLib. We need
164 * an explicit error handler here, so we can disable our atexit()
165 * which would otherwise cause a nice segfault.
166 * We g_debug() instead of g_warning(), because g_warning()
167 * could possibly be redirected to the log
168 */
169 g_debug ("%s: Fatal IO error %d (%s) on X server %s.\n",
170 g_get_prgname (),
171 errno, g_strerror (errno),
172 display ? DisplayString (display) : "");
173
174 _exit (status: 1);
175}
176
177/* X error handler. Keep the name the same because people are used to
178 * breaking on it in the debugger.
179 */
180static int
181gdk_x_error (Display *xdisplay,
182 XErrorEvent *error)
183{
184 if (error->error_code)
185 {
186 GdkDisplay *error_display;
187 GdkDisplayManager *manager;
188 GSList *displays;
189
190 /* Figure out which GdkDisplay if any got the error. */
191 error_display = NULL;
192 manager = gdk_display_manager_get ();
193 displays = gdk_display_manager_list_displays (manager);
194 while (displays != NULL)
195 {
196 GdkX11Display *gdk_display = displays->data;
197
198 if (GDK_IS_X11_DISPLAY (gdk_display) &&
199 xdisplay == gdk_display->xdisplay)
200 {
201 error_display = GDK_DISPLAY (gdk_display);
202 g_slist_free (list: displays);
203 displays = NULL;
204 }
205 else
206 {
207 displays = g_slist_delete_link (list: displays, link_: displays);
208 }
209 }
210
211 if (error_display == NULL)
212 {
213 /* Error on an X display not opened by GDK. Ignore. */
214
215 return 0;
216 }
217 else
218 {
219 _gdk_x11_display_error_event (display: error_display, error);
220 }
221 }
222
223 return 0;
224}
225
226void
227_gdk_x11_error_handler_push (void)
228{
229 GdkXErrorHandler previous;
230
231 previous = XSetErrorHandler (gdk_x_error);
232
233 if (_gdk_error_handler_push_count > 0)
234 {
235 if (previous != gdk_x_error)
236 g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
237 }
238 else
239 {
240 _gdk_old_error_handler = previous;
241 }
242
243 _gdk_error_handler_push_count += 1;
244}
245
246void
247_gdk_x11_error_handler_pop (void)
248{
249 g_return_if_fail (_gdk_error_handler_push_count > 0);
250
251 _gdk_error_handler_push_count -= 1;
252
253 if (_gdk_error_handler_push_count == 0)
254 {
255 XSetErrorHandler (_gdk_old_error_handler);
256 _gdk_old_error_handler = NULL;
257 }
258}
259
260int
261_gdk_x11_display_send_xevent (GdkDisplay *display,
262 Window window,
263 gboolean propagate,
264 glong event_mask,
265 XEvent *event_send)
266{
267 gboolean result;
268
269 if (gdk_display_is_closed (display))
270 return FALSE;
271
272 gdk_x11_display_error_trap_push (display);
273 result = XSendEvent (GDK_DISPLAY_XDISPLAY (display), window,
274 propagate, event_mask, event_send);
275 XSync (GDK_DISPLAY_XDISPLAY (display), False);
276
277 if (gdk_x11_display_error_trap_pop (display))
278 return FALSE;
279
280 return result;
281}
282
283void
284_gdk_x11_region_get_xrectangles (const cairo_region_t *region,
285 int x_offset,
286 int y_offset,
287 int scale,
288 XRectangle **rects,
289 int *n_rects)
290{
291 XRectangle *rectangles;
292 cairo_rectangle_int_t box;
293 int i, n;
294
295 n = cairo_region_num_rectangles (region);
296 rectangles = g_new (XRectangle, n);
297
298 for (i = 0; i < n; i++)
299 {
300 cairo_region_get_rectangle (region, nth: i, rectangle: &box);
301 rectangles[i].x = CLAMP ((box.x + x_offset) * scale, G_MINSHORT, G_MAXSHORT);
302 rectangles[i].y = CLAMP ((box.y + y_offset) * scale, G_MINSHORT, G_MAXSHORT);
303 rectangles[i].width = CLAMP (box.width * scale, G_MINSHORT, G_MAXSHORT);
304 rectangles[i].height = CLAMP (box.height * scale, G_MINSHORT, G_MAXSHORT);
305 }
306
307 *n_rects = n;
308 *rects = rectangles;
309}
310

source code of gtk/gdk/x11/gdkmain-x11.c