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