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

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