]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkscreen-x11.c
Start implementing display/screen closing scheme; keep a flag for whether
[~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 <glib.h>
25 #include "gdkscreen.h"
26 #include "gdkscreen-x11.h"
27 #include "gdkdisplay.h"
28 #include "gdkdisplay-x11.h"
29 #include "gdkx.h"
30
31 #ifdef HAVE_SOLARIS_XINERAMA
32 #include <X11/extensions/xinerama.h>
33 #endif
34 #ifdef HAVE_XFREE_XINERAMA
35 #include <X11/extensions/Xinerama.h>
36 #endif
37
38 static void         gdk_screen_x11_class_init  (GdkScreenX11Class *klass);
39 static void         gdk_screen_x11_dispose     (GObject           *object);
40 static void         gdk_screen_x11_finalize    (GObject           *object);
41 static void         init_xinerama_support      (GdkScreen         *screen);
42
43
44 static gpointer parent_class = NULL;
45
46 GType
47 _gdk_screen_x11_get_type ()
48 {
49   static GType object_type = 0;
50
51   if (!object_type)
52     {
53       static const GTypeInfo object_info =
54         {
55           sizeof (GdkScreenX11Class),
56           (GBaseInitFunc) NULL,
57           (GBaseFinalizeFunc) gdk_screen_x11_finalize,
58           (GClassInitFunc) gdk_screen_x11_class_init,
59           NULL,                 /* class_finalize */
60           NULL,                 /* class_data */
61           sizeof (GdkScreenX11),
62           0,                    /* n_preallocs */
63           (GInstanceInitFunc) NULL,
64         };
65       object_type = g_type_register_static (GDK_TYPE_SCREEN,
66                                             "GdkScreenX11",
67                                             &object_info, 0);
68     }
69   return object_type;
70 }
71
72 void
73 gdk_screen_x11_class_init (GdkScreenX11Class *klass)
74 {
75   GObjectClass *object_class = G_OBJECT_CLASS (klass);
76   
77   object_class->dispose = gdk_screen_x11_dispose;
78   object_class->finalize = gdk_screen_x11_finalize;
79
80   parent_class = g_type_class_peek_parent (klass);
81 }
82
83 /**
84  * gdk_screen_get_display:
85  * @screen: a #GdkScreen
86  *
87  * Gets the display to which the @screen belongs.
88  * 
89  * Returns: the display to which @screen belongs
90  **/
91 GdkDisplay *
92 gdk_screen_get_display (GdkScreen *screen)
93 {
94   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
95
96   return GDK_SCREEN_X11 (screen)->display;
97 }
98 /**
99  * gdk_screen_get_width:
100  * @screen: a #GdkScreen
101  *
102  * Gets the width of @screen in pixels
103  * 
104  * Returns: the width of @screen in pixels.
105  **/
106 gint
107 gdk_screen_get_width (GdkScreen *screen)
108 {
109   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
110
111   return WidthOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
112 }
113
114 /**
115  * gdk_screen_get_height:
116  * @screen: a #GdkScreen
117  *
118  * Gets the height of @screen in pixels
119  * 
120  * Returns: the height of @screen in pixels.
121  **/
122 gint
123 gdk_screen_get_height (GdkScreen *screen)
124 {
125   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
126
127   return HeightOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
128 }
129
130 /**
131  * gdk_screen_get_width_mm:
132  * @screen: a #GdkScreen
133  *
134  * Gets the width of @screen in millimeters. 
135  * Note that on some X servers this value will not be correct.
136  * 
137  * Returns: the width of @screen in pixels.
138  **/
139 gint
140 gdk_screen_get_width_mm (GdkScreen *screen)
141 {
142   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
143
144   return WidthMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
145 }
146
147 /**
148  * gdk_screen_get_height_mm:
149  * @screen: a #GdkScreen
150  *
151  * Returns the height of @screen in millimeters. 
152  * Note that on some X servers this value will not be correct.
153  * 
154  * Returns: the heigth of @screen in pixels.
155  **/
156 gint
157 gdk_screen_get_height_mm (GdkScreen *screen)
158 {
159   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
160
161   return HeightMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
162 }
163
164 /**
165  * gdk_screen_get_number:
166  * @screen: a #GdkScreen
167  *
168  * Gets the index of @screen among the screens in the display
169  * to which it belongs. (See gdk_screen_get_display())
170  * 
171  * Returns: the index
172  **/
173 gint
174 gdk_screen_get_number (GdkScreen *screen)
175 {
176   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
177   
178   return GDK_SCREEN_X11 (screen)->screen_num;
179 }
180
181 /**
182  * gdk_screen_get_root_window:
183  * @screen: a #GdkScreen
184  *
185  * Gets the root window of @screen. 
186  * 
187  * Returns: the root window
188  **/
189 GdkWindow *
190 gdk_screen_get_root_window (GdkScreen *screen)
191 {
192   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
193
194   return GDK_SCREEN_X11 (screen)->root_window;
195 }
196
197 /**
198  * gdk_screen_get_default_colormap:
199  * @screen: a #GdkScreen
200  *
201  * Gets the default colormap for @screen.
202  * 
203  * Returns: the default #GdkColormap.
204  **/
205 GdkColormap *
206 gdk_screen_get_default_colormap (GdkScreen *screen)
207 {
208   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
209
210   return GDK_SCREEN_X11 (screen)->default_colormap;
211 }
212
213 /**
214  * gdk_screen_set_default_colormap:
215  * @screen: a #GdkScreen
216  * @colormap: a #GdkColormap
217  *
218  * Sets the default @colormap for @screen.
219  **/
220 void
221 gdk_screen_set_default_colormap (GdkScreen   *screen,
222                                  GdkColormap *colormap)
223 {
224   g_return_if_fail (GDK_IS_SCREEN (screen));
225   g_return_if_fail (GDK_IS_COLORMAP (colormap));
226   
227   GDK_SCREEN_X11 (screen)->default_colormap = colormap;
228 }
229
230 static void
231 gdk_screen_x11_dispose (GObject *object)
232 {
233   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
234
235   screen_x11->root_window = NULL;
236
237   screen_x11->xdisplay = NULL;
238   screen_x11->xscreen = NULL;
239   screen_x11->screen_num = -1;
240   screen_x11->xroot_window = None;
241   screen_x11->wmspec_check_window = None;
242
243   G_OBJECT_CLASS (parent_class)->dispose (object);
244 }
245
246 static void
247 gdk_screen_x11_finalize (GObject *object)
248 {
249   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
250   /* int i; */
251   g_object_unref (G_OBJECT (screen_x11->root_window));
252   
253   /* Visual Part (Need to implement finalize for Visuals for a clean
254    * finalize) */
255   /* for (i=0;i<screen_x11->nvisuals;i++)
256     g_object_unref (G_OBJECT (screen_x11->visuals[i]));*/
257   g_free (screen_x11->visuals);
258   g_hash_table_destroy (screen_x11->visual_hash);
259   /* X settings */
260   g_free (screen_x11->xsettings_client);
261
262   g_free (screen_x11->monitors);
263   
264   G_OBJECT_CLASS (parent_class)->finalize (object);
265 }
266
267 /**
268  * gdk_screen_get_n_monitors:
269  * @screen : a #GdkScreen.
270  *
271  * Returns the number of monitors being part of the virtual screen
272  *
273  * Returns: number of monitors part of the virtual screen or
274  *          0 if @screen is not in virtual screen mode.
275  **/
276 gint 
277 gdk_screen_get_n_monitors (GdkScreen *screen)
278 {
279   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
280   
281   return GDK_SCREEN_X11 (screen)->num_monitors;
282 }
283
284 /**
285  * gdk_screen_get_monitor_geometry:
286  * @screen : a #GdkScreen.
287  * @monitor_num: the monitor number. 
288  * @dest : a #GdkRectangle to be filled with the monitor geometry
289  *
290  * Retrieves the #GdkRectangle representing the size and start
291  * coordinates of the individual monitor within the the entire virtual
292  * screen.
293  * 
294  * Note that the virtual screen coordinates can be retrieved via 
295  * gdk_screen_get_width() and gdk_screen_get_height().
296  *
297  **/
298 void 
299 gdk_screen_get_monitor_geometry (GdkScreen    *screen,
300                                  gint          monitor_num,
301                                  GdkRectangle *dest)
302 {
303   g_return_if_fail (GDK_IS_SCREEN (screen));
304   g_return_if_fail (monitor_num < GDK_SCREEN_X11 (screen)->num_monitors);
305
306   *dest = GDK_SCREEN_X11 (screen)->monitors[monitor_num];
307 }
308
309 /**
310  * gdk_x11_screen_get_xscreen:
311  * @screen: a #GdkScreen.
312  * @returns: an Xlib <type>Screen*</type>
313  *
314  * Returns the screen of a #GdkScreen.
315  */
316 Screen *
317 gdk_x11_screen_get_xscreen (GdkScreen *screen)
318 {
319   return GDK_SCREEN_X11 (screen)->xscreen;
320 }
321
322
323 /**
324  * gdk_x11_screen_get_screen_number:
325  * @screen: a #GdkScreen.
326  * @returns: the position of @screen among the screens of
327  *   its display.
328  *
329  * Returns the index of a #GdkScreen.
330  */
331 int
332 gdk_x11_screen_get_screen_number (GdkScreen *screen)
333 {
334   return GDK_SCREEN_X11 (screen)->screen_num;
335 }
336
337 GdkScreen *
338 _gdk_x11_screen_new (GdkDisplay *display,
339                      gint        screen_number) 
340 {
341   GdkScreen *screen;
342   GdkScreenX11 *screen_x11;
343   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
344
345   screen = g_object_new (GDK_TYPE_SCREEN_X11, NULL);
346
347   screen_x11 = GDK_SCREEN_X11 (screen);
348   screen_x11->display = display;
349   screen_x11->xdisplay = display_x11->xdisplay;
350   screen_x11->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
351   screen_x11->screen_num = screen_number;
352   screen_x11->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
353   screen_x11->wmspec_check_window = None;
354
355   init_xinerama_support (screen);
356   
357   _gdk_visual_init (screen);
358   _gdk_windowing_window_init (screen);
359   _gdk_x11_events_init_screen (screen);
360
361   return screen;
362 }
363
364 #ifdef HAVE_XINERAMA
365 static gboolean
366 check_solaris_xinerama (GdkScreen *screen)
367 {
368 #ifdef HAVE_SOLARIS_XINERAMA
369   
370   if (XineramaGetState (GDK_SCREEN_XDISPLAY (screen),
371                         gdk_screen_get_number (screen)))
372     {
373       XRectangle monitors[MAXFRAMEBUFFERS];
374       unsigned char hints[16];
375       gint result;
376       GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
377
378       result = XineramaGetInfo (GDK_SCREEN_XDISPLAY (screen),
379                                 gdk_screen_get_number (screen),
380                                 monitors, hints,
381                                 &screen_x11->num_monitors);
382       /* Yes I know it should be Success but the current implementation 
383           returns the num of monitor*/
384       if (result == 0)
385         {
386           /* FIXME: We need to trap errors, since XINERAMA isn't always XINERAMA.
387            */ 
388           g_error ("error while retrieving Xinerama information");
389         }
390       else
391         {
392           int i;
393           screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
394           
395           for (i = 0; i < screen_x11->num_monitors; i++)
396             {
397               screen_x11->monitors[i].x = monitors[i].x;
398               screen_x11->monitors[i].y = monitors[i].y;
399               screen_x11->monitors[i].width = monitors[i].width;
400               screen_x11->monitors[i].height = monitors[i].height;
401             }
402
403           return TRUE;
404         }
405     }
406 #endif /* HAVE_SOLARIS_XINERAMA */
407   
408   return FALSE;
409 }
410
411 static gboolean
412 check_xfree_xinerama (GdkScreen *screen)
413 {
414 #ifdef HAVE_XFREE_XINERAMA
415   if (XineramaIsActive (GDK_SCREEN_XDISPLAY (screen)))
416     {
417       XineramaScreenInfo *monitors = XineramaQueryScreens (GDK_SCREEN_XDISPLAY (screen),
418                                                            &screen_x11->num_monitors);
419       if (screen_x11->num_monitors <= 0)
420         {
421           /* FIXME: We need to trap errors, since XINERAMA isn't always XINERAMA.
422            *        I don't think the num_monitors <= 0 check has any validity.
423            */ 
424           g_error ("error while retrieving Xinerama information");
425         }
426       else
427         {
428           int i;
429           screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
430           
431           for (i = 0; i < screen_x11->num_monitors; i++)
432             {
433               screen_x11->monitors[i].x = monitors[i].x_org;
434               screen_x11->monitors[i].y = monitors[i].y_org;
435               screen_x11->monitors[i].width = monitors[i].width;
436               screen_x11->monitors[i].height = monitors[i].height;
437             }
438
439           XFree (monitors);
440
441           return TRUE;
442         }
443     }
444 #endif /* HAVE_XFREE_XINERAMA */
445   
446   return FALSE;
447 }
448 #endif /* HAVE_XINERAMA */
449
450 static void
451 init_xinerama_support (GdkScreen * screen)
452 {
453   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
454   
455 #ifdef HAVE_XINERAMA
456   int opcode, firstevent, firsterror;
457   gint result;
458   
459   if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
460                        &opcode, &firstevent, &firsterror))
461     {
462       if (check_solaris_xinerama (screen) ||
463           check_xfree_xinerama (screen))
464         return;
465     }
466 #endif /* HAVE_XINERAMA */
467
468   /* No Xinerama
469    */
470   screen_x11->num_monitors = 1;
471   screen_x11->monitors = g_new0 (GdkRectangle, 1);
472   screen_x11->monitors[0].x = 0;
473   screen_x11->monitors[0].y = 0;
474   screen_x11->monitors[0].width = WidthOfScreen (screen_x11->xscreen);
475   screen_x11->monitors[0].height = HeightOfScreen (screen_x11->xscreen);
476 }
477