1 /* GDK - The GIMP Drawing Kit
2 * gdkdisplay-x11.c
3 *
4 * Copyright 2001 Sun Microsystems Inc.
5 * Copyright (C) 2004 Nokia Corporation
6 *
7 * Erwann Chenede <erwann.chenede@sun.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24
25 #define VK_USE_PLATFORM_XLIB_KHR
26
27 #include "gdkdisplay-x11.h"
28 #include "gdkdisplayprivate.h"
29
30 #include "gdkasync.h"
31 #include "gdkdisplay.h"
32 #include "gdkeventsource.h"
33 #include "gdkeventtranslator.h"
34 #include "gdkframeclockprivate.h"
35 #include "gdkinternals.h"
36 #include "gdkdeviceprivate.h"
37 #include "gdksurfaceprivate.h"
38 #include "gdkkeysprivate.h"
39 #include "gdkmarshalers.h"
40 #include "xsettings-client.h"
41
42 #include "gdkcairocontext-x11.h"
43 #include "gdkclipboard-x11.h"
44 #include "gdkglcontext-x11.h"
45 #include "gdkkeys-x11.h"
46 #include "gdkprivate-x11.h"
47 #include "gdkscreen-x11.h"
48 #include "gdkvulkancontext-x11.h"
49
50 #include "gdk-private.h"
51
52 #include <glib.h>
53 #include <glib/gprintf.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <errno.h>
57 #include <unistd.h>
58
59 #include <X11/Xatom.h>
60 #include <X11/Xlibint.h>
61
62 #ifdef HAVE_XKB
63 #include <X11/XKBlib.h>
64 #endif
65
66 #ifdef HAVE_XFIXES
67 #include <X11/extensions/Xfixes.h>
68 #endif
69
70 #include <X11/extensions/shape.h>
71
72 #ifdef HAVE_RANDR
73 #include <X11/extensions/Xrandr.h>
74 #endif
75
76 enum {
77 XEVENT,
78 LAST_SIGNAL
79 };
80
81 typedef struct _GdkErrorTrap GdkErrorTrap;
82
83 struct _GdkErrorTrap
84 {
85 /* Next sequence when trap was pushed, i.e. first sequence to
86 * ignore
87 */
88 gulong start_sequence;
89
90 /* Next sequence when trap was popped, i.e. first sequence
91 * to not ignore. 0 if trap is still active.
92 */
93 gulong end_sequence;
94
95 /* Most recent error code within the sequence */
96 int error_code;
97 };
98
99 static void gdk_x11_display_dispose (GObject *object);
100 static void gdk_x11_display_finalize (GObject *object);
101
102 static void gdk_x11_display_event_translator_init (GdkEventTranslatorIface *iface);
103
104 static GdkEvent * gdk_x11_display_translate_event (GdkEventTranslator *translator,
105 GdkDisplay *display,
106 const XEvent *xevent);
107
108 static void gdk_internal_connection_watch (Display *display,
109 XPointer arg,
110 int fd,
111 gboolean opening,
112 XPointer *watch_data);
113
114 typedef struct _GdkEventTypeX11 GdkEventTypeX11;
115
116 struct _GdkEventTypeX11
117 {
118 int base;
119 int n_events;
120 };
121
122 /* Note that we never *directly* use WM_LOCALE_NAME, WM_PROTOCOLS,
123 * but including them here has the side-effect of getting them
124 * into the internal Xlib cache
125 */
126 static const char *const precache_atoms[] = {
127 "UTF8_STRING",
128 "WM_CLIENT_LEADER",
129 "WM_DELETE_WINDOW",
130 "WM_ICON_NAME",
131 "WM_LOCALE_NAME",
132 "WM_NAME",
133 "WM_PROTOCOLS",
134 "WM_TAKE_FOCUS",
135 "WM_WINDOW_ROLE",
136 "WM_STATE",
137 "_NET_ACTIVE_WINDOW",
138 "_NET_CURRENT_DESKTOP",
139 "_NET_FRAME_EXTENTS",
140 "_NET_STARTUP_ID",
141 "_NET_WM_CM_S0",
142 "_NET_WM_DESKTOP",
143 "_NET_WM_ICON",
144 "_NET_WM_ICON_NAME",
145 "_NET_WM_NAME",
146 "_NET_WM_PID",
147 "_NET_WM_PING",
148 "_NET_WM_STATE",
149 "_NET_WM_STATE_ABOVE",
150 "_NET_WM_STATE_BELOW",
151 "_NET_WM_STATE_FULLSCREEN",
152 "_NET_WM_STATE_HIDDEN",
153 "_NET_WM_STATE_MODAL",
154 "_NET_WM_STATE_MAXIMIZED_VERT",
155 "_NET_WM_STATE_MAXIMIZED_HORZ",
156 "_NET_WM_STATE_SKIP_TASKBAR",
157 "_NET_WM_STATE_SKIP_PAGER",
158 "_NET_WM_STATE_STICKY",
159 "_NET_WM_SYNC_REQUEST",
160 "_NET_WM_SYNC_REQUEST_COUNTER",
161 "_NET_WM_WINDOW_TYPE",
162 "_NET_WM_WINDOW_TYPE_COMBO",
163 "_NET_WM_WINDOW_TYPE_DIALOG",
164 "_NET_WM_WINDOW_TYPE_DND",
165 "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
166 "_NET_WM_WINDOW_TYPE_MENU",
167 "_NET_WM_WINDOW_TYPE_NORMAL",
168 "_NET_WM_WINDOW_TYPE_POPUP_MENU",
169 "_NET_WM_WINDOW_TYPE_TOOLTIP",
170 "_NET_WM_WINDOW_TYPE_UTILITY",
171 "_NET_WM_USER_TIME",
172 "_NET_WM_USER_TIME_WINDOW",
173 "_NET_VIRTUAL_ROOTS",
174 "GDK_SELECTION",
175 "_NET_WM_STATE_FOCUSED",
176 "GDK_VISUALS",
177 "XdndAware",
178 "XdndProxy",
179 "XdndActionAsk",
180 "XdndActionCopy",
181 "XdndActionLink",
182 "XdndActionList",
183 "XdndActionMove",
184 "XdndActionPrivate",
185 "XdndDrop",
186 "XdndEnter",
187 "XdndFinished",
188 "XdndLeave",
189 "XdndPosition",
190 "XdndSelection",
191 "XdndStatus",
192 "XdndTypeList"
193 };
194
195 static char *gdk_sm_client_id;
196
197 static guint signals[LAST_SIGNAL] = { 0 };
198
G_DEFINE_TYPE_WITH_CODE(GdkX11Display,gdk_x11_display,GDK_TYPE_DISPLAY,G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,gdk_x11_display_event_translator_init))199 G_DEFINE_TYPE_WITH_CODE (GdkX11Display, gdk_x11_display, GDK_TYPE_DISPLAY,
200 G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
201 gdk_x11_display_event_translator_init))
202
203 static void
204 gdk_x11_display_init (GdkX11Display *self)
205 {
206 self->monitors = g_list_store_new (GDK_TYPE_MONITOR);
207 }
208
209 static void
gdk_x11_display_event_translator_init(GdkEventTranslatorIface * iface)210 gdk_x11_display_event_translator_init (GdkEventTranslatorIface *iface)
211 {
212 iface->translate_event = gdk_x11_display_translate_event;
213 }
214
215 #define ANY_EDGE_TILED (GDK_TOPLEVEL_STATE_LEFT_TILED | \
216 GDK_TOPLEVEL_STATE_RIGHT_TILED | \
217 GDK_TOPLEVEL_STATE_TOP_TILED | \
218 GDK_TOPLEVEL_STATE_BOTTOM_TILED)
219
220 static void
do_edge_constraint_state_check(GdkSurface * surface,GdkToplevelState old_state,GdkToplevelState * set,GdkToplevelState * unset)221 do_edge_constraint_state_check (GdkSurface *surface,
222 GdkToplevelState old_state,
223 GdkToplevelState *set,
224 GdkToplevelState *unset)
225 {
226 GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface);
227 GdkToplevelState local_set, local_unset;
228 guint edge_constraints;
229
230 local_set = *set;
231 local_unset = *unset;
232 edge_constraints = toplevel->edge_constraints;
233
234 /* If the WM doesn't support _GTK_EDGE_CONSTRAINTS, rely on the fallback
235 * implementation. If it supports _GTK_EDGE_CONSTRAINTS, arrange for
236 * GDK_TOPLEVEL_STATE_TILED to be set if any edge is tiled, and cleared
237 * if no edge is tiled.
238 */
239 if (!gdk_x11_surface_supports_edge_constraints (surface))
240 {
241 /* FIXME: we rely on implementation details of mutter here:
242 * mutter only tiles horizontally, and sets maxvert when it does
243 * and if it tiles, it always affects all edges
244 */
245 if (old_state & GDK_TOPLEVEL_STATE_TILED)
246 {
247 if (!toplevel->have_maxvert)
248 local_unset |= GDK_TOPLEVEL_STATE_TILED;
249 }
250 else
251 {
252 if (toplevel->have_maxvert && !toplevel->have_maxhorz)
253 local_set |= GDK_TOPLEVEL_STATE_TILED;
254 }
255 }
256 else
257 {
258 if (old_state & GDK_TOPLEVEL_STATE_TILED)
259 {
260 if (!(edge_constraints & ANY_EDGE_TILED))
261 local_unset |= GDK_TOPLEVEL_STATE_TILED;
262 }
263 else
264 {
265 if (edge_constraints & ANY_EDGE_TILED)
266 local_set |= GDK_TOPLEVEL_STATE_TILED;
267 }
268 }
269
270 /* Top edge */
271 if (old_state & GDK_TOPLEVEL_STATE_TOP_TILED)
272 {
273 if ((edge_constraints & GDK_TOPLEVEL_STATE_TOP_TILED) == 0)
274 local_unset |= GDK_TOPLEVEL_STATE_TOP_TILED;
275 }
276 else
277 {
278 if (edge_constraints & GDK_TOPLEVEL_STATE_TOP_TILED)
279 local_set |= GDK_TOPLEVEL_STATE_TOP_TILED;
280 }
281
282 if (old_state & GDK_TOPLEVEL_STATE_TOP_RESIZABLE)
283 {
284 if ((edge_constraints & GDK_TOPLEVEL_STATE_TOP_RESIZABLE) == 0)
285 local_unset |= GDK_TOPLEVEL_STATE_TOP_RESIZABLE;
286 }
287 else
288 {
289 if (edge_constraints & GDK_TOPLEVEL_STATE_TOP_RESIZABLE)
290 local_set |= GDK_TOPLEVEL_STATE_TOP_RESIZABLE;
291 }
292
293 /* Right edge */
294 if (old_state & GDK_TOPLEVEL_STATE_RIGHT_TILED)
295 {
296 if ((edge_constraints & GDK_TOPLEVEL_STATE_RIGHT_TILED) == 0)
297 local_unset |= GDK_TOPLEVEL_STATE_RIGHT_TILED;
298 }
299 else
300 {
301 if (edge_constraints & GDK_TOPLEVEL_STATE_RIGHT_TILED)
302 local_set |= GDK_TOPLEVEL_STATE_RIGHT_TILED;
303 }
304
305 if (old_state & GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE)
306 {
307 if ((edge_constraints & GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE) == 0)
308 local_unset |= GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE;
309 }
310 else
311 {
312 if (edge_constraints & GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE)
313 local_set |= GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE;
314 }
315
316 /* Bottom edge */
317 if (old_state & GDK_TOPLEVEL_STATE_BOTTOM_TILED)
318 {
319 if ((edge_constraints & GDK_TOPLEVEL_STATE_BOTTOM_TILED) == 0)
320 local_unset |= GDK_TOPLEVEL_STATE_BOTTOM_TILED;
321 }
322 else
323 {
324 if (edge_constraints & GDK_TOPLEVEL_STATE_BOTTOM_TILED)
325 local_set |= GDK_TOPLEVEL_STATE_BOTTOM_TILED;
326 }
327
328 if (old_state & GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE)
329 {
330 if ((edge_constraints & GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE) == 0)
331 local_unset |= GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE;
332 }
333 else
334 {
335 if (edge_constraints & GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE)
336 local_set |= GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE;
337 }
338
339 /* Left edge */
340 if (old_state & GDK_TOPLEVEL_STATE_LEFT_TILED)
341 {
342 if ((edge_constraints & GDK_TOPLEVEL_STATE_LEFT_TILED) == 0)
343 local_unset |= GDK_TOPLEVEL_STATE_LEFT_TILED;
344 }
345 else
346 {
347 if (edge_constraints & GDK_TOPLEVEL_STATE_LEFT_TILED)
348 local_set |= GDK_TOPLEVEL_STATE_LEFT_TILED;
349 }
350
351 if (old_state & GDK_TOPLEVEL_STATE_LEFT_RESIZABLE)
352 {
353 if ((edge_constraints & GDK_TOPLEVEL_STATE_LEFT_RESIZABLE) == 0)
354 local_unset |= GDK_TOPLEVEL_STATE_LEFT_RESIZABLE;
355 }
356 else
357 {
358 if (edge_constraints & GDK_TOPLEVEL_STATE_LEFT_RESIZABLE)
359 local_set |= GDK_TOPLEVEL_STATE_LEFT_RESIZABLE;
360 }
361
362 *set = local_set;
363 *unset = local_unset;
364 }
365
366 static void
do_net_wm_state_changes(GdkSurface * surface)367 do_net_wm_state_changes (GdkSurface *surface)
368 {
369 GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface);
370 GdkToplevelState old_state, set, unset;
371
372 if (GDK_SURFACE_DESTROYED (surface) ||
373 !GDK_IS_TOPLEVEL (surface))
374 return;
375
376 old_state = gdk_toplevel_get_state (GDK_TOPLEVEL (surface));
377
378 set = unset = 0;
379
380 if (old_state & GDK_TOPLEVEL_STATE_FULLSCREEN)
381 {
382 if (!toplevel->have_fullscreen)
383 unset |= GDK_TOPLEVEL_STATE_FULLSCREEN;
384 }
385 else
386 {
387 if (toplevel->have_fullscreen)
388 set |= GDK_TOPLEVEL_STATE_FULLSCREEN;
389 }
390
391 /* Our "maximized" means both vertical and horizontal; if only one,
392 * we don't expose that via GDK
393 */
394 if (old_state & GDK_TOPLEVEL_STATE_MAXIMIZED)
395 {
396 if (!(toplevel->have_maxvert && toplevel->have_maxhorz))
397 unset |= GDK_TOPLEVEL_STATE_MAXIMIZED;
398 }
399 else
400 {
401 if (toplevel->have_maxvert && toplevel->have_maxhorz)
402 set |= GDK_TOPLEVEL_STATE_MAXIMIZED;
403 }
404
405 if (old_state & GDK_TOPLEVEL_STATE_FOCUSED)
406 {
407 if (!toplevel->have_focused)
408 unset |= GDK_TOPLEVEL_STATE_FOCUSED;
409 }
410 else
411 {
412 if (toplevel->have_focused)
413 set |= GDK_TOPLEVEL_STATE_FOCUSED;
414 }
415
416 if (old_state & GDK_TOPLEVEL_STATE_MINIMIZED)
417 {
418 if (!toplevel->have_hidden)
419 unset |= GDK_TOPLEVEL_STATE_MINIMIZED;
420 }
421 else
422 {
423 if (toplevel->have_hidden)
424 set |= GDK_TOPLEVEL_STATE_MINIMIZED;
425 }
426
427 /* Update edge constraints and tiling */
428 do_edge_constraint_state_check (surface, old_state, &set, &unset);
429
430 gdk_synthesize_surface_state (surface, unset, set);
431 }
432
433 static void
gdk_check_wm_desktop_changed(GdkSurface * surface)434 gdk_check_wm_desktop_changed (GdkSurface *surface)
435 {
436 GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface);
437 GdkDisplay *display = GDK_SURFACE_DISPLAY (surface);
438
439 Atom type;
440 int format;
441 gulong nitems;
442 gulong bytes_after;
443 guchar *data;
444 gulong *desktop;
445
446 type = None;
447 gdk_x11_display_error_trap_push (display);
448 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
449 GDK_SURFACE_XID (surface),
450 gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
451 0, G_MAXLONG, False, XA_CARDINAL, &type,
452 &format, &nitems,
453 &bytes_after, &data);
454 gdk_x11_display_error_trap_pop_ignored (display);
455
456 if (type != None)
457 {
458 desktop = (gulong *)data;
459 toplevel->on_all_desktops = ((*desktop & 0xFFFFFFFF) == 0xFFFFFFFF);
460 XFree (desktop);
461 }
462 else
463 toplevel->on_all_desktops = FALSE;
464
465 do_net_wm_state_changes (surface);
466 }
467
468 static void
gdk_check_wm_state_changed(GdkSurface * surface)469 gdk_check_wm_state_changed (GdkSurface *surface)
470 {
471 GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface);
472 GdkDisplay *display = GDK_SURFACE_DISPLAY (surface);
473 GdkX11Screen *screen = GDK_SURFACE_SCREEN (surface);
474
475 Atom type;
476 int format;
477 gulong nitems;
478 gulong bytes_after;
479 guchar *data;
480 Atom *atoms = NULL;
481 gulong i;
482
483 toplevel->have_maxvert = FALSE;
484 toplevel->have_maxhorz = FALSE;
485 toplevel->have_fullscreen = FALSE;
486 toplevel->have_focused = FALSE;
487 toplevel->have_hidden = FALSE;
488
489 type = None;
490 gdk_x11_display_error_trap_push (display);
491 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (surface),
492 gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
493 0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
494 &bytes_after, &data);
495 gdk_x11_display_error_trap_pop_ignored (display);
496
497 if (type != None)
498 {
499 Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
500 Atom maxhorz_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
501 Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
502 Atom focused_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FOCUSED");
503 Atom hidden_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_HIDDEN");
504
505 atoms = (Atom *)data;
506
507 i = 0;
508 while (i < nitems)
509 {
510 if (atoms[i] == maxvert_atom)
511 toplevel->have_maxvert = TRUE;
512 else if (atoms[i] == maxhorz_atom)
513 toplevel->have_maxhorz = TRUE;
514 else if (atoms[i] == fullscreen_atom)
515 toplevel->have_fullscreen = TRUE;
516 else if (atoms[i] == focused_atom)
517 toplevel->have_focused = TRUE;
518 else if (atoms[i] == hidden_atom)
519 toplevel->have_hidden = TRUE;
520
521 ++i;
522 }
523
524 XFree (atoms);
525 }
526
527 if (!gdk_x11_screen_supports_net_wm_hint (screen,
528 g_intern_static_string ("_NET_WM_STATE_FOCUSED")))
529 toplevel->have_focused = TRUE;
530
531 do_net_wm_state_changes (surface);
532 }
533
534 static void
gdk_check_edge_constraints_changed(GdkSurface * surface)535 gdk_check_edge_constraints_changed (GdkSurface *surface)
536 {
537 GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (surface);
538 GdkDisplay *display = GDK_SURFACE_DISPLAY (surface);
539
540 Atom type;
541 int format;
542 gulong nitems;
543 gulong bytes_after;
544 guchar *data;
545 gulong *constraints;
546
547 type = None;
548 gdk_x11_display_error_trap_push (display);
549 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
550 GDK_SURFACE_XID (surface),
551 gdk_x11_get_xatom_by_name_for_display (display, "_GTK_EDGE_CONSTRAINTS"),
552 0, G_MAXLONG, False, XA_CARDINAL, &type,
553 &format, &nitems,
554 &bytes_after, &data);
555 gdk_x11_display_error_trap_pop_ignored (display);
556
557 if (type != None)
558 {
559 constraints = (gulong *)data;
560
561 /* The GDK enum for these states does not begin at zero so, to avoid
562 * messing around with shifts, just make the passed value and GDK's
563 * enum values match by shifting to the first tiled state.
564 */
565 toplevel->edge_constraints = constraints[0] << 8;
566
567 XFree (constraints);
568 }
569 else
570 {
571 toplevel->edge_constraints = 0;
572 }
573
574 do_net_wm_state_changes (surface);
575 }
576
577 static Window
get_event_xwindow(const XEvent * xevent)578 get_event_xwindow (const XEvent *xevent)
579 {
580 Window xwindow;
581
582 switch (xevent->type)
583 {
584 case DestroyNotify:
585 xwindow = xevent->xdestroywindow.window;
586 break;
587 case UnmapNotify:
588 xwindow = xevent->xunmap.window;
589 break;
590 case MapNotify:
591 xwindow = xevent->xmap.window;
592 break;
593 case ConfigureNotify:
594 xwindow = xevent->xconfigure.window;
595 break;
596 case ReparentNotify:
597 xwindow = xevent->xreparent.window;
598 break;
599 case GravityNotify:
600 xwindow = xevent->xgravity.window;
601 break;
602 case CirculateNotify:
603 xwindow = xevent->xcirculate.window;
604 break;
605 default:
606 xwindow = xevent->xany.window;
607 }
608
609 return xwindow;
610 }
611
612 static GdkEvent *
gdk_x11_display_translate_event(GdkEventTranslator * translator,GdkDisplay * display,const XEvent * xevent)613 gdk_x11_display_translate_event (GdkEventTranslator *translator,
614 GdkDisplay *display,
615 const XEvent *xevent)
616 {
617 Window xwindow;
618 GdkSurface *surface;
619 GdkX11Surface *surface_impl = NULL;
620 GdkX11Screen *x11_screen = NULL;
621 GdkToplevelX11 *toplevel = NULL;
622 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
623 GdkEvent *event;
624
625 event = NULL;
626
627 xwindow = get_event_xwindow (xevent);
628 if (xwindow != xevent->xany.window)
629 return NULL;
630
631 surface = gdk_x11_surface_lookup_for_display (display, xwindow);
632 if (surface)
633 {
634 /* We may receive events such as NoExpose/GraphicsExpose
635 * and ShmCompletion for pixmaps
636 */
637 if (!GDK_IS_SURFACE (surface))
638 return NULL;
639
640 x11_screen = GDK_SURFACE_SCREEN (surface);
641 toplevel = _gdk_x11_surface_get_toplevel (surface);
642 surface_impl = GDK_X11_SURFACE (surface);
643
644 g_object_ref (surface);
645 }
646
647 if (surface && GDK_SURFACE_DESTROYED (surface))
648 {
649 if (xevent->type != DestroyNotify)
650 goto done;
651 }
652
653 if (xevent->type == DestroyNotify)
654 {
655 x11_screen = GDK_X11_DISPLAY (display)->screen;
656
657 if (x11_screen->wmspec_check_window == xevent->xdestroywindow.window)
658 {
659 x11_screen->wmspec_check_window = None;
660 x11_screen->last_wmspec_check_time = 0;
661 g_free (x11_screen->window_manager_name);
662 x11_screen->window_manager_name = g_strdup ("unknown");
663
664 /* careful, reentrancy */
665 _gdk_x11_screen_window_manager_changed (x11_screen);
666
667 goto done;
668 }
669 }
670
671 /* We do a "manual" conversion of the XEvent to a
672 * GdkEvent. The structures are mostly the same so
673 * the conversion is fairly straightforward. We also
674 * optionally print debugging info regarding events
675 * received.
676 */
677
678 switch (xevent->type)
679 {
680 case KeymapNotify:
681 GDK_DISPLAY_NOTE (display, EVENTS, g_message ("keymap notify"));
682
683 /* Not currently handled */
684 break;
685
686 case Expose:
687 GDK_DISPLAY_NOTE (display, EVENTS,
688 g_message ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d",
689 xevent->xexpose.window, xevent->xexpose.count,
690 xevent->xexpose.x, xevent->xexpose.y,
691 xevent->xexpose.width, xevent->xexpose.height));
692
693 if (surface == NULL)
694 break;
695
696 {
697 GdkRectangle expose_rect;
698 int x2, y2;
699
700 expose_rect.x = xevent->xexpose.x / surface_impl->surface_scale;
701 expose_rect.y = xevent->xexpose.y / surface_impl->surface_scale;
702
703 x2 = (xevent->xexpose.x + xevent->xexpose.width + surface_impl->surface_scale -1) / surface_impl->surface_scale;
704 expose_rect.width = x2 - expose_rect.x;
705
706 y2 = (xevent->xexpose.y + xevent->xexpose.height + surface_impl->surface_scale -1) / surface_impl->surface_scale;
707 expose_rect.height = y2 - expose_rect.y;
708
709 gdk_surface_invalidate_rect (surface, &expose_rect);
710 }
711
712 break;
713
714 case GraphicsExpose:
715 {
716 GdkRectangle expose_rect;
717 int x2, y2;
718
719 GDK_DISPLAY_NOTE (display, EVENTS,
720 g_message ("graphics expose:\tdrawable: %ld",
721 xevent->xgraphicsexpose.drawable));
722
723 if (surface == NULL)
724 break;
725
726 expose_rect.x = xevent->xgraphicsexpose.x / surface_impl->surface_scale;
727 expose_rect.y = xevent->xgraphicsexpose.y / surface_impl->surface_scale;
728
729 x2 = (xevent->xgraphicsexpose.x + xevent->xgraphicsexpose.width + surface_impl->surface_scale -1) / surface_impl->surface_scale;
730 expose_rect.width = x2 - expose_rect.x;
731
732 y2 = (xevent->xgraphicsexpose.y + xevent->xgraphicsexpose.height + surface_impl->surface_scale -1) / surface_impl->surface_scale;
733 expose_rect.height = y2 - expose_rect.y;
734
735 gdk_surface_invalidate_rect (surface, &expose_rect);
736 }
737 break;
738
739 case VisibilityNotify:
740 #ifdef G_ENABLE_DEBUG
741 if (GDK_DISPLAY_DEBUG_CHECK (display, EVENTS))
742 switch (xevent->xvisibility.state)
743 {
744 case VisibilityFullyObscured:
745 g_message ("visibility notify:\twindow: %ld none",
746 xevent->xvisibility.window);
747 break;
748 case VisibilityPartiallyObscured:
749 g_message ("visibility notify:\twindow: %ld partial",
750 xevent->xvisibility.window);
751 break;
752 case VisibilityUnobscured:
753 g_message ("visibility notify:\twindow: %ld full",
754 xevent->xvisibility.window);
755 break;
756 default:
757 break;
758 }
759 #endif /* G_ENABLE_DEBUG */
760 /* not handled */
761 break;
762
763 case CreateNotify:
764 GDK_DISPLAY_NOTE (display, EVENTS,
765 g_message ("create notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d parent: %ld ovr: %d",
766 xevent->xcreatewindow.window,
767 xevent->xcreatewindow.x,
768 xevent->xcreatewindow.y,
769 xevent->xcreatewindow.width,
770 xevent->xcreatewindow.height,
771 xevent->xcreatewindow.border_width,
772 xevent->xcreatewindow.parent,
773 xevent->xcreatewindow.override_redirect));
774 /* not really handled */
775 break;
776
777 case DestroyNotify:
778 GDK_DISPLAY_NOTE (display, EVENTS,
779 g_message ("destroy notify:\twindow: %ld",
780 xevent->xdestroywindow.window));
781
782 if (surface)
783 event = gdk_delete_event_new (surface);
784
785 if (surface && GDK_SURFACE_XID (surface) != x11_screen->xroot_window)
786 gdk_surface_destroy_notify (surface);
787
788 break;
789
790 case UnmapNotify:
791 GDK_DISPLAY_NOTE (display, EVENTS,
792 g_message ("unmap notify:\t\twindow: %ld",
793 xevent->xmap.window));
794
795 if (surface)
796 {
797 /* If the WM supports the _NET_WM_STATE_HIDDEN hint, we do not want to
798 * interpret UnmapNotify events as implying iconic state.
799 * http://bugzilla.gnome.org/show_bug.cgi?id=590726.
800 */
801 if (x11_screen &&
802 !gdk_x11_screen_supports_net_wm_hint (x11_screen,
803 g_intern_static_string ("_NET_WM_STATE_HIDDEN")))
804 {
805 /* If we are shown (not withdrawn) and get an unmap, it means we were
806 * iconified in the X sense. If we are withdrawn, and get an unmap, it
807 * means we hid the window ourselves, so we will have already flipped
808 * the minimized bit off.
809 */
810 if (GDK_SURFACE_IS_MAPPED (surface))
811 gdk_synthesize_surface_state (surface,
812 0,
813 GDK_TOPLEVEL_STATE_MINIMIZED);
814 }
815
816 if (surface_impl->toplevel &&
817 surface_impl->toplevel->frame_pending)
818 {
819 surface_impl->toplevel->frame_pending = FALSE;
820 gdk_surface_thaw_updates (surface);
821 }
822
823 if (toplevel)
824 gdk_surface_freeze_updates (surface);
825
826 _gdk_x11_surface_grab_check_unmap (surface, xevent->xany.serial);
827
828 gdk_profiler_add_markf (GDK_PROFILER_CURRENT_TIME, 0, "unmapped window", "0x%lx", GDK_SURFACE_XID (surface));
829 }
830
831 break;
832
833 case MapNotify:
834 GDK_DISPLAY_NOTE (display, EVENTS,
835 g_message ("map notify:\t\twindow: %ld",
836 xevent->xmap.window));
837
838 if (surface)
839 {
840 /* Unset minimized if it was set */
841 if (surface->state & GDK_TOPLEVEL_STATE_MINIMIZED)
842 gdk_synthesize_surface_state (surface,
843 GDK_TOPLEVEL_STATE_MINIMIZED,
844 0);
845
846 if (toplevel)
847 gdk_surface_thaw_updates (surface);
848
849 if (GDK_PROFILER_IS_RUNNING)
850 {
851 gdk_profiler_end_markf (surface_impl->map_time, "mapped window", "0x%lx", GDK_SURFACE_XID (surface));
852 surface_impl->map_time = 0;
853 }
854 }
855
856 break;
857
858 case ReparentNotify:
859 GDK_DISPLAY_NOTE (display, EVENTS,
860 g_message ("reparent notify:\twindow: %ld x,y: %d %d parent: %ld ovr: %d",
861 xevent->xreparent.window,
862 xevent->xreparent.x,
863 xevent->xreparent.y,
864 xevent->xreparent.parent,
865 xevent->xreparent.override_redirect));
866
867 /* Not currently handled */
868 break;
869
870 case ConfigureNotify:
871 GDK_DISPLAY_NOTE (display, EVENTS,
872 g_message ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d b-w: %d above: %ld ovr: %d%s",
873 xevent->xconfigure.window,
874 xevent->xconfigure.x,
875 xevent->xconfigure.y,
876 xevent->xconfigure.width,
877 xevent->xconfigure.height,
878 xevent->xconfigure.border_width,
879 xevent->xconfigure.above,
880 xevent->xconfigure.override_redirect,
881 !surface ? " (discarding)" : ""));
882 if (_gdk_x11_display_is_root_window (display, xevent->xconfigure.window))
883 {
884 _gdk_x11_screen_size_changed (x11_screen, xevent);
885 }
886
887 #ifdef HAVE_XSYNC
888 if (toplevel && display_x11->use_sync && toplevel->pending_counter_value != 0)
889 {
890 toplevel->configure_counter_value = toplevel->pending_counter_value;
891 toplevel->configure_counter_value_is_extended = toplevel->pending_counter_value_is_extended;
892 toplevel->pending_counter_value = 0;
893 }
894 #endif
895
896 if (surface &&
897 xevent->xconfigure.event == xevent->xconfigure.window)
898 {
899 int x, y;
900 int configured_width;
901 int configured_height;
902 int new_abs_x, new_abs_y;
903
904 configured_width =
905 (xevent->xconfigure.width + surface_impl->surface_scale - 1) /
906 surface_impl->surface_scale;
907 configured_height =
908 (xevent->xconfigure.height + surface_impl->surface_scale - 1) /
909 surface_impl->surface_scale;
910
911 if (!xevent->xconfigure.send_event &&
912 !xevent->xconfigure.override_redirect &&
913 !GDK_SURFACE_DESTROYED (surface))
914 {
915 int tx = 0;
916 int ty = 0;
917 Window child_window = 0;
918
919 x = y = 0;
920 gdk_x11_display_error_trap_push (display);
921 if (XTranslateCoordinates (GDK_SURFACE_XDISPLAY (surface),
922 GDK_SURFACE_XID (surface),
923 x11_screen->xroot_window,
924 0, 0,
925 &tx, &ty,
926 &child_window))
927 {
928 x = tx / surface_impl->surface_scale;
929 y = ty / surface_impl->surface_scale;
930 }
931 gdk_x11_display_error_trap_pop_ignored (display);
932 }
933 else
934 {
935 x = xevent->xconfigure.x / surface_impl->surface_scale;
936 y = xevent->xconfigure.y / surface_impl->surface_scale;
937 }
938
939 new_abs_x = x;
940 new_abs_y = y;
941
942 surface_impl->abs_x = new_abs_x;
943 surface_impl->abs_y = new_abs_y;
944
945 if (surface->parent)
946 {
947 GdkX11Surface *parent_impl =
948 GDK_X11_SURFACE (surface->parent);
949
950 surface->x = new_abs_x - parent_impl->abs_x;
951 surface->y = new_abs_y - parent_impl->abs_y;
952 }
953
954 if (surface_impl->unscaled_width != xevent->xconfigure.width ||
955 surface_impl->unscaled_height != xevent->xconfigure.height)
956 {
957 surface_impl->unscaled_width = xevent->xconfigure.width;
958 surface_impl->unscaled_height = xevent->xconfigure.height;
959
960 surface_impl->next_layout.configured_width = configured_width;
961 surface_impl->next_layout.configured_height = configured_height;
962 surface_impl->next_layout.surface_geometry_dirty = TRUE;
963 surface_impl->next_layout.configure_pending = TRUE;
964 gdk_surface_request_layout (surface);
965 }
966
967 if (surface->resize_count >= 1)
968 {
969 surface->resize_count -= 1;
970
971 if (surface->resize_count == 0)
972 _gdk_x11_moveresize_configure_done (display, surface);
973 }
974
975 gdk_x11_surface_update_popups (surface);
976 gdk_x11_surface_enter_leave_monitors (surface);
977 }
978 break;
979
980 case PropertyNotify:
981 GDK_DISPLAY_NOTE (display, EVENTS,
982 g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
983 xevent->xproperty.window,
984 xevent->xproperty.atom,
985 "\"",
986 gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom),
987 "\""));
988
989 if (surface == NULL)
990 break;
991
992 /* We compare with the serial of the last time we mapped the
993 * window to avoid refetching properties that we set ourselves
994 */
995 if (toplevel &&
996 xevent->xproperty.serial >= toplevel->map_serial)
997 {
998 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"))
999 gdk_check_wm_state_changed (surface);
1000
1001 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
1002 gdk_check_wm_desktop_changed (surface);
1003
1004 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_GTK_EDGE_CONSTRAINTS"))
1005 gdk_check_edge_constraints_changed (surface);
1006 }
1007 break;
1008
1009 case ColormapNotify:
1010 GDK_DISPLAY_NOTE (display, EVENTS,
1011 g_message ("colormap notify:\twindow: %ld",
1012 xevent->xcolormap.window));
1013
1014 /* Not currently handled */
1015 break;
1016
1017 case ClientMessage:
1018 GDK_DISPLAY_NOTE (display, EVENTS,
1019 g_message ("client message:\twindow: %ld",
1020 xevent->xclient.window));
1021
1022 /* Not currently handled */
1023 break;
1024
1025 case MappingNotify:
1026 GDK_DISPLAY_NOTE (display, EVENTS,
1027 g_message ("mapping notify"));
1028
1029 /* Let XLib know that there is a new keyboard mapping.
1030 */
1031 XRefreshKeyboardMapping ((XMappingEvent *) xevent);
1032 _gdk_x11_keymap_keys_changed (display);
1033 break;
1034
1035 default:
1036 #ifdef HAVE_RANDR
1037 if (xevent->type - display_x11->xrandr_event_base == RRScreenChangeNotify ||
1038 xevent->type - display_x11->xrandr_event_base == RRNotify)
1039 {
1040 if (display_x11->screen)
1041 _gdk_x11_screen_size_changed (display_x11->screen, xevent);
1042 }
1043 else
1044 #endif
1045 #ifdef HAVE_XKB
1046 if (xevent->type == display_x11->xkb_event_type)
1047 {
1048 XkbEvent *xkb_event = (XkbEvent *) xevent;
1049
1050 switch (xkb_event->any.xkb_type)
1051 {
1052 case XkbNewKeyboardNotify:
1053 case XkbMapNotify:
1054 _gdk_x11_keymap_keys_changed (display);
1055 break;
1056
1057 case XkbStateNotify:
1058 _gdk_x11_keymap_state_changed (display, xevent);
1059 break;
1060 default:
1061 break;
1062 }
1063 }
1064 #endif
1065 }
1066
1067 done:
1068 if (surface)
1069 g_object_unref (surface);
1070
1071 return event;
1072 }
1073
1074 static GdkFrameTimings *
find_frame_timings(GdkFrameClock * clock,guint64 serial)1075 find_frame_timings (GdkFrameClock *clock,
1076 guint64 serial)
1077 {
1078 gint64 start_frame, end_frame, i;
1079
1080 start_frame = gdk_frame_clock_get_history_start (clock);
1081 end_frame = gdk_frame_clock_get_frame_counter (clock);
1082 for (i = end_frame; i >= start_frame; i--)
1083 {
1084 GdkFrameTimings *timings = gdk_frame_clock_get_timings (clock, i);
1085
1086 if (timings->cookie == serial)
1087 return timings;
1088 }
1089
1090 return NULL;
1091 }
1092
1093 /* _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages represent time
1094 * as a "high resolution server time" - this is the server time interpolated
1095 * to microsecond resolution. The advantage of this time representation
1096 * is that if X server is running on the same computer as a client, and
1097 * the Xserver uses 'clock_gettime(CLOCK_MONOTONIC, ...)' for the server
1098 * time, the client can detect this, and all such clients will share a
1099 * a time representation with high accuracy. If there is not a common
1100 * time source, then the time synchronization will be less accurate.
1101 */
1102 static gint64
server_time_to_monotonic_time(GdkX11Display * display_x11,gint64 server_time)1103 server_time_to_monotonic_time (GdkX11Display *display_x11,
1104 gint64 server_time)
1105 {
1106 if (display_x11->server_time_query_time == 0 ||
1107 (!display_x11->server_time_is_monotonic_time &&
1108 server_time > display_x11->server_time_query_time + 10*1000*1000)) /* 10 seconds */
1109 {
1110 gint64 current_server_time = gdk_x11_get_server_time (display_x11->leader_gdk_surface);
1111 gint64 current_server_time_usec = (gint64)current_server_time * 1000;
1112 gint64 current_monotonic_time = g_get_monotonic_time ();
1113 display_x11->server_time_query_time = current_monotonic_time;
1114
1115 /* If the server time is within a second of the monotonic time,
1116 * we assume that they are identical. This seems like a big margin,
1117 * but we want to be as robust as possible even if the system
1118 * is under load and our processing of the server response is
1119 * delayed.
1120 */
1121 if (current_server_time_usec > current_monotonic_time - 1000*1000 &&
1122 current_server_time_usec < current_monotonic_time + 1000*1000)
1123 display_x11->server_time_is_monotonic_time = TRUE;
1124
1125 display_x11->server_time_offset = current_server_time_usec - current_monotonic_time;
1126 }
1127
1128 if (display_x11->server_time_is_monotonic_time)
1129 return server_time;
1130 else
1131 return server_time - display_x11->server_time_offset;
1132 }
1133
1134 GdkFilterReturn
_gdk_wm_protocols_filter(const XEvent * xevent,GdkSurface * win,GdkEvent ** event,gpointer data)1135 _gdk_wm_protocols_filter (const XEvent *xevent,
1136 GdkSurface *win,
1137 GdkEvent **event,
1138 gpointer data)
1139 {
1140 GdkDisplay *display;
1141 Atom atom;
1142
1143 if (!GDK_IS_X11_SURFACE (win) || GDK_SURFACE_DESTROYED (win))
1144 return GDK_FILTER_CONTINUE;
1145
1146 if (xevent->type != ClientMessage)
1147 return GDK_FILTER_CONTINUE;
1148
1149 display = GDK_SURFACE_DISPLAY (win);
1150
1151 /* This isn't actually WM_PROTOCOLS because that wouldn't leave enough space
1152 * in the message for everything that gets stuffed in */
1153 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN"))
1154 {
1155 GdkX11Surface *surface_impl;
1156 surface_impl = GDK_X11_SURFACE (win);
1157 if (surface_impl->toplevel)
1158 {
1159 guint32 d0 = xevent->xclient.data.l[0];
1160 guint32 d1 = xevent->xclient.data.l[1];
1161 guint32 d2 = xevent->xclient.data.l[2];
1162 guint32 d3 = xevent->xclient.data.l[3];
1163
1164 guint64 serial = ((guint64)d1 << 32) | d0;
1165 gint64 frame_drawn_time = server_time_to_monotonic_time (GDK_X11_DISPLAY (display), ((guint64)d3 << 32) | d2);
1166 gint64 refresh_interval, presentation_time;
1167
1168 GdkFrameClock *clock = gdk_surface_get_frame_clock (win);
1169 GdkFrameTimings *timings = find_frame_timings (clock, serial);
1170
1171 if (timings)
1172 timings->drawn_time = frame_drawn_time;
1173
1174 if (!surface_impl->toplevel->frame_still_painting && surface_impl->toplevel->frame_pending)
1175 {
1176 surface_impl->toplevel->frame_pending = FALSE;
1177 gdk_surface_thaw_updates (win);
1178 }
1179
1180 gdk_frame_clock_get_refresh_info (clock,
1181 frame_drawn_time,
1182 &refresh_interval,
1183 &presentation_time);
1184 if (presentation_time != 0)
1185 surface_impl->toplevel->throttled_presentation_time = presentation_time + refresh_interval;
1186 }
1187
1188 return GDK_FILTER_REMOVE;
1189 }
1190
1191 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_TIMINGS"))
1192 {
1193 GdkX11Surface *surface_impl;
1194 surface_impl = GDK_X11_SURFACE (win);
1195 if (surface_impl->toplevel)
1196 {
1197 guint32 d0 = xevent->xclient.data.l[0];
1198 guint32 d1 = xevent->xclient.data.l[1];
1199 guint32 d2 = xevent->xclient.data.l[2];
1200 guint32 d3 = xevent->xclient.data.l[3];
1201
1202 guint64 serial = ((guint64)d1 << 32) | d0;
1203
1204 GdkFrameClock *clock = gdk_surface_get_frame_clock (win);
1205 GdkFrameTimings *timings = find_frame_timings (clock, serial);
1206
1207 if (timings)
1208 {
1209 gint32 presentation_time_offset = (gint32)d2;
1210 gint32 refresh_interval = d3;
1211
1212 if (timings->drawn_time && presentation_time_offset)
1213 timings->presentation_time = timings->drawn_time + presentation_time_offset;
1214
1215 if (refresh_interval)
1216 timings->refresh_interval = refresh_interval;
1217
1218 timings->complete = TRUE;
1219 #ifdef G_ENABLE_DEBUG
1220 if (GDK_DISPLAY_DEBUG_CHECK (display, FRAMES))
1221 _gdk_frame_clock_debug_print_timings (clock, timings);
1222
1223 if (GDK_PROFILER_IS_RUNNING)
1224 _gdk_frame_clock_add_timings_to_profiler (clock, timings);
1225 #endif /* G_ENABLE_DEBUG */
1226 }
1227 }
1228 }
1229
1230 if (xevent->xclient.message_type != gdk_x11_get_xatom_by_name_for_display (display, "WM_PROTOCOLS"))
1231 return GDK_FILTER_CONTINUE;
1232
1233 atom = (Atom) xevent->xclient.data.l[0];
1234
1235 if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
1236 {
1237 /* The delete window request specifies a window
1238 * to delete. We don't actually destroy the
1239 * window because "it is only a request". (The
1240 * window might contain vital data that the
1241 * program does not want destroyed). Instead
1242 * the event is passed along to the program,
1243 * which should then destroy the window.
1244 */
1245 GDK_DISPLAY_NOTE (display, EVENTS,
1246 g_message ("delete window:\t\twindow: %ld",
1247 xevent->xclient.window));
1248
1249 *event = gdk_delete_event_new (win);
1250
1251 gdk_x11_surface_set_user_time (win, xevent->xclient.data.l[1]);
1252
1253 return GDK_FILTER_TRANSLATE;
1254 }
1255 else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
1256 {
1257 GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (win);
1258
1259 /* There is no way of knowing reliably whether we are viewable;
1260 * so trap errors asynchronously around the XSetInputFocus call
1261 */
1262 if (toplevel)
1263 {
1264 gdk_x11_display_error_trap_push (display);
1265 XSetInputFocus (GDK_DISPLAY_XDISPLAY (display),
1266 toplevel->focus_window,
1267 RevertToParent,
1268 xevent->xclient.data.l[1]);
1269 gdk_x11_display_error_trap_pop_ignored (display);
1270 }
1271
1272 return GDK_FILTER_REMOVE;
1273 }
1274 else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING") &&
1275 !_gdk_x11_display_is_root_window (display, xevent->xclient.window))
1276 {
1277 XClientMessageEvent xclient = xevent->xclient;
1278
1279 xclient.window = GDK_SURFACE_XROOTWIN (win);
1280 XSendEvent (GDK_SURFACE_XDISPLAY (win),
1281 xclient.window,
1282 False,
1283 SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
1284
1285 return GDK_FILTER_REMOVE;
1286 }
1287 else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST") &&
1288 GDK_X11_DISPLAY (display)->use_sync)
1289 {
1290 GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (win);
1291 if (toplevel)
1292 {
1293 #ifdef HAVE_XSYNC
1294 toplevel->pending_counter_value = xevent->xclient.data.l[2] + ((gint64)xevent->xclient.data.l[3] << 32);
1295 toplevel->pending_counter_value_is_extended = xevent->xclient.data.l[4] != 0;
1296 #endif
1297 }
1298 return GDK_FILTER_REMOVE;
1299 }
1300
1301 return GDK_FILTER_CONTINUE;
1302 }
1303
1304 static void
gdk_event_init(GdkDisplay * display)1305 gdk_event_init (GdkDisplay *display)
1306 {
1307 GdkX11Display *display_x11;
1308
1309 display_x11 = GDK_X11_DISPLAY (display);
1310 display_x11->event_source = gdk_x11_event_source_new (display);
1311
1312 gdk_x11_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
1313 GDK_EVENT_TRANSLATOR (display));
1314
1315 gdk_x11_event_source_add_translator ((GdkEventSource *) display_x11->event_source,
1316 GDK_EVENT_TRANSLATOR (display_x11->device_manager));
1317 }
1318
1319 static void
set_sm_client_id(GdkDisplay * display,const char * sm_client_id)1320 set_sm_client_id (GdkDisplay *display,
1321 const char *sm_client_id)
1322 {
1323 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
1324
1325 if (gdk_display_is_closed (display))
1326 return;
1327
1328 if (sm_client_id && strcmp (sm_client_id, ""))
1329 XChangeProperty (display_x11->xdisplay, display_x11->leader_window,
1330 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"),
1331 XA_STRING, 8, PropModeReplace, (guchar *)sm_client_id,
1332 strlen (sm_client_id));
1333 else
1334 XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
1335 gdk_x11_get_xatom_by_name_for_display (display, "SM_CLIENT_ID"));
1336 }
1337
1338 static void
gdk_x11_display_query_default_visual(GdkX11Display * self,Visual ** out_visual,int * out_depth)1339 gdk_x11_display_query_default_visual (GdkX11Display *self,
1340 Visual **out_visual,
1341 int *out_depth)
1342 {
1343 XVisualInfo template, *visinfo;
1344 int n_visuals;
1345 Display *dpy;
1346
1347 dpy = gdk_x11_display_get_xdisplay (GDK_DISPLAY (self));
1348
1349 template.screen = self->screen->screen_num;
1350 template.depth = 32;
1351 template.red_mask = 0xff0000;
1352 template.green_mask = 0x00ff00;
1353 template.blue_mask = 0x0000ff;
1354
1355 visinfo = XGetVisualInfo (dpy,
1356 VisualScreenMask | VisualDepthMask
1357 | VisualRedMaskMask | VisualGreenMaskMask | VisualBlueMaskMask,
1358 &template,
1359 &n_visuals);
1360 if (visinfo != NULL)
1361 {
1362 *out_visual = visinfo[0].visual;
1363 *out_depth = visinfo[0].depth;
1364 XFree (visinfo);
1365 return;
1366 }
1367
1368 *out_visual = DefaultVisual (dpy, self->screen->screen_num);
1369 *out_depth = DefaultDepth (dpy, self->screen->screen_num);
1370 }
1371
1372 static void
gdk_x11_display_init_leader_surface(GdkX11Display * self)1373 gdk_x11_display_init_leader_surface (GdkX11Display *self)
1374 {
1375 GdkDisplay *display = GDK_DISPLAY (self);
1376 Display *xdisplay = gdk_x11_display_get_xdisplay (display);
1377
1378 self->window_colormap = XCreateColormap (xdisplay,
1379 DefaultRootWindow (xdisplay),
1380 self->window_visual,
1381 AllocNone);
1382 gdk_display_set_rgba (display, self->window_depth == 32);
1383
1384 /* We need to initialize events after we have the screen
1385 * structures in places
1386 */
1387 _gdk_x11_xsettings_init (GDK_X11_SCREEN (self->screen));
1388
1389 self->device_manager = _gdk_x11_device_manager_new (display);
1390
1391 gdk_event_init (display);
1392
1393 self->leader_gdk_surface =
1394 _gdk_x11_display_create_surface (display,
1395 GDK_SURFACE_TEMP,
1396 NULL,
1397 -100, -100, 1, 1);
1398
1399 (_gdk_x11_surface_get_toplevel (self->leader_gdk_surface))->is_leader = TRUE;
1400 self->leader_window = GDK_SURFACE_XID (self->leader_gdk_surface);
1401 self->leader_window_title_set = FALSE;
1402 }
1403
1404 /**
1405 * gdk_x11_display_open:
1406 * @display_name: (nullable): name of the X display.
1407 * See the XOpenDisplay() for details.
1408 *
1409 * Tries to open a new display to the X server given by
1410 * @display_name. If opening the display fails, %NULL is
1411 * returned.
1412 *
1413 * Returns: (nullable) (transfer full): The new display
1414 */
1415 GdkDisplay *
gdk_x11_display_open(const char * display_name)1416 gdk_x11_display_open (const char *display_name)
1417 {
1418 Display *xdisplay;
1419 GdkDisplay *display;
1420 GdkX11Display *display_x11;
1421 int argc;
1422 char *argv[1];
1423 XClassHint *class_hint;
1424 int ignore;
1425 int maj, min;
1426 char *cm_name;
1427
1428 XInitThreads ();
1429
1430 xdisplay = XOpenDisplay (display_name);
1431 if (!xdisplay)
1432 return NULL;
1433
1434 display = g_object_new (GDK_TYPE_X11_DISPLAY, NULL);
1435 display_x11 = GDK_X11_DISPLAY (display);
1436
1437 display_x11->xdisplay = xdisplay;
1438
1439 /* Set up handlers for Xlib internal connections */
1440 XAddConnectionWatch (xdisplay, gdk_internal_connection_watch, NULL);
1441
1442 _gdk_x11_precache_atoms (display, precache_atoms, G_N_ELEMENTS (precache_atoms));
1443
1444 /* RandR must be initialized before we initialize the screens */
1445 display_x11->have_randr12 = FALSE;
1446 display_x11->have_randr13 = FALSE;
1447 display_x11->have_randr15 = FALSE;
1448 #ifdef HAVE_RANDR
1449 if (XRRQueryExtension (display_x11->xdisplay,
1450 &display_x11->xrandr_event_base, &ignore))
1451 {
1452 int major, minor;
1453
1454 XRRQueryVersion (display_x11->xdisplay, &major, &minor);
1455
1456 if ((major == 1 && minor >= 2) || major > 1) {
1457 display_x11->have_randr12 = TRUE;
1458 if (minor >= 3 || major > 1)
1459 display_x11->have_randr13 = TRUE;
1460 #ifdef HAVE_RANDR15
1461 if (minor >= 5 || major > 1)
1462 display_x11->have_randr15 = TRUE;
1463 #endif
1464 }
1465 }
1466 #endif
1467
1468 /* initialize the display's screens */
1469 display_x11->screen = _gdk_x11_screen_new (display, DefaultScreen (display_x11->xdisplay));
1470
1471 /* If GL is available we want to pick better default/rgba visuals,
1472 * as we care about GLX details such as alpha/depth/stencil depth,
1473 * stereo and double buffering
1474 *
1475 * Note that this also sets up the leader surface while creating the inital
1476 * GL context.
1477 */
1478 if (!gdk_display_prepare_gl (display, NULL))
1479 {
1480 gdk_x11_display_query_default_visual (display_x11, &display_x11->window_visual, &display_x11->window_depth);
1481 gdk_x11_display_init_leader_surface (display_x11);
1482 }
1483
1484 #ifdef HAVE_XFIXES
1485 if (XFixesQueryExtension (display_x11->xdisplay,
1486 &display_x11->xfixes_event_base,
1487 &ignore))
1488 {
1489 display_x11->have_xfixes = TRUE;
1490 }
1491 else
1492 #endif
1493 display_x11->have_xfixes = FALSE;
1494
1495 display_x11->have_shapes = FALSE;
1496 display_x11->have_input_shapes = FALSE;
1497
1498 if (XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (display), &display_x11->shape_event_base, &ignore))
1499 {
1500 display_x11->have_shapes = TRUE;
1501 #ifdef ShapeInput
1502 if (XShapeQueryVersion (GDK_DISPLAY_XDISPLAY (display), &maj, &min))
1503 display_x11->have_input_shapes = (maj == 1 && min >= 1);
1504 #endif
1505 }
1506
1507 gdk_display_set_input_shapes (display, display_x11->have_input_shapes);
1508
1509 display_x11->trusted_client = TRUE;
1510 {
1511 Window root, child;
1512 int rootx, rooty, winx, winy;
1513 unsigned int xmask;
1514
1515 gdk_x11_display_error_trap_push (display);
1516 XQueryPointer (display_x11->xdisplay,
1517 GDK_X11_SCREEN (display_x11->screen)->xroot_window,
1518 &root, &child, &rootx, &rooty, &winx, &winy, &xmask);
1519 if (G_UNLIKELY (gdk_x11_display_error_trap_pop (display) == BadWindow))
1520 {
1521 g_warning ("Connection to display %s appears to be untrusted. Pointer and keyboard grabs and inter-client communication may not work as expected.", gdk_display_get_name (display));
1522 display_x11->trusted_client = FALSE;
1523 }
1524 }
1525
1526 if (g_getenv ("GDK_SYNCHRONIZE"))
1527 XSynchronize (display_x11->xdisplay, True);
1528
1529 class_hint = XAllocClassHint();
1530 class_hint->res_name = (char *) g_get_prgname ();
1531 class_hint->res_class = (char *) g_get_prgname ();
1532
1533 /* XmbSetWMProperties sets the RESOURCE_NAME environment variable
1534 * from argv[0], so we just synthesize an argument array here.
1535 */
1536 argc = 1;
1537 argv[0] = (char *) g_get_prgname ();
1538
1539 XmbSetWMProperties (display_x11->xdisplay,
1540 display_x11->leader_window,
1541 NULL, NULL, argv, argc, NULL, NULL,
1542 class_hint);
1543 XFree (class_hint);
1544
1545 if (gdk_sm_client_id)
1546 set_sm_client_id (display, gdk_sm_client_id);
1547
1548 if (!gdk_running_in_sandbox ())
1549 {
1550 /* if sandboxed, we're likely in a pid namespace and would only confuse the wm with this */
1551 long pid = getpid ();
1552 XChangeProperty (display_x11->xdisplay,
1553 display_x11->leader_window,
1554 gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"),
1555 XA_CARDINAL, 32, PropModeReplace, (guchar *) & pid, 1);
1556 }
1557
1558 /* We don't yet know a valid time. */
1559 display_x11->user_time = 0;
1560
1561 #ifdef HAVE_XKB
1562 {
1563 int xkb_major = XkbMajorVersion;
1564 int xkb_minor = XkbMinorVersion;
1565 if (XkbLibraryVersion (&xkb_major, &xkb_minor))
1566 {
1567 xkb_major = XkbMajorVersion;
1568 xkb_minor = XkbMinorVersion;
1569
1570 if (XkbQueryExtension (display_x11->xdisplay,
1571 NULL, &display_x11->xkb_event_type, NULL,
1572 &xkb_major, &xkb_minor))
1573 {
1574 Bool detectable_autorepeat_supported;
1575
1576 display_x11->use_xkb = TRUE;
1577
1578 XkbSelectEvents (display_x11->xdisplay,
1579 XkbUseCoreKbd,
1580 XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
1581 XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
1582
1583 /* keep this in sync with _gdk_x11_keymap_state_changed() */
1584 XkbSelectEventDetails (display_x11->xdisplay,
1585 XkbUseCoreKbd, XkbStateNotify,
1586 XkbAllStateComponentsMask,
1587 XkbModifierStateMask|XkbGroupStateMask);
1588
1589 XkbSetDetectableAutoRepeat (display_x11->xdisplay,
1590 True,
1591 &detectable_autorepeat_supported);
1592
1593 GDK_NOTE (MISC, g_message ("Detectable autorepeat %s.",
1594 detectable_autorepeat_supported ?
1595 "supported" : "not supported"));
1596
1597 display_x11->have_xkb_autorepeat = detectable_autorepeat_supported;
1598 }
1599 }
1600 }
1601 #endif
1602
1603 display_x11->use_sync = FALSE;
1604 #ifdef HAVE_XSYNC
1605 {
1606 int major, minor;
1607 int error_base, event_base;
1608
1609 if (XSyncQueryExtension (display_x11->xdisplay,
1610 &event_base, &error_base) &&
1611 XSyncInitialize (display_x11->xdisplay,
1612 &major, &minor))
1613 display_x11->use_sync = TRUE;
1614 }
1615 #endif
1616
1617 #ifdef HAVE_XDAMAGE
1618 display_x11->have_damage = FALSE;
1619 if (XDamageQueryExtension (display_x11->xdisplay,
1620 &display_x11->damage_event_base,
1621 &display_x11->damage_error_base))
1622 display_x11->have_damage = TRUE;
1623 #endif
1624
1625 display->clipboard = gdk_x11_clipboard_new (display, "CLIPBOARD");
1626 display->primary_clipboard = gdk_x11_clipboard_new (display, "PRIMARY");
1627
1628 /*
1629 * It is important that we first request the selection
1630 * notification, and then setup the initial state of
1631 * is_composited to avoid a race condition here.
1632 */
1633 cm_name = g_strdup_printf ("_NET_WM_CM_S%d", DefaultScreen (GDK_DISPLAY_XDISPLAY (display)));
1634 gdk_x11_display_request_selection_notification (display, cm_name);
1635 gdk_display_set_composited (GDK_DISPLAY (display),
1636 XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
1637 gdk_x11_get_xatom_by_name_for_display (display, cm_name)) != None);
1638 g_free (cm_name);
1639
1640 gdk_display_emit_opened (display);
1641
1642 return display;
1643 }
1644
1645 /**
1646 * gdk_x11_display_set_program_class:
1647 * @display: a `GdkDisplay`
1648 * @program_class: a string
1649 *
1650 * Sets the program class.
1651 *
1652 * The X11 backend uses the program class to set the class name part
1653 * of the `WM_CLASS` property on toplevel windows; see the ICCCM.
1654 */
1655 void
gdk_x11_display_set_program_class(GdkDisplay * display,const char * program_class)1656 gdk_x11_display_set_program_class (GdkDisplay *display,
1657 const char *program_class)
1658 {
1659 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
1660 XClassHint *class_hint;
1661
1662 g_free (display_x11->program_class);
1663 display_x11->program_class = g_strdup (program_class);
1664
1665 class_hint = XAllocClassHint();
1666 class_hint->res_name = (char *) g_get_prgname ();
1667 class_hint->res_class = (char *) program_class;
1668 XSetClassHint (display_x11->xdisplay, display_x11->leader_window, class_hint);
1669 XFree (class_hint);
1670 }
1671
1672 /*
1673 * XLib internal connection handling
1674 */
1675 typedef struct _GdkInternalConnection GdkInternalConnection;
1676
1677 struct _GdkInternalConnection
1678 {
1679 int fd;
1680 GSource *source;
1681 Display *display;
1682 };
1683
1684 static gboolean
process_internal_connection(GIOChannel * gioc,GIOCondition cond,gpointer data)1685 process_internal_connection (GIOChannel *gioc,
1686 GIOCondition cond,
1687 gpointer data)
1688 {
1689 GdkInternalConnection *connection = (GdkInternalConnection *)data;
1690
1691 XProcessInternalConnection ((Display*)connection->display, connection->fd);
1692
1693 return TRUE;
1694 }
1695
1696 static gulong
gdk_x11_display_get_next_serial(GdkDisplay * display)1697 gdk_x11_display_get_next_serial (GdkDisplay *display)
1698 {
1699 return NextRequest (GDK_DISPLAY_XDISPLAY (display));
1700 }
1701
1702
1703 static GdkInternalConnection *
gdk_add_connection_handler(Display * display,guint fd)1704 gdk_add_connection_handler (Display *display,
1705 guint fd)
1706 {
1707 GIOChannel *io_channel;
1708 GdkInternalConnection *connection;
1709
1710 connection = g_new (GdkInternalConnection, 1);
1711
1712 connection->fd = fd;
1713 connection->display = display;
1714
1715 io_channel = g_io_channel_unix_new (fd);
1716
1717 connection->source = g_io_create_watch (io_channel, G_IO_IN);
1718 g_source_set_callback (connection->source,
1719 (GSourceFunc)process_internal_connection, connection, NULL);
1720 g_source_attach (connection->source, NULL);
1721
1722 g_io_channel_unref (io_channel);
1723
1724 return connection;
1725 }
1726
1727 static void
gdk_remove_connection_handler(GdkInternalConnection * connection)1728 gdk_remove_connection_handler (GdkInternalConnection *connection)
1729 {
1730 g_source_destroy (connection->source);
1731 g_free (connection);
1732 }
1733
1734 static void
gdk_internal_connection_watch(Display * display,XPointer arg,int fd,gboolean opening,XPointer * watch_data)1735 gdk_internal_connection_watch (Display *display,
1736 XPointer arg,
1737 int fd,
1738 gboolean opening,
1739 XPointer *watch_data)
1740 {
1741 if (opening)
1742 *watch_data = (XPointer)gdk_add_connection_handler (display, fd);
1743 else
1744 gdk_remove_connection_handler ((GdkInternalConnection *)*watch_data);
1745 }
1746
1747 static const char *
gdk_x11_display_get_name(GdkDisplay * display)1748 gdk_x11_display_get_name (GdkDisplay *display)
1749 {
1750 return (char *) DisplayString (GDK_X11_DISPLAY (display)->xdisplay);
1751 }
1752
1753 gboolean
_gdk_x11_display_is_root_window(GdkDisplay * display,Window xroot_window)1754 _gdk_x11_display_is_root_window (GdkDisplay *display,
1755 Window xroot_window)
1756 {
1757 GdkX11Display *display_x11;
1758
1759 display_x11 = GDK_X11_DISPLAY (display);
1760
1761 return GDK_SCREEN_XROOTWIN (display_x11->screen) == xroot_window;
1762 }
1763
1764 struct XPointerUngrabInfo {
1765 GdkDisplay *display;
1766 guint32 time;
1767 };
1768
1769 static void
device_grab_update_callback(GdkDisplay * display,gpointer data,gulong serial)1770 device_grab_update_callback (GdkDisplay *display,
1771 gpointer data,
1772 gulong serial)
1773 {
1774 GdkDevice *device = data;
1775
1776 _gdk_display_device_grab_update (display, device, serial);
1777 }
1778
1779 #define XSERVER_TIME_IS_LATER(time1, time2) \
1780 ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) || \
1781 (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 )) \
1782 )
1783
1784 void
_gdk_x11_display_update_grab_info(GdkDisplay * display,GdkDevice * device,int status)1785 _gdk_x11_display_update_grab_info (GdkDisplay *display,
1786 GdkDevice *device,
1787 int status)
1788 {
1789 if (status == GrabSuccess)
1790 _gdk_x11_roundtrip_async (display, device_grab_update_callback, device);
1791 }
1792
1793 void
_gdk_x11_display_update_grab_info_ungrab(GdkDisplay * display,GdkDevice * device,guint32 time,gulong serial)1794 _gdk_x11_display_update_grab_info_ungrab (GdkDisplay *display,
1795 GdkDevice *device,
1796 guint32 time,
1797 gulong serial)
1798 {
1799 GdkDeviceGrabInfo *grab;
1800
1801 XFlush (GDK_DISPLAY_XDISPLAY (display));
1802
1803 grab = _gdk_display_get_last_device_grab (display, device);
1804 if (grab &&
1805 (time == GDK_CURRENT_TIME ||
1806 grab->time == GDK_CURRENT_TIME ||
1807 !XSERVER_TIME_IS_LATER (grab->time, time)))
1808 {
1809 grab->serial_end = serial;
1810 _gdk_x11_roundtrip_async (display, device_grab_update_callback, device);
1811 }
1812 }
1813
1814 static void
gdk_x11_display_beep(GdkDisplay * display)1815 gdk_x11_display_beep (GdkDisplay *display)
1816 {
1817 if (!GDK_X11_DISPLAY (display)->trusted_client)
1818 return;
1819
1820 #ifdef HAVE_XKB
1821 XkbBell (GDK_DISPLAY_XDISPLAY (display), None, 0, None);
1822 #else
1823 XBell (GDK_DISPLAY_XDISPLAY (display), 0);
1824 #endif
1825 }
1826
1827 static void
gdk_x11_display_sync(GdkDisplay * display)1828 gdk_x11_display_sync (GdkDisplay *display)
1829 {
1830 XSync (GDK_DISPLAY_XDISPLAY (display), False);
1831 }
1832
1833 static void
gdk_x11_display_flush(GdkDisplay * display)1834 gdk_x11_display_flush (GdkDisplay *display)
1835 {
1836 if (!display->closed)
1837 XFlush (GDK_DISPLAY_XDISPLAY (display));
1838 }
1839
1840 static gboolean
gdk_x11_display_has_pending(GdkDisplay * display)1841 gdk_x11_display_has_pending (GdkDisplay *display)
1842 {
1843 return XPending (GDK_DISPLAY_XDISPLAY (display));
1844 }
1845
1846 /**
1847 * gdk_x11_display_get_default_group:
1848 * @display: (type GdkX11Display): a `GdkDisplay`
1849 *
1850 * Returns the default group leader surface for all toplevel surfaces
1851 * on @display. This surface is implicitly created by GDK.
1852 * See gdk_x11_surface_set_group().
1853 *
1854 * Returns: (transfer none): The default group leader surface
1855 * for @display
1856 */
1857 GdkSurface *
gdk_x11_display_get_default_group(GdkDisplay * display)1858 gdk_x11_display_get_default_group (GdkDisplay *display)
1859 {
1860 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1861
1862 return GDK_X11_DISPLAY (display)->leader_gdk_surface;
1863 }
1864
1865 /**
1866 * gdk_x11_display_grab:
1867 * @display: (type GdkX11Display): a `GdkDisplay`
1868 *
1869 * Call XGrabServer() on @display.
1870 * To ungrab the display again, use gdk_x11_display_ungrab().
1871 *
1872 * gdk_x11_display_grab()/gdk_x11_display_ungrab() calls can be nested.
1873 **/
1874 void
gdk_x11_display_grab(GdkDisplay * display)1875 gdk_x11_display_grab (GdkDisplay *display)
1876 {
1877 GdkX11Display *display_x11;
1878
1879 g_return_if_fail (GDK_IS_DISPLAY (display));
1880
1881 display_x11 = GDK_X11_DISPLAY (display);
1882
1883 if (display_x11->grab_count == 0)
1884 XGrabServer (display_x11->xdisplay);
1885 display_x11->grab_count++;
1886 }
1887
1888 /**
1889 * gdk_x11_display_ungrab:
1890 * @display: (type GdkX11Display): a `GdkDisplay`
1891 *
1892 * Ungrab @display after it has been grabbed with
1893 * gdk_x11_display_grab().
1894 **/
1895 void
gdk_x11_display_ungrab(GdkDisplay * display)1896 gdk_x11_display_ungrab (GdkDisplay *display)
1897 {
1898 GdkX11Display *display_x11;
1899
1900 g_return_if_fail (GDK_IS_DISPLAY (display));
1901
1902 display_x11 = GDK_X11_DISPLAY (display);;
1903 g_return_if_fail (display_x11->grab_count > 0);
1904
1905 display_x11->grab_count--;
1906 if (display_x11->grab_count == 0)
1907 {
1908 XUngrabServer (display_x11->xdisplay);
1909 XFlush (display_x11->xdisplay);
1910 }
1911 }
1912
1913 static void
gdk_x11_display_dispose(GObject * object)1914 gdk_x11_display_dispose (GObject *object)
1915 {
1916 GdkX11Display *display_x11 = GDK_X11_DISPLAY (object);
1917
1918 if (display_x11->event_source)
1919 {
1920 g_source_destroy (display_x11->event_source);
1921 g_source_unref (display_x11->event_source);
1922 display_x11->event_source = NULL;
1923 }
1924
1925 G_OBJECT_CLASS (gdk_x11_display_parent_class)->dispose (object);
1926 }
1927
1928 static void
gdk_x11_display_finalize(GObject * object)1929 gdk_x11_display_finalize (GObject *object)
1930 {
1931 GdkX11Display *display_x11 = GDK_X11_DISPLAY (object);
1932
1933 /* Keymap */
1934 if (display_x11->keymap)
1935 g_object_unref (display_x11->keymap);
1936
1937 _gdk_x11_cursor_display_finalize (GDK_DISPLAY (display_x11));
1938
1939 /* Get rid of pending streams */
1940 g_slist_free_full (display_x11->streams, g_object_unref);
1941
1942 /* Atom Hashtable */
1943 g_hash_table_destroy (display_x11->atom_from_string);
1944 g_hash_table_destroy (display_x11->atom_to_string);
1945
1946 /* Leader Window */
1947 XDestroyWindow (display_x11->xdisplay, display_x11->leader_window);
1948
1949 /* Free all GdkX11Screens */
1950 g_object_unref (display_x11->screen);
1951
1952 g_list_store_remove_all (display_x11->monitors);
1953 g_object_unref (display_x11->monitors);
1954
1955 g_free (display_x11->startup_notification_id);
1956
1957 /* X ID hashtable */
1958 g_hash_table_destroy (display_x11->xid_ht);
1959
1960 XCloseDisplay (display_x11->xdisplay);
1961
1962 g_clear_error (&display_x11->gl_error);
1963
1964 /* error traps */
1965 while (display_x11->error_traps != NULL)
1966 {
1967 GdkErrorTrap *trap = display_x11->error_traps->data;
1968
1969 display_x11->error_traps =
1970 g_slist_delete_link (display_x11->error_traps,
1971 display_x11->error_traps);
1972
1973 if (trap->end_sequence == 0)
1974 g_warning ("Display finalized with an unpopped error trap");
1975
1976 g_slice_free (GdkErrorTrap, trap);
1977 }
1978
1979 g_free (display_x11->program_class);
1980
1981 G_OBJECT_CLASS (gdk_x11_display_parent_class)->finalize (object);
1982 }
1983
1984 /**
1985 * gdk_x11_lookup_xdisplay:
1986 * @xdisplay: a pointer to an X Display
1987 *
1988 * Find the `GdkDisplay` corresponding to @xdisplay, if any exists.
1989 *
1990 * Returns: (transfer none) (type GdkX11Display): the `GdkDisplay`, if found, otherwise %NULL.
1991 **/
1992 GdkDisplay *
gdk_x11_lookup_xdisplay(Display * xdisplay)1993 gdk_x11_lookup_xdisplay (Display *xdisplay)
1994 {
1995 GSList *list, *l;
1996 GdkDisplay *display;
1997
1998 display = NULL;
1999
2000 list = gdk_display_manager_list_displays (gdk_display_manager_get ());
2001
2002 for (l = list; l; l = l->next)
2003 {
2004 if (GDK_IS_X11_DISPLAY (l->data) &&
2005 GDK_DISPLAY_XDISPLAY (l->data) == xdisplay)
2006 {
2007 display = l->data;
2008 break;
2009 }
2010 }
2011
2012 g_slist_free (list);
2013
2014 return display;
2015 }
2016
2017 /**
2018 * gdk_x11_display_get_xdisplay:
2019 * @display: (type GdkX11Display): a `GdkDisplay`
2020 *
2021 * Returns the X display of a `GdkDisplay`.
2022 *
2023 * Returns: (transfer none): an X display
2024 */
2025 Display *
gdk_x11_display_get_xdisplay(GdkDisplay * display)2026 gdk_x11_display_get_xdisplay (GdkDisplay *display)
2027 {
2028 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
2029
2030 return GDK_X11_DISPLAY (display)->xdisplay;
2031 }
2032
2033 /**
2034 * gdk_x11_display_get_xscreen:
2035 * @display: (type GdkX11Display): a `GdkDisplay`
2036 *
2037 * Returns the X Screen used by `GdkDisplay`.
2038 *
2039 * Returns: (transfer none): an X Screen
2040 */
2041 Screen *
gdk_x11_display_get_xscreen(GdkDisplay * display)2042 gdk_x11_display_get_xscreen (GdkDisplay *display)
2043 {
2044 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
2045
2046 return GDK_X11_SCREEN (GDK_X11_DISPLAY (display)->screen)->xscreen;
2047 }
2048
2049 /**
2050 * gdk_x11_display_get_xrootwindow:
2051 * @display: (type GdkX11Display): a `GdkDisplay`
2052 *
2053 * Returns the root X window used by `GdkDisplay`.
2054 *
2055 * Returns: an X Window
2056 */
2057 Window
gdk_x11_display_get_xrootwindow(GdkDisplay * display)2058 gdk_x11_display_get_xrootwindow (GdkDisplay *display)
2059 {
2060 g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
2061
2062 return GDK_SCREEN_XROOTWIN (GDK_X11_DISPLAY (display)->screen);
2063 }
2064
2065 static void
gdk_x11_display_make_default(GdkDisplay * display)2066 gdk_x11_display_make_default (GdkDisplay *display)
2067 {
2068 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
2069 const char *startup_id;
2070
2071 g_free (display_x11->startup_notification_id);
2072 display_x11->startup_notification_id = NULL;
2073
2074 startup_id = gdk_get_startup_notification_id ();
2075 if (startup_id)
2076 gdk_x11_display_set_startup_notification_id (display, startup_id);
2077 }
2078
2079 static void
broadcast_xmessage(GdkDisplay * display,const char * message_type,const char * message_type_begin,const char * message)2080 broadcast_xmessage (GdkDisplay *display,
2081 const char *message_type,
2082 const char *message_type_begin,
2083 const char *message)
2084 {
2085 Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
2086 Window xroot_window = GDK_DISPLAY_XROOTWIN (display);
2087
2088 Atom type_atom;
2089 Atom type_atom_begin;
2090 Window xwindow;
2091
2092 if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
2093 return;
2094
2095 {
2096 XSetWindowAttributes attrs;
2097
2098 attrs.override_redirect = True;
2099 attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
2100
2101 xwindow =
2102 XCreateWindow (xdisplay,
2103 xroot_window,
2104 -100, -100, 1, 1,
2105 0,
2106 CopyFromParent,
2107 CopyFromParent,
2108 (Visual *)CopyFromParent,
2109 CWOverrideRedirect | CWEventMask,
2110 &attrs);
2111 }
2112
2113 type_atom = gdk_x11_get_xatom_by_name_for_display (display, message_type);
2114 type_atom_begin = gdk_x11_get_xatom_by_name_for_display (display, message_type_begin);
2115
2116 {
2117 XClientMessageEvent xclient;
2118 const char *src;
2119 const char *src_end;
2120 char *dest;
2121 char *dest_end;
2122
2123 memset(&xclient, 0, sizeof (xclient));
2124 xclient.type = ClientMessage;
2125 xclient.message_type = type_atom_begin;
2126 xclient.display =xdisplay;
2127 xclient.window = xwindow;
2128 xclient.format = 8;
2129
2130 src = message;
2131 src_end = message + strlen (message) + 1; /* +1 to include nul byte */
2132
2133 while (src != src_end)
2134 {
2135 dest = &xclient.data.b[0];
2136 dest_end = dest + 20;
2137
2138 while (dest != dest_end &&
2139 src != src_end)
2140 {
2141 *dest = *src;
2142 ++dest;
2143 ++src;
2144 }
2145
2146 while (dest != dest_end)
2147 {
2148 *dest = 0;
2149 ++dest;
2150 }
2151
2152 XSendEvent (xdisplay,
2153 xroot_window,
2154 False,
2155 PropertyChangeMask,
2156 (XEvent *)&xclient);
2157
2158 xclient.message_type = type_atom;
2159 }
2160 }
2161
2162 XDestroyWindow (xdisplay, xwindow);
2163 XFlush (xdisplay);
2164 }
2165
2166 /**
2167 * gdk_x11_display_broadcast_startup_message:
2168 * @display: (type GdkX11Display): a `GdkDisplay`
2169 * @message_type: startup notification message type ("new", "change",
2170 * or "remove")
2171 * @...: a list of key/value pairs (as strings), terminated by a
2172 * %NULL key. (A %NULL value for a key will cause that key to be
2173 * skipped in the output.)
2174 *
2175 * Sends a startup notification message of type @message_type to
2176 * @display.
2177 *
2178 * This is a convenience function for use by code that implements the
2179 * freedesktop startup notification specification. Applications should
2180 * not normally need to call it directly. See the
2181 * [Startup Notification Protocol specification](http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt)
2182 * for definitions of the message types and keys that can be used.
2183 **/
2184 void
gdk_x11_display_broadcast_startup_message(GdkDisplay * display,const char * message_type,...)2185 gdk_x11_display_broadcast_startup_message (GdkDisplay *display,
2186 const char *message_type,
2187 ...)
2188 {
2189 GString *message;
2190 va_list ap;
2191 const char *key, *value, *p;
2192
2193 message = g_string_new (message_type);
2194 g_string_append_c (message, ':');
2195
2196 va_start (ap, message_type);
2197 while ((key = va_arg (ap, const char *)))
2198 {
2199 value = va_arg (ap, const char *);
2200 if (!value)
2201 continue;
2202
2203 g_string_append_printf (message, " %s=\"", key);
2204 for (p = value; *p; p++)
2205 {
2206 switch (*p)
2207 {
2208 case ' ':
2209 case '"':
2210 case '\\':
2211 g_string_append_c (message, '\\');
2212 break;
2213 default:
2214 break;
2215 }
2216
2217 g_string_append_c (message, *p);
2218 }
2219 g_string_append_c (message, '\"');
2220 }
2221 va_end (ap);
2222
2223 broadcast_xmessage (display,
2224 "_NET_STARTUP_INFO",
2225 "_NET_STARTUP_INFO_BEGIN",
2226 message->str);
2227
2228 g_string_free (message, TRUE);
2229 }
2230
2231 static void
gdk_x11_display_notify_startup_complete(GdkDisplay * display,const char * startup_id)2232 gdk_x11_display_notify_startup_complete (GdkDisplay *display,
2233 const char *startup_id)
2234 {
2235 char *free_this = NULL;
2236
2237 if (startup_id == NULL)
2238 {
2239 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
2240
2241 startup_id = free_this = display_x11->startup_notification_id;
2242 display_x11->startup_notification_id = NULL;
2243
2244 if (startup_id == NULL)
2245 return;
2246 }
2247
2248 gdk_x11_display_broadcast_startup_message (display, "remove",
2249 "ID", startup_id,
2250 NULL);
2251
2252 g_free (free_this);
2253 }
2254
2255 gboolean
gdk_x11_display_request_selection_notification(GdkDisplay * display,const char * selection)2256 gdk_x11_display_request_selection_notification (GdkDisplay *display,
2257 const char *selection)
2258
2259 {
2260 #ifdef HAVE_XFIXES
2261 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
2262 Atom atom;
2263
2264 if (display_x11->have_xfixes)
2265 {
2266 atom = gdk_x11_get_xatom_by_name_for_display (display, selection);
2267 XFixesSelectSelectionInput (display_x11->xdisplay,
2268 display_x11->leader_window,
2269 atom,
2270 XFixesSetSelectionOwnerNotifyMask |
2271 XFixesSelectionWindowDestroyNotifyMask |
2272 XFixesSelectionClientCloseNotifyMask);
2273 return TRUE;
2274 }
2275 else
2276 #endif
2277 return FALSE;
2278 }
2279
2280 /**
2281 * gdk_x11_display_get_user_time:
2282 * @display: (type GdkX11Display): a `GdkDisplay`
2283 *
2284 * Returns the timestamp of the last user interaction on
2285 * @display. The timestamp is taken from events caused
2286 * by user interaction such as key presses or pointer
2287 * movements. See gdk_x11_surface_set_user_time().
2288 *
2289 * Returns: the timestamp of the last user interaction
2290 */
2291 guint32
gdk_x11_display_get_user_time(GdkDisplay * display)2292 gdk_x11_display_get_user_time (GdkDisplay *display)
2293 {
2294 return GDK_X11_DISPLAY (display)->user_time;
2295 }
2296
2297 /**
2298 * gdk_x11_display_get_startup_notification_id:
2299 * @display: (type GdkX11Display): a `GdkDisplay`
2300 *
2301 * Gets the startup notification ID for a display.
2302 *
2303 * Returns: the startup notification ID for @display
2304 */
2305 const char *
gdk_x11_display_get_startup_notification_id(GdkDisplay * display)2306 gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
2307 {
2308 return GDK_X11_DISPLAY (display)->startup_notification_id;
2309 }
2310
2311 /**
2312 * gdk_x11_display_set_startup_notification_id:
2313 * @display: (type GdkX11Display): a `GdkDisplay`
2314 * @startup_id: the startup notification ID (must be valid utf8)
2315 *
2316 * Sets the startup notification ID for a display.
2317 *
2318 * This is usually taken from the value of the DESKTOP_STARTUP_ID
2319 * environment variable, but in some cases (such as the application not
2320 * being launched using exec()) it can come from other sources.
2321 *
2322 * If the ID contains the string "_TIME" then the portion following that
2323 * string is taken to be the X11 timestamp of the event that triggered
2324 * the application to be launched and the GDK current event time is set
2325 * accordingly.
2326 *
2327 * The startup ID is also what is used to signal that the startup is
2328 * complete (for example, when opening a window or when calling
2329 * gdk_display_notify_startup_complete()).
2330 **/
2331 void
gdk_x11_display_set_startup_notification_id(GdkDisplay * display,const char * startup_id)2332 gdk_x11_display_set_startup_notification_id (GdkDisplay *display,
2333 const char *startup_id)
2334 {
2335 GdkX11Display *display_x11;
2336 char *time_str;
2337
2338 display_x11 = GDK_X11_DISPLAY (display);
2339
2340 g_free (display_x11->startup_notification_id);
2341 display_x11->startup_notification_id = g_strdup (startup_id);
2342
2343 if (startup_id != NULL)
2344 {
2345 /* Find the launch time from the startup_id, if it's there. Newer spec
2346 * states that the startup_id is of the form <unique>_TIME<timestamp>
2347 */
2348 time_str = g_strrstr (startup_id, "_TIME");
2349 if (time_str != NULL)
2350 {
2351 gulong retval;
2352 char *end;
2353 errno = 0;
2354
2355 /* Skip past the "_TIME" part */
2356 time_str += 5;
2357
2358 retval = strtoul (time_str, &end, 0);
2359 if (end != time_str && errno == 0)
2360 display_x11->user_time = retval;
2361 }
2362 else
2363 display_x11->user_time = 0;
2364
2365 /* Set the startup id on the leader window so it
2366 * applies to all windows we create on this display
2367 */
2368 XChangeProperty (display_x11->xdisplay,
2369 display_x11->leader_window,
2370 gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
2371 gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
2372 PropModeReplace,
2373 (guchar *)startup_id, strlen (startup_id));
2374 }
2375 else
2376 {
2377 XDeleteProperty (display_x11->xdisplay, display_x11->leader_window,
2378 gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"));
2379 display_x11->user_time = 0;
2380 }
2381 }
2382
2383 /* look up the extension name for a given major opcode. grubs around in
2384 * xlib to do it since a) it’s already cached there b) XQueryExtension
2385 * emits protocol so we can’t use it in an error handler.
2386 */
2387 static const char *
_gdk_x11_decode_request_code(Display * dpy,int code)2388 _gdk_x11_decode_request_code(Display *dpy, int code)
2389 {
2390 _XExtension *ext;
2391
2392 if (code < 128)
2393 return "core protocol";
2394
2395 for (ext = dpy->ext_procs; ext; ext = ext->next)
2396 {
2397 if (ext->codes.major_opcode == code)
2398 return ext->name;
2399 }
2400
2401 return "unknown";
2402 }
2403
2404 /* compare X sequence numbers handling wraparound */
2405 #define SEQUENCE_COMPARE(a,op,b) (((long) (a) - (long) (b)) op 0)
2406
2407 /* delivers an error event from the error handler in gdkmain-x11.c */
2408 void
_gdk_x11_display_error_event(GdkDisplay * display,XErrorEvent * error)2409 _gdk_x11_display_error_event (GdkDisplay *display,
2410 XErrorEvent *error)
2411 {
2412 GdkX11Display *display_x11;
2413 GSList *tmp_list;
2414 gboolean ignore;
2415
2416 display_x11 = GDK_X11_DISPLAY (display);
2417
2418 ignore = FALSE;
2419 for (tmp_list = display_x11->error_traps;
2420 tmp_list != NULL;
2421 tmp_list = tmp_list->next)
2422 {
2423 GdkErrorTrap *trap;
2424
2425 trap = tmp_list->data;
2426
2427 if (SEQUENCE_COMPARE (trap->start_sequence, <=, error->serial) &&
2428 (trap->end_sequence == 0 ||
2429 SEQUENCE_COMPARE (trap->end_sequence, >, error->serial)))
2430 {
2431 ignore = TRUE;
2432 trap->error_code = error->error_code;
2433 break; /* only innermost trap gets the error code */
2434 }
2435 }
2436
2437 if (!ignore)
2438 {
2439 char buf[64];
2440 char *msg;
2441
2442 XGetErrorText (display_x11->xdisplay, error->error_code, buf, 63);
2443
2444 msg =
2445 g_strdup_printf ("The program '%s' received an X Window System error.\n"
2446 "This probably reflects a bug in the program.\n"
2447 "The error was '%s'.\n"
2448 " (Details: serial %ld error_code %d request_code %d (%s) minor_code %d)\n"
2449 " (Note to programmers: normally, X errors are reported asynchronously;\n"
2450 " that is, you will receive the error a while after causing it.\n"
2451 " To debug your program, run it with the GDK_SYNCHRONIZE environment\n"
2452 " variable to change this behavior. You can then get a meaningful\n"
2453 " backtrace from your debugger if you break on the gdk_x_error() function.)",
2454 g_get_prgname (),
2455 buf,
2456 error->serial,
2457 error->error_code,
2458 error->request_code,
2459 _gdk_x11_decode_request_code(display_x11->xdisplay,
2460 error->request_code),
2461 error->minor_code);
2462
2463 #ifdef G_ENABLE_DEBUG
2464 g_error ("%s", msg);
2465 #else /* !G_ENABLE_DEBUG */
2466 g_warning ("%s", msg);
2467
2468 _exit (1);
2469 #endif /* G_ENABLE_DEBUG */
2470 }
2471 }
2472
2473 static void
delete_outdated_error_traps(GdkX11Display * display_x11)2474 delete_outdated_error_traps (GdkX11Display *display_x11)
2475 {
2476 GSList *tmp_list;
2477 gulong processed_sequence;
2478
2479 processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
2480
2481 tmp_list = display_x11->error_traps;
2482 while (tmp_list != NULL)
2483 {
2484 GdkErrorTrap *trap = tmp_list->data;
2485
2486 if (trap->end_sequence != 0 &&
2487 SEQUENCE_COMPARE (trap->end_sequence, <=, processed_sequence))
2488 {
2489 GSList *free_me = tmp_list;
2490
2491 tmp_list = tmp_list->next;
2492 display_x11->error_traps =
2493 g_slist_delete_link (display_x11->error_traps, free_me);
2494 g_slice_free (GdkErrorTrap, trap);
2495 }
2496 else
2497 {
2498 tmp_list = tmp_list->next;
2499 }
2500 }
2501 }
2502
2503 /**
2504 * gdk_x11_display_error_trap_push:
2505 * @display: (type GdkX11Display): a `GdkDisplay`
2506 *
2507 * Begins a range of X requests on @display for which X error events
2508 * will be ignored. Unignored errors (when no trap is pushed) will abort
2509 * the application. Use gdk_x11_display_error_trap_pop() or
2510 * gdk_x11_display_error_trap_pop_ignored()to lift a trap pushed
2511 * with this function.
2512 */
2513 void
gdk_x11_display_error_trap_push(GdkDisplay * display)2514 gdk_x11_display_error_trap_push (GdkDisplay *display)
2515 {
2516 GdkX11Display *display_x11;
2517 GdkErrorTrap *trap;
2518
2519 display_x11 = GDK_X11_DISPLAY (display);
2520
2521 delete_outdated_error_traps (display_x11);
2522
2523 /* set up the Xlib callback to tell us about errors */
2524 _gdk_x11_error_handler_push ();
2525
2526 trap = g_slice_new0 (GdkErrorTrap);
2527
2528 trap->start_sequence = XNextRequest (display_x11->xdisplay);
2529 trap->error_code = Success;
2530
2531 display_x11->error_traps =
2532 g_slist_prepend (display_x11->error_traps, trap);
2533 }
2534
2535 static int
gdk_x11_display_error_trap_pop_internal(GdkDisplay * display,gboolean need_code)2536 gdk_x11_display_error_trap_pop_internal (GdkDisplay *display,
2537 gboolean need_code)
2538 {
2539 GdkX11Display *display_x11;
2540 GdkErrorTrap *trap;
2541 GSList *tmp_list;
2542 int result;
2543
2544 display_x11 = GDK_X11_DISPLAY (display);
2545
2546 g_return_val_if_fail (display_x11->error_traps != NULL, Success);
2547
2548 /* Find the first trap that hasn't been popped already */
2549 trap = NULL; /* quiet gcc */
2550 for (tmp_list = display_x11->error_traps;
2551 tmp_list != NULL;
2552 tmp_list = tmp_list->next)
2553 {
2554 trap = tmp_list->data;
2555
2556 if (trap->end_sequence == 0)
2557 break;
2558 }
2559
2560 if (trap == NULL)
2561 {
2562 g_critical ("gdk_x11_display_error_trap_pop() called without gdk_x11_display_error_trap_push()");
2563 return Success;
2564 }
2565 g_assert (trap->end_sequence == 0);
2566
2567 /* May need to sync to fill in trap->error_code if we care about
2568 * getting an error code.
2569 */
2570 if (need_code)
2571 {
2572 gulong processed_sequence;
2573 gulong next_sequence;
2574
2575 next_sequence = XNextRequest (display_x11->xdisplay);
2576 processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
2577
2578 /* If our last request was already processed, there is no point
2579 * in syncing. i.e. if last request was a round trip (or even if
2580 * we got an event with the serial of a non-round-trip)
2581 */
2582 if ((next_sequence - 1) != processed_sequence)
2583 {
2584 XSync (display_x11->xdisplay, False);
2585 }
2586
2587 result = trap->error_code;
2588 }
2589 else
2590 {
2591 result = Success;
2592 }
2593
2594 /* record end of trap, giving us a range of
2595 * error sequences we'll ignore.
2596 */
2597 trap->end_sequence = XNextRequest (display_x11->xdisplay);
2598
2599 /* remove the Xlib callback */
2600 _gdk_x11_error_handler_pop ();
2601
2602 /* we may already be outdated */
2603 delete_outdated_error_traps (display_x11);
2604
2605 return result;
2606 }
2607
2608 /**
2609 * gdk_x11_display_set_surface_scale:
2610 * @display: (type GdkX11Display): the display
2611 * @scale: The new scale value
2612 *
2613 * Forces a specific window scale for all windows on this display,
2614 * instead of using the default or user configured scale. This
2615 * is can be used to disable scaling support by setting @scale to
2616 * 1, or to programmatically set the window scale.
2617 *
2618 * Once the scale is set by this call it will not change in response
2619 * to later user configuration changes.
2620 */
2621 void
gdk_x11_display_set_surface_scale(GdkDisplay * display,int scale)2622 gdk_x11_display_set_surface_scale (GdkDisplay *display,
2623 int scale)
2624 {
2625 GdkX11Screen *x11_screen;
2626 gboolean need_reread_settings = FALSE;
2627
2628 g_return_if_fail (GDK_IS_X11_DISPLAY (display));
2629
2630 scale = MAX (scale, 1);
2631
2632 x11_screen = GDK_X11_SCREEN (GDK_X11_DISPLAY (display)->screen);
2633
2634 if (!x11_screen->fixed_surface_scale)
2635 {
2636 x11_screen->fixed_surface_scale = TRUE;
2637
2638 /* We treat screens with a window scale set differently when
2639 * reading xsettings, so we need to reread
2640 */
2641 need_reread_settings = TRUE;
2642 }
2643
2644 _gdk_x11_screen_set_surface_scale (x11_screen, scale);
2645
2646 if (need_reread_settings)
2647 _gdk_x11_settings_force_reread (x11_screen);
2648 }
2649
2650
2651 /**
2652 * gdk_x11_display_error_trap_pop:
2653 * @display: (type GdkX11Display): the display
2654 *
2655 * Pops the error trap pushed by gdk_x11_display_error_trap_push().
2656 * Will XSync() if necessary and will always block until
2657 * the error is known to have occurred or not occurred,
2658 * so the error code can be returned.
2659 *
2660 * If you don’t need to use the return value,
2661 * gdk_x11_display_error_trap_pop_ignored() would be more efficient.
2662 *
2663 * Returns: X error code or 0 on success
2664 */
2665 int
gdk_x11_display_error_trap_pop(GdkDisplay * display)2666 gdk_x11_display_error_trap_pop (GdkDisplay *display)
2667 {
2668 g_return_val_if_fail (GDK_IS_X11_DISPLAY (display), Success);
2669
2670 return gdk_x11_display_error_trap_pop_internal (display, TRUE);
2671 }
2672
2673 /**
2674 * gdk_x11_display_error_trap_pop_ignored:
2675 * @display: (type GdkX11Display): the display
2676 *
2677 * Pops the error trap pushed by gdk_x11_display_error_trap_push().
2678 * Does not block to see if an error occurred; merely records the
2679 * range of requests to ignore errors for, and ignores those errors
2680 * if they arrive asynchronously.
2681 */
2682 void
gdk_x11_display_error_trap_pop_ignored(GdkDisplay * display)2683 gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display)
2684 {
2685 g_return_if_fail (GDK_IS_X11_DISPLAY (display));
2686
2687 gdk_x11_display_error_trap_pop_internal (display, FALSE);
2688 }
2689
2690 /**
2691 * gdk_x11_set_sm_client_id:
2692 * @sm_client_id: (nullable): the client id assigned by the session manager
2693 * when the connection was opened, or %NULL to remove the property.
2694 *
2695 * Sets the `SM_CLIENT_ID` property on the application’s leader window so that
2696 * the window manager can save the application’s state using the X11R6 ICCCM
2697 * session management protocol.
2698 *
2699 * See the X Session Management Library documentation for more information on
2700 * session management and the Inter-Client Communication Conventions Manual
2701 */
2702 void
gdk_x11_set_sm_client_id(const char * sm_client_id)2703 gdk_x11_set_sm_client_id (const char *sm_client_id)
2704 {
2705 GSList *displays, *l;
2706
2707 g_free (gdk_sm_client_id);
2708 gdk_sm_client_id = g_strdup (sm_client_id);
2709
2710 displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
2711 for (l = displays; l; l = l->next)
2712 {
2713 if (GDK_IS_X11_DISPLAY (l->data))
2714 set_sm_client_id (l->data, sm_client_id);
2715 }
2716
2717 g_slist_free (displays);
2718 }
2719
2720 gsize
gdk_x11_display_get_max_request_size(GdkDisplay * display)2721 gdk_x11_display_get_max_request_size (GdkDisplay *display)
2722 {
2723 Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
2724 gsize size;
2725
2726 size = XExtendedMaxRequestSize (xdisplay);
2727 if (size <= 0)
2728 size = XMaxRequestSize (xdisplay);
2729
2730 size = MIN (262144, size - 100);
2731 return size;
2732 }
2733
2734 /**
2735 * gdk_x11_display_get_screen:
2736 * @display: (type GdkX11Display): a `GdkX11Display`
2737 *
2738 * Retrieves the `GdkX11Screen` of the @display.
2739 *
2740 * Returns: (transfer none): the `GdkX11Screen`
2741 */
2742 GdkX11Screen *
gdk_x11_display_get_screen(GdkDisplay * display)2743 gdk_x11_display_get_screen (GdkDisplay *display)
2744 {
2745 return GDK_X11_DISPLAY (display)->screen;
2746 }
2747
2748 static GdkKeymap *
gdk_x11_display_get_keymap(GdkDisplay * display)2749 gdk_x11_display_get_keymap (GdkDisplay *display)
2750 {
2751 GdkX11Display *display_x11;
2752 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
2753 display_x11 = GDK_X11_DISPLAY (display);
2754
2755 if (!display_x11->keymap)
2756 {
2757 display_x11->keymap = g_object_new (GDK_TYPE_X11_KEYMAP, NULL);
2758 display_x11->keymap->display = display; /* beware of ref cycle */
2759 }
2760
2761 return display_x11->keymap;
2762 }
2763
2764 static GdkSeat *
gdk_x11_display_get_default_seat(GdkDisplay * display)2765 gdk_x11_display_get_default_seat (GdkDisplay *display)
2766 {
2767 GList *seats, *l;
2768 int device_id;
2769 gboolean result = FALSE;
2770
2771 seats = gdk_display_list_seats (display);
2772
2773 gdk_x11_display_error_trap_push (display);
2774 result = XIGetClientPointer (GDK_DISPLAY_XDISPLAY (display),
2775 None, &device_id);
2776 gdk_x11_display_error_trap_pop_ignored (display);
2777
2778 for (l = seats; l; l = l->next)
2779 {
2780 GdkDevice *pointer;
2781
2782 pointer = gdk_seat_get_pointer (l->data);
2783
2784 if (gdk_x11_device_get_id (pointer) == device_id || !result)
2785 {
2786 GdkSeat *seat = l->data;
2787 g_list_free (seats);
2788
2789 return seat;
2790 }
2791 }
2792
2793 g_list_free (seats);
2794
2795 return NULL;
2796 }
2797
2798 static GListModel *
gdk_x11_display_get_monitors(GdkDisplay * display)2799 gdk_x11_display_get_monitors (GdkDisplay *display)
2800 {
2801 GdkX11Display *self = GDK_X11_DISPLAY (display);
2802
2803 return G_LIST_MODEL (self->monitors);
2804 }
2805
2806 /**
2807 * gdk_x11_display_get_primary_monitor:
2808 * @display: (type GdkX11Display): a `GdkDisplay`
2809 *
2810 * Gets the primary monitor for the display.
2811 *
2812 * The primary monitor is considered the monitor where the “main desktop”
2813 * lives. While normal application surfaces typically allow the window
2814 * manager to place the surfaces, specialized desktop applications
2815 * such as panels should place themselves on the primary monitor.
2816 *
2817 * If no monitor is the designated primary monitor, any monitor
2818 * (usually the first) may be returned.
2819 *
2820 * Returns: (transfer none): the primary monitor, or any monitor if no
2821 * primary monitor is configured by the user
2822 */
2823 GdkMonitor *
gdk_x11_display_get_primary_monitor(GdkDisplay * display)2824 gdk_x11_display_get_primary_monitor (GdkDisplay *display)
2825 {
2826 GdkX11Display *self = GDK_X11_DISPLAY (display);
2827 GdkMonitor *monitor;
2828
2829 monitor = g_list_model_get_item (G_LIST_MODEL (self->monitors), self->primary_monitor);
2830 if (monitor == NULL)
2831 monitor = g_list_model_get_item (G_LIST_MODEL (self->monitors), 0);
2832
2833 /* because g_list_model_get_item() returns a ref */
2834 if (monitor)
2835 g_object_unref (monitor);
2836
2837 return monitor;
2838 }
2839
2840 int
gdk_x11_display_get_window_depth(GdkX11Display * display)2841 gdk_x11_display_get_window_depth (GdkX11Display *display)
2842 {
2843 return display->window_depth;
2844 }
2845
2846 Visual *
gdk_x11_display_get_window_visual(GdkX11Display * display)2847 gdk_x11_display_get_window_visual (GdkX11Display *display)
2848 {
2849 return display->window_visual;
2850 }
2851
2852 Colormap
gdk_x11_display_get_window_colormap(GdkX11Display * display)2853 gdk_x11_display_get_window_colormap (GdkX11Display *display)
2854 {
2855 return display->window_colormap;
2856 }
2857
2858 static gboolean
gdk_x11_display_get_setting(GdkDisplay * display,const char * name,GValue * value)2859 gdk_x11_display_get_setting (GdkDisplay *display,
2860 const char *name,
2861 GValue *value)
2862 {
2863 return gdk_x11_screen_get_setting (GDK_X11_DISPLAY (display)->screen, name, value);
2864 }
2865
2866 GList *
gdk_x11_display_get_toplevel_windows(GdkDisplay * display)2867 gdk_x11_display_get_toplevel_windows (GdkDisplay *display)
2868 {
2869 return GDK_X11_DISPLAY (display)->toplevels;
2870 }
2871
2872 static gboolean
gdk_boolean_handled_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)2873 gdk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2874 GValue *return_accu,
2875 const GValue *handler_return,
2876 gpointer dummy)
2877 {
2878 gboolean continue_emission;
2879 gboolean signal_handled;
2880
2881 signal_handled = g_value_get_boolean (handler_return);
2882 g_value_set_boolean (return_accu, signal_handled);
2883 continue_emission = !signal_handled;
2884
2885 return continue_emission;
2886 }
2887
2888 static gboolean
gdk_x11_display_init_gl_backend(GdkX11Display * self,Visual ** out_visual,int * out_depth,GError ** error)2889 gdk_x11_display_init_gl_backend (GdkX11Display *self,
2890 Visual **out_visual,
2891 int *out_depth,
2892 GError **error)
2893 {
2894 GdkDisplay *display G_GNUC_UNUSED = GDK_DISPLAY (self);
2895
2896 if (GDK_DISPLAY_DEBUG_CHECK (display, GL_EGL))
2897 return gdk_x11_display_init_egl (self, TRUE, out_visual, out_depth, error);
2898 if (GDK_DISPLAY_DEBUG_CHECK (display, GL_GLX))
2899 return gdk_x11_display_init_glx (self, out_visual, out_depth, error);
2900
2901 /* No env vars set, do the regular GL initialization.
2902 *
2903 * We try EGL first, but are very picky about what we accept.
2904 * If that fails, we try to go with GLX instead.
2905 * And if that also fails, we try EGL again, but this time accept anything.
2906 *
2907 * The idea here is that EGL is the preferred method going forward, but GLX is
2908 * the tried and tested method that we know works. So if we detect issues with
2909 * EGL, we want to avoid using it in favor of GLX.
2910 */
2911
2912 if (gdk_x11_display_init_egl (self, FALSE, out_visual, out_depth, error))
2913 return TRUE;
2914 g_clear_error (error);
2915
2916 if (gdk_x11_display_init_glx (self, out_visual, out_depth, error))
2917 return TRUE;
2918 g_clear_error (error);
2919
2920 return gdk_x11_display_init_egl (self, TRUE, out_visual, out_depth, error);
2921 }
2922
2923 static GdkGLContext *
gdk_x11_display_init_gl(GdkDisplay * display,GError ** error)2924 gdk_x11_display_init_gl (GdkDisplay *display,
2925 GError **error)
2926 {
2927 GdkX11Display *self = GDK_X11_DISPLAY (display);
2928
2929 if (!gdk_x11_display_init_gl_backend (self, &self->window_visual, &self->window_depth, error))
2930 return FALSE;
2931
2932 gdk_x11_display_init_leader_surface (self);
2933
2934 if (self->egl_display)
2935 return g_object_new (GDK_TYPE_X11_GL_CONTEXT_EGL, "surface", self->leader_gdk_surface, NULL);
2936 else if (self->glx_config != NULL)
2937 return g_object_new (GDK_TYPE_X11_GL_CONTEXT_GLX, "surface", self->leader_gdk_surface, NULL);
2938 else
2939 g_return_val_if_reached (NULL);
2940 }
2941
2942 static void
gdk_x11_display_class_init(GdkX11DisplayClass * class)2943 gdk_x11_display_class_init (GdkX11DisplayClass * class)
2944 {
2945 GObjectClass *object_class = G_OBJECT_CLASS (class);
2946 GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (class);
2947
2948 object_class->dispose = gdk_x11_display_dispose;
2949 object_class->finalize = gdk_x11_display_finalize;
2950
2951 display_class->cairo_context_type = GDK_TYPE_X11_CAIRO_CONTEXT;
2952 #ifdef GDK_RENDERING_VULKAN
2953 display_class->vk_context_type = GDK_TYPE_X11_VULKAN_CONTEXT;
2954 display_class->vk_extension_name = VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
2955 #endif
2956
2957 display_class->get_name = gdk_x11_display_get_name;
2958 display_class->beep = gdk_x11_display_beep;
2959 display_class->sync = gdk_x11_display_sync;
2960 display_class->flush = gdk_x11_display_flush;
2961 display_class->make_default = gdk_x11_display_make_default;
2962 display_class->has_pending = gdk_x11_display_has_pending;
2963 display_class->queue_events = _gdk_x11_display_queue_events;
2964 display_class->get_app_launch_context = _gdk_x11_display_get_app_launch_context;
2965
2966 display_class->get_next_serial = gdk_x11_display_get_next_serial;
2967 display_class->get_startup_notification_id = gdk_x11_display_get_startup_notification_id;
2968 display_class->notify_startup_complete = gdk_x11_display_notify_startup_complete;
2969 display_class->create_surface = _gdk_x11_display_create_surface;
2970 display_class->get_keymap = gdk_x11_display_get_keymap;
2971
2972 display_class->init_gl = gdk_x11_display_init_gl;
2973
2974 display_class->get_default_seat = gdk_x11_display_get_default_seat;
2975
2976 display_class->get_monitors = gdk_x11_display_get_monitors;
2977 display_class->get_setting = gdk_x11_display_get_setting;
2978 display_class->set_cursor_theme = gdk_x11_display_set_cursor_theme;
2979
2980 class->xevent = gdk_event_source_xevent;
2981
2982 /**
2983 * GdkX11Display::xevent:
2984 * @display: (type GdkX11Display): the object on which the signal is emitted
2985 * @xevent: a pointer to the XEvent to process
2986 *
2987 * The ::xevent signal is a low level signal that is emitted
2988 * whenever an XEvent has been received.
2989 *
2990 * When handlers to this signal return %TRUE, no other handlers will be
2991 * invoked. In particular, the default handler for this function is
2992 * GDK's own event handling mechanism, so by returning %TRUE for an event
2993 * that GDK expects to translate, you may break GDK and/or GTK+ in
2994 * interesting ways. You have been warned.
2995 *
2996 * If you want this signal handler to queue a `GdkEvent`, you can use
2997 * gdk_display_put_event().
2998 *
2999 * If you are interested in X GenericEvents, bear in mind that
3000 * XGetEventData() has been already called on the event, and
3001 * XFreeEventData() will be called afterwards.
3002 *
3003 * Returns: %TRUE to stop other handlers from being invoked for the event.
3004 * %FALSE to propagate the event further.
3005 */
3006 signals[XEVENT] =
3007 g_signal_new (g_intern_static_string ("xevent"),
3008 G_OBJECT_CLASS_TYPE (object_class),
3009 G_SIGNAL_RUN_LAST,
3010 G_STRUCT_OFFSET (GdkX11DisplayClass, xevent),
3011 gdk_boolean_handled_accumulator, NULL,
3012 _gdk_marshal_BOOLEAN__POINTER,
3013 G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
3014
3015 _gdk_x11_surfaceing_init ();
3016 }
3017