]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkscreen-x11.c
x11: Don't keep an "in_init" variable
[~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 gboolean
438 check_is_composited (GdkDisplay *display,
439                      GdkX11Screen *x11_screen)
440 {
441   Atom xselection = gdk_x11_atom_to_xatom_for_display (display, x11_screen->cm_selection_atom);
442   Window xwindow;
443   
444   xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), xselection);
445
446   return xwindow != None;
447 }
448
449 static GdkAtom
450 make_cm_atom (int screen_number)
451 {
452   gchar *name = g_strdup_printf ("_NET_WM_CM_S%d", screen_number);
453   GdkAtom atom = gdk_atom_intern (name, FALSE);
454   g_free (name);
455   return atom;
456 }
457
458 static void
459 init_monitor_geometry (GdkX11Monitor *monitor,
460                        int x, int y, int width, int height)
461 {
462   monitor->geometry.x = x;
463   monitor->geometry.y = y;
464   monitor->geometry.width = width;
465   monitor->geometry.height = height;
466
467   monitor->output = None;
468   monitor->width_mm = -1;
469   monitor->height_mm = -1;
470   monitor->output_name = NULL;
471   monitor->manufacturer = NULL;
472 }
473
474 static gboolean
475 init_fake_xinerama (GdkScreen *screen)
476 {
477 #ifdef G_ENABLE_DEBUG
478   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
479   XSetWindowAttributes atts;
480   Window win;
481   gint w, h;
482
483   if (!(_gdk_debug_flags & GDK_DEBUG_XINERAMA))
484     return FALSE;
485   
486   /* Fake Xinerama mode by splitting the screen into 4 monitors.
487    * Also draw a little cross to make the monitor boundaries visible.
488    */
489   w = WidthOfScreen (x11_screen->xscreen);
490   h = HeightOfScreen (x11_screen->xscreen);
491
492   x11_screen->n_monitors = 4;
493   x11_screen->monitors = g_new0 (GdkX11Monitor, 4);
494   init_monitor_geometry (&x11_screen->monitors[0], 0, 0, w / 2, h / 2);
495   init_monitor_geometry (&x11_screen->monitors[1], w / 2, 0, w / 2, h / 2);
496   init_monitor_geometry (&x11_screen->monitors[2], 0, h / 2, w / 2, h / 2);
497   init_monitor_geometry (&x11_screen->monitors[3], w / 2, h / 2, w / 2, h / 2);
498   
499   atts.override_redirect = 1;
500   atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen), 
501                                      x11_screen->screen_num);
502   win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
503                       x11_screen->xroot_window, 0, h / 2, w, 1, 0, 
504                       DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
505                                    x11_screen->screen_num),
506                       InputOutput, 
507                       DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
508                                     x11_screen->screen_num),
509                       CWOverrideRedirect|CWBackPixel, 
510                       &atts);
511   XMapRaised(GDK_SCREEN_XDISPLAY (screen), win); 
512   win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
513                       x11_screen->xroot_window, w/2 , 0, 1, h, 0, 
514                       DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
515                                    x11_screen->screen_num),
516                       InputOutput, 
517                       DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
518                                     x11_screen->screen_num),
519                       CWOverrideRedirect|CWBackPixel, 
520                       &atts);
521   XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
522   return TRUE;
523 #endif
524   
525   return FALSE;
526 }
527
528 static void
529 free_monitors (GdkX11Monitor *monitors,
530                gint           n_monitors)
531 {
532   int i;
533
534   for (i = 0; i < n_monitors; ++i)
535     {
536       g_free (monitors[i].output_name);
537       g_free (monitors[i].manufacturer);
538     }
539
540   g_free (monitors);
541 }
542
543 #ifdef HAVE_RANDR
544 static int
545 monitor_compare_function (GdkX11Monitor *monitor1,
546                           GdkX11Monitor *monitor2)
547 {
548   /* Sort the leftmost/topmost monitors first.
549    * For "cloned" monitors, sort the bigger ones first
550    * (giving preference to taller monitors over wider
551    * monitors)
552    */
553
554   if (monitor1->geometry.x != monitor2->geometry.x)
555     return monitor1->geometry.x - monitor2->geometry.x;
556
557   if (monitor1->geometry.y != monitor2->geometry.y)
558     return monitor1->geometry.y - monitor2->geometry.y;
559
560   if (monitor1->geometry.height != monitor2->geometry.height)
561     return - (monitor1->geometry.height - monitor2->geometry.height);
562
563   if (monitor1->geometry.width != monitor2->geometry.width)
564     return - (monitor1->geometry.width - monitor2->geometry.width);
565
566   return 0;
567 }
568 #endif
569
570 static gboolean
571 init_randr13 (GdkScreen *screen)
572 {
573 #ifdef HAVE_RANDR
574   GdkDisplay *display = gdk_screen_get_display (screen);
575   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
576   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
577   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
578   XRRScreenResources *resources;
579   RROutput primary_output;
580   RROutput first_output = None;
581   int i;
582   GArray *monitors;
583   gboolean randr12_compat = FALSE;
584
585   if (!display_x11->have_randr13)
586       return FALSE;
587
588   resources = XRRGetScreenResourcesCurrent (x11_screen->xdisplay,
589                                             x11_screen->xroot_window);
590   if (!resources)
591     return FALSE;
592
593   monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor),
594                                 resources->noutput);
595
596   for (i = 0; i < resources->noutput; ++i)
597     {
598       XRROutputInfo *output =
599         XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
600
601       /* Non RandR1.2 X driver have output name "default" */
602       randr12_compat |= !g_strcmp0 (output->name, "default");
603
604       if (output->connection == RR_Disconnected)
605         {
606           XRRFreeOutputInfo (output);
607           continue;
608         }
609
610       if (output->crtc)
611         {
612           GdkX11Monitor monitor;
613           XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, output->crtc);
614
615           monitor.geometry.x = crtc->x;
616           monitor.geometry.y = crtc->y;
617           monitor.geometry.width = crtc->width;
618           monitor.geometry.height = crtc->height;
619
620           monitor.output = resources->outputs[i];
621           monitor.width_mm = output->mm_width;
622           monitor.height_mm = output->mm_height;
623           monitor.output_name = g_strdup (output->name);
624           /* FIXME: need EDID parser */
625           monitor.manufacturer = NULL;
626
627           g_array_append_val (monitors, monitor);
628
629           XRRFreeCrtcInfo (crtc);
630         }
631
632       XRRFreeOutputInfo (output);
633     }
634
635   if (resources->noutput > 0)
636     first_output = resources->outputs[0];
637
638   XRRFreeScreenResources (resources);
639
640   /* non RandR 1.2 X driver doesn't return any usable multihead data */
641   if (randr12_compat)
642     {
643       guint n_monitors = monitors->len;
644
645       free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE),
646                      n_monitors);
647
648       return FALSE;
649     }
650
651   g_array_sort (monitors,
652                 (GCompareFunc) monitor_compare_function);
653   x11_screen->n_monitors = monitors->len;
654   x11_screen->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);
655
656   x11_screen->primary_monitor = 0;
657
658   primary_output = XRRGetOutputPrimary (x11_screen->xdisplay,
659                                         x11_screen->xroot_window);
660
661   for (i = 0; i < x11_screen->n_monitors; ++i)
662     {
663       if (x11_screen->monitors[i].output == primary_output)
664         {
665           x11_screen->primary_monitor = i;
666           break;
667         }
668
669       /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
670       if (primary_output == None &&
671           g_ascii_strncasecmp (x11_screen->monitors[i].output_name, "LVDS", 4) == 0)
672         {
673           x11_screen->primary_monitor = i;
674           break;
675         }
676
677       /* No primary specified and no LVDS found */
678       if (x11_screen->monitors[i].output == first_output)
679         x11_screen->primary_monitor = i;
680     }
681
682   return x11_screen->n_monitors > 0;
683 #endif
684
685   return FALSE;
686 }
687
688 static gboolean
689 init_solaris_xinerama (GdkScreen *screen)
690 {
691 #ifdef HAVE_SOLARIS_XINERAMA
692   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
693   int screen_no = gdk_screen_get_number (screen);
694   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
695   XRectangle monitors[MAXFRAMEBUFFERS];
696   unsigned char hints[16];
697   gint result;
698   int n_monitors;
699   int i;
700   
701   if (!XineramaGetState (dpy, screen_no))
702     return FALSE;
703
704   result = XineramaGetInfo (dpy, screen_no, monitors, hints, &n_monitors);
705
706   /* Yes I know it should be Success but the current implementation 
707    * returns the num of monitor
708    */
709   if (result == 0)
710     {
711       return FALSE;
712     }
713
714   x11_screen->monitors = g_new0 (GdkX11Monitor, n_monitors);
715   x11_screen->n_monitors = n_monitors;
716
717   for (i = 0; i < n_monitors; i++)
718     {
719       init_monitor_geometry (&x11_screen->monitors[i],
720                              monitors[i].x, monitors[i].y,
721                              monitors[i].width, monitors[i].height);
722     }
723
724   x11_screen->primary_monitor = 0;
725
726   return TRUE;
727 #endif /* HAVE_SOLARIS_XINERAMA */
728
729   return FALSE;
730 }
731
732 static gboolean
733 init_xfree_xinerama (GdkScreen *screen)
734 {
735 #ifdef HAVE_XFREE_XINERAMA
736   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
737   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
738   XineramaScreenInfo *monitors;
739   int i, n_monitors;
740   
741   if (!XineramaIsActive (dpy))
742     return FALSE;
743
744   monitors = XineramaQueryScreens (dpy, &n_monitors);
745   
746   if (n_monitors <= 0 || monitors == NULL)
747     {
748       /* If Xinerama doesn't think we have any monitors, try acting as
749        * though we had no Xinerama. If the "no monitors" condition
750        * is because XRandR 1.2 is currently switching between CRTCs,
751        * we'll be notified again when we have our monitor back,
752        * and can go back into Xinerama-ish mode at that point.
753        */
754       if (monitors)
755         XFree (monitors);
756       
757       return FALSE;
758     }
759
760   x11_screen->n_monitors = n_monitors;
761   x11_screen->monitors = g_new0 (GdkX11Monitor, n_monitors);
762   
763   for (i = 0; i < n_monitors; ++i)
764     {
765       init_monitor_geometry (&x11_screen->monitors[i],
766                              monitors[i].x_org, monitors[i].y_org,
767                              monitors[i].width, monitors[i].height);
768     }
769   
770   XFree (monitors);
771   
772   x11_screen->primary_monitor = 0;
773
774   return TRUE;
775 #endif /* HAVE_XFREE_XINERAMA */
776   
777   return FALSE;
778 }
779
780 static gboolean
781 init_solaris_xinerama_indices (GdkX11Screen *x11_screen)
782 {
783 #ifdef HAVE_SOLARIS_XINERAMA
784   XRectangle    x_monitors[MAXFRAMEBUFFERS];
785   unsigned char hints[16];
786   gint          result;
787   gint          monitor_num;
788   gint          x_n_monitors;
789   gint          i;
790
791   if (!XineramaGetState (x11_screen->xdisplay, x11_screen->screen_num))
792     return FALSE;
793
794   result = XineramaGetInfo (x11_screen->xdisplay, x11_screen->screen_num,
795                             x_monitors, hints, &x_n_monitors);
796
797   if (result == 0)
798     return FALSE;
799
800
801   for (monitor_num = 0; monitor_num < x11_screen->n_monitors; ++monitor_num)
802     {
803       for (i = 0; i < x_n_monitors; ++i)
804         {
805           if (x11_screen->monitors[monitor_num].geometry.x == x_monitors[i].x &&
806               x11_screen->monitors[monitor_num].geometry.y == x_monitors[i].y &&
807               x11_screen->monitors[monitor_num].geometry.width == x_monitors[i].width &&
808               x11_screen->monitors[monitor_num].geometry.height == x_monitors[i].height)
809             {
810               g_hash_table_insert (x11_screen->xinerama_matches,
811                                    GINT_TO_POINTER (monitor_num),
812                                    GINT_TO_POINTER (i));
813             }
814         }
815     }
816   return TRUE;
817 #endif /* HAVE_SOLARIS_XINERAMA */
818
819   return FALSE;
820 }
821
822 static gboolean
823 init_xfree_xinerama_indices (GdkX11Screen *x11_screen)
824 {
825 #ifdef HAVE_XFREE_XINERAMA
826   XineramaScreenInfo *x_monitors;
827   gint                monitor_num;
828   gint                x_n_monitors;
829   gint                i;
830
831   if (!XineramaIsActive (x11_screen->xdisplay))
832     return FALSE;
833
834   x_monitors = XineramaQueryScreens (x11_screen->xdisplay, &x_n_monitors);
835   if (x_n_monitors <= 0 || x_monitors == NULL)
836     {
837       if (x_monitors)
838         XFree (x_monitors);
839
840       return FALSE;
841     }
842
843   for (monitor_num = 0; monitor_num < x11_screen->n_monitors; ++monitor_num)
844     {
845       for (i = 0; i < x_n_monitors; ++i)
846         {
847           if (x11_screen->monitors[monitor_num].geometry.x == x_monitors[i].x_org &&
848               x11_screen->monitors[monitor_num].geometry.y == x_monitors[i].y_org &&
849               x11_screen->monitors[monitor_num].geometry.width == x_monitors[i].width &&
850               x11_screen->monitors[monitor_num].geometry.height == x_monitors[i].height)
851             {
852               g_hash_table_insert (x11_screen->xinerama_matches,
853                                    GINT_TO_POINTER (monitor_num),
854                                    GINT_TO_POINTER (i));
855             }
856         }
857     }
858   XFree (x_monitors);
859   return TRUE;
860 #endif /* HAVE_XFREE_XINERAMA */
861
862   return FALSE;
863 }
864
865 static void
866 init_xinerama_indices (GdkX11Screen *x11_screen)
867 {
868   int opcode, firstevent, firsterror;
869
870   x11_screen->xinerama_matches = g_hash_table_new (g_direct_hash, g_direct_equal);
871   if (XQueryExtension (x11_screen->xdisplay, "XINERAMA",
872                        &opcode, &firstevent, &firsterror))
873     {
874       x11_screen->xinerama_matches = g_hash_table_new (g_direct_hash, g_direct_equal);
875
876       /* Solaris Xinerama first, then XFree/Xorg Xinerama
877        * to match the order in init_multihead()
878        */
879       if (init_solaris_xinerama_indices (x11_screen) == FALSE)
880         init_xfree_xinerama_indices (x11_screen);
881     }
882 }
883
884 gint
885 _gdk_x11_screen_get_xinerama_index (GdkScreen *screen,
886                                     gint       monitor_num)
887 {
888   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
889   gpointer val;
890
891   g_return_val_if_fail (monitor_num < x11_screen->n_monitors, -1);
892
893   if (x11_screen->xinerama_matches == NULL)
894     init_xinerama_indices (x11_screen);
895
896   if (g_hash_table_lookup_extended (x11_screen->xinerama_matches, GINT_TO_POINTER (monitor_num), NULL, &val))
897     return (GPOINTER_TO_INT(val));
898
899   return -1;
900 }
901
902 void
903 _gdk_x11_screen_get_edge_monitors (GdkScreen *screen,
904                                    gint      *top,
905                                    gint      *bottom,
906                                    gint      *left,
907                                    gint      *right)
908 {
909   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
910   gint          top_most_pos = HeightOfScreen (GDK_X11_SCREEN (screen)->xscreen);
911   gint          left_most_pos = WidthOfScreen (GDK_X11_SCREEN (screen)->xscreen);
912   gint          bottom_most_pos = 0;
913   gint          right_most_pos = 0;
914   gint          monitor_num;
915
916   for (monitor_num = 0; monitor_num < x11_screen->n_monitors; monitor_num++)
917     {
918       gint monitor_x = x11_screen->monitors[monitor_num].geometry.x;
919       gint monitor_y = x11_screen->monitors[monitor_num].geometry.y;
920       gint monitor_max_x = monitor_x + x11_screen->monitors[monitor_num].geometry.width;
921       gint monitor_max_y = monitor_y + x11_screen->monitors[monitor_num].geometry.height;
922
923       if (left && left_most_pos > monitor_x)
924         {
925           left_most_pos = monitor_x;
926           *left = monitor_num;
927         }
928       if (right && right_most_pos < monitor_max_x)
929         {
930           right_most_pos = monitor_max_x;
931           *right = monitor_num;
932         }
933       if (top && top_most_pos > monitor_y)
934         {
935           top_most_pos = monitor_y;
936           *top = monitor_num;
937         }
938       if (bottom && bottom_most_pos < monitor_max_y)
939         {
940           bottom_most_pos = monitor_max_y;
941           *bottom = monitor_num;
942         }
943     }
944 }
945
946 static void
947 deinit_multihead (GdkScreen *screen)
948 {
949   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
950
951   free_monitors (x11_screen->monitors, x11_screen->n_monitors);
952   g_clear_pointer (&x11_screen->xinerama_matches, g_hash_table_destroy);
953
954   x11_screen->n_monitors = 0;
955   x11_screen->monitors = NULL;
956 }
957
958 static gboolean
959 compare_monitor (GdkX11Monitor *m1,
960                  GdkX11Monitor *m2)
961 {
962   if (m1->geometry.x != m2->geometry.x ||
963       m1->geometry.y != m2->geometry.y ||
964       m1->geometry.width != m2->geometry.width ||
965       m1->geometry.height != m2->geometry.height)
966     return FALSE;
967
968   if (m1->width_mm != m2->width_mm ||
969       m1->height_mm != m2->height_mm)
970     return FALSE;
971
972   if (g_strcmp0 (m1->output_name, m2->output_name) != 0)
973     return FALSE;
974
975   if (g_strcmp0 (m1->manufacturer, m2->manufacturer) != 0)
976     return FALSE;
977
978   return TRUE;
979 }
980
981 static gboolean
982 compare_monitors (GdkX11Monitor *monitors1, gint n_monitors1,
983                   GdkX11Monitor *monitors2, gint n_monitors2)
984 {
985   gint i;
986
987   if (n_monitors1 != n_monitors2)
988     return FALSE;
989
990   for (i = 0; i < n_monitors1; i++)
991     {
992       if (!compare_monitor (monitors1 + i, monitors2 + i))
993         return FALSE;
994     }
995
996   return TRUE;
997 }
998
999 static void
1000 init_multihead (GdkScreen *screen)
1001 {
1002   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1003   int opcode, firstevent, firsterror;
1004
1005   /* There are four different implementations of multihead support: 
1006    *
1007    *  1. Fake Xinerama for debugging purposes
1008    *  2. RandR 1.2
1009    *  3. Solaris Xinerama
1010    *  4. XFree86/Xorg Xinerama
1011    *
1012    * We use them in that order.
1013    */
1014   if (init_fake_xinerama (screen))
1015     return;
1016
1017   if (init_randr13 (screen))
1018     return;
1019
1020   if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
1021                        &opcode, &firstevent, &firsterror))
1022     {
1023       if (init_solaris_xinerama (screen))
1024         return;
1025       
1026       if (init_xfree_xinerama (screen))
1027         return;
1028     }
1029
1030   /* No multihead support of any kind for this screen */
1031   x11_screen->n_monitors = 1;
1032   x11_screen->monitors = g_new0 (GdkX11Monitor, 1);
1033   x11_screen->primary_monitor = 0;
1034
1035   init_monitor_geometry (x11_screen->monitors, 0, 0,
1036                          WidthOfScreen (x11_screen->xscreen),
1037                          HeightOfScreen (x11_screen->xscreen));
1038 }
1039
1040 GdkScreen *
1041 _gdk_x11_screen_new (GdkDisplay *display,
1042                      gint        screen_number) 
1043 {
1044   GdkScreen *screen;
1045   GdkX11Screen *x11_screen;
1046   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
1047
1048   screen = g_object_new (GDK_TYPE_X11_SCREEN, NULL);
1049
1050   x11_screen = GDK_X11_SCREEN (screen);
1051   x11_screen->display = display;
1052   x11_screen->xdisplay = display_x11->xdisplay;
1053   x11_screen->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
1054   x11_screen->screen_num = screen_number;
1055   x11_screen->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
1056   x11_screen->wmspec_check_window = None;
1057   /* we want this to be always non-null */
1058   x11_screen->window_manager_name = g_strdup ("unknown");
1059   
1060   init_multihead (screen);
1061   init_randr_support (screen);
1062   
1063   _gdk_x11_screen_init_visuals (screen);
1064   _gdk_x11_screen_init_root_window (screen);
1065   
1066   return screen;
1067 }
1068
1069 /*
1070  * It is important that we first request the selection
1071  * notification, and then setup the initial state of
1072  * is_composited to avoid a race condition here.
1073  */
1074 void
1075 _gdk_x11_screen_setup (GdkScreen *screen)
1076 {
1077   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1078
1079   x11_screen->cm_selection_atom = make_cm_atom (x11_screen->screen_num);
1080   gdk_display_request_selection_notification (x11_screen->display,
1081                                               x11_screen->cm_selection_atom);
1082   x11_screen->is_composited = check_is_composited (x11_screen->display, x11_screen);
1083 }
1084
1085 static gboolean
1086 gdk_x11_screen_is_composited (GdkScreen *screen)
1087 {
1088   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1089
1090   return x11_screen->is_composited;
1091 }
1092
1093 static void
1094 init_randr_support (GdkScreen *screen)
1095 {
1096   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1097
1098   /* NB: This is also needed for XSettings, so don't remove. */
1099   XSelectInput (GDK_SCREEN_XDISPLAY (screen),
1100                 x11_screen->xroot_window,
1101                 StructureNotifyMask);
1102
1103 #ifdef HAVE_RANDR
1104   if (!GDK_X11_DISPLAY (gdk_screen_get_display (screen))->have_randr12)
1105     return;
1106
1107   XRRSelectInput (GDK_SCREEN_XDISPLAY (screen),
1108                   x11_screen->xroot_window,
1109                   RRScreenChangeNotifyMask
1110                   | RRCrtcChangeNotifyMask
1111                   | RROutputPropertyNotifyMask);
1112 #endif
1113 }
1114
1115 static void
1116 process_monitors_change (GdkScreen *screen)
1117 {
1118   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1119   gint           n_monitors;
1120   gint           primary_monitor;
1121   GdkX11Monitor *monitors;
1122   gboolean changed;
1123
1124   primary_monitor = x11_screen->primary_monitor;
1125   n_monitors = x11_screen->n_monitors;
1126   monitors = x11_screen->monitors;
1127
1128   x11_screen->n_monitors = 0;
1129   x11_screen->monitors = NULL;
1130
1131   init_multihead (screen);
1132
1133   changed =
1134     !compare_monitors (monitors, n_monitors,
1135                        x11_screen->monitors, x11_screen->n_monitors) ||
1136     x11_screen->primary_monitor != primary_monitor;
1137
1138
1139   free_monitors (monitors, n_monitors);
1140
1141   if (changed)
1142     g_signal_emit_by_name (screen, "monitors-changed");
1143 }
1144
1145 void
1146 _gdk_x11_screen_size_changed (GdkScreen *screen,
1147                               XEvent    *event)
1148 {
1149   gint width, height;
1150 #ifdef HAVE_RANDR
1151   GdkX11Display *display_x11;
1152 #endif
1153
1154   width = gdk_screen_get_width (screen);
1155   height = gdk_screen_get_height (screen);
1156
1157 #ifdef HAVE_RANDR
1158   display_x11 = GDK_X11_DISPLAY (gdk_screen_get_display (screen));
1159
1160   if (display_x11->have_randr13 && event->type == ConfigureNotify)
1161     return;
1162
1163   XRRUpdateConfiguration (event);
1164 #else
1165   if (event->type == ConfigureNotify)
1166     {
1167       XConfigureEvent *rcevent = (XConfigureEvent *) event;
1168       Screen        *xscreen = gdk_x11_screen_get_xscreen (screen);
1169
1170       xscreen->width   = rcevent->width;
1171       xscreen->height  = rcevent->height;
1172     }
1173   else
1174     return;
1175 #endif
1176
1177   process_monitors_change (screen);
1178
1179   if (width != gdk_screen_get_width (screen) ||
1180       height != gdk_screen_get_height (screen))
1181     g_signal_emit_by_name (screen, "size-changed");
1182 }
1183
1184 void
1185 _gdk_x11_screen_window_manager_changed (GdkScreen *screen)
1186 {
1187   g_signal_emit (screen, signals[WINDOW_MANAGER_CHANGED], 0);
1188 }
1189
1190 void
1191 _gdk_x11_screen_process_owner_change (GdkScreen *screen,
1192                                       XEvent *event)
1193 {
1194 #ifdef HAVE_XFIXES
1195   XFixesSelectionNotifyEvent *selection_event = (XFixesSelectionNotifyEvent *)event;
1196   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1197   Atom xcm_selection_atom = gdk_x11_atom_to_xatom_for_display (x11_screen->display,
1198                                                                x11_screen->cm_selection_atom);
1199
1200   if (selection_event->selection == xcm_selection_atom)
1201     {
1202       gboolean composited = selection_event->owner != None;
1203
1204       if (composited != x11_screen->is_composited)
1205         {
1206           x11_screen->is_composited = composited;
1207
1208           g_signal_emit_by_name (screen, "composited-changed");
1209         }
1210     }
1211 #endif
1212 }
1213
1214 static gchar *
1215 substitute_screen_number (const gchar *display_name,
1216                           gint         screen_number)
1217 {
1218   GString *str;
1219   gchar   *p;
1220
1221   str = g_string_new (display_name);
1222
1223   p = strrchr (str->str, '.');
1224   if (p && p >  strchr (str->str, ':'))
1225     g_string_truncate (str, p - str->str);
1226
1227   g_string_append_printf (str, ".%d", screen_number);
1228
1229   return g_string_free (str, FALSE);
1230 }
1231
1232 static gchar *
1233 gdk_x11_screen_make_display_name (GdkScreen *screen)
1234 {
1235   const gchar *old_display;
1236
1237   old_display = gdk_display_get_name (gdk_screen_get_display (screen));
1238
1239   return substitute_screen_number (old_display,
1240                                    gdk_screen_get_number (screen));
1241 }
1242
1243 static GdkWindow *
1244 gdk_x11_screen_get_active_window (GdkScreen *screen)
1245 {
1246   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1247   GdkWindow *ret = NULL;
1248   Atom type_return;
1249   gint format_return;
1250   gulong nitems_return;
1251   gulong bytes_after_return;
1252   guchar *data = NULL;
1253
1254   if (!gdk_x11_screen_supports_net_wm_hint (screen,
1255                                             gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW")))
1256     return NULL;
1257
1258   if (XGetWindowProperty (x11_screen->xdisplay, x11_screen->xroot_window,
1259                           gdk_x11_get_xatom_by_name_for_display (x11_screen->display,
1260                                                                  "_NET_ACTIVE_WINDOW"),
1261                           0, 1, False, XA_WINDOW, &type_return,
1262                           &format_return, &nitems_return,
1263                           &bytes_after_return, &data)
1264       == Success)
1265     {
1266       if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
1267         {
1268           Window window = *(Window *) data;
1269
1270           if (window != None)
1271             {
1272               ret = gdk_x11_window_foreign_new_for_display (x11_screen->display,
1273                                                             window);
1274             }
1275         }
1276     }
1277
1278   if (data)
1279     XFree (data);
1280
1281   return ret;
1282 }
1283
1284 static GList *
1285 gdk_x11_screen_get_window_stack (GdkScreen *screen)
1286 {
1287   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1288   GList *ret = NULL;
1289   Atom type_return;
1290   gint format_return;
1291   gulong nitems_return;
1292   gulong bytes_after_return;
1293   guchar *data = NULL;
1294
1295   if (!gdk_x11_screen_supports_net_wm_hint (screen,
1296                                             gdk_atom_intern_static_string ("_NET_CLIENT_LIST_STACKING")))
1297     return NULL;
1298
1299   if (XGetWindowProperty (x11_screen->xdisplay, x11_screen->xroot_window,
1300                           gdk_x11_get_xatom_by_name_for_display (x11_screen->display,
1301                                                                  "_NET_CLIENT_LIST_STACKING"),
1302                           0, G_MAXLONG, False, XA_WINDOW, &type_return,
1303                           &format_return, &nitems_return,
1304                           &bytes_after_return, &data)
1305       == Success)
1306     {
1307       if ((type_return == XA_WINDOW) && (format_return == 32) &&
1308           (data) && (nitems_return > 0))
1309         {
1310           gulong *stack = (gulong *) data;
1311           GdkWindow *win;
1312           int i;
1313
1314           for (i = 0; i < nitems_return; i++)
1315             {
1316               win = gdk_x11_window_foreign_new_for_display (x11_screen->display,
1317                                                             (Window)stack[i]);
1318
1319               if (win != NULL)
1320                 ret = g_list_append (ret, win);
1321             }
1322         }
1323     }
1324
1325   if (data)
1326     XFree (data);
1327
1328   return ret;
1329 }
1330
1331 static gboolean
1332 gdk_x11_screen_get_setting (GdkScreen   *screen,
1333                             const gchar *name,
1334                             GValue      *value)
1335 {
1336   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1337   const GValue *setting;
1338
1339   setting = _gdk_x11_xsettings_client_get_setting (x11_screen->xsettings_client, name);
1340   if (setting == NULL)
1341     goto out;
1342
1343   if (!g_value_type_transformable (G_VALUE_TYPE (setting), G_VALUE_TYPE (value)))
1344     {
1345       g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
1346                  name,
1347                  g_type_name (G_VALUE_TYPE (setting)),
1348                  g_type_name (G_VALUE_TYPE (value)));
1349       goto out;
1350     }
1351
1352   g_value_transform (setting, value);
1353
1354   return TRUE;
1355
1356  out:
1357   return _gdk_x11_get_xft_setting (screen, name, value);
1358 }
1359
1360 static void
1361 cleanup_atoms(gpointer data)
1362 {
1363   NetWmSupportedAtoms *supported_atoms = data;
1364   if (supported_atoms->atoms)
1365       XFree (supported_atoms->atoms);
1366   g_free (supported_atoms);
1367 }
1368
1369 static Window
1370 get_net_supporting_wm_check (GdkX11Screen *screen,
1371                              Window        window)
1372 {
1373   GdkDisplay *display;
1374   Atom type;
1375   gint format;
1376   gulong n_items;
1377   gulong bytes_after;
1378   guchar *data;
1379   Window value;
1380
1381   display = screen->display;
1382   type = None;
1383   data = NULL;
1384   value = None;
1385
1386   gdk_x11_display_error_trap_push (display);
1387   XGetWindowProperty (screen->xdisplay, window,
1388                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
1389                       0, G_MAXLONG, False, XA_WINDOW, &type, &format,
1390                       &n_items, &bytes_after, &data);
1391   gdk_x11_display_error_trap_pop_ignored (display);
1392
1393   if (type == XA_WINDOW)
1394     value = *(Window *)data;
1395
1396   if (data)
1397     XFree (data);
1398
1399   return value;
1400 }
1401
1402 static void
1403 fetch_net_wm_check_window (GdkScreen *screen)
1404 {
1405   GdkX11Screen *x11_screen;
1406   GdkDisplay *display;
1407   Window window;
1408   GTimeVal tv;
1409   gint error;
1410
1411   x11_screen = GDK_X11_SCREEN (screen);
1412   display = x11_screen->display;
1413
1414   g_return_if_fail (GDK_X11_DISPLAY (display)->trusted_client);
1415
1416   if (x11_screen->wmspec_check_window != None)
1417     return; /* already have it */
1418
1419   g_get_current_time (&tv);
1420
1421   if (ABS  (tv.tv_sec - x11_screen->last_wmspec_check_time) < 15)
1422     return; /* we've checked recently */
1423
1424   window = get_net_supporting_wm_check (x11_screen, x11_screen->xroot_window);
1425   if (window == None)
1426     return;
1427
1428   if (window != get_net_supporting_wm_check (x11_screen, window))
1429     return;
1430
1431   gdk_x11_display_error_trap_push (display);
1432
1433   /* Find out if this WM goes away, so we can reset everything. */
1434   XSelectInput (x11_screen->xdisplay, window, StructureNotifyMask);
1435
1436   error = gdk_x11_display_error_trap_pop (display);
1437   if (!error)
1438     {
1439       /* We check the window property again because after XGetWindowProperty()
1440        * and before XSelectInput() the window may have been recycled in such a
1441        * way that XSelectInput() doesn't fail but the window is no longer what
1442        * we want.
1443        */
1444       if (window != get_net_supporting_wm_check (x11_screen, window))
1445         return;
1446
1447       x11_screen->wmspec_check_window = window;
1448       x11_screen->last_wmspec_check_time = tv.tv_sec;
1449       x11_screen->need_refetch_net_supported = TRUE;
1450       x11_screen->need_refetch_wm_name = TRUE;
1451
1452       /* Careful, reentrancy */
1453       _gdk_x11_screen_window_manager_changed (screen);
1454     }
1455 }
1456
1457 /**
1458  * gdk_x11_screen_supports_net_wm_hint:
1459  * @screen: (type GdkX11Screen): the relevant #GdkScreen.
1460  * @property: a property atom.
1461  *
1462  * This function is specific to the X11 backend of GDK, and indicates
1463  * whether the window manager supports a certain hint from the
1464  * Extended Window Manager Hints Specification. You can find this
1465  * specification on
1466  * <ulink url="http://www.freedesktop.org">http://www.freedesktop.org</ulink>.
1467  *
1468  * When using this function, keep in mind that the window manager
1469  * can change over time; so you shouldn't use this function in
1470  * a way that impacts persistent application state. A common bug
1471  * is that your application can start up before the window manager
1472  * does when the user logs in, and before the window manager starts
1473  * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
1474  * You can monitor the window_manager_changed signal on #GdkScreen to detect
1475  * a window manager change.
1476  *
1477  * Return value: %TRUE if the window manager supports @property
1478  *
1479  * Since: 2.2
1480  **/
1481 gboolean
1482 gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
1483                                      GdkAtom    property)
1484 {
1485   gulong i;
1486   GdkX11Screen *x11_screen;
1487   NetWmSupportedAtoms *supported_atoms;
1488   GdkDisplay *display;
1489
1490   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
1491
1492   x11_screen = GDK_X11_SCREEN (screen);
1493   display = x11_screen->display;
1494
1495   if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
1496     return FALSE;
1497
1498   supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
1499   if (!supported_atoms)
1500     {
1501       supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
1502       g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
1503     }
1504
1505   fetch_net_wm_check_window (screen);
1506
1507   if (x11_screen->wmspec_check_window == None)
1508     return FALSE;
1509
1510   if (x11_screen->need_refetch_net_supported)
1511     {
1512       /* WM has changed since we last got the supported list,
1513        * refetch it.
1514        */
1515       Atom type;
1516       gint format;
1517       gulong bytes_after;
1518
1519       x11_screen->need_refetch_net_supported = FALSE;
1520
1521       if (supported_atoms->atoms)
1522         XFree (supported_atoms->atoms);
1523
1524       supported_atoms->atoms = NULL;
1525       supported_atoms->n_atoms = 0;
1526
1527       XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), x11_screen->xroot_window,
1528                           gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"),
1529                           0, G_MAXLONG, False, XA_ATOM, &type, &format,
1530                           &supported_atoms->n_atoms, &bytes_after,
1531                           (guchar **)&supported_atoms->atoms);
1532
1533       if (type != XA_ATOM)
1534         return FALSE;
1535     }
1536
1537   if (supported_atoms->atoms == NULL)
1538     return FALSE;
1539
1540   i = 0;
1541   while (i < supported_atoms->n_atoms)
1542     {
1543       if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property))
1544         return TRUE;
1545
1546       ++i;
1547     }
1548
1549   return FALSE;
1550 }
1551
1552 void
1553 _gdk_x11_screen_init_events (GdkScreen *screen)
1554 {
1555   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
1556
1557   x11_screen->xsettings_client = _gdk_x11_xsettings_client_new (screen);
1558 }
1559
1560 /**
1561  * gdk_x11_screen_get_window_manager_name:
1562  * @screen: (type GdkX11Screen): a #GdkScreen
1563  *
1564  * Returns the name of the window manager for @screen.
1565  *
1566  * Return value: the name of the window manager screen @screen, or
1567  * "unknown" if the window manager is unknown. The string is owned by GDK
1568  * and should not be freed.
1569  *
1570  * Since: 2.2
1571  **/
1572 const char*
1573 gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
1574 {
1575   GdkX11Screen *x11_screen;
1576   GdkDisplay *display;
1577
1578   x11_screen = GDK_X11_SCREEN (screen);
1579   display = x11_screen->display;
1580
1581   if (!G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
1582     return x11_screen->window_manager_name;
1583
1584   fetch_net_wm_check_window (screen);
1585
1586   if (x11_screen->need_refetch_wm_name)
1587     {
1588       /* Get the name of the window manager */
1589       x11_screen->need_refetch_wm_name = FALSE;
1590
1591       g_free (x11_screen->window_manager_name);
1592       x11_screen->window_manager_name = g_strdup ("unknown");
1593
1594       if (x11_screen->wmspec_check_window != None)
1595         {
1596           Atom type;
1597           gint format;
1598           gulong n_items;
1599           gulong bytes_after;
1600           gchar *name;
1601
1602           name = NULL;
1603
1604           gdk_x11_display_error_trap_push (display);
1605
1606           XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1607                               x11_screen->wmspec_check_window,
1608                               gdk_x11_get_xatom_by_name_for_display (display,
1609                                                                      "_NET_WM_NAME"),
1610                               0, G_MAXLONG, False,
1611                               gdk_x11_get_xatom_by_name_for_display (display,
1612                                                                      "UTF8_STRING"),
1613                               &type, &format,
1614                               &n_items, &bytes_after,
1615                               (guchar **)&name);
1616
1617           gdk_x11_display_error_trap_pop_ignored (display);
1618
1619           if (name != NULL)
1620             {
1621               g_free (x11_screen->window_manager_name);
1622               x11_screen->window_manager_name = g_strdup (name);
1623               XFree (name);
1624             }
1625         }
1626     }
1627
1628   return GDK_X11_SCREEN (screen)->window_manager_name;
1629 }
1630
1631 static void
1632 gdk_x11_screen_class_init (GdkX11ScreenClass *klass)
1633 {
1634   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1635   GdkScreenClass *screen_class = GDK_SCREEN_CLASS (klass);
1636
1637   object_class->dispose = gdk_x11_screen_dispose;
1638   object_class->finalize = gdk_x11_screen_finalize;
1639
1640   screen_class->get_display = gdk_x11_screen_get_display;
1641   screen_class->get_width = gdk_x11_screen_get_width;
1642   screen_class->get_height = gdk_x11_screen_get_height;
1643   screen_class->get_width_mm = gdk_x11_screen_get_width_mm;
1644   screen_class->get_height_mm = gdk_x11_screen_get_height_mm;
1645   screen_class->get_number = gdk_x11_screen_get_number;
1646   screen_class->get_root_window = gdk_x11_screen_get_root_window;
1647   screen_class->get_n_monitors = gdk_x11_screen_get_n_monitors;
1648   screen_class->get_primary_monitor = gdk_x11_screen_get_primary_monitor;
1649   screen_class->get_monitor_width_mm = gdk_x11_screen_get_monitor_width_mm;
1650   screen_class->get_monitor_height_mm = gdk_x11_screen_get_monitor_height_mm;
1651   screen_class->get_monitor_plug_name = gdk_x11_screen_get_monitor_plug_name;
1652   screen_class->get_monitor_geometry = gdk_x11_screen_get_monitor_geometry;
1653   screen_class->get_monitor_workarea = gdk_x11_screen_get_monitor_workarea;
1654   screen_class->get_system_visual = _gdk_x11_screen_get_system_visual;
1655   screen_class->get_rgba_visual = gdk_x11_screen_get_rgba_visual;
1656   screen_class->is_composited = gdk_x11_screen_is_composited;
1657   screen_class->make_display_name = gdk_x11_screen_make_display_name;
1658   screen_class->get_active_window = gdk_x11_screen_get_active_window;
1659   screen_class->get_window_stack = gdk_x11_screen_get_window_stack;
1660   screen_class->get_setting = gdk_x11_screen_get_setting;
1661   screen_class->visual_get_best_depth = _gdk_x11_screen_visual_get_best_depth;
1662   screen_class->visual_get_best_type = _gdk_x11_screen_visual_get_best_type;
1663   screen_class->visual_get_best = _gdk_x11_screen_visual_get_best;
1664   screen_class->visual_get_best_with_depth = _gdk_x11_screen_visual_get_best_with_depth;
1665   screen_class->visual_get_best_with_type = _gdk_x11_screen_visual_get_best_with_type;
1666   screen_class->visual_get_best_with_both = _gdk_x11_screen_visual_get_best_with_both;
1667   screen_class->query_depths = _gdk_x11_screen_query_depths;
1668   screen_class->query_visual_types = _gdk_x11_screen_query_visual_types;
1669   screen_class->list_visuals = _gdk_x11_screen_list_visuals;
1670
1671   signals[WINDOW_MANAGER_CHANGED] =
1672     g_signal_new (g_intern_static_string ("window-manager-changed"),
1673                   G_OBJECT_CLASS_TYPE (object_class),
1674                   G_SIGNAL_RUN_LAST,
1675                   G_STRUCT_OFFSET (GdkX11ScreenClass, window_manager_changed),
1676                   NULL, NULL,
1677                   g_cclosure_marshal_VOID__VOID,
1678                   G_TYPE_NONE,
1679                   0);
1680 }