]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkscreen-x11.c
Always select for property notify for maintaining window state.
[~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 GdkDisplay * gdk_screen_x11_get_display           (GdkScreen             *screen);
40 static gint         gdk_screen_x11_get_width             (GdkScreen             *screen);
41 static gint         gdk_screen_x11_get_height            (GdkScreen             *screen);
42 static gint         gdk_screen_x11_get_width_mm          (GdkScreen             *screen);
43 static gint         gdk_screen_x11_get_height_mm         (GdkScreen             *screen);
44 static gint         gdk_screen_x11_get_default_depth     (GdkScreen             *screen);
45 static GdkWindow *  gdk_screen_x11_get_root_window       (GdkScreen             *screen);
46 static gint         gdk_screen_x11_get_screen_num        (GdkScreen             *screen);
47 static GdkColormap *gdk_screen_x11_get_default_colormap  (GdkScreen             *screen);
48 static void         gdk_screen_x11_set_default_colormap  (GdkScreen             *screen,
49                                                           GdkColormap           *colormap);
50 static GdkWindow *  gdk_screen_x11_get_window_at_pointer (GdkScreen             *screen,
51                                                           gint                  *win_x,
52                                                           gint                  *win_y);
53 static void         gdk_screen_x11_finalize              (GObject               *object);
54
55 static gint          gdk_screen_x11_get_n_monitors        (GdkScreen       *screen);
56 static void          gdk_screen_x11_get_monitor_geometry  (GdkScreen       *screen,
57                                                            gint             num_monitor,
58                                                            GdkRectangle    *dest);
59 static void          init_xinerama_support                (GdkScreen * screen);
60
61
62 GType gdk_screen_x11_get_type ();
63 static gpointer parent_class = NULL;
64
65 GType
66 gdk_screen_x11_get_type ()
67 {
68   static GType object_type = 0;
69
70   if (!object_type)
71     {
72       static const GTypeInfo object_info =
73         {
74           sizeof (GdkScreenX11Class),
75           (GBaseInitFunc) NULL,
76           (GBaseFinalizeFunc) gdk_screen_x11_finalize,
77           (GClassInitFunc) gdk_screen_x11_class_init,
78           NULL,                 /* class_finalize */
79           NULL,                 /* class_data */
80           sizeof (GdkScreenX11),
81           0,                    /* n_preallocs */
82           (GInstanceInitFunc) NULL,
83         };
84       object_type = g_type_register_static (GDK_TYPE_SCREEN,
85                                             "GdkScreenX11",
86                                             &object_info, 0);
87     }
88   return object_type;
89 }
90
91 void
92 gdk_screen_x11_class_init (GdkScreenX11Class * klass)
93 {
94   GdkScreenClass *screen_class = GDK_SCREEN_CLASS (klass);
95   
96   screen_class->get_display = gdk_screen_x11_get_display;
97   screen_class->get_width = gdk_screen_x11_get_width;
98   screen_class->get_height = gdk_screen_x11_get_height;
99   screen_class->get_width_mm = gdk_screen_x11_get_width_mm;
100   screen_class->get_height_mm = gdk_screen_x11_get_height_mm;
101   screen_class->get_root_depth = gdk_screen_x11_get_default_depth;
102   screen_class->get_screen_num = gdk_screen_x11_get_screen_num;
103   screen_class->get_root_window = gdk_screen_x11_get_root_window;
104   screen_class->get_default_colormap = gdk_screen_x11_get_default_colormap;
105   screen_class->set_default_colormap = gdk_screen_x11_set_default_colormap;
106   screen_class->get_window_at_pointer = gdk_screen_x11_get_window_at_pointer;
107   screen_class->get_n_monitors = gdk_screen_x11_get_n_monitors;
108   screen_class->get_monitor_geometry = gdk_screen_x11_get_monitor_geometry;
109   
110   G_OBJECT_CLASS (klass)->finalize = gdk_screen_x11_finalize;
111   parent_class = g_type_class_peek_parent (klass);
112 }
113
114 static GdkDisplay *
115 gdk_screen_x11_get_display (GdkScreen *screen)
116 {
117   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
118
119   return screen_x11->display;
120 }
121
122 static gint
123 gdk_screen_x11_get_width (GdkScreen *screen)
124 {
125   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
126
127   return WidthOfScreen (screen_x11->xscreen);
128 }
129
130 static gint
131 gdk_screen_x11_get_height (GdkScreen *screen)
132 {
133   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
134
135   return HeightOfScreen (screen_x11->xscreen);
136 }
137
138 static gint
139 gdk_screen_x11_get_width_mm (GdkScreen *screen)
140 {
141   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
142
143   return WidthMMOfScreen (screen_x11->xscreen);
144 }
145
146 static gint
147 gdk_screen_x11_get_height_mm (GdkScreen *screen)
148 {
149   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
150
151   return HeightMMOfScreen (screen_x11->xscreen);
152 }
153
154 static gint
155 gdk_screen_x11_get_default_depth (GdkScreen *screen)
156 {
157   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
158
159   return DefaultDepthOfScreen (screen_x11->xscreen);
160 }
161
162 static gint
163 gdk_screen_x11_get_screen_num (GdkScreen *screen)
164 {
165   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
166   
167   return screen_x11->screen_num;
168 }
169
170 static GdkWindow *
171 gdk_screen_x11_get_root_window (GdkScreen *screen)
172 {
173   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
174
175   return screen_x11->root_window;
176 }
177
178 static GdkColormap *
179 gdk_screen_x11_get_default_colormap (GdkScreen *screen)
180 {
181   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
182
183   return screen_x11->default_colormap;
184 }
185
186 static void
187 gdk_screen_x11_set_default_colormap (GdkScreen *screen,
188                                      GdkColormap * colormap)
189 {
190   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
191   
192   screen_x11->default_colormap = colormap;
193 }
194
195 static GdkWindow *
196 gdk_screen_x11_get_window_at_pointer (GdkScreen *screen,
197                                       gint      *win_x,
198                                       gint      *win_y)
199 {
200   GdkWindow *window;
201   Window root;
202   Window xwindow;
203   Window xwindow_last = 0;
204   Display *xdisplay;
205   int rootx = -1, rooty = -1;
206   int winx, winy;
207   unsigned int xmask;
208
209   xwindow = GDK_SCREEN_XROOTWIN (screen);
210   xdisplay = GDK_SCREEN_XDISPLAY (screen);
211
212   XGrabServer (xdisplay);
213   while (xwindow)
214     {
215       xwindow_last = xwindow;
216       XQueryPointer (xdisplay, xwindow,
217                      &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
218     }
219   XUngrabServer (xdisplay);
220
221   window = gdk_window_lookup_for_display (GDK_SCREEN_DISPLAY(screen),
222                                           xwindow_last);
223   if (win_x)
224     *win_x = window ? winx : -1;
225   if (win_y)
226     *win_y = window ? winy : -1;
227
228   return window;
229 }
230
231 static void
232 gdk_screen_x11_finalize (GObject *object)
233 {
234   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
235   /* int i; */
236   g_object_unref (G_OBJECT (screen_x11->root_window));
237   
238   /* Visual Part (Need to implement finalize for Visuals for a clean
239    * finalize) */
240   /* for (i=0;i<screen_x11->nvisuals;i++)
241     g_object_unref (G_OBJECT (screen_x11->visuals[i]));*/
242   g_free (screen_x11->visuals);
243   g_hash_table_destroy (screen_x11->visual_hash);
244   /* X settings */
245   g_free (screen_x11->xsettings_client);
246   G_OBJECT_CLASS (parent_class)->finalize (object);
247 }
248
249 static gint 
250 gdk_screen_x11_get_n_monitors (GdkScreen *screen)
251 {
252   g_return_val_if_fail (GDK_IS_SCREEN (screen), 1);
253   return GDK_SCREEN_X11 (screen)->num_monitors;
254 }
255
256 static void
257 gdk_screen_x11_get_monitor_geometry (GdkScreen    *screen, 
258                                      gint          num_monitor,
259                                      GdkRectangle *dest)
260 {
261   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
262   g_return_if_fail (num_monitor < GDK_SCREEN_X11 (screen)->num_monitors);
263
264   *dest = screen_x11->monitors[num_monitor];
265 }
266
267 /**
268  * gdk_x11_screen_get_xscreen:
269  * @screen: a #GdkScreen.
270  * @returns: an Xlib <type>Screen*</type>
271  *
272  * Returns the screen of a #GdkScreen.
273  */
274 Screen *
275 gdk_x11_screen_get_xscreen (GdkScreen *screen)
276 {
277   return GDK_SCREEN_X11 (screen)->xscreen;
278 }
279
280
281 /**
282  * gdk_x11_screen_get_screen_number:
283  * @screen: a #GdkScreen.
284  * @returns: the position of @screen among the screens of
285  *   its display.
286  *
287  * Returns the index of a #GdkScreen.
288  */
289 int
290 gdk_x11_screen_get_screen_number (GdkScreen *screen)
291 {
292   return GDK_SCREEN_X11 (screen)->screen_num;
293 }
294
295 GdkScreen *
296 _gdk_x11_screen_new (GdkDisplay *display,
297                      gint        screen_number) 
298 {
299   GdkScreen *screen;
300   GdkScreenX11 *screen_x11;
301   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
302
303   screen = g_object_new (GDK_TYPE_SCREEN_X11, NULL);
304
305   screen_x11 = GDK_SCREEN_X11 (screen);
306   screen_x11->display = display;
307   screen_x11->xdisplay = display_x11->xdisplay;
308   screen_x11->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
309   screen_x11->screen_num = screen_number;
310   screen_x11->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
311   screen_x11->wmspec_check_window = None;
312
313   init_xinerama_support (screen);
314   
315   _gdk_visual_init (screen);
316   _gdk_windowing_window_init (screen);
317   _gdk_x11_events_init_screen (screen);
318
319   return screen;
320 }
321
322 #ifdef HAVE_XINERAMA
323 static gboolean
324 check_solaris_xinerama (GdkScreen *screen)
325 {
326 #ifdef HAVE_SOLARIS_XINERAMA
327   
328   if (XineramaGetState (GDK_SCREEN_XDISPLAY (screen),
329                         gdk_screen_get_number (screen)))
330     {
331       XRectangle monitors[MAXFRAMEBUFFERS];
332       char hints[16];
333       gint result;
334       GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
335
336       result = XineramaGetInfo (GDK_SCREEN_XDISPLAY (screen),
337                                 gdk_screen_get_number (screen),
338                                 monitors, hints,
339                                 &screen_x11->num_monitors);
340       /* Yes I know it should be Success but the current implementation 
341           returns the num of monitor*/
342       if (result == 0)
343         {
344           /* FIXME: We need to trap errors, since XINERAMA isn't always XINERAMA.
345            */ 
346           g_error ("error while retrieving Xinerama information");
347         }
348       else
349         {
350           int i;
351           screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
352           
353           for (i = 0; i < screen_x11->num_monitors; i++)
354             {
355               screen_x11->monitors[i].x = monitors[i].x;
356               screen_x11->monitors[i].y = monitors[i].y;
357               screen_x11->monitors[i].width = monitors[i].width;
358               screen_x11->monitors[i].height = monitors[i].height;
359             }
360
361           return TRUE;
362         }
363     }
364 #endif /* HAVE_SOLARIS_XINERAMA */
365   
366   return FALSE;
367 }
368
369 static gboolean
370 check_xfree_xinerama (GdkScreen *screen)
371 {
372 #ifdef HAVE_XFREE_XINERAMA
373   if (XineramaIsActive (GDK_SCREEN_XDISPLAY (screen)))
374     {
375       XineramaScreenInfo *monitors = XineramaQueryScreens (GDK_SCREEN_XDISPLAY (screen),
376                                                            &screen_x11->num_monitors);
377       if (screen_x11->num_monitors <= 0)
378         {
379           /* FIXME: We need to trap errors, since XINERAMA isn't always XINERAMA.
380            *        I don't think the num_monitors <= 0 check has any validity.
381            */ 
382           g_error ("error while retrieving Xinerama information");
383         }
384       else
385         {
386           int i;
387           screen_x11->monitors = g_new0 (GdkRectangle, screen_x11->num_monitors);
388           
389           for (i = 0; i < screen_x11->num_monitors; i++)
390             {
391               screen_x11->monitors[i].x = monitors[i].x_org;
392               screen_x11->monitors[i].y = monitors[i].y_org;
393               screen_x11->monitors[i].width = monitors[i].width;
394               screen_x11->monitors[i].height = monitors[i].height;
395             }
396
397           XFree (monitors);
398
399           return TRUE;
400         }
401     }
402 #endif /* HAVE_XFREE_XINERAMA */
403   
404   return FALSE;
405 }
406 #endif /* HAVE_XINERAMA */
407
408 static void
409 init_xinerama_support (GdkScreen * screen)
410 {
411   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
412   
413 #ifdef HAVE_XINERAMA
414   int opcode, firstevent, firsterror;
415   gint result;
416   
417   if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
418                        &opcode, &firstevent, &firsterror))
419     {
420       if (check_solaris_xinerama (screen) ||
421           check_xfree_xinerama (screen))
422         return;
423     }
424 #endif /* HAVE_XINERAMA */
425
426   /* No Xinerama
427    */
428   screen_x11->num_monitors = 1;
429   screen_x11->monitors = g_new0 (GdkRectangle, 1);
430   screen_x11->monitors[0].x = 0;
431   screen_x11->monitors[0].y = 0;
432   screen_x11->monitors[0].width = WidthOfScreen (screen_x11->xscreen);
433   screen_x11->monitors[0].height = HeightOfScreen (screen_x11->xscreen);
434 }
435