]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkscreen-x11.c
c8f819727b4e02573a75f0632fc9e2958466bc72
[~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 #include <glib.h>
26 #include "gdkscreen.h"
27 #include "gdkscreen-x11.h"
28 #include "gdkdisplay.h"
29 #include "gdkdisplay-x11.h"
30 #include "gdkx.h"
31
32 #ifdef HAVE_XFT
33 #include <pango/pangoxft.h>
34 #endif
35 #include <pango/pangox.h>
36
37 #ifdef HAVE_SOLARIS_XINERAMA
38 #include <X11/extensions/xinerama.h>
39 #endif
40 #ifdef HAVE_XFREE_XINERAMA
41 #include <X11/extensions/Xinerama.h>
42 #endif
43
44 static void         gdk_screen_x11_class_init  (GdkScreenX11Class *klass);
45 static void         gdk_screen_x11_dispose     (GObject           *object);
46 static void         gdk_screen_x11_finalize    (GObject           *object);
47 static void         init_xinerama_support      (GdkScreen         *screen);
48 static void         init_randr_support         (GdkScreen         *screen);
49
50 enum
51 {
52   WINDOW_MANAGER_CHANGED,
53   LAST_SIGNAL
54 };
55
56 static gpointer parent_class = NULL;
57 static guint signals[LAST_SIGNAL] = { 0 };
58
59 GType
60 _gdk_screen_x11_get_type ()
61 {
62   static GType object_type = 0;
63
64   if (!object_type)
65     {
66       static const GTypeInfo object_info =
67         {
68           sizeof (GdkScreenX11Class),
69           (GBaseInitFunc) NULL,
70           (GBaseFinalizeFunc) gdk_screen_x11_finalize,
71           (GClassInitFunc) gdk_screen_x11_class_init,
72           NULL,                 /* class_finalize */
73           NULL,                 /* class_data */
74           sizeof (GdkScreenX11),
75           0,                    /* n_preallocs */
76           (GInstanceInitFunc) NULL,
77         };
78       object_type = g_type_register_static (GDK_TYPE_SCREEN,
79                                             "GdkScreenX11",
80                                             &object_info, 0);
81     }
82   return object_type;
83 }
84
85 static void
86 gdk_screen_x11_class_init (GdkScreenX11Class *klass)
87 {
88   GObjectClass *object_class = G_OBJECT_CLASS (klass);
89   
90   object_class->dispose = gdk_screen_x11_dispose;
91   object_class->finalize = gdk_screen_x11_finalize;
92
93   parent_class = g_type_class_peek_parent (klass);
94
95   signals[WINDOW_MANAGER_CHANGED] =
96     g_signal_new ("window_manager_changed",
97                   G_OBJECT_CLASS_TYPE (object_class),
98                   G_SIGNAL_RUN_LAST,
99                   G_STRUCT_OFFSET (GdkScreenX11Class, window_manager_changed),
100                   NULL, NULL,
101                   g_cclosure_marshal_VOID__VOID,
102                   G_TYPE_NONE,
103                   0);
104 }
105
106 /**
107  * gdk_screen_get_display:
108  * @screen: a #GdkScreen
109  *
110  * Gets the display to which the @screen belongs.
111  * 
112  * Returns: the display to which @screen belongs
113  **/
114 GdkDisplay *
115 gdk_screen_get_display (GdkScreen *screen)
116 {
117   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
118
119   return GDK_SCREEN_X11 (screen)->display;
120 }
121 /**
122  * gdk_screen_get_width:
123  * @screen: a #GdkScreen
124  *
125  * Gets the width of @screen in pixels
126  * 
127  * Returns: the width of @screen in pixels.
128  **/
129 gint
130 gdk_screen_get_width (GdkScreen *screen)
131 {
132   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
133
134   return WidthOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
135 }
136
137 /**
138  * gdk_screen_get_height:
139  * @screen: a #GdkScreen
140  *
141  * Gets the height of @screen in pixels
142  * 
143  * Returns: the height of @screen in pixels.
144  **/
145 gint
146 gdk_screen_get_height (GdkScreen *screen)
147 {
148   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
149
150   return HeightOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
151 }
152
153 /**
154  * gdk_screen_get_width_mm:
155  * @screen: a #GdkScreen
156  *
157  * Gets the width of @screen in millimeters. 
158  * Note that on some X servers this value will not be correct.
159  * 
160  * Returns: the width of @screen in pixels.
161  **/
162 gint
163 gdk_screen_get_width_mm (GdkScreen *screen)
164 {
165   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
166
167   return WidthMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
168 }
169
170 /**
171  * gdk_screen_get_height_mm:
172  * @screen: a #GdkScreen
173  *
174  * Returns the height of @screen in millimeters. 
175  * Note that on some X servers this value will not be correct.
176  * 
177  * Returns: the heigth of @screen in pixels.
178  **/
179 gint
180 gdk_screen_get_height_mm (GdkScreen *screen)
181 {
182   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
183
184   return HeightMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
185 }
186
187 /**
188  * gdk_screen_get_number:
189  * @screen: a #GdkScreen
190  *
191  * Gets the index of @screen among the screens in the display
192  * to which it belongs. (See gdk_screen_get_display())
193  * 
194  * Returns: the index
195  **/
196 gint
197 gdk_screen_get_number (GdkScreen *screen)
198 {
199   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
200   
201   return GDK_SCREEN_X11 (screen)->screen_num;
202 }
203
204 /**
205  * gdk_screen_get_root_window:
206  * @screen: a #GdkScreen
207  *
208  * Gets the root window of @screen. 
209  * 
210  * Returns: the root window
211  **/
212 GdkWindow *
213 gdk_screen_get_root_window (GdkScreen *screen)
214 {
215   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
216
217   return GDK_SCREEN_X11 (screen)->root_window;
218 }
219
220 /**
221  * gdk_screen_get_default_colormap:
222  * @screen: a #GdkScreen
223  *
224  * Gets the default colormap for @screen.
225  * 
226  * Returns: the default #GdkColormap.
227  **/
228 GdkColormap *
229 gdk_screen_get_default_colormap (GdkScreen *screen)
230 {
231   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
232
233   return GDK_SCREEN_X11 (screen)->default_colormap;
234 }
235
236 /**
237  * gdk_screen_set_default_colormap:
238  * @screen: a #GdkScreen
239  * @colormap: a #GdkColormap
240  *
241  * Sets the default @colormap for @screen.
242  **/
243 void
244 gdk_screen_set_default_colormap (GdkScreen   *screen,
245                                  GdkColormap *colormap)
246 {
247   GdkColormap *old_colormap;
248   
249   g_return_if_fail (GDK_IS_SCREEN (screen));
250   g_return_if_fail (GDK_IS_COLORMAP (colormap));
251
252   old_colormap = GDK_SCREEN_X11 (screen)->default_colormap;
253
254   GDK_SCREEN_X11 (screen)->default_colormap = g_object_ref (colormap);
255   
256   if (old_colormap)
257     g_object_unref (old_colormap);
258 }
259
260 static void
261 gdk_screen_x11_dispose (GObject *object)
262 {
263   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
264
265   _gdk_x11_events_uninit_screen (GDK_SCREEN (object));
266
267   g_object_unref (screen_x11->default_colormap);
268   screen_x11->default_colormap = NULL;
269   
270   screen_x11->root_window = NULL;
271
272   screen_x11->xdisplay = NULL;
273   screen_x11->xscreen = NULL;
274   screen_x11->screen_num = -1;
275   screen_x11->xroot_window = None;
276   screen_x11->wmspec_check_window = None;
277   
278   G_OBJECT_CLASS (parent_class)->dispose (object);
279 }
280
281 static void
282 gdk_screen_x11_finalize (GObject *object)
283 {
284   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
285   /* int i; */
286   g_object_unref (screen_x11->root_window);
287   
288   /* Visual Part (Need to implement finalize for Visuals for a clean
289    * finalize) */
290   /* for (i=0;i<screen_x11->nvisuals;i++)
291     g_object_unref (screen_x11->visuals[i]);*/
292   g_free (screen_x11->visuals);
293   g_hash_table_destroy (screen_x11->visual_hash);
294
295   g_free (screen_x11->window_manager_name);  
296
297   g_hash_table_destroy (screen_x11->colormap_hash);
298   /* X settings */
299   g_free (screen_x11->xsettings_client);
300   g_free (screen_x11->monitors);
301   
302   G_OBJECT_CLASS (parent_class)->finalize (object);
303 }
304
305 /**
306  * gdk_screen_get_n_monitors:
307  * @screen : a #GdkScreen.
308  *
309  * Returns the number of monitors being part of the virtual screen
310  *
311  * Returns: number of monitors part of the virtual screen or
312  *          0 if @screen is not in virtual screen mode.
313  **/
314 gint 
315 gdk_screen_get_n_monitors (GdkScreen *screen)
316 {
317   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
318   
319   return GDK_SCREEN_X11 (screen)->num_monitors;
320 }
321
322 /**
323  * gdk_screen_get_monitor_geometry:
324  * @screen : a #GdkScreen.
325  * @monitor_num: the monitor number. 
326  * @dest : a #GdkRectangle to be filled with the monitor geometry
327  *
328  * Retrieves the #GdkRectangle representing the size and start
329  * coordinates of the individual monitor within the the entire virtual
330  * screen.
331  * 
332  * Note that the virtual screen coordinates can be retrieved via 
333  * gdk_screen_get_width() and gdk_screen_get_height().
334  *
335  **/
336 void 
337 gdk_screen_get_monitor_geometry (GdkScreen    *screen,
338                                  gint          monitor_num,
339                                  GdkRectangle *dest)
340 {
341   g_return_if_fail (GDK_IS_SCREEN (screen));
342   g_return_if_fail (monitor_num < GDK_SCREEN_X11 (screen)->num_monitors);
343   g_return_if_fail (monitor_num >= 0);
344
345   *dest = GDK_SCREEN_X11 (screen)->monitors[monitor_num];
346 }
347
348 /**
349  * gdk_x11_screen_get_xscreen:
350  * @screen: a #GdkScreen.
351  * @returns: an Xlib <type>Screen*</type>
352  *
353  * Returns the screen of a #GdkScreen.
354  */
355 Screen *
356 gdk_x11_screen_get_xscreen (GdkScreen *screen)
357 {
358   return GDK_SCREEN_X11 (screen)->xscreen;
359 }
360
361
362 /**
363  * gdk_x11_screen_get_screen_number:
364  * @screen: a #GdkScreen.
365  * @returns: the position of @screen among the screens of
366  *   its display.
367  *
368  * Returns the index of a #GdkScreen.
369  */
370 int
371 gdk_x11_screen_get_screen_number (GdkScreen *screen)
372 {
373   return GDK_SCREEN_X11 (screen)->screen_num;
374 }
375
376 GdkScreen *
377 _gdk_x11_screen_new (GdkDisplay *display,
378                      gint        screen_number) 
379 {
380   GdkScreen *screen;
381   GdkScreenX11 *screen_x11;
382   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
383
384   screen = g_object_new (GDK_TYPE_SCREEN_X11, NULL);
385
386   screen_x11 = GDK_SCREEN_X11 (screen);
387   screen_x11->display = display;
388   screen_x11->xdisplay = display_x11->xdisplay;
389   screen_x11->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
390   screen_x11->screen_num = screen_number;
391   screen_x11->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
392   screen_x11->wmspec_check_window = None;
393   /* we want this to be always non-null */
394   screen_x11->window_manager_name = g_strdup ("unknown");
395   
396   init_xinerama_support (screen);
397   init_randr_support (screen);
398   
399   _gdk_visual_init (screen);
400   _gdk_windowing_window_init (screen);
401
402   return screen;
403 }
404
405 #ifdef HAVE_XINERAMA
406 static gboolean
407 check_solaris_xinerama (GdkScreen *screen)
408 {
409 #ifdef HAVE_SOLARIS_XINERAMA
410   
411   if (XineramaGetState (GDK_SCREEN_XDISPLAY (screen),
412                         gdk_screen_get_number (screen)))
413     {
414       XRectangle monitors[MAXFRAMEBUFFERS];
415       unsigned char hints[16];
416       gint result;
417       GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
418
419       result = XineramaGetInfo (GDK_SCREEN_XDISPLAY (screen),
420                                 gdk_screen_get_number (screen),
421                                 monitors, hints,
422                                 &screen_x11->num_monitors);
423       /* Yes I know it should be Success but the current implementation 
424           returns the num of monitor*/
425       if (result == 0)
426         {
427           /* FIXME: We need to trap errors, since XINERAMA isn't always XINERAMA.
428            */ 
429           g_error ("error while retrieving Xinerama information");
430         }
431       else
432         {
433           int i;
434           screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
435           
436           for (i = 0; i < screen_x11->num_monitors; i++)
437             {
438               screen_x11->monitors[i].x = monitors[i].x;
439               screen_x11->monitors[i].y = monitors[i].y;
440               screen_x11->monitors[i].width = monitors[i].width;
441               screen_x11->monitors[i].height = monitors[i].height;
442             }
443
444           return TRUE;
445         }
446     }
447 #endif /* HAVE_SOLARIS_XINERAMA */
448   
449   return FALSE;
450 }
451
452 static gboolean
453 check_xfree_xinerama (GdkScreen *screen)
454 {
455 #ifdef HAVE_XFREE_XINERAMA
456   if (XineramaIsActive (GDK_SCREEN_XDISPLAY (screen)))
457     {
458       GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
459       XineramaScreenInfo *monitors = XineramaQueryScreens (GDK_SCREEN_XDISPLAY (screen),
460                                                            &screen_x11->num_monitors);
461       if (screen_x11->num_monitors <= 0)
462         {
463           /* FIXME: We need to trap errors, since XINERAMA isn't always XINERAMA.
464            *        I don't think the num_monitors <= 0 check has any validity.
465            */ 
466           g_error ("error while retrieving Xinerama information");
467         }
468       else
469         {
470           int i;
471           screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
472           
473           for (i = 0; i < screen_x11->num_monitors; i++)
474             {
475               screen_x11->monitors[i].x = monitors[i].x_org;
476               screen_x11->monitors[i].y = monitors[i].y_org;
477               screen_x11->monitors[i].width = monitors[i].width;
478               screen_x11->monitors[i].height = monitors[i].height;
479             }
480
481           XFree (monitors);
482
483           return TRUE;
484         }
485     }
486 #endif /* HAVE_XFREE_XINERAMA */
487   
488   return FALSE;
489 }
490 #endif /* HAVE_XINERAMA */
491
492 static void
493 init_xinerama_support (GdkScreen * screen)
494 {
495   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
496 #ifdef HAVE_XINERAMA
497   int opcode, firstevent, firsterror;
498 #endif
499
500   if (screen_x11->monitors)
501     g_free (screen_x11->monitors);
502   
503 #ifdef HAVE_XINERAMA  
504   if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
505                        &opcode, &firstevent, &firsterror))
506     {
507       if (check_solaris_xinerama (screen) ||
508           check_xfree_xinerama (screen))
509         return;
510     }
511 #endif /* HAVE_XINERAMA */
512
513   /* No Xinerama
514    */
515   screen_x11->num_monitors = 1;
516   screen_x11->monitors = g_new0 (GdkRectangle, 1);
517   screen_x11->monitors[0].x = 0;
518   screen_x11->monitors[0].y = 0;
519   screen_x11->monitors[0].width = WidthOfScreen (screen_x11->xscreen);
520   screen_x11->monitors[0].height = HeightOfScreen (screen_x11->xscreen);
521 }
522
523 static void
524 init_randr_support (GdkScreen * screen)
525 {
526   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
527   
528   XSelectInput (GDK_SCREEN_XDISPLAY (screen),
529                 screen_x11->xroot_window,
530                 StructureNotifyMask);
531 }
532
533 void
534 _gdk_x11_screen_size_changed (GdkScreen *screen,
535                               XEvent    *event)
536 {
537 #ifdef HAVE_RANDR
538   if (!XRRUpdateConfiguration (event))
539     return;
540 #else
541   if (event->type == ConfigureNotify)
542     {
543       XConfigureEvent *rcevent = (XConfigureEvent *) event;
544       Screen        *xscreen = gdk_x11_screen_get_xscreen (screen);
545       
546       xscreen->width   = rcevent->width;
547       xscreen->height  = rcevent->height;
548     }
549   else
550     return;
551 #endif
552   
553   init_xinerama_support (screen);
554   g_signal_emit_by_name (G_OBJECT (screen), "size_changed");
555 }
556
557 void
558 _gdk_x11_screen_window_manager_changed (GdkScreen *screen)
559 {
560   g_signal_emit (G_OBJECT (screen),
561                  signals[WINDOW_MANAGER_CHANGED], 0);
562 }
563
564 /**
565  * _gdk_windowing_substitute_screen_number:
566  * @display_name : The name of a display, in the form used by 
567  *                 gdk_display_open (). If %NULL a default value
568  *                 will be used. On X11, this is derived from the DISPLAY
569  *                 environment variable.
570  * @screen_number : The number of a screen within the display
571  *                  referred to by @display_name.
572  *
573  * Modifies a @display_name to make @screen_number the default
574  * screen when the display is opened.
575  *
576  * Return value: a newly allocated string holding the resulting
577  *   display name. Free with g_free().
578  */
579 gchar * 
580 _gdk_windowing_substitute_screen_number (const gchar *display_name,
581                                          gint         screen_number)
582 {
583   GString *str;
584   gchar   *p;
585
586   if (!display_name)
587     display_name = getenv ("DISPLAY");
588
589   if (!display_name)
590     return NULL;
591
592   str = g_string_new (display_name);
593
594   p = strrchr (str->str, '.');
595   if (p && p >  strchr (str->str, ':'))
596     g_string_truncate (str, p - str->str);
597
598   g_string_append_printf (str, ".%d", screen_number);
599
600   return g_string_free (str, FALSE);
601 }
602
603 /**
604  * gdk_screen_make_display_name:
605  * @screen: a #GdkScreen
606  * 
607  * Determines the name to pass to gdk_display_open() to get
608  * a #GdkDisplay with this screen as the default screen.
609  * 
610  * Return value: a newly allocated string, free with g_free()
611  **/
612 gchar *
613 gdk_screen_make_display_name (GdkScreen *screen)
614 {
615   const gchar *old_display;
616
617   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
618
619   old_display = gdk_display_get_name (gdk_screen_get_display (screen));
620
621   return _gdk_windowing_substitute_screen_number (old_display, 
622                                                   gdk_screen_get_number (screen));
623 }