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