]> Pileus Git - ~andy/gtk/blob - gdk/gdkscreen.c
Add RandR 1.2 support
[~andy/gtk] / gdk / gdkscreen.c
1 /*
2  * gdkscreen.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 "gdk.h"                /* For gdk_rectangle_intersect() */
26 #include "gdkcolor.h"
27 #include "gdkwindow.h"
28 #include "gdkscreen.h"
29 #include "gdkintl.h"
30 #include "gdkalias.h"
31
32 static void gdk_screen_dispose      (GObject        *object);
33 static void gdk_screen_finalize     (GObject        *object);
34 static void gdk_screen_set_property (GObject        *object,
35                                      guint           prop_id,
36                                      const GValue   *value,
37                                      GParamSpec     *pspec);
38 static void gdk_screen_get_property (GObject        *object,
39                                      guint           prop_id,
40                                      GValue         *value,
41                                      GParamSpec     *pspec);
42
43 enum
44 {
45   PROP_0,
46   PROP_FONT_OPTIONS,
47   PROP_RESOLUTION
48 };
49
50 enum
51 {
52   SIZE_CHANGED,
53   COMPOSITED_CHANGED,
54   MONITORS_CHANGED,
55   LAST_SIGNAL
56 };
57
58 static guint signals[LAST_SIGNAL] = { 0 };
59
60 G_DEFINE_TYPE (GdkScreen, gdk_screen, G_TYPE_OBJECT)
61
62 static void
63 gdk_screen_class_init (GdkScreenClass *klass)
64 {
65   GObjectClass *object_class = G_OBJECT_CLASS (klass);
66
67   object_class->dispose = gdk_screen_dispose;
68   object_class->finalize = gdk_screen_finalize;
69   object_class->set_property = gdk_screen_set_property;
70   object_class->get_property = gdk_screen_get_property;
71   
72   g_object_class_install_property (object_class,
73                                    PROP_FONT_OPTIONS,
74                                    g_param_spec_pointer ("font-options",
75                                                          P_("Font options"),
76                                                          P_("The default font options for the screen"),
77                                                          G_PARAM_READWRITE|G_PARAM_STATIC_NAME|
78                                                         G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
79
80   g_object_class_install_property (object_class,
81                                    PROP_RESOLUTION,
82                                    g_param_spec_double ("resolution",
83                                                         P_("Font resolution"),
84                                                         P_("The resolution for fonts on the screen"),
85                                                         -G_MAXDOUBLE,
86                                                         G_MAXDOUBLE,
87                                                         -1.0,
88                                                         G_PARAM_READWRITE|G_PARAM_STATIC_NAME|
89                                                         G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
90
91   /**
92    * GdkScreen::size-changed:
93    * @screen: the object on which the signal is emitted
94    * 
95    * The ::size_changed signal is emitted when the pixel width or 
96    * height of a screen changes.
97    *
98    * Since: 2.2
99    */
100   signals[SIZE_CHANGED] =
101     g_signal_new (g_intern_static_string ("size_changed"),
102                   G_OBJECT_CLASS_TYPE (klass),
103                   G_SIGNAL_RUN_LAST,
104                   G_STRUCT_OFFSET (GdkScreenClass, size_changed),
105                   NULL, NULL,
106                   g_cclosure_marshal_VOID__VOID,
107                   G_TYPE_NONE,
108                   0);
109
110   /**
111    * GdkScreen::composited-changed:
112    * @screen: the object on which the signal is emitted
113    *
114    * The ::composited_changed signal is emitted when the composited
115    * status of the screen changes
116    *
117    * Since: 2.10
118    */
119   signals[COMPOSITED_CHANGED] =
120     g_signal_new (g_intern_static_string ("composited_changed"),
121                   G_OBJECT_CLASS_TYPE (klass),
122                   G_SIGNAL_RUN_LAST,
123                   G_STRUCT_OFFSET (GdkScreenClass, composited_changed),
124                   NULL, NULL,
125                   g_cclosure_marshal_VOID__VOID,
126                   G_TYPE_NONE,
127                   0);
128         
129   /**
130    * GdkScreen::monitors-changed:
131    * @screen: the object on which the signal is emitted
132    *
133    * The ::monitors_changed signal is emitted when the number, size
134    * or position of the monitors attached to the screen change. 
135    *
136    * Only for X for now. Future implementations for Win32 and
137    * OS X may be a possibility.
138    *
139    * Since: 2.14
140    */
141   signals[MONITORS_CHANGED] =
142     g_signal_new (g_intern_static_string ("monitors_changed"),
143                   G_OBJECT_CLASS_TYPE (klass),
144                   G_SIGNAL_RUN_LAST,
145                   G_STRUCT_OFFSET (GdkScreenClass, monitors_changed),
146                   NULL, NULL,
147                   g_cclosure_marshal_VOID__VOID,
148                   G_TYPE_NONE,
149                   0);
150 }
151
152 static void
153 gdk_screen_init (GdkScreen *screen)
154 {
155     screen->resolution = -1.;
156 }
157
158 static void
159 gdk_screen_dispose (GObject *object)
160 {
161   GdkScreen *screen = GDK_SCREEN (object);
162   gint i;
163
164   for (i = 0; i < 32; ++i)
165     {
166       if (screen->exposure_gcs[i])
167         {
168           g_object_unref (screen->exposure_gcs[i]);
169           screen->exposure_gcs[i] = NULL;
170         }
171
172       if (screen->normal_gcs[i])
173         {
174           g_object_unref (screen->normal_gcs[i]);
175           screen->normal_gcs[i] = NULL;
176         }
177     }
178
179   G_OBJECT_CLASS (gdk_screen_parent_class)->dispose (object);
180 }
181
182 static void
183 gdk_screen_finalize (GObject *object)
184 {
185   GdkScreen *screen = GDK_SCREEN (object);
186
187   if (screen->font_options)
188       cairo_font_options_destroy (screen->font_options);
189
190   G_OBJECT_CLASS (gdk_screen_parent_class)->finalize (object);
191 }
192
193 void 
194 _gdk_screen_close (GdkScreen *screen)
195 {
196   g_return_if_fail (GDK_IS_SCREEN (screen));
197
198   if (!screen->closed)
199     {
200       screen->closed = TRUE;
201       g_object_run_dispose (G_OBJECT (screen));
202     }
203 }
204
205 /* Fallback used when the monitor "at" a point or window
206  * doesn't exist.
207  */
208 static gint
209 get_nearest_monitor (GdkScreen *screen,
210                      gint       x,
211                      gint       y)
212 {
213   gint num_monitors, i;
214   gint nearest_dist = G_MAXINT;
215   gint nearest_monitor = 0;
216   
217   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
218
219   num_monitors = gdk_screen_get_n_monitors (screen);
220   
221   for (i = 0; i < num_monitors; i++)
222     {
223       GdkRectangle monitor;
224       gint dist_x, dist_y;
225       
226       gdk_screen_get_monitor_geometry (screen, i, &monitor);
227
228       if (x < monitor.x)
229         dist_x = monitor.x - x;
230       else if (x >= monitor.x + monitor.width)
231         dist_x = x - (monitor.x + monitor.width) + 1;
232       else
233         dist_x = 0;
234
235       if (y < monitor.y)
236         dist_y = monitor.y - y;
237       else if (y >= monitor.y + monitor.height)
238         dist_y = y - (monitor.y + monitor.height) + 1;
239       else
240         dist_y = 0;
241
242       if (MIN (dist_x, dist_y) < nearest_dist)
243         {
244           nearest_dist = MIN (dist_x, dist_y);
245           nearest_monitor = i;
246         }
247     }
248
249   return nearest_monitor;
250 }
251
252 /**
253  * gdk_screen_get_monitor_at_point:
254  * @screen: a #GdkScreen.
255  * @x: the x coordinate in the virtual screen.
256  * @y: the y coordinate in the virtual screen.
257  *
258  * Returns the monitor number in which the point (@x,@y) is located.
259  *
260  * Returns: the monitor number in which the point (@x,@y) lies, or
261  *   a monitor close to (@x,@y) if the point is not in any monitor.
262  *
263  * Since: 2.2
264  **/
265 gint 
266 gdk_screen_get_monitor_at_point (GdkScreen *screen,
267                                  gint       x,
268                                  gint       y)
269 {
270   gint num_monitors, i;
271   
272   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
273
274   num_monitors = gdk_screen_get_n_monitors (screen);
275   
276   for (i=0;i<num_monitors;i++)
277     {
278       GdkRectangle monitor;
279       
280       gdk_screen_get_monitor_geometry (screen, i, &monitor);
281
282       if (x >= monitor.x &&
283           x < monitor.x + monitor.width &&
284           y >= monitor.y &&
285           y < (monitor.y + monitor.height))
286         return i;
287     }
288
289   return get_nearest_monitor (screen, x, y);
290 }
291
292 /**
293  * gdk_screen_get_monitor_at_window:
294  * @screen: a #GdkScreen.
295  * @window: a #GdkWindow
296  * @returns: the monitor number in which most of @window is located,
297  *           or if @window does not intersect any monitors, a monitor,
298  *           close to @window.
299  *
300  * Returns the number of the monitor in which the largest area of the 
301  * bounding rectangle of @window resides.
302  *
303  * Since: 2.2
304  **/
305 gint 
306 gdk_screen_get_monitor_at_window (GdkScreen      *screen,
307                                   GdkWindow      *window)
308 {
309   gint num_monitors, i, area = 0, screen_num = -1;
310   GdkRectangle win_rect;
311   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
312   
313   gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width,
314                            &win_rect.height, NULL);
315   gdk_window_get_origin (window, &win_rect.x, &win_rect.y);
316   num_monitors = gdk_screen_get_n_monitors (screen);
317   
318   for (i=0;i<num_monitors;i++)
319     {
320       GdkRectangle tmp_monitor, intersect;
321       
322       gdk_screen_get_monitor_geometry (screen, i, &tmp_monitor);
323       gdk_rectangle_intersect (&win_rect, &tmp_monitor, &intersect);
324       
325       if (intersect.width * intersect.height > area)
326         { 
327           area = intersect.width * intersect.height;
328           screen_num = i;
329         }
330     }
331   if (screen_num >= 0)
332     return screen_num;
333   else
334     return get_nearest_monitor (screen,
335                                 win_rect.x + win_rect.width / 2,
336                                 win_rect.y + win_rect.height / 2);
337 }
338
339 /**
340  * gdk_screen_width:
341  * 
342  * Returns the width of the default screen in pixels.
343  * 
344  * Return value: the width of the default screen in pixels.
345  **/
346 gint
347 gdk_screen_width (void)
348 {
349   return gdk_screen_get_width (gdk_screen_get_default());
350 }
351
352 /**
353  * gdk_screen_height:
354  * 
355  * Returns the height of the default screen in pixels.
356  * 
357  * Return value: the height of the default screen in pixels.
358  **/
359 gint
360 gdk_screen_height (void)
361 {
362   return gdk_screen_get_height (gdk_screen_get_default());
363 }
364
365 /**
366  * gdk_screen_width_mm:
367  * 
368  * Returns the width of the default screen in millimeters.
369  * Note that on many X servers this value will not be correct.
370  * 
371  * Return value: the width of the default screen in millimeters,
372  * though it is not always correct.
373  **/
374 gint
375 gdk_screen_width_mm (void)
376 {
377   return gdk_screen_get_width_mm (gdk_screen_get_default());
378 }
379
380 /**
381  * gdk_screen_height_mm:
382  * 
383  * Returns the height of the default screen in millimeters.
384  * Note that on many X servers this value will not be correct.
385  * 
386  * Return value: the height of the default screen in millimeters,
387  * though it is not always correct.
388  **/
389 gint
390 gdk_screen_height_mm (void)
391 {
392   return gdk_screen_get_height_mm (gdk_screen_get_default ());
393 }
394
395 /**
396  * gdk_screen_set_font_options:
397  * @screen: a #GdkScreen
398  * @options: a #cairo_font_options_t, or %NULL to unset any
399  *   previously set default font options.
400  *
401  * Sets the default font options for the screen. These
402  * options will be set on any #PangoContext's newly created
403  * with gdk_pango_context_get_for_screen(). Changing the
404  * default set of font options does not affect contexts that
405  * have already been created.
406  *
407  * Since: 2.10
408  **/
409 void
410 gdk_screen_set_font_options (GdkScreen                  *screen,
411                              const cairo_font_options_t *options)
412 {
413     g_return_if_fail (GDK_IS_SCREEN (screen));
414
415     if (screen->font_options != options)
416       {
417         if (screen->font_options)
418           cairo_font_options_destroy (screen->font_options);
419         
420         if (options)
421           screen->font_options = cairo_font_options_copy (options);
422         else
423           screen->font_options = NULL;
424         
425         g_object_notify (G_OBJECT (screen), "font-options");
426       }
427 }
428
429 /**
430  * gdk_screen_get_font_options:
431  * @screen: a #GdkScreen
432  * 
433  * Gets any options previously set with gdk_screen_set_font_options().
434  * 
435  * Return value: the current font options, or %NULL if no default
436  *  font options have been set.
437  *
438  * Since: 2.10
439  **/
440 const cairo_font_options_t *
441 gdk_screen_get_font_options (GdkScreen *screen)
442 {
443     g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
444
445     return screen->font_options;
446 }
447
448 /**
449  * gdk_screen_set_resolution:
450  * @screen: a #GdkScreen
451  * @dpi: the resolution in "dots per inch". (Physical inches aren't actually
452  *   involved; the terminology is conventional.)
453  
454  * Sets the resolution for font handling on the screen. This is a
455  * scale factor between points specified in a #PangoFontDescription
456  * and cairo units. The default value is 96, meaning that a 10 point
457  * font will be 13 units high. (10 * 96. / 72. = 13.3).
458  *
459  * Since: 2.10
460  **/
461 void
462 gdk_screen_set_resolution (GdkScreen *screen,
463                            gdouble    dpi)
464 {
465     g_return_if_fail (GDK_IS_SCREEN (screen));
466
467     if (dpi < 0)
468       dpi = -1.0;
469
470     if (screen->resolution != dpi)
471       {
472         screen->resolution = dpi;
473
474         g_object_notify (G_OBJECT (screen), "resolution");
475       }
476 }
477
478 /**
479  * gdk_screen_get_resolution:
480  * @screen: a #GdkScreen
481  * 
482  * Gets the resolution for font handling on the screen; see
483  * gdk_screen_set_resolution() for full details.
484  * 
485  * Return value: the current resolution, or -1 if no resolution
486  * has been set.
487  *
488  * Since: 2.10
489  **/
490 gdouble
491 gdk_screen_get_resolution (GdkScreen *screen)
492 {
493     g_return_val_if_fail (GDK_IS_SCREEN (screen), -1.);
494
495     return screen->resolution;
496 }
497
498 static void
499 gdk_screen_get_property (GObject      *object,
500                          guint         prop_id,
501                          GValue       *value,
502                          GParamSpec   *pspec)
503 {
504   GdkScreen *screen = GDK_SCREEN (object);
505
506   switch (prop_id)
507     {
508     case PROP_FONT_OPTIONS:
509       g_value_set_pointer (value, gdk_screen_get_font_options (screen));
510       break;
511     case PROP_RESOLUTION:
512       g_value_set_double (value, gdk_screen_get_resolution (screen));
513       break;
514     default:
515       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
516       break;
517     }
518 }
519
520 static void
521 gdk_screen_set_property (GObject      *object,
522                          guint         prop_id,
523                          const GValue *value,
524                          GParamSpec   *pspec)
525 {
526   GdkScreen *screen = GDK_SCREEN (object);
527
528   switch (prop_id)
529     {
530     case PROP_FONT_OPTIONS:
531       gdk_screen_set_font_options (screen, g_value_get_pointer (value));
532       break;
533     case PROP_RESOLUTION:
534       gdk_screen_set_resolution (screen, g_value_get_double (value));
535       break;
536     default:
537       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
538       break;
539     }
540 }
541
542 #define __GDK_SCREEN_C__
543 #include "gdkaliasdef.c"