]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkscreen-x11.c
More error trap cleanups
[~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 <stdlib.h>
27 #include <string.h>
28
29 #include <glib.h>
30 #include "gdkscreen.h"
31 #include "gdkscreen-x11.h"
32 #include "gdkdisplay.h"
33 #include "gdkdisplay-x11.h"
34 #include "gdkx.h"
35
36 #include <X11/Xatom.h>
37
38 #ifdef HAVE_SOLARIS_XINERAMA
39 #include <X11/extensions/xinerama.h>
40 #endif
41 #ifdef HAVE_XFREE_XINERAMA
42 #include <X11/extensions/Xinerama.h>
43 #endif
44
45 #ifdef HAVE_RANDR
46 #include <X11/extensions/Xrandr.h>
47 #endif
48
49 #ifdef HAVE_XFIXES
50 #include <X11/extensions/Xfixes.h>
51 #endif
52
53 #include "gdksettings.c"
54
55 static void         gdk_screen_x11_dispose     (GObject           *object);
56 static void         gdk_screen_x11_finalize    (GObject           *object);
57 static void         init_randr_support         (GdkScreen         *screen);
58 static void         deinit_multihead           (GdkScreen         *screen);
59
60 enum
61 {
62   WINDOW_MANAGER_CHANGED,
63   LAST_SIGNAL
64 };
65
66 static guint signals[LAST_SIGNAL] = { 0 };
67
68 G_DEFINE_TYPE (GdkScreenX11, _gdk_screen_x11, GDK_TYPE_SCREEN)
69
70 typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
71
72 struct _NetWmSupportedAtoms
73 {
74   Atom *atoms;
75   gulong n_atoms;
76 };
77
78 struct _GdkX11Monitor
79 {
80   GdkRectangle  geometry;
81   XID           output;
82   int           width_mm;
83   int           height_mm;
84   char *        output_name;
85   char *        manufacturer;
86 };
87
88 static void
89 _gdk_screen_x11_class_init (GdkScreenX11Class *klass)
90 {
91   GObjectClass *object_class = G_OBJECT_CLASS (klass);
92   
93   object_class->dispose = gdk_screen_x11_dispose;
94   object_class->finalize = gdk_screen_x11_finalize;
95
96   signals[WINDOW_MANAGER_CHANGED] =
97     g_signal_new (g_intern_static_string ("window_manager_changed"),
98                   G_OBJECT_CLASS_TYPE (object_class),
99                   G_SIGNAL_RUN_LAST,
100                   G_STRUCT_OFFSET (GdkScreenX11Class, window_manager_changed),
101                   NULL, NULL,
102                   g_cclosure_marshal_VOID__VOID,
103                   G_TYPE_NONE,
104                   0);
105 }
106
107 static void
108 _gdk_screen_x11_init (GdkScreenX11 *screen)
109 {
110 }
111
112 /**
113  * gdk_screen_get_display:
114  * @screen: a #GdkScreen
115  *
116  * Gets the display to which the @screen belongs.
117  * 
118  * Returns: the display to which @screen belongs
119  *
120  * Since: 2.2
121  **/
122 GdkDisplay *
123 gdk_screen_get_display (GdkScreen *screen)
124 {
125   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
126
127   return GDK_SCREEN_X11 (screen)->display;
128 }
129 /**
130  * gdk_screen_get_width:
131  * @screen: a #GdkScreen
132  *
133  * Gets the width of @screen in pixels
134  * 
135  * Returns: the width of @screen in pixels.
136  *
137  * Since: 2.2
138  **/
139 gint
140 gdk_screen_get_width (GdkScreen *screen)
141 {
142   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
143
144   return WidthOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
145 }
146
147 /**
148  * gdk_screen_get_height:
149  * @screen: a #GdkScreen
150  *
151  * Gets the height of @screen in pixels
152  * 
153  * Returns: the height of @screen in pixels.
154  *
155  * Since: 2.2
156  **/
157 gint
158 gdk_screen_get_height (GdkScreen *screen)
159 {
160   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
161
162   return HeightOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
163 }
164
165 /**
166  * gdk_screen_get_width_mm:
167  * @screen: a #GdkScreen
168  *
169  * Gets the width of @screen in millimeters. 
170  * Note that on some X servers this value will not be correct.
171  * 
172  * Returns: the width of @screen in millimeters.
173  *
174  * Since: 2.2
175  **/
176 gint
177 gdk_screen_get_width_mm (GdkScreen *screen)
178 {
179   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
180
181   return WidthMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
182 }
183
184 /**
185  * gdk_screen_get_height_mm:
186  * @screen: a #GdkScreen
187  *
188  * Returns the height of @screen in millimeters. 
189  * Note that on some X servers this value will not be correct.
190  * 
191  * Returns: the heigth of @screen in millimeters.
192  *
193  * Since: 2.2
194  **/
195 gint
196 gdk_screen_get_height_mm (GdkScreen *screen)
197 {
198   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
199
200   return HeightMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
201 }
202
203 /**
204  * gdk_screen_get_number:
205  * @screen: a #GdkScreen
206  *
207  * Gets the index of @screen among the screens in the display
208  * to which it belongs. (See gdk_screen_get_display())
209  * 
210  * Returns: the index
211  *
212  * Since: 2.2
213  **/
214 gint
215 gdk_screen_get_number (GdkScreen *screen)
216 {
217   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
218   
219   return GDK_SCREEN_X11 (screen)->screen_num;
220 }
221
222 /**
223  * gdk_screen_get_root_window:
224  * @screen: a #GdkScreen
225  *
226  * Gets the root window of @screen.
227  *
228  * Returns: (transfer none): the root window
229  *
230  * Since: 2.2
231  **/
232 GdkWindow *
233 gdk_screen_get_root_window (GdkScreen *screen)
234 {
235   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
236
237   return GDK_SCREEN_X11 (screen)->root_window;
238 }
239
240 /**
241  * gdk_screen_get_default_colormap:
242  * @screen: a #GdkScreen
243  *
244  * Gets the default colormap for @screen.
245  * 
246  * Returns: (transfer none): the default #GdkColormap.
247  *
248  * Since: 2.2
249  **/
250 GdkColormap *
251 gdk_screen_get_default_colormap (GdkScreen *screen)
252 {
253   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
254
255   return GDK_SCREEN_X11 (screen)->default_colormap;
256 }
257
258 /**
259  * gdk_screen_set_default_colormap:
260  * @screen: a #GdkScreen
261  * @colormap: a #GdkColormap
262  *
263  * Sets the default @colormap for @screen.
264  *
265  * Since: 2.2
266  **/
267 void
268 gdk_screen_set_default_colormap (GdkScreen   *screen,
269                                  GdkColormap *colormap)
270 {
271   GdkColormap *old_colormap;
272   
273   g_return_if_fail (GDK_IS_SCREEN (screen));
274   g_return_if_fail (GDK_IS_COLORMAP (colormap));
275
276   old_colormap = GDK_SCREEN_X11 (screen)->default_colormap;
277
278   GDK_SCREEN_X11 (screen)->default_colormap = g_object_ref (colormap);
279   
280   if (old_colormap)
281     g_object_unref (old_colormap);
282 }
283
284 static void
285 _gdk_screen_x11_events_uninit (GdkScreen *screen)
286 {
287   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
288
289   if (screen_x11->xsettings_client)
290     {
291       xsettings_client_destroy (screen_x11->xsettings_client);
292       screen_x11->xsettings_client = NULL;
293     }
294 }
295
296 static void
297 gdk_screen_x11_dispose (GObject *object)
298 {
299   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
300   int i;
301
302   for (i = 0; i < 32; ++i)
303     {
304       if (screen_x11->subwindow_gcs[i])
305         {
306           XFreeGC (screen_x11->xdisplay, screen_x11->subwindow_gcs[i]);
307           screen_x11->subwindow_gcs[i] = 0;
308         }
309     }
310
311   _gdk_screen_x11_events_uninit (GDK_SCREEN (object));
312
313   if (screen_x11->default_colormap)
314     {
315       g_object_unref (screen_x11->default_colormap);
316       screen_x11->default_colormap = NULL;
317     }
318
319   if (screen_x11->system_colormap)
320     {
321       g_object_unref (screen_x11->system_colormap);
322       screen_x11->system_colormap = NULL;
323     }
324
325   if (screen_x11->rgba_colormap)
326     {
327       g_object_unref (screen_x11->rgba_colormap);
328       screen_x11->rgba_colormap = NULL;
329     }
330
331   if (screen_x11->root_window)
332     _gdk_window_destroy (screen_x11->root_window, TRUE);
333
334   G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->dispose (object);
335
336   screen_x11->xdisplay = NULL;
337   screen_x11->xscreen = NULL;
338   screen_x11->screen_num = -1;
339   screen_x11->xroot_window = None;
340   screen_x11->wmspec_check_window = None;
341 }
342
343 static void
344 gdk_screen_x11_finalize (GObject *object)
345 {
346   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
347   gint          i;
348
349   if (screen_x11->root_window)
350     g_object_unref (screen_x11->root_window);
351
352   /* Visual Part */
353   for (i = 0; i < screen_x11->nvisuals; i++)
354     g_object_unref (screen_x11->visuals[i]);
355   g_free (screen_x11->visuals);
356   g_hash_table_destroy (screen_x11->visual_hash);
357
358   g_free (screen_x11->window_manager_name);
359
360   g_hash_table_destroy (screen_x11->colormap_hash);
361
362   deinit_multihead (GDK_SCREEN (object));
363   
364   G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->finalize (object);
365 }
366
367 /**
368  * gdk_screen_get_n_monitors:
369  * @screen: a #GdkScreen
370  *
371  * Returns the number of monitors which @screen consists of.
372  *
373  * Returns: number of monitors which @screen consists of
374  *
375  * Since: 2.2
376  */
377 gint
378 gdk_screen_get_n_monitors (GdkScreen *screen)
379 {
380   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
381
382   return GDK_SCREEN_X11 (screen)->n_monitors;
383 }
384
385 /**
386  * gdk_screen_get_primary_monitor:
387  * @screen: a #GdkScreen.
388  *
389  * Gets the primary monitor for @screen.  The primary monitor
390  * is considered the monitor where the 'main desktop' lives.
391  * While normal application windows typically allow the window
392  * manager to place the windows, specialized desktop applications
393  * such as panels should place themselves on the primary monitor.
394  *
395  * If no primary monitor is configured by the user, the return value
396  * will be 0, defaulting to the first monitor.
397  *
398  * Returns: An integer index for the primary monitor, or 0 if none is configured.
399  *
400  * Since: 2.20
401  */
402 gint
403 gdk_screen_get_primary_monitor (GdkScreen *screen)
404 {
405   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
406
407   return GDK_SCREEN_X11 (screen)->primary_monitor;
408 }
409
410 /**
411  * gdk_screen_get_monitor_width_mm:
412  * @screen: a #GdkScreen
413  * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
414  *
415  * Gets the width in millimeters of the specified monitor, if available.
416  *
417  * Returns: the width of the monitor, or -1 if not available
418  *
419  * Since: 2.14
420  */
421 gint
422 gdk_screen_get_monitor_width_mm (GdkScreen *screen,
423                                  gint       monitor_num)
424 {
425   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
426
427   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
428   g_return_val_if_fail (monitor_num >= 0, -1);
429   g_return_val_if_fail (monitor_num < screen_x11->n_monitors, -1);
430
431   return screen_x11->monitors[monitor_num].width_mm;
432 }
433
434 /**
435  * gdk_screen_get_monitor_height_mm:
436  * @screen: a #GdkScreen
437  * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
438  *
439  * Gets the height in millimeters of the specified monitor.
440  *
441  * Returns: the height of the monitor, or -1 if not available
442  *
443  * Since: 2.14
444  */
445 gint
446 gdk_screen_get_monitor_height_mm (GdkScreen *screen,
447                                   gint       monitor_num)
448 {
449   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
450
451   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
452   g_return_val_if_fail (monitor_num >= 0, -1);
453   g_return_val_if_fail (monitor_num < screen_x11->n_monitors, -1);
454
455   return screen_x11->monitors[monitor_num].height_mm;
456 }
457
458 /**
459  * gdk_screen_get_monitor_plug_name:
460  * @screen: a #GdkScreen
461  * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
462  *
463  * Returns the output name of the specified monitor.
464  * Usually something like VGA, DVI, or TV, not the actual
465  * product name of the display device.
466  *
467  * Returns: a newly-allocated string containing the name of the monitor,
468  *   or %NULL if the name cannot be determined
469  *
470  * Since: 2.14
471  */
472 gchar *
473 gdk_screen_get_monitor_plug_name (GdkScreen *screen,
474                                   gint       monitor_num)
475 {
476   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
477
478   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
479   g_return_val_if_fail (monitor_num >= 0, NULL);
480   g_return_val_if_fail (monitor_num < screen_x11->n_monitors, NULL);
481
482   return g_strdup (screen_x11->monitors[monitor_num].output_name);
483 }
484
485 /**
486  * gdk_x11_screen_get_monitor_output:
487  * @screen: a #GdkScreen
488  * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
489  *
490  * Gets the XID of the specified output/monitor.
491  * If the X server does not support version 1.2 of the RANDR
492  * extension, 0 is returned.
493  *
494  * Returns: the XID of the monitor
495  *
496  * Since: 2.14
497  */
498 XID
499 gdk_x11_screen_get_monitor_output (GdkScreen *screen,
500                                    gint       monitor_num)
501 {
502   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
503
504   g_return_val_if_fail (GDK_IS_SCREEN (screen), None);
505   g_return_val_if_fail (monitor_num >= 0, None);
506   g_return_val_if_fail (monitor_num < screen_x11->n_monitors, None);
507
508   return screen_x11->monitors[monitor_num].output;
509 }
510
511 /**
512  * gdk_screen_get_monitor_geometry:
513  * @screen : a #GdkScreen
514  * @monitor_num: the monitor number, between 0 and gdk_screen_get_n_monitors (screen)
515  * @dest : a #GdkRectangle to be filled with the monitor geometry
516  *
517  * Retrieves the #GdkRectangle representing the size and position of
518  * the individual monitor within the entire screen area.
519  *
520  * Note that the size of the entire screen area can be retrieved via
521  * gdk_screen_get_width() and gdk_screen_get_height().
522  *
523  * Since: 2.2
524  */
525 void
526 gdk_screen_get_monitor_geometry (GdkScreen    *screen,
527                                  gint          monitor_num,
528                                  GdkRectangle *dest)
529 {
530   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
531
532   g_return_if_fail (GDK_IS_SCREEN (screen));
533   g_return_if_fail (monitor_num >= 0);
534   g_return_if_fail (monitor_num < screen_x11->n_monitors);
535
536   if (dest)
537     *dest = screen_x11->monitors[monitor_num].geometry;
538 }
539
540 /**
541  * gdk_screen_get_rgba_colormap:
542  * @screen: a #GdkScreen.
543  * 
544  * Gets a colormap to use for creating windows or pixmaps with an
545  * alpha channel. The windowing system on which GTK+ is running
546  * may not support this capability, in which case %NULL will
547  * be returned. Even if a non-%NULL value is returned, its
548  * possible that the window's alpha channel won't be honored
549  * when displaying the window on the screen: in particular, for
550  * X an appropriate windowing manager and compositing manager
551  * must be running to provide appropriate display.
552  *
553  * This functionality is not implemented in the Windows backend.
554  *
555  * For setting an overall opacity for a top-level window, see
556  * gdk_window_set_opacity().
557
558  * Return value: (transfer none): a colormap to use for windows with
559  *     an alpha channel or %NULL if the capability is not available.
560  *
561  * Since: 2.8
562  **/
563 GdkColormap *
564 gdk_screen_get_rgba_colormap (GdkScreen *screen)
565 {
566   GdkScreenX11 *screen_x11;
567
568   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
569
570   screen_x11 = GDK_SCREEN_X11 (screen);
571
572   if (!screen_x11->rgba_visual)
573     return NULL;
574
575   if (!screen_x11->rgba_colormap)
576     screen_x11->rgba_colormap = gdk_colormap_new (screen_x11->rgba_visual,
577                                                   FALSE);
578   
579   return screen_x11->rgba_colormap;
580 }
581
582 /**
583  * gdk_screen_get_rgba_visual:
584  * @screen: a #GdkScreen
585  * 
586  * Gets a visual to use for creating windows or pixmaps with an
587  * alpha channel. See the docs for gdk_screen_get_rgba_colormap()
588  * for caveats.
589  * 
590  * Return value: (transfer none): a visual to use for windows with an
591  *     alpha channel or %NULL if the capability is not available.
592  *
593  * Since: 2.8
594  **/
595 GdkVisual *
596 gdk_screen_get_rgba_visual (GdkScreen *screen)
597 {
598   GdkScreenX11 *screen_x11;
599
600   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
601
602   screen_x11 = GDK_SCREEN_X11 (screen);
603
604   return screen_x11->rgba_visual;
605 }
606
607 /**
608  * gdk_x11_screen_get_xscreen:
609  * @screen: a #GdkScreen.
610  * @returns: (transfer none): an Xlib <type>Screen*</type>
611  *
612  * Returns the screen of a #GdkScreen.
613  *
614  * Since: 2.2
615  */
616 Screen *
617 gdk_x11_screen_get_xscreen (GdkScreen *screen)
618 {
619   return GDK_SCREEN_X11 (screen)->xscreen;
620 }
621
622 /**
623  * gdk_x11_screen_get_screen_number:
624  * @screen: a #GdkScreen.
625  * @returns: the position of @screen among the screens of
626  *   its display.
627  *
628  * Returns the index of a #GdkScreen.
629  *
630  * Since: 2.2
631  */
632 int
633 gdk_x11_screen_get_screen_number (GdkScreen *screen)
634 {
635   return GDK_SCREEN_X11 (screen)->screen_num;
636 }
637
638 static gboolean
639 check_is_composited (GdkDisplay *display,
640                      GdkScreenX11 *screen_x11)
641 {
642   Atom xselection = gdk_x11_atom_to_xatom_for_display (display, screen_x11->cm_selection_atom);
643   Window xwindow;
644   
645   xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), xselection);
646
647   return xwindow != None;
648 }
649
650 static GdkAtom
651 make_cm_atom (int screen_number)
652 {
653   gchar *name = g_strdup_printf ("_NET_WM_CM_S%d", screen_number);
654   GdkAtom atom = gdk_atom_intern (name, FALSE);
655   g_free (name);
656   return atom;
657 }
658
659 static void
660 init_monitor_geometry (GdkX11Monitor *monitor,
661                        int x, int y, int width, int height)
662 {
663   monitor->geometry.x = x;
664   monitor->geometry.y = y;
665   monitor->geometry.width = width;
666   monitor->geometry.height = height;
667
668   monitor->output = None;
669   monitor->width_mm = -1;
670   monitor->height_mm = -1;
671   monitor->output_name = NULL;
672   monitor->manufacturer = NULL;
673 }
674
675 static gboolean
676 init_fake_xinerama (GdkScreen *screen)
677 {
678 #ifdef G_ENABLE_DEBUG
679   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
680   XSetWindowAttributes atts;
681   Window win;
682   gint w, h;
683
684   if (!(_gdk_debug_flags & GDK_DEBUG_XINERAMA))
685     return FALSE;
686   
687   /* Fake Xinerama mode by splitting the screen into 4 monitors.
688    * Also draw a little cross to make the monitor boundaries visible.
689    */
690   w = WidthOfScreen (screen_x11->xscreen);
691   h = HeightOfScreen (screen_x11->xscreen);
692
693   screen_x11->n_monitors = 4;
694   screen_x11->monitors = g_new0 (GdkX11Monitor, 4);
695   init_monitor_geometry (&screen_x11->monitors[0], 0, 0, w / 2, h / 2);
696   init_monitor_geometry (&screen_x11->monitors[1], w / 2, 0, w / 2, h / 2);
697   init_monitor_geometry (&screen_x11->monitors[2], 0, h / 2, w / 2, h / 2);
698   init_monitor_geometry (&screen_x11->monitors[3], w / 2, h / 2, w / 2, h / 2);
699   
700   atts.override_redirect = 1;
701   atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen), 
702                                      screen_x11->screen_num);
703   win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
704                       screen_x11->xroot_window, 0, h / 2, w, 1, 0, 
705                       DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
706                                    screen_x11->screen_num),
707                       InputOutput, 
708                       DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
709                                     screen_x11->screen_num),
710                       CWOverrideRedirect|CWBackPixel, 
711                       &atts);
712   XMapRaised(GDK_SCREEN_XDISPLAY (screen), win); 
713   win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
714                       screen_x11->xroot_window, w/2 , 0, 1, h, 0, 
715                       DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
716                                    screen_x11->screen_num),
717                       InputOutput, 
718                       DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
719                                     screen_x11->screen_num),
720                       CWOverrideRedirect|CWBackPixel, 
721                       &atts);
722   XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
723   return TRUE;
724 #endif
725   
726   return FALSE;
727 }
728
729 static void
730 free_monitors (GdkX11Monitor *monitors,
731                gint           n_monitors)
732 {
733   int i;
734
735   for (i = 0; i < n_monitors; ++i)
736     {
737       g_free (monitors[i].output_name);
738       g_free (monitors[i].manufacturer);
739     }
740
741   g_free (monitors);
742 }
743
744 #ifdef HAVE_RANDR
745 static int
746 monitor_compare_function (GdkX11Monitor *monitor1,
747                           GdkX11Monitor *monitor2)
748 {
749   /* Sort the leftmost/topmost monitors first.
750    * For "cloned" monitors, sort the bigger ones first
751    * (giving preference to taller monitors over wider
752    * monitors)
753    */
754
755   if (monitor1->geometry.x != monitor2->geometry.x)
756     return monitor1->geometry.x - monitor2->geometry.x;
757
758   if (monitor1->geometry.y != monitor2->geometry.y)
759     return monitor1->geometry.y - monitor2->geometry.y;
760
761   if (monitor1->geometry.height != monitor2->geometry.height)
762     return - (monitor1->geometry.height - monitor2->geometry.height);
763
764   if (monitor1->geometry.width != monitor2->geometry.width)
765     return - (monitor1->geometry.width - monitor2->geometry.width);
766
767   return 0;
768 }
769 #endif
770
771 static gboolean
772 init_randr13 (GdkScreen *screen)
773 {
774 #ifdef HAVE_RANDR
775   GdkDisplay *display = gdk_screen_get_display (screen);
776   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
777   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
778   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
779   XRRScreenResources *resources;
780   RROutput primary_output;
781   RROutput first_output = None;
782   int i;
783   GArray *monitors;
784   gboolean randr12_compat = FALSE;
785
786   if (!display_x11->have_randr13)
787       return FALSE;
788
789   resources = XRRGetScreenResourcesCurrent (screen_x11->xdisplay,
790                                             screen_x11->xroot_window);
791   if (!resources)
792     return FALSE;
793
794   monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor),
795                                 resources->noutput);
796
797   for (i = 0; i < resources->noutput; ++i)
798     {
799       XRROutputInfo *output =
800         XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
801
802       /* Non RandR1.2 X driver have output name "default" */
803       randr12_compat |= !g_strcmp0 (output->name, "default");
804
805       if (output->connection == RR_Disconnected)
806         {
807           XRRFreeOutputInfo (output);
808           continue;
809         }
810
811       if (output->crtc)
812         {
813           GdkX11Monitor monitor;
814           XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, output->crtc);
815
816           monitor.geometry.x = crtc->x;
817           monitor.geometry.y = crtc->y;
818           monitor.geometry.width = crtc->width;
819           monitor.geometry.height = crtc->height;
820
821           monitor.output = resources->outputs[i];
822           monitor.width_mm = output->mm_width;
823           monitor.height_mm = output->mm_height;
824           monitor.output_name = g_strdup (output->name);
825           /* FIXME: need EDID parser */
826           monitor.manufacturer = NULL;
827
828           g_array_append_val (monitors, monitor);
829
830           XRRFreeCrtcInfo (crtc);
831         }
832
833       XRRFreeOutputInfo (output);
834     }
835
836   if (resources->noutput > 0)
837     first_output = resources->outputs[0];
838
839   XRRFreeScreenResources (resources);
840
841   /* non RandR 1.2 X driver doesn't return any usable multihead data */
842   if (randr12_compat)
843     {
844       guint n_monitors = monitors->len;
845
846       free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE),
847                      n_monitors);
848
849       return FALSE;
850     }
851
852   g_array_sort (monitors,
853                 (GCompareFunc) monitor_compare_function);
854   screen_x11->n_monitors = monitors->len;
855   screen_x11->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);
856
857   screen_x11->primary_monitor = 0;
858
859   primary_output = XRRGetOutputPrimary (screen_x11->xdisplay,
860                                         screen_x11->xroot_window);
861
862   for (i = 0; i < screen_x11->n_monitors; ++i)
863     {
864       if (screen_x11->monitors[i].output == primary_output)
865         {
866           screen_x11->primary_monitor = i;
867           break;
868         }
869
870       /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
871       if (primary_output == None &&
872           g_ascii_strncasecmp (screen_x11->monitors[i].output_name, "LVDS", 4) == 0)
873         {
874           screen_x11->primary_monitor = i;
875           break;
876         }
877
878       /* No primary specified and no LVDS found */
879       if (screen_x11->monitors[i].output == first_output)
880         screen_x11->primary_monitor = i;
881     }
882
883   return screen_x11->n_monitors > 0;
884 #endif
885
886   return FALSE;
887 }
888
889 static gboolean
890 init_solaris_xinerama (GdkScreen *screen)
891 {
892 #ifdef HAVE_SOLARIS_XINERAMA
893   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
894   int screen_no = gdk_screen_get_number (screen);
895   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
896   XRectangle monitors[MAXFRAMEBUFFERS];
897   unsigned char hints[16];
898   gint result;
899   int n_monitors;
900   int i;
901   
902   if (!XineramaGetState (dpy, screen_no))
903     return FALSE;
904
905   result = XineramaGetInfo (dpy, screen_no, monitors, hints, &n_monitors);
906
907   /* Yes I know it should be Success but the current implementation 
908    * returns the num of monitor
909    */
910   if (result == 0)
911     {
912       return FALSE;
913     }
914
915   screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
916   screen_x11->n_monitors = n_monitors;
917
918   for (i = 0; i < n_monitors; i++)
919     {
920       init_monitor_geometry (&screen_x11->monitors[i],
921                              monitors[i].x, monitors[i].y,
922                              monitors[i].width, monitors[i].height);
923     }
924
925   screen_x11->primary_monitor = 0;
926
927   return TRUE;
928 #endif /* HAVE_SOLARIS_XINERAMA */
929
930   return FALSE;
931 }
932
933 static gboolean
934 init_xfree_xinerama (GdkScreen *screen)
935 {
936 #ifdef HAVE_XFREE_XINERAMA
937   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
938   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
939   XineramaScreenInfo *monitors;
940   int i, n_monitors;
941   
942   if (!XineramaIsActive (dpy))
943     return FALSE;
944
945   monitors = XineramaQueryScreens (dpy, &n_monitors);
946   
947   if (n_monitors <= 0 || monitors == NULL)
948     {
949       /* If Xinerama doesn't think we have any monitors, try acting as
950        * though we had no Xinerama. If the "no monitors" condition
951        * is because XRandR 1.2 is currently switching between CRTCs,
952        * we'll be notified again when we have our monitor back,
953        * and can go back into Xinerama-ish mode at that point.
954        */
955       if (monitors)
956         XFree (monitors);
957       
958       return FALSE;
959     }
960
961   screen_x11->n_monitors = n_monitors;
962   screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
963   
964   for (i = 0; i < n_monitors; ++i)
965     {
966       init_monitor_geometry (&screen_x11->monitors[i],
967                              monitors[i].x_org, monitors[i].y_org,
968                              monitors[i].width, monitors[i].height);
969     }
970   
971   XFree (monitors);
972   
973   screen_x11->primary_monitor = 0;
974
975   return TRUE;
976 #endif /* HAVE_XFREE_XINERAMA */
977   
978   return FALSE;
979 }
980
981 static void
982 deinit_multihead (GdkScreen *screen)
983 {
984   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
985
986   free_monitors (screen_x11->monitors, screen_x11->n_monitors);
987
988   screen_x11->n_monitors = 0;
989   screen_x11->monitors = NULL;
990 }
991
992 static gboolean
993 compare_monitor (GdkX11Monitor *m1,
994                  GdkX11Monitor *m2)
995 {
996   if (m1->geometry.x != m2->geometry.x ||
997       m1->geometry.y != m2->geometry.y ||
998       m1->geometry.width != m2->geometry.width ||
999       m1->geometry.height != m2->geometry.height)
1000     return FALSE;
1001
1002   if (m1->width_mm != m2->width_mm ||
1003       m1->height_mm != m2->height_mm)
1004     return FALSE;
1005
1006   if (g_strcmp0 (m1->output_name, m2->output_name) != 0)
1007     return FALSE;
1008
1009   if (g_strcmp0 (m1->manufacturer, m2->manufacturer) != 0)
1010     return FALSE;
1011
1012   return TRUE;
1013 }
1014
1015 static gboolean
1016 compare_monitors (GdkX11Monitor *monitors1, gint n_monitors1,
1017                   GdkX11Monitor *monitors2, gint n_monitors2)
1018 {
1019   gint i;
1020
1021   if (n_monitors1 != n_monitors2)
1022     return FALSE;
1023
1024   for (i = 0; i < n_monitors1; i++)
1025     {
1026       if (!compare_monitor (monitors1 + i, monitors2 + i))
1027         return FALSE;
1028     }
1029
1030   return TRUE;
1031 }
1032
1033 static void
1034 init_multihead (GdkScreen *screen)
1035 {
1036   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1037   int opcode, firstevent, firsterror;
1038
1039   /* There are four different implementations of multihead support: 
1040    *
1041    *  1. Fake Xinerama for debugging purposes
1042    *  2. RandR 1.2
1043    *  3. Solaris Xinerama
1044    *  4. XFree86/Xorg Xinerama
1045    *
1046    * We use them in that order.
1047    */
1048   if (init_fake_xinerama (screen))
1049     return;
1050
1051   if (init_randr13 (screen))
1052     return;
1053
1054   if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
1055                        &opcode, &firstevent, &firsterror))
1056     {
1057       if (init_solaris_xinerama (screen))
1058         return;
1059       
1060       if (init_xfree_xinerama (screen))
1061         return;
1062     }
1063
1064   /* No multihead support of any kind for this screen */
1065   screen_x11->n_monitors = 1;
1066   screen_x11->monitors = g_new0 (GdkX11Monitor, 1);
1067   screen_x11->primary_monitor = 0;
1068
1069   init_monitor_geometry (screen_x11->monitors, 0, 0,
1070                          WidthOfScreen (screen_x11->xscreen),
1071                          HeightOfScreen (screen_x11->xscreen));
1072 }
1073
1074 GdkScreen *
1075 _gdk_x11_screen_new (GdkDisplay *display,
1076                      gint        screen_number) 
1077 {
1078   GdkScreen *screen;
1079   GdkScreenX11 *screen_x11;
1080   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
1081
1082   screen = g_object_new (GDK_TYPE_SCREEN_X11, NULL);
1083
1084   screen_x11 = GDK_SCREEN_X11 (screen);
1085   screen_x11->display = display;
1086   screen_x11->xdisplay = display_x11->xdisplay;
1087   screen_x11->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
1088   screen_x11->screen_num = screen_number;
1089   screen_x11->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
1090   screen_x11->wmspec_check_window = None;
1091   /* we want this to be always non-null */
1092   screen_x11->window_manager_name = g_strdup ("unknown");
1093   
1094   init_multihead (screen);
1095   init_randr_support (screen);
1096   
1097   _gdk_visual_init (screen);
1098   _gdk_windowing_window_init (screen);
1099   
1100   return screen;
1101 }
1102
1103 /*
1104  * It is important that we first request the selection
1105  * notification, and then setup the initial state of
1106  * is_composited to avoid a race condition here.
1107  */
1108 void
1109 _gdk_x11_screen_setup (GdkScreen *screen)
1110 {
1111   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1112
1113   screen_x11->cm_selection_atom = make_cm_atom (screen_x11->screen_num);
1114   gdk_display_request_selection_notification (screen_x11->display,
1115                                               screen_x11->cm_selection_atom);
1116   screen_x11->is_composited = check_is_composited (screen_x11->display, screen_x11);
1117 }
1118
1119 /**
1120  * gdk_screen_is_composited:
1121  * @screen: a #GdkScreen
1122  * 
1123  * Returns whether windows with an RGBA visual can reasonably
1124  * be expected to have their alpha channel drawn correctly on
1125  * the screen.
1126  *
1127  * On X11 this function returns whether a compositing manager is
1128  * compositing @screen.
1129  * 
1130  * Return value: Whether windows with RGBA visuals can reasonably be
1131  * expected to have their alpha channels drawn correctly on the screen.
1132  * 
1133  * Since: 2.10
1134  **/
1135 gboolean
1136 gdk_screen_is_composited (GdkScreen *screen)
1137 {
1138   GdkScreenX11 *screen_x11;
1139
1140   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
1141
1142   screen_x11 = GDK_SCREEN_X11 (screen);
1143
1144   return screen_x11->is_composited;
1145 }
1146
1147 static void
1148 init_randr_support (GdkScreen * screen)
1149 {
1150   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1151   
1152   XSelectInput (GDK_SCREEN_XDISPLAY (screen),
1153                 screen_x11->xroot_window,
1154                 StructureNotifyMask);
1155
1156 #ifdef HAVE_RANDR
1157   XRRSelectInput (GDK_SCREEN_XDISPLAY (screen),
1158                   screen_x11->xroot_window,
1159                   RRScreenChangeNotifyMask      |
1160                   RRCrtcChangeNotifyMask        |
1161                   RROutputPropertyNotifyMask);
1162 #endif
1163 }
1164
1165 static void
1166 process_monitors_change (GdkScreen *screen)
1167 {
1168   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1169   gint           n_monitors;
1170   GdkX11Monitor *monitors;
1171   gboolean changed;
1172
1173   n_monitors = screen_x11->n_monitors;
1174   monitors = screen_x11->monitors;
1175
1176   screen_x11->n_monitors = 0;
1177   screen_x11->monitors = NULL;
1178
1179   init_multihead (screen);
1180
1181   changed = !compare_monitors (monitors, n_monitors,
1182                                screen_x11->monitors, screen_x11->n_monitors);
1183
1184   free_monitors (monitors, n_monitors);
1185
1186   if (changed)
1187     g_signal_emit_by_name (screen, "monitors-changed");
1188 }
1189
1190 void
1191 _gdk_x11_screen_size_changed (GdkScreen *screen,
1192                               XEvent    *event)
1193 {
1194   gint width, height;
1195 #ifdef HAVE_RANDR
1196   GdkDisplayX11 *display_x11;
1197 #endif
1198
1199   width = gdk_screen_get_width (screen);
1200   height = gdk_screen_get_height (screen);
1201
1202 #ifdef HAVE_RANDR
1203   display_x11 = GDK_DISPLAY_X11 (gdk_screen_get_display (screen));
1204
1205   if (display_x11->have_randr13 && event->type == ConfigureNotify)
1206     {
1207       g_signal_emit_by_name (screen, "monitors-changed");
1208       return;
1209     }
1210
1211   XRRUpdateConfiguration (event);
1212 #else
1213   if (event->type == ConfigureNotify)
1214     {
1215       XConfigureEvent *rcevent = (XConfigureEvent *) event;
1216       Screen        *xscreen = gdk_x11_screen_get_xscreen (screen);
1217
1218       xscreen->width   = rcevent->width;
1219       xscreen->height  = rcevent->height;
1220     }
1221   else
1222     return;
1223 #endif
1224
1225   process_monitors_change (screen);
1226
1227   if (width != gdk_screen_get_width (screen) ||
1228       height != gdk_screen_get_height (screen))
1229     g_signal_emit_by_name (screen, "size-changed");
1230 }
1231
1232 void
1233 _gdk_x11_screen_window_manager_changed (GdkScreen *screen)
1234 {
1235   g_signal_emit (screen, signals[WINDOW_MANAGER_CHANGED], 0);
1236 }
1237
1238 void
1239 _gdk_x11_screen_process_owner_change (GdkScreen *screen,
1240                                       XEvent *event)
1241 {
1242 #ifdef HAVE_XFIXES
1243   XFixesSelectionNotifyEvent *selection_event = (XFixesSelectionNotifyEvent *)event;
1244   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1245   Atom xcm_selection_atom = gdk_x11_atom_to_xatom_for_display (screen_x11->display,
1246                                                                screen_x11->cm_selection_atom);
1247
1248   if (selection_event->selection == xcm_selection_atom)
1249     {
1250       gboolean composited = selection_event->owner != None;
1251
1252       if (composited != screen_x11->is_composited)
1253         {
1254           screen_x11->is_composited = composited;
1255
1256           g_signal_emit_by_name (screen, "composited-changed");
1257         }
1258     }
1259 #endif
1260 }
1261
1262 /**
1263  * _gdk_windowing_substitute_screen_number:
1264  * @display_name : The name of a display, in the form used by 
1265  *                 gdk_display_open (). If %NULL a default value
1266  *                 will be used. On X11, this is derived from the DISPLAY
1267  *                 environment variable.
1268  * @screen_number : The number of a screen within the display
1269  *                  referred to by @display_name.
1270  *
1271  * Modifies a @display_name to make @screen_number the default
1272  * screen when the display is opened.
1273  *
1274  * Return value: a newly allocated string holding the resulting
1275  *   display name. Free with g_free().
1276  */
1277 gchar * 
1278 _gdk_windowing_substitute_screen_number (const gchar *display_name,
1279                                          gint         screen_number)
1280 {
1281   GString *str;
1282   gchar   *p;
1283
1284   if (!display_name)
1285     display_name = getenv ("DISPLAY");
1286
1287   if (!display_name)
1288     return NULL;
1289
1290   str = g_string_new (display_name);
1291
1292   p = strrchr (str->str, '.');
1293   if (p && p >  strchr (str->str, ':'))
1294     g_string_truncate (str, p - str->str);
1295
1296   g_string_append_printf (str, ".%d", screen_number);
1297
1298   return g_string_free (str, FALSE);
1299 }
1300
1301 /**
1302  * gdk_screen_make_display_name:
1303  * @screen: a #GdkScreen
1304  * 
1305  * Determines the name to pass to gdk_display_open() to get
1306  * a #GdkDisplay with this screen as the default screen.
1307  * 
1308  * Return value: a newly allocated string, free with g_free()
1309  *
1310  * Since: 2.2
1311  **/
1312 gchar *
1313 gdk_screen_make_display_name (GdkScreen *screen)
1314 {
1315   const gchar *old_display;
1316
1317   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1318
1319   old_display = gdk_display_get_name (gdk_screen_get_display (screen));
1320
1321   return _gdk_windowing_substitute_screen_number (old_display, 
1322                                                   gdk_screen_get_number (screen));
1323 }
1324
1325 /**
1326  * gdk_screen_get_active_window
1327  * @screen: a #GdkScreen
1328  *
1329  * Returns the screen's currently active window.
1330  *
1331  * On X11, this is done by inspecting the _NET_ACTIVE_WINDOW property
1332  * on the root window, as described in the <ulink
1333  * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window
1334  * Manager Hints</ulink>. If there is no currently currently active
1335  * window, or the window manager does not support the
1336  * _NET_ACTIVE_WINDOW hint, this function returns %NULL.
1337  *
1338  * On other platforms, this function may return %NULL, depending on whether
1339  * it is implementable on that platform.
1340  *
1341  * The returned window should be unrefed using g_object_unref() when
1342  * no longer needed.
1343  *
1344  * Return value: the currently active window, or %NULL.
1345  *
1346  * Since: 2.10
1347  **/
1348 GdkWindow *
1349 gdk_screen_get_active_window (GdkScreen *screen)
1350 {
1351   GdkScreenX11 *screen_x11;
1352   GdkWindow *ret = NULL;
1353   Atom type_return;
1354   gint format_return;
1355   gulong nitems_return;
1356   gulong bytes_after_return;
1357   guchar *data = NULL;
1358
1359   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1360
1361   if (!gdk_x11_screen_supports_net_wm_hint (screen,
1362                                             gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW")))
1363     return NULL;
1364
1365   screen_x11 = GDK_SCREEN_X11 (screen);
1366
1367   if (XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
1368                           gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
1369                                                                  "_NET_ACTIVE_WINDOW"),
1370                           0, 1, False, XA_WINDOW, &type_return,
1371                           &format_return, &nitems_return,
1372                           &bytes_after_return, &data)
1373       == Success)
1374     {
1375       if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
1376         {
1377           GdkNativeWindow window = *(GdkNativeWindow *) data;
1378
1379           if (window != None)
1380             {
1381               ret = gdk_window_foreign_new_for_display (screen_x11->display,
1382                                                         *(GdkNativeWindow *) data);
1383             }
1384         }
1385     }
1386
1387   if (data)
1388     XFree (data);
1389
1390   return ret;
1391 }
1392
1393 /**
1394  * gdk_screen_get_window_stack:
1395  * @screen: a #GdkScreen
1396  *
1397  * Returns a #GList of #GdkWindow<!-- -->s representing the current
1398  * window stack.
1399  *
1400  * On X11, this is done by inspecting the _NET_CLIENT_LIST_STACKING
1401  * property on the root window, as described in the <ulink
1402  * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window
1403  * Manager Hints</ulink>. If the window manager does not support the
1404  * _NET_CLIENT_LIST_STACKING hint, this function returns %NULL.
1405  *
1406  * On other platforms, this function may return %NULL, depending on whether
1407  * it is implementable on that platform.
1408  *
1409  * The returned list is newly allocated and owns references to the
1410  * windows it contains, so it should be freed using g_list_free() and
1411  * its windows unrefed using g_object_unref() when no longer needed.
1412  *
1413  * Return value: (transfer full) (element-type GdkWindow):
1414  *     a list of #GdkWindow<!-- -->s for the current window stack,
1415  *               or %NULL.
1416  *
1417  * Since: 2.10
1418  **/
1419 GList *
1420 gdk_screen_get_window_stack (GdkScreen *screen)
1421 {
1422   GdkScreenX11 *screen_x11;
1423   GList *ret = NULL;
1424   Atom type_return;
1425   gint format_return;
1426   gulong nitems_return;
1427   gulong bytes_after_return;
1428   guchar *data = NULL;
1429
1430   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1431
1432   if (!gdk_x11_screen_supports_net_wm_hint (screen,
1433                                             gdk_atom_intern_static_string ("_NET_CLIENT_LIST_STACKING")))
1434     return NULL;
1435
1436   screen_x11 = GDK_SCREEN_X11 (screen);
1437
1438   if (XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
1439                           gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
1440                                                                  "_NET_CLIENT_LIST_STACKING"),
1441                           0, G_MAXLONG, False, XA_WINDOW, &type_return,
1442                           &format_return, &nitems_return,
1443                           &bytes_after_return, &data)
1444       == Success)
1445     {
1446       if ((type_return == XA_WINDOW) && (format_return == 32) &&
1447           (data) && (nitems_return > 0))
1448         {
1449           gulong *stack = (gulong *) data;
1450           GdkWindow *win;
1451           int i;
1452
1453           for (i = 0; i < nitems_return; i++)
1454             {
1455               win = gdk_window_foreign_new_for_display (screen_x11->display,
1456                                                         (GdkNativeWindow)stack[i]);
1457
1458               if (win != NULL)
1459                 ret = g_list_append (ret, win);
1460             }
1461         }
1462     }
1463
1464   if (data)
1465     XFree (data);
1466
1467   return ret;
1468 }
1469
1470 /* Sends a ClientMessage to all toplevel client windows */
1471 static gboolean
1472 gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
1473                                               XEvent     *xev,
1474                                               guint32     xid,
1475                                               guint       level)
1476 {
1477   Atom type = None;
1478   int format;
1479   unsigned long nitems, after;
1480   unsigned char *data;
1481   Window *ret_children, ret_root, ret_parent;
1482   unsigned int ret_nchildren;
1483   gboolean send = FALSE;
1484   gboolean found = FALSE;
1485   gboolean result = FALSE;
1486   int i;
1487
1488   gdk_error_trap_push ();
1489
1490   if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
1491                           gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE"),
1492                           0, 0, False, AnyPropertyType,
1493                           &type, &format, &nitems, &after, &data) != Success)
1494     goto out;
1495
1496   if (type)
1497     {
1498       send = TRUE;
1499       XFree (data);
1500     }
1501   else
1502     {
1503       /* OK, we're all set, now let's find some windows to send this to */
1504       if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xid,
1505                       &ret_root, &ret_parent,
1506                       &ret_children, &ret_nchildren))
1507         goto out;
1508
1509       for(i = 0; i < ret_nchildren; i++)
1510         if (gdk_event_send_client_message_to_all_recurse (display, xev, ret_children[i], level + 1))
1511           found = TRUE;
1512
1513       XFree (ret_children);
1514     }
1515
1516   if (send || (!found && (level == 1)))
1517     {
1518       xev->xclient.window = xid;
1519       _gdk_send_xevent (display, xid, False, NoEventMask, xev);
1520     }
1521
1522   result = send || found;
1523
1524  out:
1525   gdk_error_trap_pop_ignored ();
1526
1527   return result;
1528 }
1529
1530 /**
1531  * gdk_screen_broadcast_client_message:
1532  * @screen: the #GdkScreen where the event will be broadcasted.
1533  * @event: the #GdkEvent.
1534  *
1535  * On X11, sends an X ClientMessage event to all toplevel windows on
1536  * @screen.
1537  *
1538  * Toplevel windows are determined by checking for the WM_STATE property,
1539  * as described in the Inter-Client Communication Conventions Manual (ICCCM).
1540  * If no windows are found with the WM_STATE property set, the message is
1541  * sent to all children of the root window.
1542  *
1543  * On Windows, broadcasts a message registered with the name
1544  * GDK_WIN32_CLIENT_MESSAGE to all top-level windows. The amount of
1545  * data is limited to one long, i.e. four bytes.
1546  *
1547  * Since: 2.2
1548  */
1549
1550 void
1551 gdk_screen_broadcast_client_message (GdkScreen *screen,
1552                                      GdkEvent  *event)
1553 {
1554   XEvent sev;
1555   GdkWindow *root_window;
1556
1557   g_return_if_fail (event != NULL);
1558
1559   root_window = gdk_screen_get_root_window (screen);
1560
1561   /* Set up our event to send, with the exception of its target window */
1562   sev.xclient.type = ClientMessage;
1563   sev.xclient.display = GDK_WINDOW_XDISPLAY (root_window);
1564   sev.xclient.format = event->client.data_format;
1565   memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
1566   sev.xclient.message_type =
1567     gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (root_window),
1568                                        event->client.message_type);
1569
1570   gdk_event_send_client_message_to_all_recurse (gdk_screen_get_display (screen),
1571                                                 &sev,
1572                                                 GDK_WINDOW_XID (root_window),
1573                                                 0);
1574 }
1575
1576 static gboolean
1577 check_transform (const gchar *xsettings_name,
1578                  GType        src_type,
1579                  GType        dest_type)
1580 {
1581   if (!g_value_type_transformable (src_type, dest_type))
1582     {
1583       g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
1584                  xsettings_name,
1585                  g_type_name (src_type),
1586                  g_type_name (dest_type));
1587       return FALSE;
1588     }
1589   else
1590     return TRUE;
1591 }
1592
1593 /**
1594  * gdk_screen_get_setting:
1595  * @screen: the #GdkScreen where the setting is located
1596  * @name: the name of the setting
1597  * @value: location to store the value of the setting
1598  *
1599  * Retrieves a desktop-wide setting such as double-click time
1600  * for the #GdkScreen @screen.
1601  *
1602  * FIXME needs a list of valid settings here, or a link to
1603  * more information.
1604  *
1605  * Returns: %TRUE if the setting existed and a value was stored
1606  *   in @value, %FALSE otherwise.
1607  *
1608  * Since: 2.2
1609  **/
1610 gboolean
1611 gdk_screen_get_setting (GdkScreen   *screen,
1612                         const gchar *name,
1613                         GValue      *value)
1614 {
1615
1616   const char *xsettings_name = NULL;
1617   XSettingsResult result;
1618   XSettingsSetting *setting = NULL;
1619   GdkScreenX11 *screen_x11;
1620   gboolean success = FALSE;
1621   gint i;
1622   GValue tmp_val = { 0, };
1623
1624   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
1625
1626   screen_x11 = GDK_SCREEN_X11 (screen);
1627
1628   for (i = 0; i < GDK_SETTINGS_N_ELEMENTS(); i++)
1629     if (strcmp (GDK_SETTINGS_GDK_NAME (i), name) == 0)
1630       {
1631         xsettings_name = GDK_SETTINGS_X_NAME (i);
1632         break;
1633       }
1634
1635   if (!xsettings_name)
1636     goto out;
1637
1638   result = xsettings_client_get_setting (screen_x11->xsettings_client,
1639                                          xsettings_name, &setting);
1640   if (result != XSETTINGS_SUCCESS)
1641     goto out;
1642
1643   switch (setting->type)
1644     {
1645     case XSETTINGS_TYPE_INT:
1646       if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
1647         {
1648           g_value_init (&tmp_val, G_TYPE_INT);
1649           g_value_set_int (&tmp_val, setting->data.v_int);
1650           g_value_transform (&tmp_val, value);
1651
1652           success = TRUE;
1653         }
1654       break;
1655     case XSETTINGS_TYPE_STRING:
1656       if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
1657         {
1658           g_value_init (&tmp_val, G_TYPE_STRING);
1659           g_value_set_string (&tmp_val, setting->data.v_string);
1660           g_value_transform (&tmp_val, value);
1661
1662           success = TRUE;
1663         }
1664       break;
1665     case XSETTINGS_TYPE_COLOR:
1666       if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
1667         {
1668           GdkColor color;
1669
1670           g_value_init (&tmp_val, GDK_TYPE_COLOR);
1671
1672           color.pixel = 0;
1673           color.red = setting->data.v_color.red;
1674           color.green = setting->data.v_color.green;
1675           color.blue = setting->data.v_color.blue;
1676
1677           g_value_set_boxed (&tmp_val, &color);
1678
1679           g_value_transform (&tmp_val, value);
1680
1681           success = TRUE;
1682         }
1683       break;
1684     }
1685
1686   g_value_unset (&tmp_val);
1687
1688  out:
1689   if (setting)
1690     xsettings_setting_free (setting);
1691
1692   if (success)
1693     return TRUE;
1694   else
1695     return _gdk_x11_get_xft_setting (screen, name, value);
1696 }
1697
1698 static void
1699 cleanup_atoms(gpointer data)
1700 {
1701   NetWmSupportedAtoms *supported_atoms = data;
1702   if (supported_atoms->atoms)
1703       XFree (supported_atoms->atoms);
1704   g_free (supported_atoms);
1705 }
1706
1707 static void
1708 fetch_net_wm_check_window (GdkScreen *screen)
1709 {
1710   GdkScreenX11 *screen_x11;
1711   GdkDisplay *display;
1712   Atom type;
1713   gint format;
1714   gulong n_items;
1715   gulong bytes_after;
1716   guchar *data;
1717   Window *xwindow;
1718   GTimeVal tv;
1719   gint error;
1720
1721   screen_x11 = GDK_SCREEN_X11 (screen);
1722   display = screen_x11->display;
1723
1724   g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client);
1725   
1726   g_get_current_time (&tv);
1727
1728   if (ABS  (tv.tv_sec - screen_x11->last_wmspec_check_time) < 15)
1729     return; /* we've checked recently */
1730
1731   screen_x11->last_wmspec_check_time = tv.tv_sec;
1732
1733   data = NULL;
1734   XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
1735                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
1736                       0, G_MAXLONG, False, XA_WINDOW, &type, &format,
1737                       &n_items, &bytes_after, &data);
1738   
1739   if (type != XA_WINDOW)
1740     {
1741       if (data)
1742         XFree (data);
1743       return;
1744     }
1745
1746   xwindow = (Window *)data;
1747
1748   if (screen_x11->wmspec_check_window == *xwindow)
1749     {
1750       XFree (xwindow);
1751       return;
1752     }
1753
1754   gdk_error_trap_push ();
1755
1756   /* Find out if this WM goes away, so we can reset everything. */
1757   XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask);
1758
1759   error = gdk_error_trap_pop ();
1760   if (!error)
1761     {
1762       screen_x11->wmspec_check_window = *xwindow;
1763       screen_x11->need_refetch_net_supported = TRUE;
1764       screen_x11->need_refetch_wm_name = TRUE;
1765
1766       /* Careful, reentrancy */
1767       _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
1768     }
1769   else if (error == BadWindow)
1770     {
1771       /* Leftover property, try again immediately, new wm may be starting up */
1772       screen_x11->last_wmspec_check_time = 0;
1773     }
1774
1775   XFree (xwindow);
1776 }
1777
1778 /**
1779  * gdk_x11_screen_supports_net_wm_hint:
1780  * @screen: the relevant #GdkScreen.
1781  * @property: a property atom.
1782  *
1783  * This function is specific to the X11 backend of GDK, and indicates
1784  * whether the window manager supports a certain hint from the
1785  * Extended Window Manager Hints Specification. You can find this
1786  * specification on
1787  * <ulink url="http://www.freedesktop.org">http://www.freedesktop.org</ulink>.
1788  *
1789  * When using this function, keep in mind that the window manager
1790  * can change over time; so you shouldn't use this function in
1791  * a way that impacts persistent application state. A common bug
1792  * is that your application can start up before the window manager
1793  * does when the user logs in, and before the window manager starts
1794  * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
1795  * You can monitor the window_manager_changed signal on #GdkScreen to detect
1796  * a window manager change.
1797  *
1798  * Return value: %TRUE if the window manager supports @property
1799  *
1800  * Since: 2.2
1801  **/
1802 gboolean
1803 gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
1804                                      GdkAtom    property)
1805 {
1806   gulong i;
1807   GdkScreenX11 *screen_x11;
1808   NetWmSupportedAtoms *supported_atoms;
1809   GdkDisplay *display;
1810
1811   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
1812
1813   screen_x11 = GDK_SCREEN_X11 (screen);
1814   display = screen_x11->display;
1815
1816   if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
1817     return FALSE;
1818
1819   supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
1820   if (!supported_atoms)
1821     {
1822       supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
1823       g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
1824     }
1825
1826   fetch_net_wm_check_window (screen);
1827
1828   if (screen_x11->wmspec_check_window == None)
1829     return FALSE;
1830
1831   if (screen_x11->need_refetch_net_supported)
1832     {
1833       /* WM has changed since we last got the supported list,
1834        * refetch it.
1835        */
1836       Atom type;
1837       gint format;
1838       gulong bytes_after;
1839
1840       screen_x11->need_refetch_net_supported = FALSE;
1841
1842       if (supported_atoms->atoms)
1843         XFree (supported_atoms->atoms);
1844
1845       supported_atoms->atoms = NULL;
1846       supported_atoms->n_atoms = 0;
1847
1848       XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window,
1849                           gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"),
1850                           0, G_MAXLONG, False, XA_ATOM, &type, &format,
1851                           &supported_atoms->n_atoms, &bytes_after,
1852                           (guchar **)&supported_atoms->atoms);
1853
1854       if (type != XA_ATOM)
1855         return FALSE;
1856     }
1857
1858   if (supported_atoms->atoms == NULL)
1859     return FALSE;
1860
1861   i = 0;
1862   while (i < supported_atoms->n_atoms)
1863     {
1864       if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property))
1865         return TRUE;
1866
1867       ++i;
1868     }
1869
1870   return FALSE;
1871 }
1872
1873 /**
1874  * gdk_net_wm_supports:
1875  * @property: a property atom.
1876  *
1877  * This function is specific to the X11 backend of GDK, and indicates
1878  * whether the window manager for the default screen supports a certain
1879  * hint from the Extended Window Manager Hints Specification. See
1880  * gdk_x11_screen_supports_net_wm_hint() for complete details.
1881  *
1882  * Return value: %TRUE if the window manager supports @property
1883  **/
1884 gboolean
1885 gdk_net_wm_supports (GdkAtom property)
1886 {
1887   return gdk_x11_screen_supports_net_wm_hint (gdk_screen_get_default (), property);
1888 }
1889
1890 static void
1891 refcounted_grab_server (Display *xdisplay)
1892 {
1893   GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
1894
1895   gdk_x11_display_grab (display);
1896 }
1897
1898 static void
1899 refcounted_ungrab_server (Display *xdisplay)
1900 {
1901   GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
1902
1903   gdk_x11_display_ungrab (display);
1904 }
1905
1906 static GdkFilterReturn
1907 gdk_xsettings_client_event_filter (GdkXEvent *xevent,
1908                                    GdkEvent  *event,
1909                                    gpointer   data)
1910 {
1911   GdkScreenX11 *screen = data;
1912
1913   if (xsettings_client_process_event (screen->xsettings_client, (XEvent *)xevent))
1914     return GDK_FILTER_REMOVE;
1915   else
1916     return GDK_FILTER_CONTINUE;
1917 }
1918
1919 static Bool
1920 gdk_xsettings_watch_cb (Window   window,
1921                         Bool     is_start,
1922                         long     mask,
1923                         void    *cb_data)
1924 {
1925   GdkWindow *gdkwin;
1926   GdkScreen *screen = cb_data;
1927
1928   gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window);
1929
1930   if (is_start)
1931     {
1932       if (gdkwin)
1933         g_object_ref (gdkwin);
1934       else
1935         {
1936           gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
1937           
1938           /* gdk_window_foreign_new_for_display() can fail and return NULL if the
1939            * window has already been destroyed.
1940            */
1941           if (!gdkwin)
1942             return False;
1943         }
1944
1945       gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
1946     }
1947   else
1948     {
1949       if (!gdkwin)
1950         {
1951           /* gdkwin should not be NULL here, since if starting the watch succeeded
1952            * we have a reference on the window. It might mean that the caller didn't
1953            * remove the watch when it got a DestroyNotify event. Or maybe the
1954            * caller ignored the return value when starting the watch failed.
1955            */
1956           g_warning ("gdk_xsettings_watch_cb(): Couldn't find window to unwatch");
1957           return False;
1958         }
1959       
1960       gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
1961       g_object_unref (gdkwin);
1962     }
1963
1964   return True;
1965 }
1966
1967 static void
1968 gdk_xsettings_notify_cb (const char       *name,
1969                          XSettingsAction   action,
1970                          XSettingsSetting *setting,
1971                          void             *data)
1972 {
1973   GdkEvent new_event;
1974   GdkScreen *screen = data;
1975   GdkScreenX11 *screen_x11 = data;
1976   int i;
1977
1978   if (screen_x11->xsettings_in_init)
1979     return;
1980   
1981   new_event.type = GDK_SETTING;
1982   new_event.setting.window = gdk_screen_get_root_window (screen);
1983   new_event.setting.send_event = FALSE;
1984   new_event.setting.name = NULL;
1985
1986   for (i = 0; i < GDK_SETTINGS_N_ELEMENTS() ; i++)
1987     if (strcmp (GDK_SETTINGS_X_NAME (i), name) == 0)
1988       {
1989         new_event.setting.name = (char*) GDK_SETTINGS_GDK_NAME (i);
1990         break;
1991       }
1992   
1993   if (!new_event.setting.name)
1994     return;
1995   
1996   switch (action)
1997     {
1998     case XSETTINGS_ACTION_NEW:
1999       new_event.setting.action = GDK_SETTING_ACTION_NEW;
2000       break;
2001     case XSETTINGS_ACTION_CHANGED:
2002       new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
2003       break;
2004     case XSETTINGS_ACTION_DELETED:
2005       new_event.setting.action = GDK_SETTING_ACTION_DELETED;
2006       break;
2007     }
2008
2009   gdk_event_put (&new_event);
2010 }
2011
2012 void
2013 _gdk_screen_x11_events_init (GdkScreen *screen)
2014 {
2015   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
2016
2017   /* Keep a flag to avoid extra notifies that we don't need
2018    */
2019   screen_x11->xsettings_in_init = TRUE;
2020   screen_x11->xsettings_client = xsettings_client_new_with_grab_funcs (screen_x11->xdisplay,
2021                                                                        screen_x11->screen_num,
2022                                                                        gdk_xsettings_notify_cb,
2023                                                                        gdk_xsettings_watch_cb,
2024                                                                        screen,
2025                                                                        refcounted_grab_server,
2026                                                                        refcounted_ungrab_server);
2027   screen_x11->xsettings_in_init = FALSE;
2028 }
2029
2030 /**
2031  * gdk_x11_screen_get_window_manager_name:
2032  * @screen: a #GdkScreen
2033  *
2034  * Returns the name of the window manager for @screen.
2035  *
2036  * Return value: the name of the window manager screen @screen, or
2037  * "unknown" if the window manager is unknown. The string is owned by GDK
2038  * and should not be freed.
2039  *
2040  * Since: 2.2
2041  **/
2042 const char*
2043 gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
2044 {
2045   GdkScreenX11 *screen_x11;
2046
2047   screen_x11 = GDK_SCREEN_X11 (screen);
2048
2049   if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client))
2050     return screen_x11->window_manager_name;
2051
2052   fetch_net_wm_check_window (screen);
2053
2054   if (screen_x11->need_refetch_wm_name)
2055     {
2056       /* Get the name of the window manager */
2057       screen_x11->need_refetch_wm_name = FALSE;
2058
2059       g_free (screen_x11->window_manager_name);
2060       screen_x11->window_manager_name = g_strdup ("unknown");
2061
2062       if (screen_x11->wmspec_check_window != None)
2063         {
2064           Atom type;
2065           gint format;
2066           gulong n_items;
2067           gulong bytes_after;
2068           gchar *name;
2069
2070           name = NULL;
2071
2072           gdk_error_trap_push ();
2073
2074           XGetWindowProperty (GDK_DISPLAY_XDISPLAY (screen_x11->display),
2075                               screen_x11->wmspec_check_window,
2076                               gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
2077                                                                      "_NET_WM_NAME"),
2078                               0, G_MAXLONG, False,
2079                               gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
2080                                                                      "UTF8_STRING"),
2081                               &type, &format,
2082                               &n_items, &bytes_after,
2083                               (guchar **)&name);
2084
2085           gdk_error_trap_pop_ignored ();
2086
2087           if (name != NULL)
2088             {
2089               g_free (screen_x11->window_manager_name);
2090               screen_x11->window_manager_name = g_strdup (name);
2091               XFree (name);
2092             }
2093         }
2094     }
2095
2096   return GDK_SCREEN_X11 (screen)->window_manager_name;
2097 }