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
49static void gdk_x11_screen_dispose (GObject *object);
50static void gdk_x11_screen_finalize (GObject *object);
51static void init_randr_support (GdkX11Screen *screen);
52static void process_monitors_change (GdkX11Screen *screen);
53
54enum
55{
56 WINDOW_MANAGER_CHANGED,
57 LAST_SIGNAL
58};
59
60static guint signals[LAST_SIGNAL] = { 0 };
61
62G_DEFINE_TYPE (GdkX11Screen, gdk_x11_screen, G_TYPE_OBJECT)
63
64typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
65
66struct _NetWmSupportedAtoms
67{
68 Atom *atoms;
69 gulong n_atoms;
70};
71
72static void
73gdk_x11_screen_init (GdkX11Screen *screen)
74{
75}
76
77static void
78gdk_x11_screen_dispose (GObject *object)
79{
80 GdkX11Screen *x11_screen = GDK_X11_SCREEN (object);
81 int i;
82
83 for (i = 0; i < 32; ++i)
84 {
85 if (x11_screen->subwindow_gcs[i])
86 {
87 XFreeGC (x11_screen->xdisplay, x11_screen->subwindow_gcs[i]);
88 x11_screen->subwindow_gcs[i] = 0;
89 }
90 }
91
92 _gdk_x11_xsettings_finish (x11_screen);
93
94 G_OBJECT_CLASS (gdk_x11_screen_parent_class)->dispose (object);
95
96 x11_screen->xdisplay = NULL;
97 x11_screen->xscreen = NULL;
98 x11_screen->xroot_window = None;
99 x11_screen->wmspec_check_window = None;
100}
101
102static void
103gdk_x11_screen_finalize (GObject *object)
104{
105 GdkX11Screen *x11_screen = GDK_X11_SCREEN (object);
106
107 g_free (mem: x11_screen->window_manager_name);
108
109 G_OBJECT_CLASS (gdk_x11_screen_parent_class)->finalize (object);
110}
111
112/**
113 * gdk_x11_screen_get_monitor_output:
114 * @screen: a `GdkX11Screen`
115 * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
116 *
117 * Gets the XID of the specified output/monitor.
118 * If the X server does not support version 1.2 of the RANDR
119 * extension, 0 is returned.
120 *
121 * Returns: the XID of the monitor
122 */
123XID
124gdk_x11_screen_get_monitor_output (GdkX11Screen *x11_screen,
125 int monitor_num)
126{
127 GdkX11Display *x11_display = GDK_X11_DISPLAY (x11_screen->display);
128 GdkX11Monitor *monitor;
129 XID output;
130
131 g_return_val_if_fail (monitor_num >= 0, None);
132 g_return_val_if_fail (monitor_num < g_list_model_get_n_items (G_LIST_MODEL (x11_display->monitors)), None);
133
134 monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: monitor_num);
135 output = monitor->output;
136 g_object_unref (object: monitor);
137
138 return output;
139}
140
141static int
142get_current_desktop (GdkX11Screen *screen)
143{
144 Display *display;
145 Window win;
146 Atom current_desktop, type;
147 int format;
148 unsigned long n_items, bytes_after;
149 unsigned char *data_return = NULL;
150 int workspace = 0;
151
152 if (!gdk_x11_screen_supports_net_wm_hint (screen,
153 property_name: g_intern_static_string (string: "_NET_CURRENT_DESKTOP")))
154 return workspace;
155
156 display = GDK_DISPLAY_XDISPLAY (GDK_SCREEN_DISPLAY (screen));
157 win = XRootWindow (display, gdk_x11_screen_get_screen_number (screen));
158
159 current_desktop = XInternAtom (display, "_NET_CURRENT_DESKTOP", True);
160
161 XGetWindowProperty (display,
162 win,
163 current_desktop,
164 0, G_MAXLONG,
165 False, XA_CARDINAL,
166 &type, &format, &n_items, &bytes_after,
167 &data_return);
168
169 if (type == XA_CARDINAL && format == 32 && n_items > 0)
170 workspace = ((long *) data_return)[0];
171
172 if (data_return)
173 XFree (data_return);
174
175 return workspace;
176}
177
178gboolean
179_gdk_x11_screen_get_monitor_work_area (GdkX11Screen *x11_screen,
180 GdkMonitor *monitor,
181 GdkRectangle *area)
182{
183 Display *xdisplay;
184 Atom net_workareas;
185 int current_desktop;
186 char *workareas_dn_name;
187 Atom workareas_dn;
188 int screen_number;
189 Window xroot;
190 int result;
191 Atom type;
192 int format;
193 gulong num;
194 gulong leftovers;
195 guchar *ret_workarea;
196 long *workareas;
197 GdkRectangle geometry;
198 int i;
199
200 if (!gdk_x11_screen_supports_net_wm_hint (screen: x11_screen,
201 property_name: g_intern_static_string (string: "_GTK_WORKAREAS")))
202 return FALSE;
203
204 xdisplay = gdk_x11_display_get_xdisplay (display: x11_screen->display);
205 net_workareas = XInternAtom (xdisplay, "_GTK_WORKAREAS", False);
206
207 if (net_workareas == None)
208 return FALSE;
209
210 current_desktop = get_current_desktop (screen: x11_screen);
211 workareas_dn_name = g_strdup_printf (format: "_GTK_WORKAREAS_D%d", current_desktop);
212 workareas_dn = XInternAtom (xdisplay, workareas_dn_name, True);
213 g_free (mem: workareas_dn_name);
214
215 if (workareas_dn == None)
216 return FALSE;
217
218 screen_number = gdk_x11_screen_get_screen_number (screen: x11_screen);
219 xroot = XRootWindow (xdisplay, screen_number);
220
221 gdk_x11_display_error_trap_push (display: x11_screen->display);
222
223 ret_workarea = NULL;
224 result = XGetWindowProperty (xdisplay,
225 xroot,
226 workareas_dn,
227 0,
228 G_MAXLONG,
229 False,
230 AnyPropertyType,
231 &type,
232 &format,
233 &num,
234 &leftovers,
235 &ret_workarea);
236
237 gdk_x11_display_error_trap_pop_ignored (display: x11_screen->display);
238
239 if (result != Success ||
240 type == None ||
241 format == 0 ||
242 leftovers ||
243 num % 4 != 0)
244 {
245 XFree (ret_workarea);
246
247 return FALSE;
248 }
249
250 workareas = (long *) ret_workarea;
251
252 gdk_monitor_get_geometry (monitor, geometry: &geometry);
253 *area = geometry;
254
255 for (i = 0; i < num / 4; i++)
256 {
257 GdkRectangle work_area;
258
259 work_area = (GdkRectangle) {
260 .x = workareas[0] / x11_screen->surface_scale,
261 .y = workareas[1] / x11_screen->surface_scale,
262 .width = workareas[2] / x11_screen->surface_scale,
263 .height = workareas[3] / x11_screen->surface_scale,
264 };
265
266 if (gdk_rectangle_intersect (src1: area, src2: &work_area, dest: &work_area))
267 *area = work_area;
268
269 workareas += 4;
270 }
271
272 XFree (ret_workarea);
273
274 return TRUE;
275}
276
277void
278gdk_x11_screen_get_work_area (GdkX11Screen *x11_screen,
279 GdkRectangle *area)
280{
281 Atom workarea;
282 Atom type;
283 Window win;
284 int format;
285 gulong num;
286 gulong leftovers;
287 gulong max_len = 4 * 32;
288 guchar *ret_workarea = NULL;
289 long *workareas;
290 int result;
291 int desktop;
292 Display *display;
293
294 display = GDK_SCREEN_XDISPLAY (x11_screen);
295 workarea = XInternAtom (display, "_NET_WORKAREA", True);
296
297 /* Defaults in case of error */
298 area->x = 0;
299 area->y = 0;
300 area->width = WidthOfScreen (x11_screen->xscreen);
301 area->height = HeightOfScreen (x11_screen->xscreen);
302
303 if (!gdk_x11_screen_supports_net_wm_hint (screen: x11_screen,
304 property_name: g_intern_static_string (string: "_NET_WORKAREA")))
305 return;
306
307 if (workarea == None)
308 return;
309
310 win = XRootWindow (display, gdk_x11_screen_get_screen_number (screen: x11_screen));
311 result = XGetWindowProperty (display,
312 win,
313 workarea,
314 0,
315 max_len,
316 False,
317 AnyPropertyType,
318 &type,
319 &format,
320 &num,
321 &leftovers,
322 &ret_workarea);
323 if (result != Success ||
324 type == None ||
325 format == 0 ||
326 leftovers ||
327 num % 4 != 0)
328 goto out;
329
330 desktop = get_current_desktop (screen: x11_screen);
331 if (desktop + 1 > num / 4) /* fvwm gets this wrong */
332 goto out;
333
334 workareas = (long *) ret_workarea;
335 area->x = workareas[desktop * 4];
336 area->y = workareas[desktop * 4 + 1];
337 area->width = workareas[desktop * 4 + 2];
338 area->height = workareas[desktop * 4 + 3];
339
340 area->x /= x11_screen->surface_scale;
341 area->y /= x11_screen->surface_scale;
342 area->width /= x11_screen->surface_scale;
343 area->height /= x11_screen->surface_scale;
344
345out:
346 if (ret_workarea)
347 XFree (ret_workarea);
348}
349
350/**
351 * gdk_x11_screen_get_xscreen:
352 * @screen: a `GdkX11Screen`
353 *
354 * Returns the screen of a `GdkX11Screen`.
355 *
356 * Returns: (transfer none): an Xlib Screen*
357 */
358Screen *
359gdk_x11_screen_get_xscreen (GdkX11Screen *screen)
360{
361 return screen->xscreen;
362}
363
364/**
365 * gdk_x11_screen_get_screen_number:
366 * @screen: a `GdkX11Screen`
367 *
368 * Returns the index of a `GdkX11Screen`.
369 *
370 * Returns: the position of @screen among the screens
371 * of its display
372 */
373int
374gdk_x11_screen_get_screen_number (GdkX11Screen *screen)
375{
376 return screen->screen_num;
377}
378
379static void
380notify_surface_monitor_change (GdkX11Display *display,
381 GdkMonitor *monitor)
382{
383 GHashTableIter iter;
384 GdkSurface *surface;
385
386 /* We iterate the surfaces via the hash table here because it's the only
387 * thing that contains all the surfaces.
388 */
389 if (display->xid_ht == NULL)
390 return;
391
392 g_hash_table_iter_init (iter: &iter, hash_table: display->xid_ht);
393 while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer *)&surface))
394 {
395 gdk_x11_surface_check_monitor (surface, monitor);
396 }
397}
398
399static GdkX11Monitor *
400find_monitor_by_output (GdkX11Display *x11_display, XID output)
401{
402 int i;
403
404 for (i = 0; i < g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)); i++)
405 {
406 GdkX11Monitor *monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
407 g_object_unref (object: monitor);
408 if (monitor->output == output)
409 return monitor;
410 }
411
412 return NULL;
413}
414
415static GdkSubpixelLayout
416translate_subpixel_order (int subpixel)
417{
418 switch (subpixel)
419 {
420 case 1: return GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB;
421 case 2: return GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR;
422 case 3: return GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB;
423 case 4: return GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR;
424 case 5: return GDK_SUBPIXEL_LAYOUT_NONE;
425 default: return GDK_SUBPIXEL_LAYOUT_UNKNOWN;
426 }
427}
428
429static gboolean
430init_randr15 (GdkX11Screen *x11_screen)
431{
432#ifdef HAVE_RANDR15
433 GdkDisplay *display = GDK_SCREEN_DISPLAY (x11_screen);
434 GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
435 XRRScreenResources *resources;
436 RROutput primary_output = None;
437 RROutput first_output = None;
438 int i;
439 XRRMonitorInfo *rr_monitors;
440 int num_rr_monitors;
441
442 if (!x11_display->have_randr15)
443 return FALSE;
444
445 resources = XRRGetScreenResourcesCurrent (dpy: x11_screen->xdisplay,
446 window: x11_screen->xroot_window);
447 if (!resources)
448 return FALSE;
449
450 rr_monitors = XRRGetMonitors (dpy: x11_screen->xdisplay,
451 window: x11_screen->xroot_window,
452 True,
453 nmonitors: &num_rr_monitors);
454 if (!rr_monitors)
455 return FALSE;
456
457 for (i = 0; i < g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)); i++)
458 {
459 GdkX11Monitor *monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
460 monitor->add = FALSE;
461 monitor->remove = TRUE;
462 g_object_unref (object: monitor);
463 }
464
465 for (i = 0; i < num_rr_monitors; i++)
466 {
467 RROutput output = rr_monitors[i].outputs[0];
468 XRROutputInfo *output_info;
469 GdkX11Monitor *monitor;
470 GdkRectangle geometry;
471 GdkRectangle newgeo;
472 char *name;
473 char *manufacturer = NULL;
474 int refresh_rate = 0;
475
476 gdk_x11_display_error_trap_push (display);
477 output_info = XRRGetOutputInfo (dpy: x11_screen->xdisplay, resources, output);
478 if (gdk_x11_display_error_trap_pop (display))
479 continue;
480
481 if (output_info == NULL)
482 continue;
483
484 if (output_info->connection == RR_Disconnected)
485 {
486 XRRFreeOutputInfo (outputInfo: output_info);
487 continue;
488 }
489
490 if (first_output == None)
491 first_output = output;
492
493 if (output_info->crtc)
494 {
495 XRRCrtcInfo *crtc;
496 int j;
497
498 gdk_x11_display_error_trap_push (display);
499 crtc = XRRGetCrtcInfo (dpy: x11_screen->xdisplay, resources,
500 crtc: output_info->crtc);
501 if (gdk_x11_display_error_trap_pop (display))
502 {
503 XRRFreeOutputInfo (outputInfo: output_info);
504 continue;
505 }
506
507 for (j = 0; j < resources->nmode; j++)
508 {
509 XRRModeInfo *xmode = &resources->modes[j];
510 if (xmode->id == crtc->mode)
511 {
512 if (xmode->hTotal != 0 && xmode->vTotal != 0)
513 refresh_rate = (1000 * xmode->dotClock) / (xmode->hTotal * xmode->vTotal);
514 break;
515 }
516 }
517
518 XRRFreeCrtcInfo (crtcInfo: crtc);
519 }
520
521 monitor = find_monitor_by_output (x11_display, output);
522 if (monitor)
523 monitor->remove = FALSE;
524 else
525 {
526 monitor = g_object_new (GDK_TYPE_X11_MONITOR,
527 first_property_name: "display", display,
528 NULL);
529 monitor->output = output;
530 monitor->add = TRUE;
531 g_list_store_append (store: x11_display->monitors, item: monitor);
532 }
533
534 /* Fetch minimal manufacturer information (PNP ID) from EDID */
535 {
536 #define EDID_LENGTH 128
537 Atom actual_type, edid_atom;
538 char tmp[3];
539 int actual_format;
540 unsigned char *prop;
541 unsigned long nbytes, bytes_left;
542 Display *disp = GDK_DISPLAY_XDISPLAY (x11_display);
543
544 edid_atom = XInternAtom (disp, RR_PROPERTY_RANDR_EDID, FALSE);
545
546 XRRGetOutputProperty (dpy: disp, output,
547 property: edid_atom,
548 offset: 0,
549 EDID_LENGTH,
550 FALSE,
551 FALSE,
552 AnyPropertyType,
553 actual_type: &actual_type,
554 actual_format: &actual_format,
555 nitems: &nbytes,
556 bytes_after: &bytes_left,
557 prop: &prop);
558
559 // Check partial EDID header (whole header: 00 ff ff ff ff ff ff 00)
560 if (nbytes >= EDID_LENGTH && prop[0] == 0x00 && prop[1] == 0xff)
561 {
562 /* decode the Vendor ID from three 5 bit words packed into 2 bytes
563 * /--08--\/--09--\
564 * 7654321076543210
565 * |\---/\---/\---/
566 * R C1 C2 C3 */
567 tmp[0] = 'A' + ((prop[8] & 0x7c) / 4) - 1;
568 tmp[1] = 'A' + ((prop[8] & 0x3) * 8) + ((prop[9] & 0xe0) / 32) - 1;
569 tmp[2] = 'A' + (prop[9] & 0x1f) - 1;
570
571 manufacturer = g_strndup (str: tmp, n: sizeof (tmp));
572 }
573
574 XFree(prop);
575 #undef EDID_LENGTH
576 }
577
578 gdk_monitor_get_geometry (GDK_MONITOR (monitor), geometry: &geometry);
579 name = g_strndup (str: output_info->name, n: output_info->nameLen);
580
581 newgeo.x = rr_monitors[i].x / x11_screen->surface_scale;
582 newgeo.y = rr_monitors[i].y / x11_screen->surface_scale;
583 newgeo.width = rr_monitors[i].width / x11_screen->surface_scale;
584 newgeo.height = rr_monitors[i].height / x11_screen->surface_scale;
585
586 gdk_monitor_set_geometry (GDK_MONITOR (monitor), geometry: &newgeo);
587 gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
588 width_mm: rr_monitors[i].mwidth,
589 height_mm: rr_monitors[i].mheight);
590 gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor),
591 subpixel: translate_subpixel_order (subpixel: output_info->subpixel_order));
592 gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh_rate);
593 gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), scale: x11_screen->surface_scale);
594 gdk_monitor_set_model (GDK_MONITOR (monitor), model: name);
595 gdk_monitor_set_connector (GDK_MONITOR (monitor), connector: name);
596 gdk_monitor_set_manufacturer (GDK_MONITOR (monitor), manufacturer);
597 g_free (mem: manufacturer);
598 g_free (mem: name);
599
600 if (rr_monitors[i].primary)
601 primary_output = monitor->output;
602
603 XRRFreeOutputInfo (outputInfo: output_info);
604 }
605
606 XRRFreeMonitors (monitors: rr_monitors);
607 XRRFreeScreenResources (resources);
608
609 for (i = g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)) - 1; i >= 0; i--)
610 {
611 GdkX11Monitor *monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
612
613 notify_surface_monitor_change (display: x11_display, GDK_MONITOR (monitor));
614 if (monitor->remove)
615 {
616 g_list_store_remove (store: x11_display->monitors, position: i);
617 gdk_monitor_invalidate (GDK_MONITOR (monitor));
618 }
619 g_object_unref (object: monitor);
620 }
621
622 x11_display->primary_monitor = 0;
623 for (i = 0; i < g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)); i++)
624 {
625 GdkX11Monitor *monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
626 g_object_unref (object: monitor);
627 if (monitor->output == primary_output)
628 {
629 x11_display->primary_monitor = i;
630 break;
631 }
632
633 /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
634 if (primary_output == None &&
635 g_ascii_strncasecmp (s1: gdk_monitor_get_model (GDK_MONITOR (monitor)), s2: "LVDS", n: 4) == 0)
636 {
637 x11_display->primary_monitor = i;
638 break;
639 }
640
641 /* No primary specified and no LVDS found */
642 if (monitor->output == first_output)
643 x11_display->primary_monitor = i;
644 }
645
646 return g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)) > 0;
647#endif
648
649 return FALSE;
650}
651
652static gboolean
653init_randr13 (GdkX11Screen *x11_screen)
654{
655#ifdef HAVE_RANDR
656 GdkDisplay *display = GDK_SCREEN_DISPLAY (x11_screen);
657 GdkX11Display *x11_display = GDK_X11_DISPLAY (display);
658 XRRScreenResources *resources;
659 RROutput primary_output = None;
660 RROutput first_output = None;
661 int i;
662
663 if (!x11_display->have_randr13)
664 return FALSE;
665
666 resources = XRRGetScreenResourcesCurrent (dpy: x11_screen->xdisplay,
667 window: x11_screen->xroot_window);
668 if (!resources)
669 return FALSE;
670
671 for (i = 0; i < g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)); i++)
672 {
673 GdkX11Monitor *monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
674 monitor->add = FALSE;
675 monitor->remove = TRUE;
676 g_object_unref (object: monitor);
677 }
678
679 for (i = 0; i < resources->noutput; ++i)
680 {
681 RROutput output = resources->outputs[i];
682 XRROutputInfo *output_info =
683 XRRGetOutputInfo (dpy: x11_screen->xdisplay, resources, output);
684
685 if (output_info->connection == RR_Disconnected)
686 {
687 XRRFreeOutputInfo (outputInfo: output_info);
688 continue;
689 }
690
691 if (output_info->crtc)
692 {
693 GdkX11Monitor *monitor;
694 XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy: x11_screen->xdisplay, resources, crtc: output_info->crtc);
695 char *name;
696 GdkRectangle geometry;
697 GdkRectangle newgeo;
698 int j;
699 int refresh_rate = 0;
700
701 for (j = 0; j < resources->nmode; j++)
702 {
703 XRRModeInfo *xmode = &resources->modes[j];
704 if (xmode->id == crtc->mode)
705 {
706 if (xmode->hTotal != 0 && xmode->vTotal != 0)
707 refresh_rate = (1000 * xmode->dotClock) / (xmode->hTotal * xmode->vTotal);
708 break;
709 }
710 }
711
712 monitor = find_monitor_by_output (x11_display, output);
713 if (monitor)
714 monitor->remove = FALSE;
715 else
716 {
717 monitor = g_object_new (object_type: gdk_x11_monitor_get_type (),
718 first_property_name: "display", display,
719 NULL);
720 monitor->output = output;
721 monitor->add = TRUE;
722 g_list_store_append (store: x11_display->monitors, item: monitor);
723 }
724
725 gdk_monitor_get_geometry (GDK_MONITOR (monitor), geometry: &geometry);
726 name = g_strndup (str: output_info->name, n: output_info->nameLen);
727
728 newgeo.x = crtc->x / x11_screen->surface_scale;
729 newgeo.y = crtc->y / x11_screen->surface_scale;
730 newgeo.width = crtc->width / x11_screen->surface_scale;
731 newgeo.height = crtc->height / x11_screen->surface_scale;
732
733 gdk_monitor_set_geometry (GDK_MONITOR (monitor), geometry: &newgeo);
734 gdk_monitor_set_physical_size (GDK_MONITOR (monitor),
735 width_mm: output_info->mm_width,
736 height_mm: output_info->mm_height);
737 gdk_monitor_set_subpixel_layout (GDK_MONITOR (monitor),
738 subpixel: translate_subpixel_order (subpixel: output_info->subpixel_order));
739 gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh_rate);
740 gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), scale: x11_screen->surface_scale);
741 gdk_monitor_set_model (GDK_MONITOR (monitor), model: name);
742
743 g_free (mem: name);
744
745 XRRFreeCrtcInfo (crtcInfo: crtc);
746 }
747
748 XRRFreeOutputInfo (outputInfo: output_info);
749 }
750
751 if (resources->noutput > 0)
752 first_output = resources->outputs[0];
753
754 XRRFreeScreenResources (resources);
755
756 /* Which usable multihead data is not returned in non RandR 1.2+ X driver? */
757
758 for (i = g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)) - 1; i >= 0; i--)
759 {
760 GdkX11Monitor *monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
761
762 notify_surface_monitor_change (display: x11_display, GDK_MONITOR (monitor));
763 if (monitor->remove)
764 {
765 g_list_store_remove (store: x11_display->monitors, position: i);
766 gdk_monitor_invalidate (GDK_MONITOR (monitor));
767 }
768 g_object_unref (object: monitor);
769 }
770
771 x11_display->primary_monitor = 0;
772 primary_output = XRRGetOutputPrimary (dpy: x11_screen->xdisplay,
773 window: x11_screen->xroot_window);
774
775 for (i = 0; i < g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)); i++)
776 {
777 GdkX11Monitor *monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
778 g_object_unref (object: monitor);
779 if (monitor->output == primary_output)
780 {
781 x11_display->primary_monitor = i;
782 break;
783 }
784
785 /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
786 if (primary_output == None &&
787 g_ascii_strncasecmp (s1: gdk_monitor_get_model (GDK_MONITOR (monitor)), s2: "LVDS", n: 4) == 0)
788 {
789 x11_display->primary_monitor = i;
790 break;
791 }
792
793 /* No primary specified and no LVDS found */
794 if (monitor->output == first_output)
795 x11_display->primary_monitor = i;
796 }
797
798 return g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)) > 0;
799#endif
800
801 return FALSE;
802}
803
804static void
805init_no_multihead (GdkX11Screen *x11_screen)
806{
807 GdkX11Display *x11_display = GDK_X11_DISPLAY (x11_screen->display);
808 GdkX11Monitor *monitor;
809 int width_mm, height_mm;
810 int width, height;
811 int i;
812
813 for (i = 0; i < g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)); i++)
814 {
815 monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
816 monitor->add = FALSE;
817 monitor->remove = TRUE;
818 g_object_unref (object: monitor);
819 }
820
821 monitor = find_monitor_by_output (x11_display, output: 0);
822 if (monitor)
823 monitor->remove = FALSE;
824 else
825 {
826 monitor = g_object_new (object_type: gdk_x11_monitor_get_type (),
827 first_property_name: "display", x11_display,
828 NULL);
829 monitor->output = 0;
830 monitor->add = TRUE;
831 g_list_store_append (store: x11_display->monitors, item: monitor);
832 }
833
834 width_mm = WidthMMOfScreen (x11_screen->xscreen);
835 height_mm = HeightMMOfScreen (x11_screen->xscreen);
836 width = WidthOfScreen (x11_screen->xscreen);
837 height = HeightOfScreen (x11_screen->xscreen);
838
839 gdk_monitor_set_geometry (GDK_MONITOR (monitor), geometry: &(GdkRectangle) { 0, 0, width, height });
840 gdk_monitor_set_physical_size (GDK_MONITOR (monitor), width_mm, height_mm);
841 gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), scale: x11_screen->surface_scale);
842
843 x11_display->primary_monitor = 0;
844
845 for (i = g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)) - 1; i >= 0; i--)
846 {
847 monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
848
849 notify_surface_monitor_change (display: x11_display, GDK_MONITOR (monitor));
850 if (monitor->remove)
851 {
852 g_list_store_remove (store: x11_display->monitors, position: i);
853 gdk_monitor_invalidate (GDK_MONITOR (monitor));
854 }
855 g_object_unref (object: monitor);
856 }
857}
858
859static void
860init_multihead (GdkX11Screen *screen)
861{
862 if (!init_randr15 (x11_screen: screen) &&
863 !init_randr13 (x11_screen: screen))
864 init_no_multihead (x11_screen: screen);
865}
866
867GdkX11Screen *
868_gdk_x11_screen_new (GdkDisplay *display,
869 int screen_number)
870{
871 GdkX11Screen *x11_screen;
872 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
873 const char *scale_str;
874
875 x11_screen = g_object_new (GDK_TYPE_X11_SCREEN, NULL);
876
877 x11_screen->display = display;
878 x11_screen->xdisplay = display_x11->xdisplay;
879 x11_screen->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
880 x11_screen->screen_num = screen_number;
881 x11_screen->xroot_window = RootWindow (display_x11->xdisplay, screen_number);
882 x11_screen->wmspec_check_window = None;
883 /* we want this to be always non-null */
884 x11_screen->window_manager_name = g_strdup (str: "unknown");
885
886 scale_str = g_getenv (variable: "GDK_SCALE");
887 if (scale_str)
888 {
889 x11_screen->fixed_surface_scale = TRUE;
890 x11_screen->surface_scale = atol (nptr: scale_str);
891 if (x11_screen->surface_scale <= 0)
892 x11_screen->surface_scale = 1;
893 }
894 else
895 x11_screen->surface_scale = 1;
896
897 init_randr_support (screen: x11_screen);
898 init_multihead (screen: x11_screen);
899
900 return x11_screen;
901}
902
903void
904_gdk_x11_screen_set_surface_scale (GdkX11Screen *x11_screen,
905 int scale)
906{
907 GdkX11Display *x11_display = GDK_X11_DISPLAY (x11_screen->display);
908 GList *toplevels, *l;
909 int i;
910
911 if (x11_screen->surface_scale == scale)
912 return;
913
914 x11_screen->surface_scale = scale;
915
916 toplevels = gdk_x11_display_get_toplevel_windows (display: x11_screen->display);
917
918 for (l = toplevels; l != NULL; l = l->next)
919 {
920 GdkSurface *surface = l->data;
921
922 _gdk_x11_surface_set_surface_scale (window: surface, scale);
923 }
924
925 for (i = 0; i < g_list_model_get_n_items (list: G_LIST_MODEL (ptr: x11_display->monitors)); i++)
926 {
927 GdkMonitor *monitor = g_list_model_get_item (list: G_LIST_MODEL (ptr: x11_display->monitors), position: i);
928
929 gdk_monitor_set_scale_factor (monitor, scale);
930
931 g_object_unref (object: monitor);
932 }
933
934 /* We re-read the monitor sizes so we can apply the new scale */
935 process_monitors_change (screen: x11_screen);
936}
937
938static void
939init_randr_support (GdkX11Screen *x11_screen)
940{
941 /* NB: This is also needed for XSettings, so don't remove. */
942 XSelectInput (GDK_SCREEN_XDISPLAY (x11_screen),
943 x11_screen->xroot_window,
944 StructureNotifyMask);
945
946#ifdef HAVE_RANDR
947 if (!GDK_X11_DISPLAY (GDK_SCREEN_DISPLAY (x11_screen))->have_randr12)
948 return;
949
950 XRRSelectInput (GDK_SCREEN_XDISPLAY (x11_screen),
951 window: x11_screen->xroot_window,
952 RRScreenChangeNotifyMask
953 | RRCrtcChangeNotifyMask
954 | RROutputPropertyNotifyMask);
955#endif
956}
957
958static void
959process_monitors_change (GdkX11Screen *screen)
960{
961 init_multihead (screen);
962}
963
964void
965_gdk_x11_screen_size_changed (GdkX11Screen *screen,
966 const XEvent *event)
967{
968#ifdef HAVE_RANDR
969 GdkX11Display *display_x11;
970
971 display_x11 = GDK_X11_DISPLAY (GDK_SCREEN_DISPLAY (screen));
972
973 if (display_x11->have_randr13 && event->type == ConfigureNotify)
974 return;
975
976 XRRUpdateConfiguration (event: (XEvent *) event);
977#else
978 if (event->type != ConfigureNotify)
979 return;
980#endif
981
982 process_monitors_change (screen);
983}
984
985void
986_gdk_x11_screen_get_edge_monitors (GdkX11Screen *x11_screen,
987 int *top,
988 int *bottom,
989 int *left,
990 int *right)
991{
992#ifdef HAVE_XFREE_XINERAMA
993 int top_most_pos = HeightOfScreen (x11_screen->xscreen);
994 int left_most_pos = WidthOfScreen (x11_screen->xscreen);
995 int bottom_most_pos = 0;
996 int right_most_pos = 0;
997 int i;
998 XineramaScreenInfo *x_monitors;
999 int x_n_monitors;
1000#endif
1001
1002 *top = *bottom = *left = *right = -1;
1003
1004#ifdef HAVE_XFREE_XINERAMA
1005 if (!XineramaIsActive (dpy: x11_screen->xdisplay))
1006 return;
1007
1008 x_monitors = XineramaQueryScreens (dpy: x11_screen->xdisplay, number: &x_n_monitors);
1009 if (x_n_monitors <= 0 || x_monitors == NULL)
1010 {
1011 if (x_monitors)
1012 XFree (x_monitors);
1013
1014 return;
1015 }
1016
1017 for (i = 0; i < x_n_monitors; i++)
1018 {
1019 if (left && left_most_pos > x_monitors[i].x_org)
1020 {
1021 left_most_pos = x_monitors[i].x_org;
1022 *left = i;
1023 }
1024 if (right && right_most_pos < x_monitors[i].x_org + x_monitors[i].width)
1025 {
1026 right_most_pos = x_monitors[i].x_org + x_monitors[i].width;
1027 *right = i;
1028 }
1029 if (top && top_most_pos > x_monitors[i].y_org)
1030 {
1031 top_most_pos = x_monitors[i].y_org;
1032 *top = i;
1033 }
1034 if (bottom && bottom_most_pos < x_monitors[i].y_org + x_monitors[i].height)
1035 {
1036 bottom_most_pos = x_monitors[i].y_org + x_monitors[i].height;
1037 *bottom = i;
1038 }
1039 }
1040
1041 XFree (x_monitors);
1042#endif
1043}
1044
1045void
1046_gdk_x11_screen_window_manager_changed (GdkX11Screen *screen)
1047{
1048 g_signal_emit (instance: screen, signal_id: signals[WINDOW_MANAGER_CHANGED], detail: 0);
1049}
1050
1051gboolean
1052gdk_x11_screen_get_setting (GdkX11Screen *x11_screen,
1053 const char *name,
1054 GValue *value)
1055{
1056 const GValue *setting;
1057
1058 if (x11_screen->xsettings == NULL)
1059 goto out;
1060 setting = g_hash_table_lookup (hash_table: x11_screen->xsettings, key: name);
1061 if (setting == NULL)
1062 goto out;
1063
1064 if (!g_value_transform (src_value: setting, dest_value: value))
1065 {
1066 g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
1067 name,
1068 g_type_name (G_VALUE_TYPE (setting)),
1069 g_type_name (G_VALUE_TYPE (value)));
1070 goto out;
1071 }
1072
1073 return TRUE;
1074
1075 out:
1076 return _gdk_x11_screen_get_xft_setting (screen: x11_screen, name, value);
1077}
1078
1079static void
1080cleanup_atoms(gpointer data)
1081{
1082 NetWmSupportedAtoms *supported_atoms = data;
1083 if (supported_atoms->atoms)
1084 XFree (supported_atoms->atoms);
1085 g_free (mem: supported_atoms);
1086}
1087
1088static Window
1089get_net_supporting_wm_check (GdkX11Screen *screen,
1090 Window window)
1091{
1092 GdkDisplay *display;
1093 Atom type;
1094 int format;
1095 gulong n_items;
1096 gulong bytes_after;
1097 guchar *data;
1098 Window value;
1099
1100 display = screen->display;
1101 type = None;
1102 data = NULL;
1103 value = None;
1104
1105 gdk_x11_display_error_trap_push (display);
1106 XGetWindowProperty (screen->xdisplay, window,
1107 gdk_x11_get_xatom_by_name_for_display (display, atom_name: "_NET_SUPPORTING_WM_CHECK"),
1108 0, G_MAXLONG, False, XA_WINDOW, &type, &format,
1109 &n_items, &bytes_after, &data);
1110 gdk_x11_display_error_trap_pop_ignored (display);
1111
1112 if (type == XA_WINDOW)
1113 value = *(Window *)data;
1114
1115 if (data)
1116 XFree (data);
1117
1118 return value;
1119}
1120
1121static void
1122fetch_net_wm_check_window (GdkX11Screen *x11_screen)
1123{
1124 GdkDisplay *display;
1125 Window window;
1126 guint64 now;
1127 int error;
1128
1129 display = x11_screen->display;
1130
1131 g_return_if_fail (GDK_X11_DISPLAY (display)->trusted_client);
1132
1133 if (x11_screen->wmspec_check_window != None)
1134 return; /* already have it */
1135
1136 now = g_get_monotonic_time ();
1137
1138 if ((now - x11_screen->last_wmspec_check_time) / 1e6 < 15)
1139 return; /* we've checked recently */
1140
1141 window = get_net_supporting_wm_check (screen: x11_screen, window: x11_screen->xroot_window);
1142 if (window == None)
1143 return;
1144
1145 if (window != get_net_supporting_wm_check (screen: x11_screen, window))
1146 return;
1147
1148 gdk_x11_display_error_trap_push (display);
1149
1150 /* Find out if this WM goes away, so we can reset everything. */
1151 XSelectInput (x11_screen->xdisplay, window, StructureNotifyMask);
1152
1153 error = gdk_x11_display_error_trap_pop (display);
1154 if (!error)
1155 {
1156 /* We check the window property again because after XGetWindowProperty()
1157 * and before XSelectInput() the window may have been recycled in such a
1158 * way that XSelectInput() doesn't fail but the window is no longer what
1159 * we want.
1160 */
1161 if (window != get_net_supporting_wm_check (screen: x11_screen, window))
1162 return;
1163
1164 x11_screen->wmspec_check_window = window;
1165 x11_screen->last_wmspec_check_time = now;
1166 x11_screen->need_refetch_net_supported = TRUE;
1167 x11_screen->need_refetch_wm_name = TRUE;
1168
1169 /* Careful, reentrancy */
1170 _gdk_x11_screen_window_manager_changed (screen: x11_screen);
1171 }
1172}
1173
1174/**
1175 * gdk_x11_screen_supports_net_wm_hint:
1176 * @screen: the relevant `GdkX11Screen`.
1177 * @property_name: name of the WM property
1178 *
1179 * This function is specific to the X11 backend of GDK, and indicates
1180 * whether the window manager supports a certain hint from the
1181 * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
1182 *
1183 * When using this function, keep in mind that the window manager
1184 * can change over time; so you shouldn’t use this function in
1185 * a way that impacts persistent application state. A common bug
1186 * is that your application can start up before the window manager
1187 * does when the user logs in, and before the window manager starts
1188 * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
1189 * You can monitor the window_manager_changed signal on `GdkX11Screen` to detect
1190 * a window manager change.
1191 *
1192 * Returns: %TRUE if the window manager supports @property
1193 **/
1194gboolean
1195gdk_x11_screen_supports_net_wm_hint (GdkX11Screen *x11_screen,
1196 const char *property_name)
1197{
1198 gulong i;
1199 NetWmSupportedAtoms *supported_atoms;
1200 GdkDisplay *display;
1201 Atom atom;
1202
1203 display = x11_screen->display;
1204
1205 if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
1206 return FALSE;
1207
1208 supported_atoms = g_object_get_data (G_OBJECT (x11_screen), key: "gdk-net-wm-supported-atoms");
1209 if (!supported_atoms)
1210 {
1211 supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
1212 g_object_set_data_full (G_OBJECT (x11_screen), key: "gdk-net-wm-supported-atoms", data: supported_atoms, destroy: cleanup_atoms);
1213 }
1214
1215 fetch_net_wm_check_window (x11_screen);
1216
1217 if (x11_screen->wmspec_check_window == None)
1218 return FALSE;
1219
1220 if (x11_screen->need_refetch_net_supported)
1221 {
1222 /* WM has changed since we last got the supported list,
1223 * refetch it.
1224 */
1225 Atom type;
1226 int format;
1227 gulong bytes_after;
1228
1229 x11_screen->need_refetch_net_supported = FALSE;
1230
1231 if (supported_atoms->atoms)
1232 XFree (supported_atoms->atoms);
1233
1234 supported_atoms->atoms = NULL;
1235 supported_atoms->n_atoms = 0;
1236
1237 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), x11_screen->xroot_window,
1238 gdk_x11_get_xatom_by_name_for_display (display, atom_name: "_NET_SUPPORTED"),
1239 0, G_MAXLONG, False, XA_ATOM, &type, &format,
1240 &supported_atoms->n_atoms, &bytes_after,
1241 (guchar **)&supported_atoms->atoms);
1242
1243 if (type != XA_ATOM)
1244 return FALSE;
1245 }
1246
1247 if (supported_atoms->atoms == NULL)
1248 return FALSE;
1249
1250 atom = gdk_x11_get_xatom_by_name_for_display (display, atom_name: property_name);
1251
1252 for (i = 0; i < supported_atoms->n_atoms; i++)
1253 {
1254 if (supported_atoms->atoms[i] == atom)
1255 return TRUE;
1256 }
1257
1258 return FALSE;
1259}
1260
1261/**
1262 * gdk_x11_screen_get_window_manager_name:
1263 * @screen: a `GdkX11Screen`
1264 *
1265 * Returns the name of the window manager for @screen.
1266 *
1267 * Returns: the name of the window manager screen @screen, or
1268 * "unknown" if the window manager is unknown. The string is owned by GDK
1269 * and should not be freed.
1270 **/
1271const char*
1272gdk_x11_screen_get_window_manager_name (GdkX11Screen *x11_screen)
1273{
1274 GdkDisplay *display;
1275
1276 display = x11_screen->display;
1277
1278 if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
1279 return x11_screen->window_manager_name;
1280
1281 fetch_net_wm_check_window (x11_screen);
1282
1283 if (x11_screen->need_refetch_wm_name)
1284 {
1285 /* Get the name of the window manager */
1286 x11_screen->need_refetch_wm_name = FALSE;
1287
1288 g_free (mem: x11_screen->window_manager_name);
1289 x11_screen->window_manager_name = g_strdup (str: "unknown");
1290
1291 if (x11_screen->wmspec_check_window != None)
1292 {
1293 Atom type;
1294 int format;
1295 gulong n_items;
1296 gulong bytes_after;
1297 char *name;
1298
1299 name = NULL;
1300
1301 gdk_x11_display_error_trap_push (display);
1302
1303 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1304 x11_screen->wmspec_check_window,
1305 gdk_x11_get_xatom_by_name_for_display (display,
1306 atom_name: "_NET_WM_NAME"),
1307 0, G_MAXLONG, False,
1308 gdk_x11_get_xatom_by_name_for_display (display,
1309 atom_name: "UTF8_STRING"),
1310 &type, &format,
1311 &n_items, &bytes_after,
1312 (guchar **)&name);
1313
1314 gdk_x11_display_error_trap_pop_ignored (display);
1315
1316 if (name != NULL)
1317 {
1318 g_free (mem: x11_screen->window_manager_name);
1319 x11_screen->window_manager_name = g_strdup (str: name);
1320 XFree (name);
1321 }
1322 }
1323 }
1324
1325 return x11_screen->window_manager_name;
1326}
1327
1328static void
1329gdk_x11_screen_class_init (GdkX11ScreenClass *klass)
1330{
1331 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1332
1333 object_class->dispose = gdk_x11_screen_dispose;
1334 object_class->finalize = gdk_x11_screen_finalize;
1335
1336 signals[WINDOW_MANAGER_CHANGED] =
1337 g_signal_new (signal_name: g_intern_static_string (string: "window-manager-changed"),
1338 G_OBJECT_CLASS_TYPE (object_class),
1339 signal_flags: G_SIGNAL_RUN_LAST,
1340 G_STRUCT_OFFSET (GdkX11ScreenClass, window_manager_changed),
1341 NULL, NULL,
1342 NULL,
1343 G_TYPE_NONE,
1344 n_params: 0);
1345}
1346
1347static guint32
1348get_netwm_cardinal_property (GdkX11Screen *x11_screen,
1349 const char *name)
1350{
1351 guint32 prop = 0;
1352 Atom type;
1353 int format;
1354 gulong nitems;
1355 gulong bytes_after;
1356 guchar *data;
1357
1358 if (!gdk_x11_screen_supports_net_wm_hint (x11_screen, property_name: name))
1359 return 0;
1360
1361 XGetWindowProperty (x11_screen->xdisplay,
1362 x11_screen->xroot_window,
1363 gdk_x11_get_xatom_by_name_for_display (GDK_SCREEN_DISPLAY (x11_screen), atom_name: name),
1364 0, G_MAXLONG,
1365 False, XA_CARDINAL, &type, &format, &nitems,
1366 &bytes_after, &data);
1367 if (type == XA_CARDINAL)
1368 {
1369 prop = *(gulong *)data;
1370 XFree (data);
1371 }
1372
1373 return prop;
1374}
1375
1376/**
1377 * gdk_x11_screen_get_number_of_desktops:
1378 * @screen: a `GdkX11Screen`
1379 *
1380 * Returns the number of workspaces for @screen when running under a
1381 * window manager that supports multiple workspaces, as described
1382 * in the
1383 * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
1384 *
1385 * Returns: the number of workspaces, or 0 if workspaces are not supported
1386 */
1387guint32
1388gdk_x11_screen_get_number_of_desktops (GdkX11Screen *screen)
1389{
1390 return get_netwm_cardinal_property (x11_screen: screen, name: "_NET_NUMBER_OF_DESKTOPS");
1391}
1392
1393/**
1394 * gdk_x11_screen_get_current_desktop:
1395 * @screen: a `GdkX11Screen`
1396 *
1397 * Returns the current workspace for @screen when running under a
1398 * window manager that supports multiple workspaces, as described
1399 * in the
1400 * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
1401 *
1402 * Returns: the current workspace, or 0 if workspaces are not supported
1403 */
1404guint32
1405gdk_x11_screen_get_current_desktop (GdkX11Screen *screen)
1406{
1407 return get_netwm_cardinal_property (x11_screen: screen, name: "_NET_CURRENT_DESKTOP");
1408}
1409

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