1 /*
2 * gdkscreen-x11.c
3 *
4 * Copyright 2001 Sun Microsystems Inc.
5 *
6 * Erwann Chenede <erwann.chenede@sun.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #include "gdkscreen-x11.h"
25 #include "gdkdisplay-x11.h"
26 #include "gdkprivate-x11.h"
27 #include "xsettings-client.h"
28 #include "gdkmonitor-x11.h"
29
30 #include <glib.h>
31
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <X11/Xatom.h>
36
37 #ifdef HAVE_XFREE_XINERAMA
38 #include <X11/extensions/Xinerama.h>
39 #endif
40
41 #ifdef HAVE_RANDR
42 #include <X11/extensions/Xrandr.h>
43 #endif
44
45 #ifdef HAVE_XFIXES
46 #include <X11/extensions/Xfixes.h>
47 #endif
48
49 static void gdk_x11_screen_dispose (GObject *object);
50 static void gdk_x11_screen_finalize (GObject *object);
51 static void init_randr_support (GdkScreen *screen);
52 static void process_monitors_change (GdkScreen *screen);
53
54 enum
55 {
56 WINDOW_MANAGER_CHANGED,
57 LAST_SIGNAL
58 };
59
60 static guint signals[LAST_SIGNAL] = { 0 };
61
62 G_DEFINE_TYPE (GdkX11Screen, gdk_x11_screen, GDK_TYPE_SCREEN)
63
64 typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
65
66 struct _NetWmSupportedAtoms
67 {
68 Atom *atoms;
69 gulong n_atoms;
70 };
71
72 static void
gdk_x11_screen_init(GdkX11Screen * screen)73 gdk_x11_screen_init (GdkX11Screen *screen)
74 {
75 }
76
77 static GdkDisplay *
gdk_x11_screen_get_display(GdkScreen * screen)78 gdk_x11_screen_get_display (GdkScreen *screen)
79 {
80 return GDK_X11_SCREEN (screen)->display;
81 }
82
83 gint
gdk_x11_screen_get_width(GdkScreen * screen)84 gdk_x11_screen_get_width (GdkScreen *screen)
85 {
86 return GDK_X11_SCREEN (screen)->width;
87 }
88
89 gint
gdk_x11_screen_get_height(GdkScreen * screen)90 gdk_x11_screen_get_height (GdkScreen *screen)
91 {
92 return GDK_X11_SCREEN (screen)->height;
93 }
94
95 static gint
gdk_x11_screen_get_width_mm(GdkScreen * screen)96 gdk_x11_screen_get_width_mm (GdkScreen *screen)
97 {
98 return WidthMMOfScreen (GDK_X11_SCREEN (screen)->xscreen);
99 }
100
101 static gint
gdk_x11_screen_get_height_mm(GdkScreen * screen)102 gdk_x11_screen_get_height_mm (GdkScreen *screen)
103 {
104 return HeightMMOfScreen (GDK_X11_SCREEN (screen)->xscreen);
105 }
106
107 gint
gdk_x11_screen_get_number(GdkScreen * screen)108 gdk_x11_screen_get_number (GdkScreen *screen)
109 {
110 return GDK_X11_SCREEN (screen)->screen_num;
111 }
112
113 static GdkWindow *
gdk_x11_screen_get_root_window(GdkScreen * screen)114 gdk_x11_screen_get_root_window (GdkScreen *screen)
115 {
116 return GDK_X11_SCREEN (screen)->root_window;
117 }
118
119 static void
gdk_x11_screen_dispose(GObject * object)120 gdk_x11_screen_dispose (GObject *object)
121 {
122 GdkX11Screen *x11_screen = GDK_X11_SCREEN (object);
123 int i;
124
125 for (i = 0; i < 32; ++i)
126 {
127 if (x11_screen->subwindow_gcs[i])
128 {
129 XFreeGC (x11_screen->xdisplay, x11_screen->subwindow_gcs[i]);
130 x11_screen->subwindow_gcs[i] = 0;
131 }
132 }
133
134 _gdk_x11_xsettings_finish (x11_screen);
135
136 if (x11_screen->root_window)
137 _gdk_window_destroy (x11_screen->root_window, TRUE);
138
139 for (i = 0; i < x11_screen->nvisuals; i++)
140 g_object_run_dispose (G_OBJECT (x11_screen->visuals[i]));
141
142 G_OBJECT_CLASS (gdk_x11_screen_parent_class)->dispose (object);
143
144 x11_screen->xdisplay = NULL;
145 x11_screen->xscreen = NULL;
146 x11_screen->screen_num = -1;
147 x11_screen->xroot_window = None;
148 x11_screen->wmspec_check_window = None;
149 }
150
151 static void
gdk_x11_screen_finalize(GObject * object)152 gdk_x11_screen_finalize (GObject *object)
153 {
154 GdkX11Screen *x11_screen = GDK_X11_SCREEN (object);
155 gint i;
156
157 if (x11_screen->root_window)
158 g_object_unref (x11_screen->root_window);
159
160 /* Visual Part */
161 for (i = 0; i < x11_screen->nvisuals; i++)
162 g_object_unref (x11_screen->visuals[i]);
163 g_free (x11_screen->visuals);
164 g_hash_table_destroy (x11_screen->visual_hash);
165
166 g_free (x11_screen->window_manager_name);
167
168 G_OBJECT_CLASS (gdk_x11_screen_parent_class)->finalize (object);
169 }
170
171 /**
172 * gdk_x11_screen_get_monitor_output:
173 * @screen: (type GdkX11Screen): a #GdkScreen
174 * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
175 *
176 * Gets the XID of the specified output/monitor.
177 * If the X server does not support version 1.2 of the RANDR
178 * extension, 0 is returned.
179 *
180 * Returns: the XID of the monitor
181 *
182 * Since: 2.14
183 */
184 XID
gdk_x11_screen_get_monitor_output(GdkScreen * screen,gint monitor_num)185 gdk_x11_screen_get_monitor_output (GdkScreen *screen,
186 gint monitor_num)
187 {
188 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
189 GdkX11Display *x11_display = GDK_X11_DISPLAY (x11_screen->display);
190 GdkX11Monitor *monitor;
191
192 g_return_val_if_fail (GDK_IS_SCREEN (screen), None);
193 g_return_val_if_fail (monitor_num >= 0, None);
194 g_return_val_if_fail (monitor_num < x11_display->monitors->len, None);
195
196 monitor = x11_display->monitors->pdata[monitor_num];
197 return monitor->output;
198 }
199
200 static int
get_current_desktop(GdkScreen * screen)201 get_current_desktop (GdkScreen *screen)
202 {
203 Display *display;
204 Window win;
205 Atom current_desktop, type;
206 int format;
207 unsigned long n_items, bytes_after;
208 unsigned char *data_return = NULL;
209 int workspace = 0;
210
211 if (!gdk_x11_screen_supports_net_wm_hint (screen,
212 gdk_atom_intern_static_string ("_NET_CURRENT_DESKTOP")))
213 return workspace;
214
215 display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
216 win = XRootWindow (display, GDK_SCREEN_XNUMBER (screen));
217
218 current_desktop = XInternAtom (display, "_NET_CURRENT_DESKTOP", True);
219
220 XGetWindowProperty (display,
221 win,
222 current_desktop,
223 0, G_MAXLONG,
224 False, XA_CARDINAL,
225 &type, &format, &n_items, &bytes_after,
226 &data_return);
227
228 if (type == XA_CARDINAL && format == 32 && n_items > 0)
229 workspace = ((long *) data_return)[0];
230
231 if (data_return)
232 XFree (data_return);
233
234 return workspace;
235 }
236
237 gboolean
_gdk_x11_screen_get_monitor_work_area(GdkScreen * screen,GdkMonitor * monitor,GdkRectangle * area)238 _gdk_x11_screen_get_monitor_work_area (GdkScreen *screen,
239 GdkMonitor *monitor,
240 GdkRectangle *area)
241 {
242 GdkX11Screen *x11_screen;
243 GdkAtom net_workareas;
244 GdkDisplay *display;
245 Display *xdisplay;
246 int current_desktop;
247 char *workareas_dn_name;
248 Atom workareas_dn;
249 int screen_number;
250 Window xroot;
251 int result;
252 Atom type;
253 int format;
254 gulong num;
255 gulong leftovers;
256 guchar *ret_workarea;
257 long *workareas;
258 GdkRectangle geometry;
259 int i;
260
261 x11_screen = GDK_X11_SCREEN (screen);
262
263 net_workareas = gdk_atom_intern_static_string ("_GTK_WORKAREAS");
264 if (!gdk_x11_screen_supports_net_wm_hint (screen, net_workareas))
265 return FALSE;
266
267 display = gdk_screen_get_display (screen);
268 xdisplay = gdk_x11_display_get_xdisplay (display);
269
270 current_desktop = get_current_desktop (screen);
271 workareas_dn_name = g_strdup_printf ("_GTK_WORKAREAS_D%d", current_desktop);
272 workareas_dn = XInternAtom (xdisplay, workareas_dn_name, True);
273 g_free (workareas_dn_name);
274
275 if (workareas_dn == None)
276 return FALSE;
277
278 screen_number = gdk_x11_screen_get_screen_number (screen);
279 xroot = XRootWindow (xdisplay, screen_number);
280
281 gdk_x11_display_error_trap_push (display);
282
283 ret_workarea = NULL;
284 result = XGetWindowProperty (xdisplay,
285 xroot,
286 workareas_dn,
287 0,
288 G_MAXLONG,
289 False,
290 AnyPropertyType,
291 &type,
292 &format,
293 &num,
294 &leftovers,
295 &ret_workarea);
296
297 gdk_x11_display_error_trap_pop_ignored (display);
298
299 if (result != Success ||
300 type == None ||
301 format == 0 ||
302 leftovers ||
303 num % 4 != 0)
304 {
305 XFree (ret_workarea);
306
307 return FALSE;
308 }
309
310 workareas = (long *) ret_workarea;
311
312 gdk_monitor_get_geometry (monitor, &geometry);
313 *area = geometry;
314
315 for (i = 0; i < num / 4; i++)
316 {
317 GdkRectangle work_area;
318
319 work_area = (GdkRectangle) {
320 .x = workareas[0] / x11_screen->window_scale,
321 .y = workareas[1] / x11_screen->window_scale,
322 .width = workareas[2] / x11_screen->window_scale,
323 .height = workareas[3] / x11_screen->window_scale,
324 };
325
326 if (gdk_rectangle_intersect (area, &work_area, &work_area))
327 *area = work_area;
328
329 workareas += 4;
330 }
331
332 XFree (ret_workarea);
333
334 return TRUE;
335 }
336
337 void
gdk_x11_screen_get_work_area(GdkScreen * screen,GdkRectangle * area)338 gdk_x11_screen_get_work_area (GdkScreen *screen,
339 GdkRectangle *area)
340 {
341 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
342 Atom workarea;
343 Atom type;
344 Window win;
345 int format;
346 gulong num;
347 gulong leftovers;
348 gulong max_len = 4 * 32;
349 guchar *ret_workarea = NULL;
350 long *workareas;
351 int result;
352 int disp_screen;
353 int desktop;
354 Display *display;
355
356 display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
357 disp_screen = GDK_SCREEN_XNUMBER (screen);
358 workarea = XInternAtom (display, "_NET_WORKAREA", True);
359
360 /* Defaults in case of error */
361 area->x = 0;
362 area->y = 0;
363 area->width = gdk_x11_screen_get_width (screen);
364 area->height = gdk_x11_screen_get_height (screen);
365
366 if (!gdk_x11_screen_supports_net_wm_hint (screen,
367 gdk_atom_intern_static_string ("_NET_WORKAREA")))
368 return;
369
370 if (workarea == None)
371 return;
372
373 win = XRootWindow (display, disp_screen);
374 result = XGetWindowProperty (display,
375 win,
376 workarea,
377 0,
378 max_len,
379 False,
380 AnyPropertyType,
381 &type,
382 &format,
383 &num,
384 &leftovers,
385 &ret_workarea);
386 if (result != Success ||
387 type == None ||
388 format == 0 ||
389 leftovers ||
390 num % 4 != 0)
391 goto out;
392
393 desktop = get_current_desktop (screen);
394 if (desktop + 1 > num / 4) /* fvwm gets this wrong */
395 goto out;
396
397 workareas = (long *) ret_workarea;
398 area->x = workareas[desktop * 4];
399 area->y = workareas[desktop * 4 + 1];
400 area->width = workareas[desktop * 4 + 2];
401 area->height = workareas[desktop * 4 + 3];
402
403 area->x /= x11_screen->window_scale;
404 area->y /= x11_screen->window_scale;
405 area->width /= x11_screen->window_scale;
406 area->height /= x11_screen->window_scale;
407
408 out:
409 if (ret_workarea)
410 XFree (ret_workarea);
411 }
412
413 static GdkVisual *
gdk_x11_screen_get_rgba_visual(GdkScreen * screen)414 gdk_x11_screen_get_rgba_visual (GdkScreen *screen)
415 {
416 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
417
418 return x11_screen->rgba_visual;
419 }
420
421 /**
422 * gdk_x11_screen_get_xscreen:
423 * @screen: (type GdkX11Screen): a #GdkScreen
424 *
425 * Returns the screen of a #GdkScreen.
426 *
427 * Returns: (transfer none): an Xlib Screen*
428 *
429 * Since: 2.2
430 */
431 Screen *
gdk_x11_screen_get_xscreen(GdkScreen * screen)432 gdk_x11_screen_get_xscreen (GdkScreen *screen)
433 {
434 return GDK_X11_SCREEN (screen)->xscreen;
435 }
436
437 /**
438 * gdk_x11_screen_get_screen_number:
439 * @screen: (type GdkX11Screen): a #GdkScreen
440 *
441 * Returns the index of a #GdkScreen.
442 *
443 * Returns: the position of @screen among the screens
444 * of its display
445 *
446 * Since: 2.2
447 */
448 int
gdk_x11_screen_get_screen_number(GdkScreen * screen)449 gdk_x11_screen_get_screen_number (GdkScreen *screen)
450 {
451 return GDK_X11_SCREEN (screen)->screen_num;
452 }
453
454 static Atom
get_cm_atom(GdkX11Screen * x11_screen)455 get_cm_atom (GdkX11Screen *x11_screen)
456 {
457 return _gdk_x11_get_xatom_for_display_printf (x11_screen->display, "_NET_WM_CM_S%d", x11_screen->screen_num);
458 }
459
460 static gboolean
check_is_composited(GdkDisplay * display,GdkX11Screen * x11_screen)461 check_is_composited (GdkDisplay *display,
462 GdkX11Screen *x11_screen)
463 {
464 Window xwindow;
465
466 xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), get_cm_atom (x11_screen));
467
468 return xwindow != None;
469 }
470
471 static GdkX11Monitor *
find_monitor_by_output(GdkX11Display * x11_display,XID output)472 find_monitor_by_output (GdkX11Display *x11_display, XID output)
473 {
474 int i;
475
476 for (i = 0; i < x11_display->monitors->len; i++)
477 {
478 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
479 if (monitor->output == output)
480 return monitor;
481 }
482
483 return NULL;
484 }
485
486 static GdkSubpixelLayout
translate_subpixel_order(int subpixel)487 translate_subpixel_order (int subpixel)
488 {
489 switch (subpixel)
490 {
491 case 1: return GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB;
492 case 2: return GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR;
493 case 3: return GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB;
494 case 4: return GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR;
495 case 5: return GDK_SUBPIXEL_LAYOUT_NONE;
496 default: return GDK_SUBPIXEL_LAYOUT_UNKNOWN;
497 }
498 }
499
500 static gboolean
init_randr15(GdkScreen * screen,gboolean * changed)501 init_randr15 (GdkScreen *screen, gboolean *changed)
502 {
503 #ifdef HAVE_RANDR15
504 GdkDisplay *display = gdk_screen_get_display (screen);
505 GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
506 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
507 XRRScreenResources *resources;
508 RROutput primary_output = None;
509 RROutput first_output = None;
510 int i;
511 gboolean randr12_compat = FALSE;
512 XRRMonitorInfo *rr_monitors;
513 int num_rr_monitors;
514 int old_primary;
515
516 if (!x11_display->have_randr15)
517 return FALSE;
518
519 resources = XRRGetScreenResourcesCurrent (x11_screen->xdisplay,
520 x11_screen->xroot_window);
521 if (!resources)
522 return FALSE;
523
524 rr_monitors = XRRGetMonitors (x11_screen->xdisplay,
525 x11_screen->xroot_window,
526 True,
527 &num_rr_monitors);
528 if (!rr_monitors)
529 return FALSE;
530
531 for (i = 0; i < x11_display->monitors->len; i++)
532 {
533 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
534 monitor->add = FALSE;
535 monitor->remove = TRUE;
536 }
537
538 for (i = 0; i < num_rr_monitors; i++)
539 {
540 RROutput output = rr_monitors[i].outputs[0];
541 XRROutputInfo *output_info;
542 GdkX11Monitor *monitor;
543 GdkRectangle geometry;
544 GdkRectangle newgeo;
545 char *name;
546 char *manufacturer = NULL;
547 int refresh_rate = 0;
548
549 gdk_x11_display_error_trap_push (display);
550 output_info = XRRGetOutputInfo (x11_screen->xdisplay, resources, output);
551 if (gdk_x11_display_error_trap_pop (display))
552 continue;
553
554 if (output_info == NULL)
555 continue;
556
557 /* Non RandR1.2+ X driver have output name "default" */
558 randr12_compat |= !g_strcmp0 (output_info->name, "default");
559
560 if (output_info->connection == RR_Disconnected)
561 {
562 XRRFreeOutputInfo (output_info);
563 continue;
564 }
565
566 if (first_output == None)
567 first_output = output;
568
569 if (output_info->crtc)
570 {
571 XRRCrtcInfo *crtc;
572 int j;
573
574 gdk_x11_display_error_trap_push (display);
575 crtc = XRRGetCrtcInfo (x11_screen->xdisplay, resources,
576 output_info->crtc);
577 if (gdk_x11_display_error_trap_pop (display))
578 {
579 XRRFreeOutputInfo (output_info);
580 continue;
581 }
582
583 for (j = 0; j < resources->nmode; j++)
584 {
585 XRRModeInfo *xmode = &resources->modes[j];
586 if (xmode->id == crtc->mode)
587 {
588 if (xmode->hTotal != 0 && xmode->vTotal != 0)
589 refresh_rate = (1000 * xmode->dotClock) / (xmode->hTotal * xmode->vTotal);
590 break;
591 }
592 }
593
594 XRRFreeCrtcInfo (crtc);
595 }
596
597 monitor = find_monitor_by_output (x11_display, output);
598 if (monitor)
599 monitor->remove = FALSE;
600 else
601 {
602 monitor = g_object_new (GDK_TYPE_X11_MONITOR,
603 "display", display,
604 NULL);
605 monitor->output = output;
606 monitor->add = TRUE;
607 g_ptr_array_add (x11_display->monitors, monitor);
608 }
609
610 /* Fetch minimal manufacturer information (PNP ID) from EDID */
611 {
612 #define EDID_LENGTH 128
613 Atom actual_type, edid_atom;
614 char tmp[3];
615 int actual_format;
616 unsigned char *prop;
617 unsigned long nbytes, bytes_left;
618 Display *disp = GDK_DISPLAY_XDISPLAY (x11_display);
619
620 edid_atom = XInternAtom (disp, RR_PROPERTY_RANDR_EDID, FALSE);
621
622 XRRGetOutputProperty (disp, output,
623 edid_atom,
624 0,
625 EDID_LENGTH,
626 FALSE,
627 FALSE,
628 AnyPropertyType,
629 &actual_type,
630 &actual_format,
631 &nbytes,
632 &bytes_left,
633 &prop);
634
635 // Check partial EDID header (whole header: 00 ff ff ff ff ff ff 00)
636 if (nbytes >= EDID_LENGTH && prop[0] == 0x00 && prop[1] == 0xff)
637 {
638 /* decode the Vendor ID from three 5 bit words packed into 2 bytes
639 * /--08--\/--09--\
640 * 7654321076543210
641 * |\---/\---/\---/
642 * R C1 C2 C3 */
643 tmp[0] = 'A' + ((prop[8] & 0x7c) / 4) - 1;
644 tmp[1] = 'A' + ((prop[8] & 0x3) * 8) + ((prop[9] & 0xe0) / 32) - 1;
645 tmp[2] = 'A' + (prop[9] & 0x1f) - 1;
646
647 manufacturer = g_strndup (tmp, sizeof (tmp));
648 }
649
650 XFree(prop);
651 #undef EDID_LENGTH
652 }
653
654 gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
655 name = g_strndup (output_info->name, output_info->nameLen);
656
657 newgeo.x = rr_monitors[i].x / x11_screen->window_scale;
658 newgeo.y = rr_monitors[i].y / x11_screen->window_scale;
659 newgeo.width = rr_monitors[i].width / x11_screen->window_scale;
660 newgeo.height = rr_monitors[i].height / x11_screen->window_scale;
661 if (newgeo.x != geometry.x ||
662 newgeo.y != geometry.y ||
663 newgeo.width != geometry.width ||
664 newgeo.height != geometry.height ||
665 rr_monitors[i].mwidth != gdk_monitor_get_width_mm (GDK_MONITOR (monitor)) ||
666 rr_monitors[i].mheight != gdk_monitor_get_height_mm (GDK_MONITOR (monitor)) ||
667 g_strcmp0 (name, gdk_monitor_get_model (GDK_MONITOR (monitor))))
668 *changed = TRUE;
669
670 gdk_monitor_set_position (GDK_MONITOR (monitor), newgeo.x, newgeo.y);
671 gdk_monitor_set_size (GDK_MONITOR (monitor), newgeo.width, newgeo.height);
672 g_object_notify (G_OBJECT (monitor), "workarea");
673 gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
674 rr_monitors[i].mwidth,
675 rr_monitors[i].mheight);
676 gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor),
677 translate_subpixel_order (output_info->subpixel_order));
678 gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh_rate);
679 gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->window_scale);
680 gdk_monitor_set_model (GDK_MONITOR (monitor), name);
681 gdk_monitor_set_connector (GDK_MONITOR (monitor), name);
682 gdk_monitor_set_manufacturer (GDK_MONITOR (monitor), manufacturer);
683 g_free (manufacturer);
684 g_free (name);
685
686 if (rr_monitors[i].primary)
687 primary_output = monitor->output;
688
689 XRRFreeOutputInfo (output_info);
690 }
691
692 XRRFreeMonitors (rr_monitors);
693 XRRFreeScreenResources (resources);
694
695 /* non RandR 1.2+ X driver doesn't return any usable multihead data */
696 if (randr12_compat)
697 {
698 for (i = 0; i < x11_display->monitors->len; i++)
699 {
700 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
701 if (monitor->remove)
702 gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
703 }
704 g_ptr_array_remove_range (x11_display->monitors, 0, x11_display->monitors->len);
705 return FALSE;
706 }
707
708 for (i = x11_display->monitors->len - 1; i >= 0; i--)
709 {
710 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
711 if (monitor->add)
712 {
713 gdk_display_monitor_added (display, GDK_MONITOR (monitor));
714 *changed = TRUE;
715 }
716 else if (monitor->remove)
717 {
718 g_object_ref (monitor);
719 g_ptr_array_remove (x11_display->monitors, monitor);
720 gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
721 g_object_unref (monitor);
722 *changed = TRUE;
723 }
724 }
725
726 old_primary = x11_display->primary_monitor;
727 x11_display->primary_monitor = 0;
728 for (i = 0; i < x11_display->monitors->len; ++i)
729 {
730 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
731 if (monitor->output == primary_output)
732 {
733 x11_display->primary_monitor = i;
734 break;
735 }
736
737 /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
738 if (primary_output == None &&
739 g_ascii_strncasecmp (gdk_monitor_get_model (GDK_MONITOR (monitor)), "LVDS", 4) == 0)
740 {
741 x11_display->primary_monitor = i;
742 break;
743 }
744
745 /* No primary specified and no LVDS found */
746 if (monitor->output == first_output)
747 x11_display->primary_monitor = i;
748 }
749
750 if (x11_display->primary_monitor != old_primary)
751 *changed = TRUE;
752
753 return x11_display->monitors->len > 0;
754 #endif
755
756 return FALSE;
757 }
758
759 static gboolean
init_randr13(GdkScreen * screen,gboolean * changed)760 init_randr13 (GdkScreen *screen, gboolean *changed)
761 {
762 #ifdef HAVE_RANDR
763 GdkDisplay *display = gdk_screen_get_display (screen);
764 GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
765 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
766 XRRScreenResources *resources;
767 RROutput primary_output = None;
768 RROutput first_output = None;
769 int i;
770 gboolean randr12_compat = FALSE;
771 int old_primary;
772
773 if (!x11_display->have_randr13)
774 return FALSE;
775
776 resources = XRRGetScreenResourcesCurrent (x11_screen->xdisplay,
777 x11_screen->xroot_window);
778 if (!resources)
779 return FALSE;
780
781 for (i = 0; i < x11_display->monitors->len; i++)
782 {
783 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
784 monitor->add = FALSE;
785 monitor->remove = TRUE;
786 }
787
788 for (i = 0; i < resources->noutput; ++i)
789 {
790 RROutput output = resources->outputs[i];
791 XRROutputInfo *output_info =
792 XRRGetOutputInfo (x11_screen->xdisplay, resources, output);
793
794 /* Non RandR1.2+ X driver have output name "default" */
795 randr12_compat |= !g_strcmp0 (output_info->name, "default");
796
797 if (output_info->connection == RR_Disconnected)
798 {
799 XRRFreeOutputInfo (output_info);
800 continue;
801 }
802
803 if (output_info->crtc)
804 {
805 GdkX11Monitor *monitor;
806 XRRCrtcInfo *crtc = XRRGetCrtcInfo (x11_screen->xdisplay, resources, output_info->crtc);
807 char *name;
808 GdkRectangle geometry;
809 GdkRectangle newgeo;
810 int j;
811 int refresh_rate = 0;
812
813 for (j = 0; j < resources->nmode; j++)
814 {
815 XRRModeInfo *xmode = &resources->modes[j];
816 if (xmode->id == crtc->mode)
817 {
818 if (xmode->hTotal != 0 && xmode->vTotal != 0)
819 refresh_rate = (1000 * xmode->dotClock) / (xmode->hTotal * xmode->vTotal);
820 break;
821 }
822 }
823
824 monitor = find_monitor_by_output (x11_display, output);
825 if (monitor)
826 monitor->remove = FALSE;
827 else
828 {
829 monitor = g_object_new (gdk_x11_monitor_get_type (),
830 "display", display,
831 NULL);
832 monitor->output = output;
833 monitor->add = TRUE;
834 g_ptr_array_add (x11_display->monitors, monitor);
835 }
836
837 gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
838 name = g_strndup (output_info->name, output_info->nameLen);
839
840 newgeo.x = crtc->x / x11_screen->window_scale;
841 newgeo.y = crtc->y / x11_screen->window_scale;
842 newgeo.width = crtc->width / x11_screen->window_scale;
843 newgeo.height = crtc->height / x11_screen->window_scale;
844 if (newgeo.x != geometry.x ||
845 newgeo.y != geometry.y ||
846 newgeo.width != geometry.width ||
847 newgeo.height != geometry.height ||
848 output_info->mm_width != gdk_monitor_get_width_mm (GDK_MONITOR (monitor)) ||
849 output_info->mm_height != gdk_monitor_get_height_mm (GDK_MONITOR (monitor)) ||
850 g_strcmp0 (name, gdk_monitor_get_model (GDK_MONITOR (monitor))) != 0)
851 *changed = TRUE;
852
853 gdk_monitor_set_position (GDK_MONITOR (monitor), newgeo.x, newgeo.y);
854 gdk_monitor_set_size (GDK_MONITOR (monitor), newgeo.width, newgeo.height);
855 g_object_notify (G_OBJECT (monitor), "workarea");
856 gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
857 output_info->mm_width,
858 output_info->mm_height);
859 gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor),
860 translate_subpixel_order (output_info->subpixel_order));
861 gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh_rate);
862 gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->window_scale);
863 gdk_monitor_set_model (GDK_MONITOR (monitor), name);
864
865 g_free (name);
866
867 XRRFreeCrtcInfo (crtc);
868 }
869
870 XRRFreeOutputInfo (output_info);
871 }
872
873 if (resources->noutput > 0)
874 first_output = resources->outputs[0];
875
876 XRRFreeScreenResources (resources);
877
878 if (randr12_compat)
879 {
880 for (i = 0; i < x11_display->monitors->len; i++)
881 {
882 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
883 if (monitor->remove)
884 gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
885 }
886 g_ptr_array_remove_range (x11_display->monitors, 0, x11_display->monitors->len);
887 return FALSE;
888 }
889
890 for (i = x11_display->monitors->len - 1; i >= 0; i--)
891 {
892 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
893 if (monitor->add)
894 {
895 gdk_display_monitor_added (display, GDK_MONITOR (monitor));
896 *changed = TRUE;
897 }
898 else if (monitor->remove)
899 {
900 g_object_ref (monitor);
901 g_ptr_array_remove (x11_display->monitors, monitor);
902 gdk_display_monitor_removed (display, GDK_MONITOR (monitor));
903 g_object_unref (monitor);
904 *changed = TRUE;
905 }
906 }
907
908 old_primary = x11_display->primary_monitor;
909 x11_display->primary_monitor = 0;
910 primary_output = XRRGetOutputPrimary (x11_screen->xdisplay,
911 x11_screen->xroot_window);
912
913 for (i = 0; i < x11_display->monitors->len; ++i)
914 {
915 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
916 if (monitor->output == primary_output)
917 {
918 x11_display->primary_monitor = i;
919 break;
920 }
921
922 /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
923 if (primary_output == None &&
924 g_ascii_strncasecmp (gdk_monitor_get_model (GDK_MONITOR (monitor)), "LVDS", 4) == 0)
925 {
926 x11_display->primary_monitor = i;
927 break;
928 }
929
930 /* No primary specified and no LVDS found */
931 if (monitor->output == first_output)
932 x11_display->primary_monitor = i;
933 }
934
935 if (x11_display->primary_monitor != old_primary)
936 *changed = TRUE;
937
938 return x11_display->monitors->len > 0;
939 #endif
940
941 return FALSE;
942 }
943
944 static void
init_no_multihead(GdkScreen * screen,gboolean * changed)945 init_no_multihead (GdkScreen *screen, gboolean *changed)
946 {
947 GdkDisplay *display = gdk_screen_get_display (screen);
948 GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
949 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
950 GdkX11Monitor *monitor;
951 GdkRectangle geometry;
952 GdkRectangle newgeo;
953 int i;
954
955 for (i = 0; i < x11_display->monitors->len; i++)
956 {
957 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
958 monitor->add = FALSE;
959 monitor->remove = TRUE;
960 }
961
962 monitor = find_monitor_by_output (x11_display, 0);
963 if (monitor)
964 monitor->remove = FALSE;
965 else
966 {
967 monitor = g_object_new (gdk_x11_monitor_get_type (),
968 "display", x11_display,
969 NULL);
970 monitor->output = 0;
971 monitor->add = TRUE;
972 g_ptr_array_add (x11_display->monitors, monitor);
973 }
974
975 gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
976
977 newgeo.x = 0;
978 newgeo.y = 0;
979 newgeo.width = DisplayWidth (x11_display->xdisplay, x11_screen->screen_num) /
980 x11_screen->window_scale;
981 newgeo.height = DisplayHeight (x11_display->xdisplay, x11_screen->screen_num) /
982 x11_screen->window_scale;
983
984 if (newgeo.x != geometry.x ||
985 newgeo.y != geometry.y ||
986 newgeo.width != geometry.width ||
987 newgeo.height != geometry.height ||
988 gdk_x11_screen_get_width_mm (screen) != gdk_monitor_get_width_mm (GDK_MONITOR (monitor)) ||
989 gdk_x11_screen_get_height_mm (screen) != gdk_monitor_get_height_mm (GDK_MONITOR (monitor)))
990 *changed = TRUE;
991
992 gdk_monitor_set_position (GDK_MONITOR (monitor), newgeo.x, newgeo.y);
993 gdk_monitor_set_size (GDK_MONITOR (monitor), newgeo.width, newgeo.height);
994
995 g_object_notify (G_OBJECT (monitor), "workarea");
996 gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
997 gdk_x11_screen_get_width_mm (screen),
998 gdk_x11_screen_get_height_mm (screen));
999 gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->window_scale);
1000
1001 if (x11_display->primary_monitor != 0)
1002 *changed = TRUE;
1003 x11_display->primary_monitor = 0;
1004
1005 for (i = x11_display->monitors->len - 1; i >= 0; i--)
1006 {
1007 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
1008 if (monitor->add)
1009 {
1010 gdk_display_monitor_added (GDK_DISPLAY (x11_display), GDK_MONITOR (monitor));
1011 *changed = TRUE;
1012 }
1013 else if (monitor->remove)
1014 {
1015 g_object_ref (monitor);
1016 g_ptr_array_remove (x11_display->monitors, monitor);
1017 gdk_display_monitor_removed (GDK_DISPLAY (x11_display), GDK_MONITOR (monitor));
1018 g_object_unref (monitor);
1019 *changed = TRUE;
1020 }
1021 }
1022 }
1023
1024 static gboolean
init_multihead(GdkScreen * screen)1025 init_multihead (GdkScreen *screen)
1026 {
1027 gboolean any_changed = FALSE;
1028
1029 if (!init_randr15 (screen, &any_changed) &&
1030 !init_randr13 (screen, &any_changed))
1031 init_no_multihead (screen, &any_changed);
1032
1033 return any_changed;
1034 }
1035
1036 static void
update_bounding_box(GdkScreen * screen)1037 update_bounding_box (GdkScreen *screen)
1038 {
1039 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1040 GdkX11Display *x11_display = GDK_X11_DISPLAY (x11_screen->display);
1041 gint i, x1, y1, x2, y2;
1042
1043 x1 = y1 = G_MAXINT;
1044 x2 = y2 = G_MININT;
1045
1046 for (i = 0; i < x11_display->monitors->len; i++)
1047 {
1048 GdkX11Monitor *monitor = x11_display->monitors->pdata[i];
1049 GdkRectangle geometry;
1050
1051 gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
1052 x1 = MIN (x1, geometry.x);
1053 y1 = MIN (y1, geometry.y);
1054 x2 = MAX (x2, geometry.x + geometry.width);
1055 y2 = MAX (y2, geometry.y + geometry.height);
1056 }
1057
1058 x11_screen->width = x2 - x1;
1059 x11_screen->height = y2 - y1;
1060 }
1061
1062 GdkScreen *
_gdk_x11_screen_new(GdkDisplay * display,gint screen_number)1063 _gdk_x11_screen_new (GdkDisplay *display,
1064 gint screen_number)
1065 {
1066 GdkScreen *screen;
1067 GdkX11Screen *x11_screen;
1068 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
1069 const char *scale_str;
1070
1071 screen = g_object_new (GDK_TYPE_X11_SCREEN, NULL);
1072
1073 x11_screen = GDK_X11_SCREEN (screen);
1074 x11_screen->display = display;
1075 x11_screen->xdisplay = display_x11->xdisplay;
1076 x11_screen->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
1077 x11_screen->screen_num = screen_number;
1078 x11_screen->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
1079 x11_screen->wmspec_check_window = None;
1080 /* we want this to be always non-null */
1081 x11_screen->window_manager_name = g_strdup ("unknown");
1082
1083 scale_str = g_getenv ("GDK_SCALE");
1084 if (scale_str)
1085 {
1086 x11_screen->fixed_window_scale = TRUE;
1087 x11_screen->window_scale = atol (scale_str);
1088 if (x11_screen->window_scale == 0)
1089 x11_screen->window_scale = 1;
1090 }
1091 else
1092 x11_screen->window_scale = 1;
1093
1094 init_randr_support (screen);
1095 init_multihead (screen);
1096
1097 _gdk_x11_screen_init_visuals (screen);
1098 _gdk_x11_screen_init_root_window (screen);
1099 update_bounding_box (screen);
1100
1101 return screen;
1102 }
1103
1104 void
_gdk_x11_screen_set_window_scale(GdkX11Screen * x11_screen,gint scale)1105 _gdk_x11_screen_set_window_scale (GdkX11Screen *x11_screen,
1106 gint scale)
1107 {
1108 GList *toplevels, *l;
1109 GdkWindow *root;
1110
1111 if (x11_screen->window_scale == scale)
1112 return;
1113
1114 x11_screen->window_scale = scale;
1115
1116 root = x11_screen->root_window;
1117 GDK_WINDOW_IMPL_X11 (root->impl)->window_scale = scale;
1118
1119 if (GDK_WINDOW_IMPL_X11 (root->impl)->cairo_surface)
1120 cairo_surface_set_device_scale (GDK_WINDOW_IMPL_X11 (root->impl)->cairo_surface,
1121 scale, scale);
1122
1123 toplevels = gdk_screen_get_toplevel_windows (GDK_SCREEN (x11_screen));
1124
1125 for (l = toplevels; l != NULL; l = l->next)
1126 {
1127 GdkWindow *window = l->data;
1128
1129 _gdk_x11_window_set_window_scale (window, scale);
1130 }
1131
1132 process_monitors_change (GDK_SCREEN (x11_screen));
1133 }
1134
1135 /*
1136 * It is important that we first request the selection
1137 * notification, and then setup the initial state of
1138 * is_composited to avoid a race condition here.
1139 */
1140 void
_gdk_x11_screen_setup(GdkScreen * screen)1141 _gdk_x11_screen_setup (GdkScreen *screen)
1142 {
1143 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1144
1145 gdk_display_request_selection_notification (x11_screen->display,
1146 gdk_x11_xatom_to_atom_for_display (x11_screen->display, get_cm_atom (x11_screen)));
1147 x11_screen->is_composited = check_is_composited (x11_screen->display, x11_screen);
1148 }
1149
1150 static gboolean
gdk_x11_screen_is_composited(GdkScreen * screen)1151 gdk_x11_screen_is_composited (GdkScreen *screen)
1152 {
1153 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1154
1155 return x11_screen->is_composited;
1156 }
1157
1158 static void
init_randr_support(GdkScreen * screen)1159 init_randr_support (GdkScreen *screen)
1160 {
1161 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1162
1163 /* NB: This is also needed for XSettings, so don't remove. */
1164 XSelectInput (GDK_SCREEN_XDISPLAY (screen),
1165 x11_screen->xroot_window,
1166 StructureNotifyMask);
1167
1168 #ifdef HAVE_RANDR
1169 if (!GDK_X11_DISPLAY (gdk_screen_get_display (screen))->have_randr12)
1170 return;
1171
1172 XRRSelectInput (GDK_SCREEN_XDISPLAY (screen),
1173 x11_screen->xroot_window,
1174 RRScreenChangeNotifyMask
1175 | RRCrtcChangeNotifyMask
1176 | RROutputPropertyNotifyMask);
1177 #endif
1178 }
1179
1180 static void
process_monitors_change(GdkScreen * screen)1181 process_monitors_change (GdkScreen *screen)
1182 {
1183 if (init_multihead (screen))
1184 {
1185 update_bounding_box (screen);
1186 g_signal_emit_by_name (screen, "monitors-changed");
1187 }
1188 }
1189
1190 void
_gdk_x11_screen_size_changed(GdkScreen * screen,XEvent * event)1191 _gdk_x11_screen_size_changed (GdkScreen *screen,
1192 XEvent *event)
1193 {
1194 gint width, height;
1195 #ifdef HAVE_RANDR
1196 GdkX11Display *display_x11;
1197 #endif
1198
1199 width = gdk_x11_screen_get_width (screen);
1200 height = gdk_x11_screen_get_height (screen);
1201
1202 #ifdef HAVE_RANDR
1203 display_x11 = GDK_X11_DISPLAY (gdk_screen_get_display (screen));
1204
1205 if (display_x11->have_randr13 && event->type == ConfigureNotify)
1206 return;
1207
1208 XRRUpdateConfiguration (event);
1209 #else
1210 if (event->type == ConfigureNotify)
1211 {
1212 XConfigureEvent *rcevent = (XConfigureEvent *) event;
1213 Screen *xscreen = gdk_x11_screen_get_xscreen (screen);
1214
1215 xscreen->width = rcevent->width;
1216 xscreen->height = rcevent->height;
1217 }
1218 else
1219 return;
1220 #endif
1221
1222 process_monitors_change (screen);
1223
1224 if (width != gdk_x11_screen_get_width (screen) ||
1225 height != gdk_x11_screen_get_height (screen))
1226 g_signal_emit_by_name (screen, "size-changed");
1227 }
1228
1229 void
_gdk_x11_screen_get_edge_monitors(GdkScreen * screen,gint * top,gint * bottom,gint * left,gint * right)1230 _gdk_x11_screen_get_edge_monitors (GdkScreen *screen,
1231 gint *top,
1232 gint *bottom,
1233 gint *left,
1234 gint *right)
1235 {
1236 #ifdef HAVE_XFREE_XINERAMA
1237 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1238 gint top_most_pos = x11_screen->height;
1239 gint left_most_pos = x11_screen->width;
1240 gint bottom_most_pos = 0;
1241 gint right_most_pos = 0;
1242 gint i;
1243 XineramaScreenInfo *x_monitors;
1244 int x_n_monitors;
1245 #endif
1246
1247 *top = *bottom = *left = *right = -1;
1248
1249 #ifdef HAVE_XFREE_XINERAMA
1250 if (!XineramaIsActive (x11_screen->xdisplay))
1251 return;
1252
1253 x_monitors = XineramaQueryScreens (x11_screen->xdisplay, &x_n_monitors);
1254 if (x_n_monitors <= 0 || x_monitors == NULL)
1255 {
1256 if (x_monitors)
1257 XFree (x_monitors);
1258
1259 return;
1260 }
1261
1262 for (i = 0; i < x_n_monitors; i++)
1263 {
1264 if (left && left_most_pos > x_monitors[i].x_org)
1265 {
1266 left_most_pos = x_monitors[i].x_org;
1267 *left = i;
1268 }
1269 if (right && right_most_pos < x_monitors[i].x_org + x_monitors[i].width)
1270 {
1271 right_most_pos = x_monitors[i].x_org + x_monitors[i].width;
1272 *right = i;
1273 }
1274 if (top && top_most_pos > x_monitors[i].y_org)
1275 {
1276 top_most_pos = x_monitors[i].y_org;
1277 *top = i;
1278 }
1279 if (bottom && bottom_most_pos < x_monitors[i].y_org + x_monitors[i].height)
1280 {
1281 bottom_most_pos = x_monitors[i].y_org + x_monitors[i].height;
1282 *bottom = i;
1283 }
1284 }
1285
1286 XFree (x_monitors);
1287 #endif
1288 }
1289
1290 void
_gdk_x11_screen_window_manager_changed(GdkScreen * screen)1291 _gdk_x11_screen_window_manager_changed (GdkScreen *screen)
1292 {
1293 g_signal_emit (screen, signals[WINDOW_MANAGER_CHANGED], 0);
1294 }
1295
1296 void
_gdk_x11_screen_process_owner_change(GdkScreen * screen,XEvent * event)1297 _gdk_x11_screen_process_owner_change (GdkScreen *screen,
1298 XEvent *event)
1299 {
1300 #ifdef HAVE_XFIXES
1301 XFixesSelectionNotifyEvent *selection_event = (XFixesSelectionNotifyEvent *)event;
1302 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1303
1304 if (selection_event->selection == get_cm_atom (x11_screen))
1305 {
1306 gboolean composited = selection_event->owner != None;
1307
1308 if (composited != x11_screen->is_composited)
1309 {
1310 x11_screen->is_composited = composited;
1311
1312 g_signal_emit_by_name (screen, "composited-changed");
1313 }
1314 }
1315 #endif
1316 }
1317
1318 static gchar *
substitute_screen_number(const gchar * display_name,gint screen_number)1319 substitute_screen_number (const gchar *display_name,
1320 gint screen_number)
1321 {
1322 GString *str;
1323 gchar *p;
1324
1325 str = g_string_new (display_name);
1326
1327 p = strrchr (str->str, '.');
1328 if (p && p > strchr (str->str, ':'))
1329 g_string_truncate (str, p - str->str);
1330
1331 g_string_append_printf (str, ".%d", screen_number);
1332
1333 return g_string_free (str, FALSE);
1334 }
1335
1336 static gchar *
gdk_x11_screen_make_display_name(GdkScreen * screen)1337 gdk_x11_screen_make_display_name (GdkScreen *screen)
1338 {
1339 const gchar *old_display;
1340
1341 old_display = gdk_display_get_name (gdk_screen_get_display (screen));
1342
1343 return substitute_screen_number (old_display,
1344 gdk_x11_screen_get_number (screen));
1345 }
1346
1347 static GdkWindow *
gdk_x11_screen_get_active_window(GdkScreen * screen)1348 gdk_x11_screen_get_active_window (GdkScreen *screen)
1349 {
1350 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1351 GdkWindow *ret = NULL;
1352 Atom type_return;
1353 gint format_return;
1354 gulong nitems_return;
1355 gulong bytes_after_return;
1356 guchar *data = NULL;
1357
1358 if (!gdk_x11_screen_supports_net_wm_hint (screen,
1359 gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW")))
1360 return NULL;
1361
1362 if (XGetWindowProperty (x11_screen->xdisplay, x11_screen->xroot_window,
1363 gdk_x11_get_xatom_by_name_for_display (x11_screen->display,
1364 "_NET_ACTIVE_WINDOW"),
1365 0, 1, False, XA_WINDOW, &type_return,
1366 &format_return, &nitems_return,
1367 &bytes_after_return, &data)
1368 == Success)
1369 {
1370 if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
1371 {
1372 Window window = *(Window *) data;
1373
1374 if (window != None)
1375 {
1376 ret = gdk_x11_window_foreign_new_for_display (x11_screen->display,
1377 window);
1378 }
1379 }
1380 }
1381
1382 if (data)
1383 XFree (data);
1384
1385 return ret;
1386 }
1387
1388 static GList *
gdk_x11_screen_get_window_stack(GdkScreen * screen)1389 gdk_x11_screen_get_window_stack (GdkScreen *screen)
1390 {
1391 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1392 GList *ret = NULL;
1393 Atom type_return;
1394 gint format_return;
1395 gulong nitems_return;
1396 gulong bytes_after_return;
1397 guchar *data = NULL;
1398
1399 if (!gdk_x11_screen_supports_net_wm_hint (screen,
1400 gdk_atom_intern_static_string ("_NET_CLIENT_LIST_STACKING")))
1401 return NULL;
1402
1403 if (XGetWindowProperty (x11_screen->xdisplay, x11_screen->xroot_window,
1404 gdk_x11_get_xatom_by_name_for_display (x11_screen->display,
1405 "_NET_CLIENT_LIST_STACKING"),
1406 0, G_MAXLONG, False, XA_WINDOW, &type_return,
1407 &format_return, &nitems_return,
1408 &bytes_after_return, &data)
1409 == Success)
1410 {
1411 if ((type_return == XA_WINDOW) && (format_return == 32) &&
1412 (data) && (nitems_return > 0))
1413 {
1414 gulong *stack = (gulong *) data;
1415 GdkWindow *win;
1416 int i;
1417
1418 for (i = 0; i < nitems_return; i++)
1419 {
1420 win = gdk_x11_window_foreign_new_for_display (x11_screen->display,
1421 (Window)stack[i]);
1422
1423 if (win != NULL)
1424 ret = g_list_append (ret, win);
1425 }
1426 }
1427 }
1428
1429 if (data)
1430 XFree (data);
1431
1432 return ret;
1433 }
1434
1435 static gboolean
gdk_x11_screen_get_setting(GdkScreen * screen,const gchar * name,GValue * value)1436 gdk_x11_screen_get_setting (GdkScreen *screen,
1437 const gchar *name,
1438 GValue *value)
1439 {
1440 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1441 const GValue *setting;
1442
1443 if (x11_screen->xsettings == NULL)
1444 goto out;
1445 setting = g_hash_table_lookup (x11_screen->xsettings, name);
1446 if (setting == NULL)
1447 goto out;
1448
1449 if (!g_value_transform (setting, value))
1450 {
1451 g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
1452 name,
1453 g_type_name (G_VALUE_TYPE (setting)),
1454 g_type_name (G_VALUE_TYPE (value)));
1455 goto out;
1456 }
1457
1458 return TRUE;
1459
1460 out:
1461 return _gdk_x11_get_xft_setting (screen, name, value);
1462 }
1463
1464 static void
cleanup_atoms(gpointer data)1465 cleanup_atoms(gpointer data)
1466 {
1467 NetWmSupportedAtoms *supported_atoms = data;
1468 if (supported_atoms->atoms)
1469 XFree (supported_atoms->atoms);
1470 g_free (supported_atoms);
1471 }
1472
1473 static Window
get_net_supporting_wm_check(GdkX11Screen * screen,Window window)1474 get_net_supporting_wm_check (GdkX11Screen *screen,
1475 Window window)
1476 {
1477 GdkDisplay *display;
1478 Atom type;
1479 gint format;
1480 gulong n_items;
1481 gulong bytes_after;
1482 guchar *data;
1483 Window value;
1484
1485 display = screen->display;
1486 type = None;
1487 data = NULL;
1488 value = None;
1489
1490 gdk_x11_display_error_trap_push (display);
1491 XGetWindowProperty (screen->xdisplay, window,
1492 gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
1493 0, G_MAXLONG, False, XA_WINDOW, &type, &format,
1494 &n_items, &bytes_after, &data);
1495 gdk_x11_display_error_trap_pop_ignored (display);
1496
1497 if (type == XA_WINDOW)
1498 value = *(Window *)data;
1499
1500 if (data)
1501 XFree (data);
1502
1503 return value;
1504 }
1505
1506 static void
fetch_net_wm_check_window(GdkScreen * screen)1507 fetch_net_wm_check_window (GdkScreen *screen)
1508 {
1509 GdkX11Screen *x11_screen;
1510 GdkDisplay *display;
1511 Window window;
1512 GTimeVal tv;
1513 gint error;
1514
1515 x11_screen = GDK_X11_SCREEN (screen);
1516 display = x11_screen->display;
1517
1518 g_return_if_fail (GDK_X11_DISPLAY (display)->trusted_client);
1519
1520 if (x11_screen->wmspec_check_window != None)
1521 return; /* already have it */
1522
1523 g_get_current_time (&tv);
1524
1525 if (ABS (tv.tv_sec - x11_screen->last_wmspec_check_time) < 15)
1526 return; /* we've checked recently */
1527
1528 window = get_net_supporting_wm_check (x11_screen, x11_screen->xroot_window);
1529 if (window == None)
1530 return;
1531
1532 if (window != get_net_supporting_wm_check (x11_screen, window))
1533 return;
1534
1535 gdk_x11_display_error_trap_push (display);
1536
1537 /* Find out if this WM goes away, so we can reset everything. */
1538 XSelectInput (x11_screen->xdisplay, window, StructureNotifyMask);
1539
1540 error = gdk_x11_display_error_trap_pop (display);
1541 if (!error)
1542 {
1543 /* We check the window property again because after XGetWindowProperty()
1544 * and before XSelectInput() the window may have been recycled in such a
1545 * way that XSelectInput() doesn't fail but the window is no longer what
1546 * we want.
1547 */
1548 if (window != get_net_supporting_wm_check (x11_screen, window))
1549 return;
1550
1551 x11_screen->wmspec_check_window = window;
1552 x11_screen->last_wmspec_check_time = tv.tv_sec;
1553 x11_screen->need_refetch_net_supported = TRUE;
1554 x11_screen->need_refetch_wm_name = TRUE;
1555
1556 /* Careful, reentrancy */
1557 _gdk_x11_screen_window_manager_changed (screen);
1558 }
1559 }
1560
1561 /**
1562 * gdk_x11_screen_supports_net_wm_hint:
1563 * @screen: (type GdkX11Screen): the relevant #GdkScreen.
1564 * @property: a property atom.
1565 *
1566 * This function is specific to the X11 backend of GDK, and indicates
1567 * whether the window manager supports a certain hint from the
1568 * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
1569 *
1570 * When using this function, keep in mind that the window manager
1571 * can change over time; so you shouldn’t use this function in
1572 * a way that impacts persistent application state. A common bug
1573 * is that your application can start up before the window manager
1574 * does when the user logs in, and before the window manager starts
1575 * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
1576 * You can monitor the window_manager_changed signal on #GdkScreen to detect
1577 * a window manager change.
1578 *
1579 * Returns: %TRUE if the window manager supports @property
1580 *
1581 * Since: 2.2
1582 **/
1583 gboolean
gdk_x11_screen_supports_net_wm_hint(GdkScreen * screen,GdkAtom property)1584 gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
1585 GdkAtom property)
1586 {
1587 gulong i;
1588 GdkX11Screen *x11_screen;
1589 NetWmSupportedAtoms *supported_atoms;
1590 GdkDisplay *display;
1591 Atom atom;
1592
1593 g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
1594
1595 x11_screen = GDK_X11_SCREEN (screen);
1596 display = x11_screen->display;
1597
1598 if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
1599 return FALSE;
1600
1601 supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
1602 if (!supported_atoms)
1603 {
1604 supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
1605 g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
1606 }
1607
1608 fetch_net_wm_check_window (screen);
1609
1610 if (x11_screen->wmspec_check_window == None)
1611 return FALSE;
1612
1613 if (x11_screen->need_refetch_net_supported)
1614 {
1615 /* WM has changed since we last got the supported list,
1616 * refetch it.
1617 */
1618 Atom type;
1619 gint format;
1620 gulong bytes_after;
1621
1622 x11_screen->need_refetch_net_supported = FALSE;
1623
1624 if (supported_atoms->atoms)
1625 XFree (supported_atoms->atoms);
1626
1627 supported_atoms->atoms = NULL;
1628 supported_atoms->n_atoms = 0;
1629
1630 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), x11_screen->xroot_window,
1631 gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"),
1632 0, G_MAXLONG, False, XA_ATOM, &type, &format,
1633 &supported_atoms->n_atoms, &bytes_after,
1634 (guchar **)&supported_atoms->atoms);
1635
1636 if (type != XA_ATOM)
1637 return FALSE;
1638 }
1639
1640 if (supported_atoms->atoms == NULL)
1641 return FALSE;
1642
1643 atom = gdk_x11_atom_to_xatom_for_display (display, property);
1644
1645 for (i = 0; i < supported_atoms->n_atoms; i++)
1646 {
1647 if (supported_atoms->atoms[i] == atom)
1648 return TRUE;
1649 }
1650
1651 return FALSE;
1652 }
1653
1654 /**
1655 * gdk_x11_screen_get_window_manager_name:
1656 * @screen: (type GdkX11Screen): a #GdkScreen
1657 *
1658 * Returns the name of the window manager for @screen.
1659 *
1660 * Returns: the name of the window manager screen @screen, or
1661 * "unknown" if the window manager is unknown. The string is owned by GDK
1662 * and should not be freed.
1663 *
1664 * Since: 2.2
1665 **/
1666 const char*
gdk_x11_screen_get_window_manager_name(GdkScreen * screen)1667 gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
1668 {
1669 GdkX11Screen *x11_screen;
1670 GdkDisplay *display;
1671
1672 x11_screen = GDK_X11_SCREEN (screen);
1673 display = x11_screen->display;
1674
1675 if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
1676 return x11_screen->window_manager_name;
1677
1678 fetch_net_wm_check_window (screen);
1679
1680 if (x11_screen->need_refetch_wm_name)
1681 {
1682 /* Get the name of the window manager */
1683 x11_screen->need_refetch_wm_name = FALSE;
1684
1685 g_free (x11_screen->window_manager_name);
1686 x11_screen->window_manager_name = g_strdup ("unknown");
1687
1688 if (x11_screen->wmspec_check_window != None)
1689 {
1690 Atom type;
1691 gint format;
1692 gulong n_items;
1693 gulong bytes_after;
1694 gchar *name;
1695
1696 name = NULL;
1697
1698 gdk_x11_display_error_trap_push (display);
1699
1700 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1701 x11_screen->wmspec_check_window,
1702 gdk_x11_get_xatom_by_name_for_display (display,
1703 "_NET_WM_NAME"),
1704 0, G_MAXLONG, False,
1705 gdk_x11_get_xatom_by_name_for_display (display,
1706 "UTF8_STRING"),
1707 &type, &format,
1708 &n_items, &bytes_after,
1709 (guchar **)&name);
1710
1711 gdk_x11_display_error_trap_pop_ignored (display);
1712
1713 if (name != NULL)
1714 {
1715 g_free (x11_screen->window_manager_name);
1716 x11_screen->window_manager_name = g_strdup (name);
1717 XFree (name);
1718 }
1719 }
1720 }
1721
1722 return GDK_X11_SCREEN (screen)->window_manager_name;
1723 }
1724
1725 static void
gdk_x11_screen_class_init(GdkX11ScreenClass * klass)1726 gdk_x11_screen_class_init (GdkX11ScreenClass *klass)
1727 {
1728 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1729 GdkScreenClass *screen_class = GDK_SCREEN_CLASS (klass);
1730
1731 object_class->dispose = gdk_x11_screen_dispose;
1732 object_class->finalize = gdk_x11_screen_finalize;
1733
1734 screen_class->get_display = gdk_x11_screen_get_display;
1735 screen_class->get_width = gdk_x11_screen_get_width;
1736 screen_class->get_height = gdk_x11_screen_get_height;
1737 screen_class->get_width_mm = gdk_x11_screen_get_width_mm;
1738 screen_class->get_height_mm = gdk_x11_screen_get_height_mm;
1739 screen_class->get_number = gdk_x11_screen_get_number;
1740 screen_class->get_root_window = gdk_x11_screen_get_root_window;
1741 screen_class->get_system_visual = _gdk_x11_screen_get_system_visual;
1742 screen_class->get_rgba_visual = gdk_x11_screen_get_rgba_visual;
1743 screen_class->is_composited = gdk_x11_screen_is_composited;
1744 screen_class->make_display_name = gdk_x11_screen_make_display_name;
1745 screen_class->get_active_window = gdk_x11_screen_get_active_window;
1746 screen_class->get_window_stack = gdk_x11_screen_get_window_stack;
1747 screen_class->get_setting = gdk_x11_screen_get_setting;
1748 screen_class->visual_get_best_depth = _gdk_x11_screen_visual_get_best_depth;
1749 screen_class->visual_get_best_type = _gdk_x11_screen_visual_get_best_type;
1750 screen_class->visual_get_best = _gdk_x11_screen_visual_get_best;
1751 screen_class->visual_get_best_with_depth = _gdk_x11_screen_visual_get_best_with_depth;
1752 screen_class->visual_get_best_with_type = _gdk_x11_screen_visual_get_best_with_type;
1753 screen_class->visual_get_best_with_both = _gdk_x11_screen_visual_get_best_with_both;
1754 screen_class->query_depths = _gdk_x11_screen_query_depths;
1755 screen_class->query_visual_types = _gdk_x11_screen_query_visual_types;
1756 screen_class->list_visuals = _gdk_x11_screen_list_visuals;
1757
1758 signals[WINDOW_MANAGER_CHANGED] =
1759 g_signal_new (g_intern_static_string ("window-manager-changed"),
1760 G_OBJECT_CLASS_TYPE (object_class),
1761 G_SIGNAL_RUN_LAST,
1762 G_STRUCT_OFFSET (GdkX11ScreenClass, window_manager_changed),
1763 NULL, NULL,
1764 NULL,
1765 G_TYPE_NONE,
1766 0);
1767 }
1768
1769 static guint32
get_netwm_cardinal_property(GdkScreen * screen,const gchar * name)1770 get_netwm_cardinal_property (GdkScreen *screen,
1771 const gchar *name)
1772 {
1773 GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1774 GdkAtom atom;
1775 guint32 prop = 0;
1776 Atom type;
1777 gint format;
1778 gulong nitems;
1779 gulong bytes_after;
1780 guchar *data;
1781
1782 atom = gdk_atom_intern_static_string (name);
1783
1784 if (!gdk_x11_screen_supports_net_wm_hint (screen, atom))
1785 return 0;
1786
1787 XGetWindowProperty (x11_screen->xdisplay,
1788 x11_screen->xroot_window,
1789 gdk_x11_get_xatom_by_name_for_display (GDK_SCREEN_DISPLAY (screen), name),
1790 0, G_MAXLONG,
1791 False, XA_CARDINAL, &type, &format, &nitems,
1792 &bytes_after, &data);
1793 if (type == XA_CARDINAL)
1794 {
1795 prop = *(gulong *)data;
1796 XFree (data);
1797 }
1798
1799 return prop;
1800 }
1801
1802 /**
1803 * gdk_x11_screen_get_number_of_desktops:
1804 * @screen: (type GdkX11Screen): a #GdkScreen
1805 *
1806 * Returns the number of workspaces for @screen when running under a
1807 * window manager that supports multiple workspaces, as described
1808 * in the
1809 * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
1810 *
1811 * Returns: the number of workspaces, or 0 if workspaces are not supported
1812 *
1813 * Since: 3.10
1814 */
1815 guint32
gdk_x11_screen_get_number_of_desktops(GdkScreen * screen)1816 gdk_x11_screen_get_number_of_desktops (GdkScreen *screen)
1817 {
1818 return get_netwm_cardinal_property (screen, "_NET_NUMBER_OF_DESKTOPS");
1819 }
1820
1821 /**
1822 * gdk_x11_screen_get_current_desktop:
1823 * @screen: (type GdkX11Screen): a #GdkScreen
1824 *
1825 * Returns the current workspace for @screen when running under a
1826 * window manager that supports multiple workspaces, as described
1827 * in the
1828 * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
1829 *
1830 * Returns: the current workspace, or 0 if workspaces are not supported
1831 *
1832 * Since: 3.10
1833 */
1834 guint32
gdk_x11_screen_get_current_desktop(GdkScreen * screen)1835 gdk_x11_screen_get_current_desktop (GdkScreen *screen)
1836 {
1837 return get_netwm_cardinal_property (screen, "_NET_CURRENT_DESKTOP");
1838 }
1839