]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkscreen-x11.c
Minor doc fix
[~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 #include "gdkalias.h"
36
37 #include <X11/Xatom.h>
38
39 #ifdef HAVE_SOLARIS_XINERAMA
40 #include <X11/extensions/xinerama.h>
41 #endif
42 #ifdef HAVE_XFREE_XINERAMA
43 #include <X11/extensions/Xinerama.h>
44 #endif
45
46 #ifdef HAVE_RANDR
47 #include <X11/extensions/Xrandr.h>
48 #endif
49
50 #ifdef HAVE_XFIXES
51 #include <X11/extensions/Xfixes.h>
52 #endif
53
54 static void         gdk_screen_x11_dispose     (GObject           *object);
55 static void         gdk_screen_x11_finalize    (GObject           *object);
56 static void         init_randr_support         (GdkScreen         *screen);
57 static void         deinit_multihead           (GdkScreen         *screen);
58
59 enum
60 {
61   WINDOW_MANAGER_CHANGED,
62   LAST_SIGNAL
63 };
64
65 static guint signals[LAST_SIGNAL] = { 0 };
66
67 G_DEFINE_TYPE (GdkScreenX11, _gdk_screen_x11, GDK_TYPE_SCREEN)
68
69 struct _GdkX11Monitor
70 {
71   GdkRectangle  geometry;
72   XID           output;
73   int           width_mm;
74   int           height_mm;
75   char *        output_name;
76   char *        manufacturer;
77 };
78
79 static void
80 _gdk_screen_x11_class_init (GdkScreenX11Class *klass)
81 {
82   GObjectClass *object_class = G_OBJECT_CLASS (klass);
83   
84   object_class->dispose = gdk_screen_x11_dispose;
85   object_class->finalize = gdk_screen_x11_finalize;
86
87   signals[WINDOW_MANAGER_CHANGED] =
88     g_signal_new (g_intern_static_string ("window_manager_changed"),
89                   G_OBJECT_CLASS_TYPE (object_class),
90                   G_SIGNAL_RUN_LAST,
91                   G_STRUCT_OFFSET (GdkScreenX11Class, window_manager_changed),
92                   NULL, NULL,
93                   g_cclosure_marshal_VOID__VOID,
94                   G_TYPE_NONE,
95                   0);
96 }
97
98 static void
99 _gdk_screen_x11_init (GdkScreenX11 *screen)
100 {
101 }
102
103 /**
104  * gdk_screen_get_display:
105  * @screen: a #GdkScreen
106  *
107  * Gets the display to which the @screen belongs.
108  * 
109  * Returns: the display to which @screen belongs
110  *
111  * Since: 2.2
112  **/
113 GdkDisplay *
114 gdk_screen_get_display (GdkScreen *screen)
115 {
116   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
117
118   return GDK_SCREEN_X11 (screen)->display;
119 }
120 /**
121  * gdk_screen_get_width:
122  * @screen: a #GdkScreen
123  *
124  * Gets the width of @screen in pixels
125  * 
126  * Returns: the width of @screen in pixels.
127  *
128  * Since: 2.2
129  **/
130 gint
131 gdk_screen_get_width (GdkScreen *screen)
132 {
133   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
134
135   return WidthOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
136 }
137
138 /**
139  * gdk_screen_get_height:
140  * @screen: a #GdkScreen
141  *
142  * Gets the height of @screen in pixels
143  * 
144  * Returns: the height of @screen in pixels.
145  *
146  * Since: 2.2
147  **/
148 gint
149 gdk_screen_get_height (GdkScreen *screen)
150 {
151   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
152
153   return HeightOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
154 }
155
156 /**
157  * gdk_screen_get_width_mm:
158  * @screen: a #GdkScreen
159  *
160  * Gets the width of @screen in millimeters. 
161  * Note that on some X servers this value will not be correct.
162  * 
163  * Returns: the width of @screen in millimeters.
164  *
165  * Since: 2.2
166  **/
167 gint
168 gdk_screen_get_width_mm (GdkScreen *screen)
169 {
170   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
171
172   return WidthMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
173 }
174
175 /**
176  * gdk_screen_get_height_mm:
177  * @screen: a #GdkScreen
178  *
179  * Returns the height of @screen in millimeters. 
180  * Note that on some X servers this value will not be correct.
181  * 
182  * Returns: the heigth of @screen in millimeters.
183  *
184  * Since: 2.2
185  **/
186 gint
187 gdk_screen_get_height_mm (GdkScreen *screen)
188 {
189   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
190
191   return HeightMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
192 }
193
194 /**
195  * gdk_screen_get_number:
196  * @screen: a #GdkScreen
197  *
198  * Gets the index of @screen among the screens in the display
199  * to which it belongs. (See gdk_screen_get_display())
200  * 
201  * Returns: the index
202  *
203  * Since: 2.2
204  **/
205 gint
206 gdk_screen_get_number (GdkScreen *screen)
207 {
208   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
209   
210   return GDK_SCREEN_X11 (screen)->screen_num;
211 }
212
213 /**
214  * gdk_screen_get_root_window:
215  * @screen: a #GdkScreen
216  *
217  * Gets the root window of @screen. 
218  * 
219  * Returns: the root window
220  *
221  * Since: 2.2
222  **/
223 GdkWindow *
224 gdk_screen_get_root_window (GdkScreen *screen)
225 {
226   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
227
228   return GDK_SCREEN_X11 (screen)->root_window;
229 }
230
231 /**
232  * gdk_screen_get_default_colormap:
233  * @screen: a #GdkScreen
234  *
235  * Gets the default colormap for @screen.
236  * 
237  * Returns: the default #GdkColormap.
238  *
239  * Since: 2.2
240  **/
241 GdkColormap *
242 gdk_screen_get_default_colormap (GdkScreen *screen)
243 {
244   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
245
246   return GDK_SCREEN_X11 (screen)->default_colormap;
247 }
248
249 /**
250  * gdk_screen_set_default_colormap:
251  * @screen: a #GdkScreen
252  * @colormap: a #GdkColormap
253  *
254  * Sets the default @colormap for @screen.
255  *
256  * Since: 2.2
257  **/
258 void
259 gdk_screen_set_default_colormap (GdkScreen   *screen,
260                                  GdkColormap *colormap)
261 {
262   GdkColormap *old_colormap;
263   
264   g_return_if_fail (GDK_IS_SCREEN (screen));
265   g_return_if_fail (GDK_IS_COLORMAP (colormap));
266
267   old_colormap = GDK_SCREEN_X11 (screen)->default_colormap;
268
269   GDK_SCREEN_X11 (screen)->default_colormap = g_object_ref (colormap);
270   
271   if (old_colormap)
272     g_object_unref (old_colormap);
273 }
274
275 static void
276 gdk_screen_x11_dispose (GObject *object)
277 {
278   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
279
280   _gdk_x11_events_uninit_screen (GDK_SCREEN (object));
281
282   if (screen_x11->default_colormap)
283     {
284       g_object_unref (screen_x11->default_colormap);
285       screen_x11->default_colormap = NULL;
286     }
287
288   if (screen_x11->system_colormap)
289     {
290       g_object_unref (screen_x11->system_colormap);
291       screen_x11->system_colormap = NULL;
292     }
293
294   if (screen_x11->rgba_colormap)
295     {
296       g_object_unref (screen_x11->rgba_colormap);
297       screen_x11->rgba_colormap = NULL;
298     }
299
300   if (screen_x11->root_window)
301     _gdk_window_destroy (screen_x11->root_window, TRUE);
302
303   G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->dispose (object);
304
305   screen_x11->xdisplay = NULL;
306   screen_x11->xscreen = NULL;
307   screen_x11->screen_num = -1;
308   screen_x11->xroot_window = None;
309   screen_x11->wmspec_check_window = None;
310 }
311
312 static void
313 gdk_screen_x11_finalize (GObject *object)
314 {
315   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
316   gint          i;
317
318   if (screen_x11->root_window)
319     g_object_unref (screen_x11->root_window);
320
321   if (screen_x11->renderer)
322     g_object_unref (screen_x11->renderer);
323
324   /* Visual Part */
325   for (i = 0; i < screen_x11->nvisuals; i++)
326     g_object_unref (screen_x11->visuals[i]);
327   g_free (screen_x11->visuals);
328   g_hash_table_destroy (screen_x11->visual_hash);
329
330   g_free (screen_x11->window_manager_name);
331
332   g_hash_table_destroy (screen_x11->colormap_hash);
333
334   deinit_multihead (GDK_SCREEN (object));
335   
336   G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->finalize (object);
337 }
338
339 /**
340  * gdk_screen_get_n_monitors:
341  * @screen: a #GdkScreen.
342  *
343  * Returns the number of monitors which @screen consists of.
344  *
345  * Returns: number of monitors which @screen consists of.
346  *
347  * Since: 2.2
348  **/
349 gint 
350 gdk_screen_get_n_monitors (GdkScreen *screen)
351 {
352   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
353   
354   return GDK_SCREEN_X11 (screen)->n_monitors;
355 }
356
357 static GdkX11Monitor *
358 get_monitor (GdkScreen *screen,
359              int        monitor_num)
360 {
361   GdkScreenX11 *screen_x11;
362
363   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
364   
365   screen_x11 = GDK_SCREEN_X11 (screen);
366   
367   g_return_val_if_fail (monitor_num < screen_x11->n_monitors, NULL);
368   g_return_val_if_fail (monitor_num >= 0, NULL);
369   
370   return &(screen_x11->monitors[monitor_num]);
371 }
372
373 /**
374  * gdk_screen_get_monitor_width_mm:
375  * @screen: a #GdkScreen
376  * @monitor_num: number of the monitor
377  *
378  * Gets the width in millimeters of the specified monitor, if available.
379  *
380  * Returns: the width of the monitor, or -1 if not available
381  *
382  * Since: 2.14
383  */
384 gint
385 gdk_screen_get_monitor_width_mm (GdkScreen *screen,
386                                  gint       monitor_num)
387 {
388   return get_monitor (screen, monitor_num)->width_mm;
389 }
390
391 /**
392  * gdk_screen_get_monitor_height_mm:
393  * @screen: a #GdkScreen
394  * @monitor_num: number of the monitor
395  *
396  * Gets the height in millimeters of the specified monitor. 
397  *
398  * Returns: the height of the monitor, or -1 if not available
399  *
400  * Since: 2.14
401  */
402 gint
403 gdk_screen_get_monitor_height_mm (GdkScreen *screen,
404                                   gint       monitor_num)
405 {
406   return get_monitor (screen, monitor_num)->height_mm;
407 }
408
409 /**
410  * gdk_screen_get_monitor_plug_name:
411  * @screen: a #GdkScreen
412  * @monitor_num: number of the monitor
413  *
414  * Returns the output name of the specified monitor. 
415  * Usually something like VGA, DVI, or TV, not the actual
416  * product name of the display device.
417  * 
418  * Returns: a newly-allocated string containing the name of the monitor,
419  *   or %NULL if the name cannot be determined
420  *
421  * Since: 2.14
422  */
423 gchar *
424 gdk_screen_get_monitor_plug_name (GdkScreen *screen,
425                                   gint       monitor_num)
426 {
427   return g_strdup (get_monitor (screen, monitor_num)->output_name);
428 }
429
430 /**
431  * gdk_x11_screen_get_monitor_output:
432  * @screen: a #GdkScreen
433  * @monitor_num: number of the monitor 
434  *
435  * Gets the XID of the specified output/monitor.
436  * If the X server does not support version 1.2 of the RANDR 
437  * extension, 0 is returned.
438  *
439  * Returns: the XID of the monitor
440  *
441  * Since: 2.14
442  */
443 XID
444 gdk_x11_screen_get_monitor_output (GdkScreen *screen,
445                                    gint       monitor_num)
446 {
447   return get_monitor (screen, monitor_num)->output;
448 }
449
450 /**
451  * gdk_screen_get_monitor_geometry:
452  * @screen : a #GdkScreen.
453  * @monitor_num: the monitor number. 
454  * @dest : a #GdkRectangle to be filled with the monitor geometry
455  *
456  * Retrieves the #GdkRectangle representing the size and position of 
457  * the individual monitor within the entire screen area.
458  * 
459  * Note that the size of the entire screen area can be retrieved via 
460  * gdk_screen_get_width() and gdk_screen_get_height().
461  *
462  * Since: 2.2
463  **/
464 void 
465 gdk_screen_get_monitor_geometry (GdkScreen    *screen,
466                                  gint          monitor_num,
467                                  GdkRectangle *dest)
468 {
469   if (dest) 
470     {
471       GdkX11Monitor *monitor = get_monitor (screen, monitor_num);
472
473       *dest = monitor->geometry;
474     }
475 }
476
477 /**
478  * gdk_screen_get_rgba_colormap:
479  * @screen: a #GdkScreen.
480  * 
481  * Gets a colormap to use for creating windows or pixmaps with an
482  * alpha channel. The windowing system on which GTK+ is running
483  * may not support this capability, in which case %NULL will
484  * be returned. Even if a non-%NULL value is returned, its
485  * possible that the window's alpha channel won't be honored
486  * when displaying the window on the screen: in particular, for
487  * X an appropriate windowing manager and compositing manager
488  * must be running to provide appropriate display.
489  *
490  * This functionality is not implemented in the Windows backend.
491  *
492  * For setting an overall opacity for a top-level window, see
493  * gdk_window_set_opacity().
494
495  * Return value: a colormap to use for windows with an alpha channel
496  *   or %NULL if the capability is not available.
497  *
498  * Since: 2.8
499  **/
500 GdkColormap *
501 gdk_screen_get_rgba_colormap (GdkScreen *screen)
502 {
503   GdkScreenX11 *screen_x11;
504
505   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
506
507   screen_x11 = GDK_SCREEN_X11 (screen);
508
509   if (!screen_x11->rgba_visual)
510     return NULL;
511
512   if (!screen_x11->rgba_colormap)
513     screen_x11->rgba_colormap = gdk_colormap_new (screen_x11->rgba_visual,
514                                                   FALSE);
515   
516   return screen_x11->rgba_colormap;
517 }
518
519 /**
520  * gdk_screen_get_rgba_visual:
521  * @screen: a #GdkScreen
522  * 
523  * Gets a visual to use for creating windows or pixmaps with an
524  * alpha channel. See the docs for gdk_screen_get_rgba_colormap()
525  * for caveats.
526  * 
527  * Return value: a visual to use for windows with an alpha channel
528  *   or %NULL if the capability is not available.
529  *
530  * Since: 2.8
531  **/
532 GdkVisual *
533 gdk_screen_get_rgba_visual (GdkScreen *screen)
534 {
535   GdkScreenX11 *screen_x11;
536
537   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
538
539   screen_x11 = GDK_SCREEN_X11 (screen);
540
541   return screen_x11->rgba_visual;
542 }
543
544 /**
545  * gdk_x11_screen_get_xscreen:
546  * @screen: a #GdkScreen.
547  * @returns: an Xlib <type>Screen*</type>
548  *
549  * Returns the screen of a #GdkScreen.
550  *
551  * Since: 2.2
552  */
553 Screen *
554 gdk_x11_screen_get_xscreen (GdkScreen *screen)
555 {
556   return GDK_SCREEN_X11 (screen)->xscreen;
557 }
558
559 /**
560  * gdk_x11_screen_get_screen_number:
561  * @screen: a #GdkScreen.
562  * @returns: the position of @screen among the screens of
563  *   its display.
564  *
565  * Returns the index of a #GdkScreen.
566  *
567  * Since: 2.2
568  */
569 int
570 gdk_x11_screen_get_screen_number (GdkScreen *screen)
571 {
572   return GDK_SCREEN_X11 (screen)->screen_num;
573 }
574
575 static gboolean
576 check_is_composited (GdkDisplay *display,
577                      GdkScreenX11 *screen_x11)
578 {
579   Atom xselection = gdk_x11_atom_to_xatom_for_display (display, screen_x11->cm_selection_atom);
580   Window xwindow;
581   
582   xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), xselection);
583
584   return xwindow != None;
585 }
586
587 static GdkAtom
588 make_cm_atom (int screen_number)
589 {
590   gchar *name = g_strdup_printf ("_NET_WM_CM_S%d", screen_number);
591   GdkAtom atom = gdk_atom_intern (name, FALSE);
592   g_free (name);
593   return atom;
594 }
595
596 static void
597 init_monitor_geometry (GdkX11Monitor *monitor,
598                        int x, int y, int width, int height)
599 {
600   monitor->geometry.x = x;
601   monitor->geometry.y = y;
602   monitor->geometry.width = width;
603   monitor->geometry.height = height;
604
605   monitor->output = None;
606   monitor->width_mm = -1;
607   monitor->height_mm = -1;
608   monitor->output_name = NULL;
609   monitor->manufacturer = NULL;
610 }
611
612 static gboolean
613 init_fake_xinerama (GdkScreen *screen)
614 {
615 #ifdef G_ENABLE_DEBUG
616   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
617   XSetWindowAttributes atts;
618   Window win;
619   gint w, h;
620
621   if (!(_gdk_debug_flags & GDK_DEBUG_XINERAMA))
622     return FALSE;
623   
624   /* Fake Xinerama mode by splitting the screen into 4 monitors.
625    * Also draw a little cross to make the monitor boundaries visible.
626    */
627   w = WidthOfScreen (screen_x11->xscreen);
628   h = HeightOfScreen (screen_x11->xscreen);
629
630   screen_x11->n_monitors = 4;
631   screen_x11->monitors = g_new0 (GdkX11Monitor, 4);
632   init_monitor_geometry (&screen_x11->monitors[0], 0, 0, w / 2, h / 2);
633   init_monitor_geometry (&screen_x11->monitors[1], w / 2, 0, w / 2, h / 2);
634   init_monitor_geometry (&screen_x11->monitors[2], 0, h / 2, w / 2, h / 2);
635   init_monitor_geometry (&screen_x11->monitors[3], w / 2, h / 2, w / 2, h / 2);
636   
637   atts.override_redirect = 1;
638   atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen), 
639                                      screen_x11->screen_num);
640   win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
641                       screen_x11->xroot_window, 0, h / 2, w, 1, 0, 
642                       DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
643                                    screen_x11->screen_num),
644                       InputOutput, 
645                       DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
646                                     screen_x11->screen_num),
647                       CWOverrideRedirect|CWBackPixel, 
648                       &atts);
649   XMapRaised(GDK_SCREEN_XDISPLAY (screen), win); 
650   win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen), 
651                       screen_x11->xroot_window, w/2 , 0, 1, h, 0, 
652                       DefaultDepth(GDK_SCREEN_XDISPLAY (screen), 
653                                    screen_x11->screen_num),
654                       InputOutput, 
655                       DefaultVisual(GDK_SCREEN_XDISPLAY (screen), 
656                                     screen_x11->screen_num),
657                       CWOverrideRedirect|CWBackPixel, 
658                       &atts);
659   XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
660   return TRUE;
661 #endif
662   
663   return FALSE;
664 }
665
666 static void
667 free_monitors (GdkX11Monitor *monitors,
668                gint           n_monitors)
669 {
670   int i;
671
672   for (i = 0; i < n_monitors; ++i)
673     {
674       g_free (monitors[i].output_name);
675       g_free (monitors[i].manufacturer);
676     }
677
678   g_free (monitors);
679 }
680
681 static int
682 monitor_compare_function (GdkX11Monitor *monitor1,
683                           GdkX11Monitor *monitor2)
684 {
685   /* Sort the leftmost/topmost monitors first.
686    * For "cloned" monitors, sort the bigger ones first
687    * (giving preference to taller monitors over wider
688    * monitors)
689    */
690
691   if (monitor1->geometry.x != monitor2->geometry.x)
692     return monitor1->geometry.x - monitor2->geometry.x;
693
694   if (monitor1->geometry.y != monitor2->geometry.y)
695     return monitor1->geometry.y - monitor2->geometry.y;
696
697   if (monitor1->geometry.height != monitor2->geometry.height)
698     return - (monitor1->geometry.height - monitor2->geometry.height);
699
700   if (monitor1->geometry.width != monitor2->geometry.width)
701     return - (monitor1->geometry.width - monitor2->geometry.width);
702
703   return 0;
704 }
705
706 static gboolean
707 init_randr13 (GdkScreen *screen)
708 {
709 #ifdef HAVE_RANDR
710   GdkDisplay *display = gdk_screen_get_display (screen);
711   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
712   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
713   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
714   XRRScreenResources *resources;
715   int i;
716   GArray *monitors;
717   gboolean randr12_compat = FALSE;
718
719   if (!display_x11->have_randr13)
720       return FALSE;
721
722   resources = XRRGetScreenResourcesCurrent (screen_x11->xdisplay,
723                                             screen_x11->xroot_window);
724   if (!resources)
725     return FALSE;
726   
727   monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor),
728                                 resources->noutput);
729
730   for (i = 0; i < resources->noutput; ++i)
731     {
732       XRROutputInfo *output =
733         XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
734
735       /* Non RandR1.2 X driver have output name "default" */
736       randr12_compat |= !g_strcmp0(output->name, "default");
737
738       if (output->connection == RR_Disconnected)
739         {
740           XRRFreeOutputInfo (output);
741           continue;
742         }
743
744       if (output->crtc)
745         {
746           GdkX11Monitor monitor;
747           XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, output->crtc);
748
749           monitor.geometry.x = crtc->x;
750           monitor.geometry.y = crtc->y;
751           monitor.geometry.width = crtc->width;
752           monitor.geometry.height = crtc->height;
753
754           monitor.output = resources->outputs[i];
755           monitor.width_mm = output->mm_width;
756           monitor.height_mm = output->mm_height;
757           monitor.output_name = g_strdup (output->name);
758           /* FIXME: need EDID parser */
759           monitor.manufacturer = NULL;
760
761           g_array_append_val (monitors, monitor);
762
763           XRRFreeCrtcInfo (crtc);
764         }
765
766       XRRFreeOutputInfo (output);
767     }
768
769   XRRFreeScreenResources (resources);
770
771   /* non RandR 1.2 X driver doesn't return any usable multihead data */
772   if (randr12_compat)
773     {
774       guint n_monitors = monitors->len;
775
776       free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE),
777                      n_monitors);
778
779       return FALSE;
780     }
781
782   g_array_sort (monitors,
783                 (GCompareFunc) monitor_compare_function);
784   screen_x11->n_monitors = monitors->len;
785   screen_x11->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);
786
787   return screen_x11->n_monitors > 0;
788 #endif
789   
790   return FALSE;
791 }
792
793 static gboolean
794 init_solaris_xinerama (GdkScreen *screen)
795 {
796 #ifdef HAVE_SOLARIS_XINERAMA
797   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
798   int screen_no = gdk_screen_get_number (screen);
799   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
800   XRectangle monitors[MAXFRAMEBUFFERS];
801   unsigned char hints[16];
802   gint result;
803   int n_monitors;
804   int i;
805   
806   if (!XineramaGetState (dpy, screen_no))
807     return FALSE;
808
809   result = XineramaGetInfo (dpy, screen_no, monitors, hints, &n_monitors);
810
811   /* Yes I know it should be Success but the current implementation 
812    * returns the num of monitor
813    */
814   if (result == 0)
815     {
816       return FALSE;
817     }
818
819   screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
820   screen_x11->n_monitors = n_monitors;
821
822   for (i = 0; i < n_monitors; i++)
823     {
824       init_monitor_geometry (&screen_x11->monitors[i],
825                              monitors[i].x, monitors[i].y,
826                              monitors[i].width, monitors[i].height);
827     }
828   
829   return TRUE;
830 #endif /* HAVE_SOLARIS_XINERAMA */
831
832   return FALSE;
833 }
834
835 static gboolean
836 init_xfree_xinerama (GdkScreen *screen)
837 {
838 #ifdef HAVE_XFREE_XINERAMA
839   Display *dpy = GDK_SCREEN_XDISPLAY (screen);
840   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
841   XineramaScreenInfo *monitors;
842   int i, n_monitors;
843   
844   if (!XineramaIsActive (dpy))
845     return FALSE;
846
847   monitors = XineramaQueryScreens (dpy, &n_monitors);
848   
849   if (n_monitors <= 0 || monitors == NULL)
850     {
851       /* If Xinerama doesn't think we have any monitors, try acting as
852        * though we had no Xinerama. If the "no monitors" condition
853        * is because XRandR 1.2 is currently switching between CRTCs,
854        * we'll be notified again when we have our monitor back,
855        * and can go back into Xinerama-ish mode at that point.
856        */
857       if (monitors)
858         XFree (monitors);
859       
860       return FALSE;
861     }
862
863   screen_x11->n_monitors = n_monitors;
864   screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
865   
866   for (i = 0; i < n_monitors; ++i)
867     {
868       init_monitor_geometry (&screen_x11->monitors[i],
869                              monitors[i].x_org, monitors[i].y_org,
870                              monitors[i].width, monitors[i].height);
871     }
872   
873   XFree (monitors);
874   
875   return TRUE;
876 #endif /* HAVE_XFREE_XINERAMA */
877   
878   return FALSE;
879 }
880
881 static void
882 deinit_multihead (GdkScreen *screen)
883 {
884   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
885
886   free_monitors (screen_x11->monitors, screen_x11->n_monitors);
887
888   screen_x11->n_monitors = 0;
889   screen_x11->monitors = NULL;
890 }
891
892 static gboolean
893 compare_monitor (GdkX11Monitor *m1,
894                  GdkX11Monitor *m2)
895 {
896   if (m1->geometry.x != m2->geometry.x ||
897       m1->geometry.y != m2->geometry.y ||
898       m1->geometry.width != m2->geometry.width ||
899       m1->geometry.height != m2->geometry.height)
900     return FALSE;
901
902   if (m1->width_mm != m2->width_mm ||
903       m1->height_mm != m2->height_mm)
904     return FALSE;
905
906   if (g_strcmp0 (m1->output_name, m2->output_name) != 0)
907     return FALSE;
908
909   if (g_strcmp0 (m1->manufacturer, m2->manufacturer) != 0)
910     return FALSE;
911
912   return TRUE;
913 }
914
915 static gboolean
916 compare_monitors (GdkX11Monitor *monitors1, gint n_monitors1,
917                   GdkX11Monitor *monitors2, gint n_monitors2)
918 {
919   gint i;
920
921   if (n_monitors1 != n_monitors2)
922     return FALSE;
923
924   for (i = 0; i < n_monitors1; i++)
925     {
926       if (!compare_monitor (monitors1 + i, monitors2 + i))
927         return FALSE;
928     }
929
930   return TRUE;
931 }
932
933 static void
934 init_multihead (GdkScreen *screen)
935 {
936   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
937   int opcode, firstevent, firsterror;
938
939   /* There are four different implementations of multihead support: 
940    *
941    *  1. Fake Xinerama for debugging purposes
942    *  2. RandR 1.2
943    *  3. Solaris Xinerama
944    *  4. XFree86/Xorg Xinerama
945    *
946    * We use them in that order.
947    */
948   if (init_fake_xinerama (screen))
949     return;
950
951   if (init_randr13 (screen))
952     return;
953
954   if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
955                        &opcode, &firstevent, &firsterror))
956     {
957       if (init_solaris_xinerama (screen))
958         return;
959       
960       if (init_xfree_xinerama (screen))
961         return;
962     }
963
964   /* No multihead support of any kind for this screen */
965   screen_x11->n_monitors = 1;
966   screen_x11->monitors = g_new0 (GdkX11Monitor, 1);
967
968   init_monitor_geometry (screen_x11->monitors, 0, 0,
969                          WidthOfScreen (screen_x11->xscreen),
970                          HeightOfScreen (screen_x11->xscreen));
971 }
972
973 GdkScreen *
974 _gdk_x11_screen_new (GdkDisplay *display,
975                      gint        screen_number) 
976 {
977   GdkScreen *screen;
978   GdkScreenX11 *screen_x11;
979   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
980
981   screen = g_object_new (GDK_TYPE_SCREEN_X11, NULL);
982
983   screen_x11 = GDK_SCREEN_X11 (screen);
984   screen_x11->display = display;
985   screen_x11->xdisplay = display_x11->xdisplay;
986   screen_x11->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
987   screen_x11->screen_num = screen_number;
988   screen_x11->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
989   screen_x11->wmspec_check_window = None;
990   /* we want this to be always non-null */
991   screen_x11->window_manager_name = g_strdup ("unknown");
992   screen_x11->cm_selection_atom = make_cm_atom (screen_number);
993   screen_x11->is_composited = check_is_composited (display, screen_x11);
994   
995   init_multihead (screen);
996   init_randr_support (screen);
997   
998   _gdk_visual_init (screen);
999   _gdk_windowing_window_init (screen);
1000   
1001   return screen;
1002 }
1003
1004 /**
1005  * gdk_screen_is_composited:
1006  * @screen: a #GdkScreen
1007  * 
1008  * Returns whether windows with an RGBA visual can reasonably
1009  * be expected to have their alpha channel drawn correctly on
1010  * the screen.
1011  *
1012  * On X11 this function returns whether a compositing manager is
1013  * compositing @screen.
1014  * 
1015  * Return value: Whether windows with RGBA visuals can reasonably be
1016  * expected to have their alpha channels drawn correctly on the screen.
1017  * 
1018  * Since: 2.10
1019  **/
1020 gboolean
1021 gdk_screen_is_composited (GdkScreen *screen)
1022 {
1023   GdkScreenX11 *screen_x11;
1024
1025   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
1026
1027   screen_x11 = GDK_SCREEN_X11 (screen);
1028
1029   return screen_x11->is_composited;
1030 }
1031
1032 static void
1033 init_randr_support (GdkScreen * screen)
1034 {
1035   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1036   
1037   XSelectInput (GDK_SCREEN_XDISPLAY (screen),
1038                 screen_x11->xroot_window,
1039                 StructureNotifyMask);
1040
1041 #ifdef HAVE_RANDR
1042   XRRSelectInput (GDK_SCREEN_XDISPLAY (screen),
1043                   screen_x11->xroot_window,
1044                   RRScreenChangeNotifyMask      |
1045                   RRCrtcChangeNotifyMask        |
1046                   RROutputPropertyNotifyMask);
1047 #endif
1048 }
1049
1050 static void
1051 process_monitors_change (GdkScreen *screen)
1052 {
1053   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1054   gint           n_monitors;
1055   GdkX11Monitor *monitors;
1056   gboolean changed;
1057
1058   n_monitors = screen_x11->n_monitors;
1059   monitors = screen_x11->monitors;
1060
1061   screen_x11->n_monitors = 0;
1062   screen_x11->monitors = NULL;
1063
1064   init_multihead (screen);
1065
1066   changed = !compare_monitors (monitors, n_monitors,
1067                                screen_x11->monitors, screen_x11->n_monitors);
1068
1069   free_monitors (monitors, n_monitors);
1070
1071   if (changed)
1072     g_signal_emit_by_name (screen, "monitors-changed");
1073 }
1074
1075 void
1076 _gdk_x11_screen_size_changed (GdkScreen *screen,
1077                               XEvent    *event)
1078 {
1079   gint width, height;
1080   GdkDisplayX11 *display_x11;
1081
1082   width = gdk_screen_get_width (screen);
1083   height = gdk_screen_get_height (screen);
1084
1085 #ifdef HAVE_RANDR
1086   display_x11 = GDK_DISPLAY_X11 (gdk_screen_get_display (screen));
1087
1088   if (display_x11->have_randr13 && event->type == ConfigureNotify)
1089     return;
1090
1091   XRRUpdateConfiguration (event);
1092 #else
1093   if (event->type == ConfigureNotify)
1094     {
1095       XConfigureEvent *rcevent = (XConfigureEvent *) event;
1096       Screen        *xscreen = gdk_x11_screen_get_xscreen (screen);
1097       
1098       xscreen->width   = rcevent->width;
1099       xscreen->height  = rcevent->height;
1100     }
1101   else
1102     return;
1103 #endif
1104
1105   process_monitors_change (screen);
1106
1107   if (width != gdk_screen_get_width (screen) ||
1108       height != gdk_screen_get_height (screen))
1109     g_signal_emit_by_name (screen, "size-changed");
1110 }
1111
1112 void
1113 _gdk_x11_screen_window_manager_changed (GdkScreen *screen)
1114 {
1115   g_signal_emit (screen, signals[WINDOW_MANAGER_CHANGED], 0);
1116 }
1117
1118 void
1119 _gdk_x11_screen_process_owner_change (GdkScreen *screen,
1120                                       XEvent *event)
1121 {
1122 #ifdef HAVE_XFIXES
1123   XFixesSelectionNotifyEvent *selection_event = (XFixesSelectionNotifyEvent *)event;
1124   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
1125   Atom xcm_selection_atom = gdk_x11_atom_to_xatom_for_display (screen_x11->display,
1126                                                                screen_x11->cm_selection_atom);
1127
1128   if (selection_event->selection == xcm_selection_atom)
1129     {
1130       gboolean composited = selection_event->owner != None;
1131
1132       if (composited != screen_x11->is_composited)
1133         {
1134           screen_x11->is_composited = composited;
1135
1136           g_signal_emit_by_name (screen, "composited-changed");
1137         }
1138     }
1139 #endif
1140 }
1141
1142 /**
1143  * _gdk_windowing_substitute_screen_number:
1144  * @display_name : The name of a display, in the form used by 
1145  *                 gdk_display_open (). If %NULL a default value
1146  *                 will be used. On X11, this is derived from the DISPLAY
1147  *                 environment variable.
1148  * @screen_number : The number of a screen within the display
1149  *                  referred to by @display_name.
1150  *
1151  * Modifies a @display_name to make @screen_number the default
1152  * screen when the display is opened.
1153  *
1154  * Return value: a newly allocated string holding the resulting
1155  *   display name. Free with g_free().
1156  */
1157 gchar * 
1158 _gdk_windowing_substitute_screen_number (const gchar *display_name,
1159                                          gint         screen_number)
1160 {
1161   GString *str;
1162   gchar   *p;
1163
1164   if (!display_name)
1165     display_name = getenv ("DISPLAY");
1166
1167   if (!display_name)
1168     return NULL;
1169
1170   str = g_string_new (display_name);
1171
1172   p = strrchr (str->str, '.');
1173   if (p && p >  strchr (str->str, ':'))
1174     g_string_truncate (str, p - str->str);
1175
1176   g_string_append_printf (str, ".%d", screen_number);
1177
1178   return g_string_free (str, FALSE);
1179 }
1180
1181 /**
1182  * gdk_screen_make_display_name:
1183  * @screen: a #GdkScreen
1184  * 
1185  * Determines the name to pass to gdk_display_open() to get
1186  * a #GdkDisplay with this screen as the default screen.
1187  * 
1188  * Return value: a newly allocated string, free with g_free()
1189  *
1190  * Since: 2.2
1191  **/
1192 gchar *
1193 gdk_screen_make_display_name (GdkScreen *screen)
1194 {
1195   const gchar *old_display;
1196
1197   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1198
1199   old_display = gdk_display_get_name (gdk_screen_get_display (screen));
1200
1201   return _gdk_windowing_substitute_screen_number (old_display, 
1202                                                   gdk_screen_get_number (screen));
1203 }
1204
1205 /**
1206  * gdk_screen_get_active_window
1207  * @screen: a #GdkScreen
1208  *
1209  * Returns the screen's currently active window.
1210  *
1211  * On X11, this is done by inspecting the _NET_ACTIVE_WINDOW property
1212  * on the root window, as described in the <ulink
1213  * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window
1214  * Manager Hints</ulink>. If there is no currently currently active
1215  * window, or the window manager does not support the
1216  * _NET_ACTIVE_WINDOW hint, this function returns %NULL.
1217  *
1218  * On other platforms, this function may return %NULL, depending on whether
1219  * it is implementable on that platform.
1220  *
1221  * The returned window should be unrefed using g_object_unref() when
1222  * no longer needed.
1223  *
1224  * Return value: the currently active window, or %NULL.
1225  *
1226  * Since: 2.10
1227  **/
1228 GdkWindow *
1229 gdk_screen_get_active_window (GdkScreen *screen)
1230 {
1231   GdkScreenX11 *screen_x11;
1232   GdkWindow *ret = NULL;
1233   Atom type_return;
1234   gint format_return;
1235   gulong nitems_return;
1236   gulong bytes_after_return;
1237   guchar *data = NULL;
1238
1239   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1240
1241   if (!gdk_x11_screen_supports_net_wm_hint (screen,
1242                                             gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW")))
1243     return NULL;
1244
1245   screen_x11 = GDK_SCREEN_X11 (screen);
1246
1247   if (XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
1248                           gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
1249                                                                  "_NET_ACTIVE_WINDOW"),
1250                           0, 1, False, XA_WINDOW, &type_return,
1251                           &format_return, &nitems_return,
1252                           &bytes_after_return, &data)
1253       == Success)
1254     {
1255       if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
1256         {
1257           GdkNativeWindow window = *(GdkNativeWindow *) data;
1258
1259           if (window != None)
1260             {
1261               ret = gdk_window_foreign_new_for_display (screen_x11->display,
1262                                                         *(GdkNativeWindow *) data);
1263             }
1264         }
1265     }
1266
1267   if (data)
1268     XFree (data);
1269
1270   return ret;
1271 }
1272
1273 /**
1274  * gdk_screen_get_window_stack
1275  * @screen: a #GdkScreen
1276  *
1277  * Returns a #GList of #GdkWindow<!-- -->s representing the current
1278  * window stack.
1279  *
1280  * On X11, this is done by inspecting the _NET_CLIENT_LIST_STACKING
1281  * property on the root window, as described in the <ulink
1282  * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window
1283  * Manager Hints</ulink>. If the window manager does not support the
1284  * _NET_CLIENT_LIST_STACKING hint, this function returns %NULL.
1285  *
1286  * On other platforms, this function may return %NULL, depending on whether
1287  * it is implementable on that platform.
1288  *
1289  * The returned list is newly allocated and owns references to the
1290  * windows it contains, so it should be freed using g_list_free() and
1291  * its windows unrefed using g_object_unref() when no longer needed.
1292  *
1293  * Return value: a list of #GdkWindow<!-- -->s for the current window stack,
1294  *               or %NULL.
1295  *
1296  * Since: 2.10
1297  **/
1298 GList *
1299 gdk_screen_get_window_stack (GdkScreen *screen)
1300 {
1301   GdkScreenX11 *screen_x11;
1302   GList *ret = NULL;
1303   Atom type_return;
1304   gint format_return;
1305   gulong nitems_return;
1306   gulong bytes_after_return;
1307   guchar *data = NULL;
1308
1309   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1310
1311   if (!gdk_x11_screen_supports_net_wm_hint (screen,
1312                                             gdk_atom_intern_static_string ("_NET_CLIENT_LIST_STACKING")))
1313     return NULL;
1314
1315   screen_x11 = GDK_SCREEN_X11 (screen);
1316
1317   if (XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
1318                           gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
1319                                                                  "_NET_CLIENT_LIST_STACKING"),
1320                           0, G_MAXLONG, False, XA_WINDOW, &type_return,
1321                           &format_return, &nitems_return,
1322                           &bytes_after_return, &data)
1323       == Success)
1324     {
1325       if ((type_return == XA_WINDOW) && (format_return == 32) &&
1326           (data) && (nitems_return > 0))
1327         {
1328           gulong *stack = (gulong *) data;
1329           GdkWindow *win;
1330           int i;
1331
1332           for (i = 0; i < nitems_return; i++)
1333             {
1334               win = gdk_window_foreign_new_for_display (screen_x11->display,
1335                                                         (GdkNativeWindow)stack[i]);
1336
1337               if (win != NULL)
1338                 ret = g_list_append (ret, win);
1339             }
1340         }
1341     }
1342
1343   if (data)
1344     XFree (data);
1345
1346   return ret;
1347 }
1348
1349 #define __GDK_SCREEN_X11_C__
1350 #include "gdkaliasdef.c"