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