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