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