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