]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkscreen-x11.c
x11: Handle case where xsettings are NULL
[~andy/gtk] / gdk / x11 / gdkscreen-x11.c
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
29 #include <glib.h>
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <X11/Xatom.h>
35
36 #ifdef HAVE_SOLARIS_XINERAMA
37 #include <X11/extensions/xinerama.h>
38 #endif
39 #ifdef HAVE_XFREE_XINERAMA
40 #include <X11/extensions/Xinerama.h>
41 #endif
42
43 #ifdef HAVE_RANDR
44 #include <X11/extensions/Xrandr.h>
45 #endif
46
47 #ifdef HAVE_XFIXES
48 #include <X11/extensions/Xfixes.h>
49 #endif
50
51 static void         gdk_x11_screen_dispose     (GObject           *object);
52 static void         gdk_x11_screen_finalize    (GObject           *object);
53 static void         init_randr_support         (GdkScreen         *screen);
54 static void         deinit_multihead           (GdkScreen         *screen);
55
56 enum
57 {
58   WINDOW_MANAGER_CHANGED,
59   LAST_SIGNAL
60 };
61
62 static guint signals[LAST_SIGNAL] = { 0 };
63
64 G_DEFINE_TYPE (GdkX11Screen, gdk_x11_screen, GDK_TYPE_SCREEN)
65
66 typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
67
68 struct _NetWmSupportedAtoms
69 {
70   Atom *atoms;
71   gulong n_atoms;
72 };
73
74 struct _GdkX11Monitor
75 {
76   GdkRectangle  geometry;
77   XID           output;
78   int           width_mm;
79   int           height_mm;
80   char *        output_name;
81   char *        manufacturer;
82 };
83
84
85 static void
86 gdk_x11_screen_init (GdkX11Screen *screen)
87 {
88 }
89
90 static GdkDisplay *
91 gdk_x11_screen_get_display (GdkScreen *screen)
92 {
93   return GDK_X11_SCREEN (screen)->display;
94 }
95
96 static gint
97 gdk_x11_screen_get_width (GdkScreen *screen)
98 {
99   return WidthOfScreen (GDK_X11_SCREEN (screen)->xscreen);
100 }
101
102 static gint
103 gdk_x11_screen_get_height (GdkScreen *screen)
104 {
105   return HeightOfScreen (GDK_X11_SCREEN (screen)->xscreen);
106 }
107
108 static gint
109 gdk_x11_screen_get_width_mm (GdkScreen *screen)
110 {
111   return WidthMMOfScreen (GDK_X11_SCREEN (screen)->xscreen);
112 }
113
114 static gint
115 gdk_x11_screen_get_height_mm (GdkScreen *screen)
116 {
117   return HeightMMOfScreen (GDK_X11_SCREEN (screen)->xscreen);
118 }
119
120 static gint
121 gdk_x11_screen_get_number (GdkScreen *screen)
122 {
123   return GDK_X11_SCREEN (screen)->screen_num;
124 }
125
126 static GdkWindow *
127 gdk_x11_screen_get_root_window (GdkScreen *screen)
128 {
129   return GDK_X11_SCREEN (screen)->root_window;
130 }
131
132 static void
133 gdk_x11_screen_dispose (GObject *object)
134 {
135   GdkX11Screen *x11_screen = GDK_X11_SCREEN (object);
136   int i;
137
138   for (i = 0; i < 32; ++i)
139     {
140       if (x11_screen->subwindow_gcs[i])
141         {
142           XFreeGC (x11_screen->xdisplay, x11_screen->subwindow_gcs[i]);
143           x11_screen->subwindow_gcs[i] = 0;
144         }
145     }
146
147   _gdk_x11_xsettings_finish (x11_screen);
148
149   if (x11_screen->root_window)
150     _gdk_window_destroy (x11_screen->root_window, TRUE);
151
152   G_OBJECT_CLASS (gdk_x11_screen_parent_class)->dispose (object);
153
154   x11_screen->xdisplay = NULL;
155   x11_screen->xscreen = NULL;
156   x11_screen->screen_num = -1;
157   x11_screen->xroot_window = None;
158   x11_screen->wmspec_check_window = None;
159 }
160
161 static void
162 gdk_x11_screen_finalize (GObject *object)
163 {
164   GdkX11Screen *x11_screen = GDK_X11_SCREEN (object);
165   gint          i;
166
167   if (x11_screen->root_window)
168     g_object_unref (x11_screen->root_window);
169
170   /* Visual Part */
171   for (i = 0; i < x11_screen->nvisuals; i++)
172     g_object_unref (x11_screen->visuals[i]);
173   g_free (x11_screen->visuals);
174   g_hash_table_destroy (x11_screen->visual_hash);
175
176   g_free (x11_screen->window_manager_name);
177
178   deinit_multihead (GDK_SCREEN (object));
179   
180   G_OBJECT_CLASS (gdk_x11_screen_parent_class)->finalize (object);
181 }
182
183 static gint
184 gdk_x11_screen_get_n_monitors (GdkScreen *screen)
185 {
186   return GDK_X11_SCREEN (screen)->n_monitors;
187 }
188
189 static gint
190 gdk_x11_screen_get_primary_monitor (GdkScreen *screen)
191 {
192   return GDK_X11_SCREEN (screen)->primary_monitor;
193 }
194
195 static gint
196 gdk_x11_screen_get_monitor_width_mm (GdkScreen *screen,
197                                      gint       monitor_num)
198 {
199   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
200
201   return x11_screen->monitors[monitor_num].width_mm;
202 }
203
204 static gint
205 gdk_x11_screen_get_monitor_height_mm (GdkScreen *screen,
206                                       gint       monitor_num)
207 {
208   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
209
210   return x11_screen->monitors[monitor_num].height_mm;
211 }
212
213 static gchar *
214 gdk_x11_screen_get_monitor_plug_name (GdkScreen *screen,
215                                       gint       monitor_num)
216 {
217   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
218
219   return g_strdup (x11_screen->monitors[monitor_num].output_name);
220 }
221
222 /**
223  * gdk_x11_screen_get_monitor_output:
224  * @screen: (type GdkX11Screen): a #GdkScreen
225  * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
226  *
227  * Gets the XID of the specified output/monitor.
228  * If the X server does not support version 1.2 of the RANDR
229  * extension, 0 is returned.
230  *
231  * Returns: the XID of the monitor
232  *
233  * Since: 2.14
234  */
235 XID
236 gdk_x11_screen_get_monitor_output (GdkScreen *screen,
237                                    gint       monitor_num)
238 {
239   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
240
241   g_return_val_if_fail (GDK_IS_SCREEN (screen), None);
242   g_return_val_if_fail (monitor_num >= 0, None);
243   g_return_val_if_fail (monitor_num < x11_screen->n_monitors, None);
244
245   return x11_screen->monitors[monitor_num].output;
246 }
247
248 static void
249 gdk_x11_screen_get_monitor_geometry (GdkScreen    *screen,
250                                      gint          monitor_num,
251                                      GdkRectangle *dest)
252 {
253   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
254
255   if (dest)
256     *dest = x11_screen->monitors[monitor_num].geometry;
257 }
258
259 static int
260 get_current_desktop (GdkScreen *screen)
261 {
262   Display *display;
263   Window win;
264   Atom current_desktop, type;
265   int format;
266   unsigned long n_items, bytes_after;
267   unsigned char *data_return = NULL;
268   int workspace = 0;
269
270   if (!gdk_x11_screen_supports_net_wm_hint (screen,
271                                             gdk_atom_intern_static_string ("_NET_CURRENT_DESKTOP")))
272     return workspace;
273
274   display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
275   win = XRootWindow (display, GDK_SCREEN_XNUMBER (screen));
276
277   current_desktop = XInternAtom (display, "_NET_CURRENT_DESKTOP", True);
278
279   XGetWindowProperty (display,
280                       win,
281                       current_desktop,
282                       0, G_MAXLONG,
283                       False, XA_CARDINAL,
284                       &type, &format, &n_items, &bytes_after,
285                       &data_return);
286
287   if (type == XA_CARDINAL && format == 32 && n_items > 0)
288     workspace = (int) data_return[0];
289
290   if (data_return)
291     XFree (data_return);
292
293   return workspace;
294 }
295
296 static void
297 get_work_area (GdkScreen    *screen,
298                GdkRectangle *area)
299 {
300   Atom            workarea;
301   Atom            type;
302   Window          win;
303   int             format;
304   gulong          num;
305   gulong          leftovers;
306   gulong          max_len = 4 * 32;
307   guchar         *ret_workarea;
308   long           *workareas;
309   int             result;
310   int             disp_screen;
311   int             desktop;
312   Display        *display;
313
314   display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
315   disp_screen = GDK_SCREEN_XNUMBER (screen);
316   workarea = XInternAtom (display, "_NET_WORKAREA", True);
317
318   /* Defaults in case of error */
319   area->x = 0;
320   area->y = 0;
321   area->width = gdk_screen_get_width (screen);
322   area->height = gdk_screen_get_height (screen);
323
324   if (!gdk_x11_screen_supports_net_wm_hint (screen,
325                                             gdk_atom_intern_static_string ("_NET_WORKAREA")))
326     return;
327
328   if (workarea == None)
329     return;
330
331   win = XRootWindow (display, disp_screen);
332   result = XGetWindowProperty (display,
333                                win,
334                                workarea,
335                                0,
336                                max_len,
337                                False,
338                                AnyPropertyType,
339                                &type,
340                                &format,
341                                &num,
342                                &leftovers,
343                                &ret_workarea);
344   if (result != Success ||
345       type == None ||
346       format == 0 ||
347       leftovers ||
348       num % 4 != 0)
349     return;
350
351   desktop = get_current_desktop (screen);
352
353   workareas = (long *) ret_workarea;
354   area->x = workareas[desktop * 4];
355   area->y = workareas[desktop * 4 + 1];
356   area->width = workareas[desktop * 4 + 2];
357   area->height = workareas[desktop * 4 + 3];
358
359   XFree (ret_workarea);
360 }
361
362 static void
363 gdk_x11_screen_get_monitor_workarea (GdkScreen    *screen,
364                                      gint          monitor_num,
365                                      GdkRectangle *dest)
366 {
367   GdkRectangle workarea;
368
369   gdk_x11_screen_get_monitor_geometry (screen, monitor_num, dest);
370
371   /* The EWMH constrains workarea to be a rectangle, so it
372    * can't adequately deal with L-shaped monitor arrangements.
373    * As a workaround, we ignore the workarea for anything
374    * but the primary monitor. Since that is where the 'desktop
375    * chrome' usually lives, this works ok in practice.
376    */
377   if (monitor_num == GDK_X11_SCREEN (screen)->primary_monitor)
378     {
379       get_work_area (screen, &workarea);
380       if (gdk_rectangle_intersect (dest, &workarea, &workarea))
381         *dest = workarea;
382     }
383 }
384
385 static GdkVisual *
386 gdk_x11_screen_get_rgba_visual (GdkScreen *screen)
387 {
388   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
389
390   return x11_screen->rgba_visual;
391 }
392
393 /**
394  * gdk_x11_screen_get_xscreen:
395  * @screen: (type GdkX11Screen): a #GdkScreen
396  *
397  * Returns the screen of a #GdkScreen.
398  *
399  * Returns: (transfer none): an Xlib <type>Screen*</type>
400  *
401  * Since: 2.2
402  */
403 Screen *
404 gdk_x11_screen_get_xscreen (GdkScreen *screen)
405 {
406   return GDK_X11_SCREEN (screen)->xscreen;
407 }
408
409 /**
410  * gdk_x11_screen_get_screen_number:
411  * @screen: (type GdkX11Screen): a #GdkScreen
412  *
413  * Returns the index of a #GdkScreen.
414  *
415  * Returns: the position of @screen among the screens
416  *     of its display
417  *
418  * Since: 2.2
419  */
420 int
421 gdk_x11_screen_get_screen_number (GdkScreen *screen)
422 {
423   return GDK_X11_SCREEN (screen)->screen_num;
424 }
425
426 static Atom
427 get_cm_atom (GdkX11Screen *x11_screen)
428 {
429   return _gdk_x11_get_xatom_for_display_printf (x11_screen->display, "_NET_WM_CM_S%d", x11_screen->screen_num);
430 }
431
432 static gboolean
433 check_is_composited (GdkDisplay *display,
434                      GdkX11Screen *x11_screen)
435 {
436   Window xwindow;
437   
438   xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), get_cm_atom (x11_screen));
439
440   return xwindow != None;
441 }
442
443 static void
444 init_monitor_geometry (GdkX11Monitor *monitor,
445                        int x, int y, int width, int height)
446 {
447   monitor->geometry.x = x;
448   monitor->geometry.y = y;
449   monitor->geometry.width = width;
450   monitor->geometry.height = height;
451
452   monitor->output = None;
453   monitor->width_mm = -1;
454   monitor->height_mm = -1;
455   monitor->output_name = NULL;
456   monitor->manufacturer = NULL;
457 }
458
459 static gboolean
460 init_fake_xinerama (GdkScreen *screen)
461 {
462 #ifdef G_ENABLE_DEBUG
463   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
464   XSetWindowAttributes atts;
465   Window win;
466   gint w, h;
467
468   if (!(_gdk_debug_flags & GDK_DEBUG_XINERAMA))
469     return FALSE;
470   
471   /* Fake Xinerama mode by splitting the screen into 4 monitors.
472    * Also draw a little cross to make the monitor boundaries visible.
473    */
474   w = WidthOfScreen (x11_screen->xscreen);
475   h = HeightOfScreen (x11_screen->xscreen);
476
477   x11_screen->n_monitors = 4;
478   x11_screen->monitors = g_new0 (GdkX11Monitor, 4);
479   init_monitor_geometry (&x11_screen->monitors[0], 0, 0, w / 2, h / 2);
480   init_monitor_geometry (&x11_screen->monitors[1], w / 2, 0, w / 2, h / 2);
481   init_monitor_geometry (&x11_screen->monitors[2], 0, h / 2, w / 2, h / 2);
482   init_monitor_geometry (&x11_screen->monitors[3], w / 2, h / 2, w / 2, h / 2);
483   
484   atts.override_redirect = 1;
485   atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen), 
486                                      x11_screen->screen_num);
487   win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
488                       x11_screen->xroot_window, 0, h / 2, w, 1, 0, 
489                       DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
490                                    x11_screen->screen_num),
491                       InputOutput, 
492                       DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
493                                     x11_screen->screen_num),
494                       CWOverrideRedirect|CWBackPixel, 
495                       &atts);
496   XMapRaised(GDK_SCREEN_XDISPLAY (screen), win); 
497   win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
498                       x11_screen->xroot_window, w/2 , 0, 1, h, 0, 
499                       DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
500                                    x11_screen->screen_num),
501                       InputOutput, 
502                       DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
503                                     x11_screen->screen_num),
504                       CWOverrideRedirect|CWBackPixel, 
505                       &atts);
506   XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
507   return TRUE;
508 #endif
509   
510   return FALSE;
511 }
512
513 static void
514 free_monitors (GdkX11Monitor *monitors,
515                gint           n_monitors)
516 {
517   int i;
518
519   for (i = 0; i < n_monitors; ++i)
520     {
521       g_free (monitors[i].output_name);
522       g_free (monitors[i].manufacturer);
523     }
524
525   g_free (monitors);
526 }
527
528 #ifdef HAVE_RANDR
529 static int
530 monitor_compare_function (GdkX11Monitor *monitor1,
531                           GdkX11Monitor *monitor2)
532 {
533   /* Sort the leftmost/topmost monitors first.
534    * For "cloned" monitors, sort the bigger ones first
535    * (giving preference to taller monitors over wider
536    * monitors)
537    */
538
539   if (monitor1->geometry.x != monitor2->geometry.x)
540     return monitor1->geometry.x - monitor2->geometry.x;
541
542   if (monitor1->geometry.y != monitor2->geometry.y)
543     return monitor1->geometry.y - monitor2->geometry.y;
544
545   if (monitor1->geometry.height != monitor2->geometry.height)
546     return - (monitor1->geometry.height - monitor2->geometry.height);
547
548   if (monitor1->geometry.width != monitor2->geometry.width)
549     return - (monitor1->geometry.width - monitor2->geometry.width);
550
551   return 0;
552 }
553 #endif
554
555 static gboolean
556 init_randr13 (GdkScreen *screen)
557 {
558 #ifdef HAVE_RANDR
559   GdkDisplay *display = gdk_screen_get_display (screen);
560   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
561   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
562   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
563   XRRScreenResources *resources;
564   RROutput primary_output;
565   RROutput first_output = None;
566   int i;
567   GArray *monitors;
568   gboolean randr12_compat = FALSE;
569
570   if (!display_x11->have_randr13)
571       return FALSE;
572
573   resources = XRRGetScreenResourcesCurrent (x11_screen->xdisplay,
574                                             x11_screen->xroot_window);
575   if (!resources)
576     return FALSE;
577
578   monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor),
579                                 resources->noutput);
580
581   for (i = 0; i < resources->noutput; ++i)
582     {
583       XRROutputInfo *output =
584         XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
585
586       /* Non RandR1.2 X driver have output name "default" */
587       randr12_compat |= !g_strcmp0 (output->name, "default");
588
589       if (output->connection == RR_Disconnected)
590         {
591           XRRFreeOutputInfo (output);
592           continue;
593         }
594
595       if (output->crtc)
596         {
597           GdkX11Monitor monitor;
598           XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, output->crtc);
599
600           monitor.geometry.x = crtc->x;
601           monitor.geometry.y = crtc->y;
602           monitor.geometry.width = crtc->width;
603           monitor.geometry.height = crtc->height;
604
605           monitor.output = resources->outputs[i];
606           monitor.width_mm = output->mm_width;
607           monitor.height_mm = output->mm_height;
608           monitor.output_name = g_strdup (output->name);
609           /* FIXME: need EDID parser */
610           monitor.manufacturer = NULL;
611
612           g_array_append_val (monitors, monitor);
613
614           XRRFreeCrtcInfo (crtc);
615         }
616
617       XRRFreeOutputInfo (output);
618     }
619
620   if (resources->noutput > 0)
621     first_output = resources->outputs[0];
622
623   XRRFreeScreenResources (resources);
624
625   /* non RandR 1.2 X driver doesn't return any usable multihead data */
626   if (randr12_compat)
627     {
628       guint n_monitors = monitors->len;
629
630       free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE),
631                      n_monitors);
632
633       return FALSE;
634     }
635
636   g_array_sort (monitors,
637                 (GCompareFunc) monitor_compare_function);
638   x11_screen->n_monitors = monitors->len;
639   x11_screen->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);
640
641   x11_screen->primary_monitor = 0;
642
643   primary_output = XRRGetOutputPrimary (x11_screen->xdisplay,
644                                         x11_screen->xroot_window);
645
646   for (i = 0; i < x11_screen->n_monitors; ++i)
647     {
648       if (x11_screen->monitors[i].output == primary_output)
649         {
650           x11_screen->primary_monitor = i;
651           break;
652         }
653
654       /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
655       if (primary_output == None &&
656           g_ascii_strncasecmp (x11_screen->monitors[i].output_name, "LVDS", 4) == 0)
657         {
658           x11_screen->primary_monitor = i;
659           break;
660         }
661
662       /* No primary specified and no LVDS found */
663       if (x11_screen->monitors[i].output == first_output)
664         x11_screen->primary_monitor = i;
665     }
666
667   return x11_screen->n_monitors > 0;
668 #endif
669
670   return FALSE;
671 }
672
673 static gboolean
674 init_solaris_xinerama (GdkScreen *screen)
675 {
676 #ifdef HAVE_SOLARIS_XINERAMA
677   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
678   int screen_no = gdk_screen_get_number (screen);
679   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
680   XRectangle monitors[MAXFRAMEBUFFERS];
681   unsigned char hints[16];
682   gint result;
683   int n_monitors;
684   int i;
685   
686   if (!XineramaGetState (dpy, screen_no))
687     return FALSE;
688
689   result = XineramaGetInfo (dpy, screen_no, monitors, hints, &n_monitors);
690
691   /* Yes I know it should be Success but the current implementation 
692    * returns the num of monitor
693    */
694   if (result == 0)
695     {
696       return FALSE;
697     }
698
699   x11_screen->monitors = g_new0 (GdkX11Monitor, n_monitors);
700   x11_screen->n_monitors = n_monitors;
701
702   for (i = 0; i < n_monitors; i++)
703     {
704       init_monitor_geometry (&x11_screen->monitors[i],
705                              monitors[i].x, monitors[i].y,
706                              monitors[i].width, monitors[i].height);
707     }
708
709   x11_screen->primary_monitor = 0;
710
711   return TRUE;
712 #endif /* HAVE_SOLARIS_XINERAMA */
713
714   return FALSE;
715 }
716
717 static gboolean
718 init_xfree_xinerama (GdkScreen *screen)
719 {
720 #ifdef HAVE_XFREE_XINERAMA
721   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
722   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
723   XineramaScreenInfo *monitors;
724   int i, n_monitors;
725   
726   if (!XineramaIsActive (dpy))
727     return FALSE;
728
729   monitors = XineramaQueryScreens (dpy, &n_monitors);
730   
731   if (n_monitors <= 0 || monitors == NULL)
732     {
733       /* If Xinerama doesn't think we have any monitors, try acting as
734        * though we had no Xinerama. If the "no monitors" condition
735        * is because XRandR 1.2 is currently switching between CRTCs,
736        * we'll be notified again when we have our monitor back,
737        * and can go back into Xinerama-ish mode at that point.
738        */
739       if (monitors)
740         XFree (monitors);
741       
742       return FALSE;
743     }
744
745   x11_screen->n_monitors = n_monitors;
746   x11_screen->monitors = g_new0 (GdkX11Monitor, n_monitors);
747   
748   for (i = 0; i < n_monitors; ++i)
749     {
750       init_monitor_geometry (&x11_screen->monitors[i],
751                              monitors[i].x_org, monitors[i].y_org,
752                              monitors[i].width, monitors[i].height);
753     }
754   
755   XFree (monitors);
756   
757   x11_screen->primary_monitor = 0;
758
759   return TRUE;
760 #endif /* HAVE_XFREE_XINERAMA */
761   
762   return FALSE;
763 }
764
765 static gboolean
766 init_solaris_xinerama_indices (GdkX11Screen *x11_screen)
767 {
768 #ifdef HAVE_SOLARIS_XINERAMA
769   XRectangle    x_monitors[MAXFRAMEBUFFERS];
770   unsigned char hints[16];
771   gint          result;
772   gint          monitor_num;
773   gint          x_n_monitors;
774   gint          i;
775
776   if (!XineramaGetState (x11_screen->xdisplay, x11_screen->screen_num))
777     return FALSE;
778
779   result = XineramaGetInfo (x11_screen->xdisplay, x11_screen->screen_num,
780                             x_monitors, hints, &x_n_monitors);
781
782   if (result == 0)
783     return FALSE;
784
785
786   for (monitor_num = 0; monitor_num < x11_screen->n_monitors; ++monitor_num)
787     {
788       for (i = 0; i < x_n_monitors; ++i)
789         {
790           if (x11_screen->monitors[monitor_num].geometry.x == x_monitors[i].x &&
791               x11_screen->monitors[monitor_num].geometry.y == x_monitors[i].y &&
792               x11_screen->monitors[monitor_num].geometry.width == x_monitors[i].width &&
793               x11_screen->monitors[monitor_num].geometry.height == x_monitors[i].height)
794             {
795               g_hash_table_insert (x11_screen->xinerama_matches,
796                                    GINT_TO_POINTER (monitor_num),
797                                    GINT_TO_POINTER (i));
798             }
799         }
800     }
801   return TRUE;
802 #endif /* HAVE_SOLARIS_XINERAMA */
803
804   return FALSE;
805 }
806
807 static gboolean
808 init_xfree_xinerama_indices (GdkX11Screen *x11_screen)
809 {
810 #ifdef HAVE_XFREE_XINERAMA
811   XineramaScreenInfo *x_monitors;
812   gint                monitor_num;
813   gint                x_n_monitors;
814   gint                i;
815
816   if (!XineramaIsActive (x11_screen->xdisplay))
817     return FALSE;
818
819   x_monitors = XineramaQueryScreens (x11_screen->xdisplay, &x_n_monitors);
820   if (x_n_monitors <= 0 || x_monitors == NULL)
821     {
822       if (x_monitors)
823         XFree (x_monitors);
824
825       return FALSE;
826     }
827
828   for (monitor_num = 0; monitor_num < x11_screen->n_monitors; ++monitor_num)
829     {
830       for (i = 0; i < x_n_monitors; ++i)
831         {
832           if (x11_screen->monitors[monitor_num].geometry.x == x_monitors[i].x_org &&
833               x11_screen->monitors[monitor_num].geometry.y == x_monitors[i].y_org &&
834               x11_screen->monitors[monitor_num].geometry.width == x_monitors[i].width &&
835               x11_screen->monitors[monitor_num].geometry.height == x_monitors[i].height)
836             {
837               g_hash_table_insert (x11_screen->xinerama_matches,
838                                    GINT_TO_POINTER (monitor_num),
839                                    GINT_TO_POINTER (i));
840             }
841         }
842     }
843   XFree (x_monitors);
844   return TRUE;
845 #endif /* HAVE_XFREE_XINERAMA */
846
847   return FALSE;
848 }
849
850 static void
851 init_xinerama_indices (GdkX11Screen *x11_screen)
852 {
853   int opcode, firstevent, firsterror;
854
855   x11_screen->xinerama_matches = g_hash_table_new (g_direct_hash, g_direct_equal);
856   if (XQueryExtension (x11_screen->xdisplay, "XINERAMA",
857                        &opcode, &firstevent, &firsterror))
858     {
859       x11_screen->xinerama_matches = g_hash_table_new (g_direct_hash, g_direct_equal);
860
861       /* Solaris Xinerama first, then XFree/Xorg Xinerama
862        * to match the order in init_multihead()
863        */
864       if (init_solaris_xinerama_indices (x11_screen) == FALSE)
865         init_xfree_xinerama_indices (x11_screen);
866     }
867 }
868
869 gint
870 _gdk_x11_screen_get_xinerama_index (GdkScreen *screen,
871                                     gint       monitor_num)
872 {
873   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
874   gpointer val;
875
876   g_return_val_if_fail (monitor_num < x11_screen->n_monitors, -1);
877
878   if (x11_screen->xinerama_matches == NULL)
879     init_xinerama_indices (x11_screen);
880
881   if (g_hash_table_lookup_extended (x11_screen->xinerama_matches, GINT_TO_POINTER (monitor_num), NULL, &val))
882     return (GPOINTER_TO_INT(val));
883
884   return -1;
885 }
886
887 void
888 _gdk_x11_screen_get_edge_monitors (GdkScreen *screen,
889                                    gint      *top,
890                                    gint      *bottom,
891                                    gint      *left,
892                                    gint      *right)
893 {
894   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
895   gint          top_most_pos = HeightOfScreen (GDK_X11_SCREEN (screen)->xscreen);
896   gint          left_most_pos = WidthOfScreen (GDK_X11_SCREEN (screen)->xscreen);
897   gint          bottom_most_pos = 0;
898   gint          right_most_pos = 0;
899   gint          monitor_num;
900
901   for (monitor_num = 0; monitor_num < x11_screen->n_monitors; monitor_num++)
902     {
903       gint monitor_x = x11_screen->monitors[monitor_num].geometry.x;
904       gint monitor_y = x11_screen->monitors[monitor_num].geometry.y;
905       gint monitor_max_x = monitor_x + x11_screen->monitors[monitor_num].geometry.width;
906       gint monitor_max_y = monitor_y + x11_screen->monitors[monitor_num].geometry.height;
907
908       if (left && left_most_pos > monitor_x)
909         {
910           left_most_pos = monitor_x;
911           *left = monitor_num;
912         }
913       if (right && right_most_pos < monitor_max_x)
914         {
915           right_most_pos = monitor_max_x;
916           *right = monitor_num;
917         }
918       if (top && top_most_pos > monitor_y)
919         {
920           top_most_pos = monitor_y;
921           *top = monitor_num;
922         }
923       if (bottom && bottom_most_pos < monitor_max_y)
924         {
925           bottom_most_pos = monitor_max_y;
926           *bottom = monitor_num;
927         }
928     }
929 }
930
931 static void
932 deinit_multihead (GdkScreen *screen)
933 {
934   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
935
936   free_monitors (x11_screen->monitors, x11_screen->n_monitors);
937   g_clear_pointer (&x11_screen->xinerama_matches, g_hash_table_destroy);
938
939   x11_screen->n_monitors = 0;
940   x11_screen->monitors = NULL;
941 }
942
943 static gboolean
944 compare_monitor (GdkX11Monitor *m1,
945                  GdkX11Monitor *m2)
946 {
947   if (m1->geometry.x != m2->geometry.x ||
948       m1->geometry.y != m2->geometry.y ||
949       m1->geometry.width != m2->geometry.width ||
950       m1->geometry.height != m2->geometry.height)
951     return FALSE;
952
953   if (m1->width_mm != m2->width_mm ||
954       m1->height_mm != m2->height_mm)
955     return FALSE;
956
957   if (g_strcmp0 (m1->output_name, m2->output_name) != 0)
958     return FALSE;
959
960   if (g_strcmp0 (m1->manufacturer, m2->manufacturer) != 0)
961     return FALSE;
962
963   return TRUE;
964 }
965
966 static gboolean
967 compare_monitors (GdkX11Monitor *monitors1, gint n_monitors1,
968                   GdkX11Monitor *monitors2, gint n_monitors2)
969 {
970   gint i;
971
972   if (n_monitors1 != n_monitors2)
973     return FALSE;
974
975   for (i = 0; i < n_monitors1; i++)
976     {
977       if (!compare_monitor (monitors1 + i, monitors2 + i))
978         return FALSE;
979     }
980
981   return TRUE;
982 }
983
984 static void
985 init_multihead (GdkScreen *screen)
986 {
987   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
988   int opcode, firstevent, firsterror;
989
990   /* There are four different implementations of multihead support: 
991    *
992    *  1. Fake Xinerama for debugging purposes
993    *  2. RandR 1.2
994    *  3. Solaris Xinerama
995    *  4. XFree86/Xorg Xinerama
996    *
997    * We use them in that order.
998    */
999   if (init_fake_xinerama (screen))
1000     return;
1001
1002   if (init_randr13 (screen))
1003     return;
1004
1005   if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
1006                        &opcode, &firstevent, &firsterror))
1007     {
1008       if (init_solaris_xinerama (screen))
1009         return;
1010       
1011       if (init_xfree_xinerama (screen))
1012         return;
1013     }
1014
1015   /* No multihead support of any kind for this screen */
1016   x11_screen->n_monitors = 1;
1017   x11_screen->monitors = g_new0 (GdkX11Monitor, 1);
1018   x11_screen->primary_monitor = 0;
1019
1020   init_monitor_geometry (x11_screen->monitors, 0, 0,
1021                          WidthOfScreen (x11_screen->xscreen),
1022                          HeightOfScreen (x11_screen->xscreen));
1023 }
1024
1025 GdkScreen *
1026 _gdk_x11_screen_new (GdkDisplay *display,
1027                      gint        screen_number) 
1028 {
1029   GdkScreen *screen;
1030   GdkX11Screen *x11_screen;
1031   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
1032
1033   screen = g_object_new (GDK_TYPE_X11_SCREEN, NULL);
1034
1035   x11_screen = GDK_X11_SCREEN (screen);
1036   x11_screen->display = display;
1037   x11_screen->xdisplay = display_x11->xdisplay;
1038   x11_screen->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
1039   x11_screen->screen_num = screen_number;
1040   x11_screen->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
1041   x11_screen->wmspec_check_window = None;
1042   /* we want this to be always non-null */
1043   x11_screen->window_manager_name = g_strdup ("unknown");
1044   
1045   init_multihead (screen);
1046   init_randr_support (screen);
1047   
1048   _gdk_x11_screen_init_visuals (screen);
1049   _gdk_x11_screen_init_root_window (screen);
1050   
1051   return screen;
1052 }
1053
1054 /*
1055  * It is important that we first request the selection
1056  * notification, and then setup the initial state of
1057  * is_composited to avoid a race condition here.
1058  */
1059 void
1060 _gdk_x11_screen_setup (GdkScreen *screen)
1061 {
1062   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1063
1064   gdk_display_request_selection_notification (x11_screen->display,
1065                                               gdk_x11_xatom_to_atom_for_display (x11_screen->display, get_cm_atom (x11_screen)));
1066   x11_screen->is_composited = check_is_composited (x11_screen->display, x11_screen);
1067 }
1068
1069 static gboolean
1070 gdk_x11_screen_is_composited (GdkScreen *screen)
1071 {
1072   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1073
1074   return x11_screen->is_composited;
1075 }
1076
1077 static void
1078 init_randr_support (GdkScreen *screen)
1079 {
1080   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1081
1082   /* NB: This is also needed for XSettings, so don't remove. */
1083   XSelectInput (GDK_SCREEN_XDISPLAY (screen),
1084                 x11_screen->xroot_window,
1085                 StructureNotifyMask);
1086
1087 #ifdef HAVE_RANDR
1088   if (!GDK_X11_DISPLAY (gdk_screen_get_display (screen))->have_randr12)
1089     return;
1090
1091   XRRSelectInput (GDK_SCREEN_XDISPLAY (screen),
1092                   x11_screen->xroot_window,
1093                   RRScreenChangeNotifyMask
1094                   | RRCrtcChangeNotifyMask
1095                   | RROutputPropertyNotifyMask);
1096 #endif
1097 }
1098
1099 static void
1100 process_monitors_change (GdkScreen *screen)
1101 {
1102   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1103   gint           n_monitors;
1104   gint           primary_monitor;
1105   GdkX11Monitor *monitors;
1106   gboolean changed;
1107
1108   primary_monitor = x11_screen->primary_monitor;
1109   n_monitors = x11_screen->n_monitors;
1110   monitors = x11_screen->monitors;
1111
1112   x11_screen->n_monitors = 0;
1113   x11_screen->monitors = NULL;
1114
1115   init_multihead (screen);
1116
1117   changed =
1118     !compare_monitors (monitors, n_monitors,
1119                        x11_screen->monitors, x11_screen->n_monitors) ||
1120     x11_screen->primary_monitor != primary_monitor;
1121
1122
1123   free_monitors (monitors, n_monitors);
1124
1125   if (changed)
1126     g_signal_emit_by_name (screen, "monitors-changed");
1127 }
1128
1129 void
1130 _gdk_x11_screen_size_changed (GdkScreen *screen,
1131                               XEvent    *event)
1132 {
1133   gint width, height;
1134 #ifdef HAVE_RANDR
1135   GdkX11Display *display_x11;
1136 #endif
1137
1138   width = gdk_screen_get_width (screen);
1139   height = gdk_screen_get_height (screen);
1140
1141 #ifdef HAVE_RANDR
1142   display_x11 = GDK_X11_DISPLAY (gdk_screen_get_display (screen));
1143
1144   if (display_x11->have_randr13 && event->type == ConfigureNotify)
1145     return;
1146
1147   XRRUpdateConfiguration (event);
1148 #else
1149   if (event->type == ConfigureNotify)
1150     {
1151       XConfigureEvent *rcevent = (XConfigureEvent *) event;
1152       Screen        *xscreen = gdk_x11_screen_get_xscreen (screen);
1153
1154       xscreen->width   = rcevent->width;
1155       xscreen->height  = rcevent->height;
1156     }
1157   else
1158     return;
1159 #endif
1160
1161   process_monitors_change (screen);
1162
1163   if (width != gdk_screen_get_width (screen) ||
1164       height != gdk_screen_get_height (screen))
1165     g_signal_emit_by_name (screen, "size-changed");
1166 }
1167
1168 void
1169 _gdk_x11_screen_window_manager_changed (GdkScreen *screen)
1170 {
1171   g_signal_emit (screen, signals[WINDOW_MANAGER_CHANGED], 0);
1172 }
1173
1174 void
1175 _gdk_x11_screen_process_owner_change (GdkScreen *screen,
1176                                       XEvent *event)
1177 {
1178 #ifdef HAVE_XFIXES
1179   XFixesSelectionNotifyEvent *selection_event = (XFixesSelectionNotifyEvent *)event;
1180   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1181
1182   if (selection_event->selection == get_cm_atom (x11_screen))
1183     {
1184       gboolean composited = selection_event->owner != None;
1185
1186       if (composited != x11_screen->is_composited)
1187         {
1188           x11_screen->is_composited = composited;
1189
1190           g_signal_emit_by_name (screen, "composited-changed");
1191         }
1192     }
1193 #endif
1194 }
1195
1196 static gchar *
1197 substitute_screen_number (const gchar *display_name,
1198                           gint         screen_number)
1199 {
1200   GString *str;
1201   gchar   *p;
1202
1203   str = g_string_new (display_name);
1204
1205   p = strrchr (str->str, '.');
1206   if (p && p >  strchr (str->str, ':'))
1207     g_string_truncate (str, p - str->str);
1208
1209   g_string_append_printf (str, ".%d", screen_number);
1210
1211   return g_string_free (str, FALSE);
1212 }
1213
1214 static gchar *
1215 gdk_x11_screen_make_display_name (GdkScreen *screen)
1216 {
1217   const gchar *old_display;
1218
1219   old_display = gdk_display_get_name (gdk_screen_get_display (screen));
1220
1221   return substitute_screen_number (old_display,
1222                                    gdk_screen_get_number (screen));
1223 }
1224
1225 static GdkWindow *
1226 gdk_x11_screen_get_active_window (GdkScreen *screen)
1227 {
1228   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1229   GdkWindow *ret = NULL;
1230   Atom type_return;
1231   gint format_return;
1232   gulong nitems_return;
1233   gulong bytes_after_return;
1234   guchar *data = NULL;
1235
1236   if (!gdk_x11_screen_supports_net_wm_hint (screen,
1237                                             gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW")))
1238     return NULL;
1239
1240   if (XGetWindowProperty (x11_screen->xdisplay, x11_screen->xroot_window,
1241                           gdk_x11_get_xatom_by_name_for_display (x11_screen->display,
1242                                                                  "_NET_ACTIVE_WINDOW"),
1243                           0, 1, False, XA_WINDOW, &type_return,
1244                           &format_return, &nitems_return,
1245                           &bytes_after_return, &data)
1246       == Success)
1247     {
1248       if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
1249         {
1250           Window window = *(Window *) data;
1251
1252           if (window != None)
1253             {
1254               ret = gdk_x11_window_foreign_new_for_display (x11_screen->display,
1255                                                             window);
1256             }
1257         }
1258     }
1259
1260   if (data)
1261     XFree (data);
1262
1263   return ret;
1264 }
1265
1266 static GList *
1267 gdk_x11_screen_get_window_stack (GdkScreen *screen)
1268 {
1269   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1270   GList *ret = NULL;
1271   Atom type_return;
1272   gint format_return;
1273   gulong nitems_return;
1274   gulong bytes_after_return;
1275   guchar *data = NULL;
1276
1277   if (!gdk_x11_screen_supports_net_wm_hint (screen,
1278                                             gdk_atom_intern_static_string ("_NET_CLIENT_LIST_STACKING")))
1279     return NULL;
1280
1281   if (XGetWindowProperty (x11_screen->xdisplay, x11_screen->xroot_window,
1282                           gdk_x11_get_xatom_by_name_for_display (x11_screen->display,
1283                                                                  "_NET_CLIENT_LIST_STACKING"),
1284                           0, G_MAXLONG, False, XA_WINDOW, &type_return,
1285                           &format_return, &nitems_return,
1286                           &bytes_after_return, &data)
1287       == Success)
1288     {
1289       if ((type_return == XA_WINDOW) && (format_return == 32) &&
1290           (data) && (nitems_return > 0))
1291         {
1292           gulong *stack = (gulong *) data;
1293           GdkWindow *win;
1294           int i;
1295
1296           for (i = 0; i < nitems_return; i++)
1297             {
1298               win = gdk_x11_window_foreign_new_for_display (x11_screen->display,
1299                                                             (Window)stack[i]);
1300
1301               if (win != NULL)
1302                 ret = g_list_append (ret, win);
1303             }
1304         }
1305     }
1306
1307   if (data)
1308     XFree (data);
1309
1310   return ret;
1311 }
1312
1313 static gboolean
1314 gdk_x11_screen_get_setting (GdkScreen   *screen,
1315                             const gchar *name,
1316                             GValue      *value)
1317 {
1318   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1319   const GValue *setting;
1320
1321   if (x11_screen->xsettings == NULL)
1322     goto out;
1323   setting = g_hash_table_lookup (x11_screen->xsettings, name);
1324   if (setting == NULL)
1325     goto out;
1326
1327   if (!g_value_type_transformable (G_VALUE_TYPE (setting), G_VALUE_TYPE (value)))
1328     {
1329       g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
1330                  name,
1331                  g_type_name (G_VALUE_TYPE (setting)),
1332                  g_type_name (G_VALUE_TYPE (value)));
1333       goto out;
1334     }
1335
1336   g_value_transform (setting, value);
1337
1338   return TRUE;
1339
1340  out:
1341   return _gdk_x11_get_xft_setting (screen, name, value);
1342 }
1343
1344 static void
1345 cleanup_atoms(gpointer data)
1346 {
1347   NetWmSupportedAtoms *supported_atoms = data;
1348   if (supported_atoms->atoms)
1349       XFree (supported_atoms->atoms);
1350   g_free (supported_atoms);
1351 }
1352
1353 static Window
1354 get_net_supporting_wm_check (GdkX11Screen *screen,
1355                              Window        window)
1356 {
1357   GdkDisplay *display;
1358   Atom type;
1359   gint format;
1360   gulong n_items;
1361   gulong bytes_after;
1362   guchar *data;
1363   Window value;
1364
1365   display = screen->display;
1366   type = None;
1367   data = NULL;
1368   value = None;
1369
1370   gdk_x11_display_error_trap_push (display);
1371   XGetWindowProperty (screen->xdisplay, window,
1372                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
1373                       0, G_MAXLONG, False, XA_WINDOW, &type, &format,
1374                       &n_items, &bytes_after, &data);
1375   gdk_x11_display_error_trap_pop_ignored (display);
1376
1377   if (type == XA_WINDOW)
1378     value = *(Window *)data;
1379
1380   if (data)
1381     XFree (data);
1382
1383   return value;
1384 }
1385
1386 static void
1387 fetch_net_wm_check_window (GdkScreen *screen)
1388 {
1389   GdkX11Screen *x11_screen;
1390   GdkDisplay *display;
1391   Window window;
1392   GTimeVal tv;
1393   gint error;
1394
1395   x11_screen = GDK_X11_SCREEN (screen);
1396   display = x11_screen->display;
1397
1398   g_return_if_fail (GDK_X11_DISPLAY (display)->trusted_client);
1399
1400   if (x11_screen->wmspec_check_window != None)
1401     return; /* already have it */
1402
1403   g_get_current_time (&tv);
1404
1405   if (ABS  (tv.tv_sec - x11_screen->last_wmspec_check_time) < 15)
1406     return; /* we've checked recently */
1407
1408   window = get_net_supporting_wm_check (x11_screen, x11_screen->xroot_window);
1409   if (window == None)
1410     return;
1411
1412   if (window != get_net_supporting_wm_check (x11_screen, window))
1413     return;
1414
1415   gdk_x11_display_error_trap_push (display);
1416
1417   /* Find out if this WM goes away, so we can reset everything. */
1418   XSelectInput (x11_screen->xdisplay, window, StructureNotifyMask);
1419
1420   error = gdk_x11_display_error_trap_pop (display);
1421   if (!error)
1422     {
1423       /* We check the window property again because after XGetWindowProperty()
1424        * and before XSelectInput() the window may have been recycled in such a
1425        * way that XSelectInput() doesn't fail but the window is no longer what
1426        * we want.
1427        */
1428       if (window != get_net_supporting_wm_check (x11_screen, window))
1429         return;
1430
1431       x11_screen->wmspec_check_window = window;
1432       x11_screen->last_wmspec_check_time = tv.tv_sec;
1433       x11_screen->need_refetch_net_supported = TRUE;
1434       x11_screen->need_refetch_wm_name = TRUE;
1435
1436       /* Careful, reentrancy */
1437       _gdk_x11_screen_window_manager_changed (screen);
1438     }
1439 }
1440
1441 /**
1442  * gdk_x11_screen_supports_net_wm_hint:
1443  * @screen: (type GdkX11Screen): the relevant #GdkScreen.
1444  * @property: a property atom.
1445  *
1446  * This function is specific to the X11 backend of GDK, and indicates
1447  * whether the window manager supports a certain hint from the
1448  * Extended Window Manager Hints Specification. You can find this
1449  * specification on
1450  * <ulink url="http://www.freedesktop.org">http://www.freedesktop.org</ulink>.
1451  *
1452  * When using this function, keep in mind that the window manager
1453  * can change over time; so you shouldn't use this function in
1454  * a way that impacts persistent application state. A common bug
1455  * is that your application can start up before the window manager
1456  * does when the user logs in, and before the window manager starts
1457  * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
1458  * You can monitor the window_manager_changed signal on #GdkScreen to detect
1459  * a window manager change.
1460  *
1461  * Return value: %TRUE if the window manager supports @property
1462  *
1463  * Since: 2.2
1464  **/
1465 gboolean
1466 gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
1467                                      GdkAtom    property)
1468 {
1469   gulong i;
1470   GdkX11Screen *x11_screen;
1471   NetWmSupportedAtoms *supported_atoms;
1472   GdkDisplay *display;
1473
1474   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
1475
1476   x11_screen = GDK_X11_SCREEN (screen);
1477   display = x11_screen->display;
1478
1479   if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
1480     return FALSE;
1481
1482   supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
1483   if (!supported_atoms)
1484     {
1485       supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
1486       g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
1487     }
1488
1489   fetch_net_wm_check_window (screen);
1490
1491   if (x11_screen->wmspec_check_window == None)
1492     return FALSE;
1493
1494   if (x11_screen->need_refetch_net_supported)
1495     {
1496       /* WM has changed since we last got the supported list,
1497        * refetch it.
1498        */
1499       Atom type;
1500       gint format;
1501       gulong bytes_after;
1502
1503       x11_screen->need_refetch_net_supported = FALSE;
1504
1505       if (supported_atoms->atoms)
1506         XFree (supported_atoms->atoms);
1507
1508       supported_atoms->atoms = NULL;
1509       supported_atoms->n_atoms = 0;
1510
1511       XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), x11_screen->xroot_window,
1512                           gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"),
1513                           0, G_MAXLONG, False, XA_ATOM, &type, &format,
1514                           &supported_atoms->n_atoms, &bytes_after,
1515                           (guchar **)&supported_atoms->atoms);
1516
1517       if (type != XA_ATOM)
1518         return FALSE;
1519     }
1520
1521   if (supported_atoms->atoms == NULL)
1522     return FALSE;
1523
1524   i = 0;
1525   while (i < supported_atoms->n_atoms)
1526     {
1527       if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property))
1528         return TRUE;
1529
1530       ++i;
1531     }
1532
1533   return FALSE;
1534 }
1535
1536 /**
1537  * gdk_x11_screen_get_window_manager_name:
1538  * @screen: (type GdkX11Screen): a #GdkScreen
1539  *
1540  * Returns the name of the window manager for @screen.
1541  *
1542  * Return value: the name of the window manager screen @screen, or
1543  * "unknown" if the window manager is unknown. The string is owned by GDK
1544  * and should not be freed.
1545  *
1546  * Since: 2.2
1547  **/
1548 const char*
1549 gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
1550 {
1551   GdkX11Screen *x11_screen;
1552   GdkDisplay *display;
1553
1554   x11_screen = GDK_X11_SCREEN (screen);
1555   display = x11_screen->display;
1556
1557   if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
1558     return x11_screen->window_manager_name;
1559
1560   fetch_net_wm_check_window (screen);
1561
1562   if (x11_screen->need_refetch_wm_name)
1563     {
1564       /* Get the name of the window manager */
1565       x11_screen->need_refetch_wm_name = FALSE;
1566
1567       g_free (x11_screen->window_manager_name);
1568       x11_screen->window_manager_name = g_strdup ("unknown");
1569
1570       if (x11_screen->wmspec_check_window != None)
1571         {
1572           Atom type;
1573           gint format;
1574           gulong n_items;
1575           gulong bytes_after;
1576           gchar *name;
1577
1578           name = NULL;
1579
1580           gdk_x11_display_error_trap_push (display);
1581
1582           XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1583                               x11_screen->wmspec_check_window,
1584                               gdk_x11_get_xatom_by_name_for_display (display,
1585                                                                      "_NET_WM_NAME"),
1586                               0, G_MAXLONG, False,
1587                               gdk_x11_get_xatom_by_name_for_display (display,
1588                                                                      "UTF8_STRING"),
1589                               &type, &format,
1590                               &n_items, &bytes_after,
1591                               (guchar **)&name);
1592
1593           gdk_x11_display_error_trap_pop_ignored (display);
1594
1595           if (name != NULL)
1596             {
1597               g_free (x11_screen->window_manager_name);
1598               x11_screen->window_manager_name = g_strdup (name);
1599               XFree (name);
1600             }
1601         }
1602     }
1603
1604   return GDK_X11_SCREEN (screen)->window_manager_name;
1605 }
1606
1607 static void
1608 gdk_x11_screen_class_init (GdkX11ScreenClass *klass)
1609 {
1610   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1611   GdkScreenClass *screen_class = GDK_SCREEN_CLASS (klass);
1612
1613   object_class->dispose = gdk_x11_screen_dispose;
1614   object_class->finalize = gdk_x11_screen_finalize;
1615
1616   screen_class->get_display = gdk_x11_screen_get_display;
1617   screen_class->get_width = gdk_x11_screen_get_width;
1618   screen_class->get_height = gdk_x11_screen_get_height;
1619   screen_class->get_width_mm = gdk_x11_screen_get_width_mm;
1620   screen_class->get_height_mm = gdk_x11_screen_get_height_mm;
1621   screen_class->get_number = gdk_x11_screen_get_number;
1622   screen_class->get_root_window = gdk_x11_screen_get_root_window;
1623   screen_class->get_n_monitors = gdk_x11_screen_get_n_monitors;
1624   screen_class->get_primary_monitor = gdk_x11_screen_get_primary_monitor;
1625   screen_class->get_monitor_width_mm = gdk_x11_screen_get_monitor_width_mm;
1626   screen_class->get_monitor_height_mm = gdk_x11_screen_get_monitor_height_mm;
1627   screen_class->get_monitor_plug_name = gdk_x11_screen_get_monitor_plug_name;
1628   screen_class->get_monitor_geometry = gdk_x11_screen_get_monitor_geometry;
1629   screen_class->get_monitor_workarea = gdk_x11_screen_get_monitor_workarea;
1630   screen_class->get_system_visual = _gdk_x11_screen_get_system_visual;
1631   screen_class->get_rgba_visual = gdk_x11_screen_get_rgba_visual;
1632   screen_class->is_composited = gdk_x11_screen_is_composited;
1633   screen_class->make_display_name = gdk_x11_screen_make_display_name;
1634   screen_class->get_active_window = gdk_x11_screen_get_active_window;
1635   screen_class->get_window_stack = gdk_x11_screen_get_window_stack;
1636   screen_class->get_setting = gdk_x11_screen_get_setting;
1637   screen_class->visual_get_best_depth = _gdk_x11_screen_visual_get_best_depth;
1638   screen_class->visual_get_best_type = _gdk_x11_screen_visual_get_best_type;
1639   screen_class->visual_get_best = _gdk_x11_screen_visual_get_best;
1640   screen_class->visual_get_best_with_depth = _gdk_x11_screen_visual_get_best_with_depth;
1641   screen_class->visual_get_best_with_type = _gdk_x11_screen_visual_get_best_with_type;
1642   screen_class->visual_get_best_with_both = _gdk_x11_screen_visual_get_best_with_both;
1643   screen_class->query_depths = _gdk_x11_screen_query_depths;
1644   screen_class->query_visual_types = _gdk_x11_screen_query_visual_types;
1645   screen_class->list_visuals = _gdk_x11_screen_list_visuals;
1646
1647   signals[WINDOW_MANAGER_CHANGED] =
1648     g_signal_new (g_intern_static_string ("window-manager-changed"),
1649                   G_OBJECT_CLASS_TYPE (object_class),
1650                   G_SIGNAL_RUN_LAST,
1651                   G_STRUCT_OFFSET (GdkX11ScreenClass, window_manager_changed),
1652                   NULL, NULL,
1653                   g_cclosure_marshal_VOID__VOID,
1654                   G_TYPE_NONE,
1655                   0);
1656 }