]> Pileus Git - ~andy/gtk/blob - gdk/gdkscreen.c
Fix for #314004, reported by Michael Reinsch:
[~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 "gdkalias.h"
30
31 static void gdk_screen_class_init  (GdkScreenClass *klass);
32 static void gdk_screen_init        (GdkScreen      *screen);
33 static void gdk_screen_dispose     (GObject        *object);
34 static void gdk_screen_finalize    (GObject        *object);
35
36 enum
37 {
38   SIZE_CHANGED,
39   LAST_SIGNAL
40 };
41
42 static guint signals[LAST_SIGNAL] = { 0 };
43
44 static gpointer parent_class = NULL;
45
46 GType
47 gdk_screen_get_type (void)
48 {
49   static GType object_type = 0;
50
51   if (!object_type)
52     {
53       static const GTypeInfo object_info =
54         {
55           sizeof (GdkScreenClass),
56           (GBaseInitFunc) gdk_screen_init,
57           (GBaseFinalizeFunc) NULL,
58           (GClassInitFunc) gdk_screen_class_init,
59           NULL,                 /* class_finalize */
60           NULL,                 /* class_data */
61           sizeof (GdkScreen),
62           0,                    /* n_preallocs */
63           (GInstanceInitFunc) NULL,
64         };
65       
66       object_type = g_type_register_static (G_TYPE_OBJECT,
67                                             "GdkScreen", &object_info, 0);
68     }
69
70   return object_type;
71 }
72
73 static void
74 gdk_screen_class_init (GdkScreenClass *klass)
75 {
76   GObjectClass *object_class = G_OBJECT_CLASS (klass);
77
78   parent_class = g_type_class_peek_parent (klass);
79   
80   object_class->dispose = gdk_screen_dispose;
81   object_class->finalize = gdk_screen_finalize;
82   
83   /**
84    * GdkScreen::size-changed:
85    * @screen: the object on which the signal is emitted
86    * 
87    * The ::size_changed signal is emitted when the pixel width or 
88    * height of a screen changes.
89    *
90    * Since: 2.2
91    */
92   signals[SIZE_CHANGED] =
93     g_signal_new ("size_changed",
94                   G_OBJECT_CLASS_TYPE (klass),
95                   G_SIGNAL_RUN_LAST,
96                   G_STRUCT_OFFSET (GdkScreenClass, size_changed),
97                   NULL, NULL,
98                   g_cclosure_marshal_VOID__VOID,
99                   G_TYPE_NONE,
100                   0);
101 }
102
103 static void
104 gdk_screen_init (GdkScreen *screen)
105 {
106     screen->resolution = -1;
107 }
108
109 static void
110 gdk_screen_dispose (GObject *object)
111 {
112   GdkScreen *screen = GDK_SCREEN (object);
113   gint i;
114
115   for (i = 0; i < 32; ++i)
116     {
117       if (screen->exposure_gcs[i])
118         g_object_unref (screen->exposure_gcs[i]);
119
120       if (screen->normal_gcs[i])
121         g_object_unref (screen->normal_gcs[i]);
122     }
123
124   G_OBJECT_CLASS (parent_class)->dispose (object);
125 }
126
127 static void
128 gdk_screen_finalize (GObject *object)
129 {
130   GdkScreen *screen = GDK_SCREEN (object);
131
132   if (screen->font_options)
133       cairo_font_options_destroy (screen->font_options);
134
135   G_OBJECT_CLASS (parent_class)->finalize (object);
136 }
137
138 void 
139 _gdk_screen_close (GdkScreen *screen)
140 {
141   g_return_if_fail (GDK_IS_SCREEN (screen));
142
143   if (!screen->closed)
144     {
145       screen->closed = TRUE;
146       g_object_run_dispose (G_OBJECT (screen));
147     }
148 }
149
150 /* Fallback used when the monitor "at" a point or window
151  * doesn't exist.
152  */
153 static gint
154 get_nearest_monitor (GdkScreen *screen,
155                      gint       x,
156                      gint       y)
157 {
158   gint num_monitors, i;
159   gint nearest_dist = G_MAXINT;
160   gint nearest_monitor = 0;
161   
162   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
163
164   num_monitors = gdk_screen_get_n_monitors (screen);
165   
166   for (i = 0; i < num_monitors; i++)
167     {
168       GdkRectangle monitor;
169       gint dist_x, dist_y;
170       
171       gdk_screen_get_monitor_geometry (screen, i, &monitor);
172
173       if (x < monitor.x)
174         dist_x = monitor.x - x;
175       else if (x >= monitor.x + monitor.width)
176         dist_x = x - (monitor.x + monitor.width) + 1;
177       else
178         dist_x = 0;
179
180       if (y < monitor.y)
181         dist_y = monitor.y - y;
182       else if (y >= monitor.y + monitor.height)
183         dist_y = y - (monitor.y + monitor.height) + 1;
184       else
185         dist_y = 0;
186
187       if (MIN (dist_x, dist_y) < nearest_dist)
188         {
189           nearest_dist = MIN (dist_x, dist_y);
190           nearest_monitor = i;
191         }
192     }
193
194   return nearest_monitor;
195 }
196
197 /**
198  * gdk_screen_get_monitor_at_point:
199  * @screen: a #GdkScreen.
200  * @x: the x coordinate in the virtual screen.
201  * @y: the y coordinate in the virtual screen.
202  *
203  * Returns the monitor number in which the point (@x,@y) is located.
204  *
205  * Returns: the monitor number in which the point (@x,@y) lies, or
206  *   a monitor close to (@x,@y) if the point is not in any monitor.
207  *
208  * Since: 2.2
209  **/
210 gint 
211 gdk_screen_get_monitor_at_point (GdkScreen *screen,
212                                  gint       x,
213                                  gint       y)
214 {
215   gint num_monitors, i;
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       
225       gdk_screen_get_monitor_geometry (screen, i, &monitor);
226
227       if (x >= monitor.x &&
228           x < monitor.x + monitor.width &&
229           y >= monitor.y &&
230           y < (monitor.y + monitor.height))
231         return i;
232     }
233
234   return get_nearest_monitor (screen, x, y);
235 }
236
237 /**
238  * gdk_screen_get_monitor_at_window:
239  * @screen: a #GdkScreen.
240  * @window: a #GdkWindow
241  * @returns: the monitor number in which most of @window is located,
242  *           or if @window does not intersect any monitors, a monitor,
243  *           close to @window.
244  *
245  * Returns the number of the monitor in which the largest area of the 
246  * bounding rectangle of @window resides.
247  *
248  * Since: 2.2
249  **/
250 gint 
251 gdk_screen_get_monitor_at_window (GdkScreen      *screen,
252                                   GdkWindow      *window)
253 {
254   gint num_monitors, i, area = 0, screen_num = -1;
255   GdkRectangle win_rect;
256   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
257   
258   gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width,
259                            &win_rect.height, NULL);
260   gdk_window_get_origin (window, &win_rect.x, &win_rect.y);
261   num_monitors = gdk_screen_get_n_monitors (screen);
262   
263   for (i=0;i<num_monitors;i++)
264     {
265       GdkRectangle tmp_monitor, intersect;
266       
267       gdk_screen_get_monitor_geometry (screen, i, &tmp_monitor);
268       gdk_rectangle_intersect (&win_rect, &tmp_monitor, &intersect);
269       
270       if (intersect.width * intersect.height > area)
271         { 
272           area = intersect.width * intersect.height;
273           screen_num = i;
274         }
275     }
276   if (screen_num >= 0)
277     return screen_num;
278   else
279     return get_nearest_monitor (screen,
280                                 win_rect.x + win_rect.width / 2,
281                                 win_rect.y + win_rect.height / 2);
282 }
283
284 /**
285  * gdk_screen_width:
286  * 
287  * Returns the width of the default screen in pixels.
288  * 
289  * Return value: the width of the default screen in pixels.
290  **/
291 gint
292 gdk_screen_width (void)
293 {
294   return gdk_screen_get_width (gdk_screen_get_default());
295 }
296
297 /**
298  * gdk_screen_height:
299  * 
300  * Returns the height of the default screen in pixels.
301  * 
302  * Return value: the height of the default screen in pixels.
303  **/
304 gint
305 gdk_screen_height (void)
306 {
307   return gdk_screen_get_height (gdk_screen_get_default());
308 }
309
310 /**
311  * gdk_screen_width_mm:
312  * 
313  * Returns the width of the default screen in millimeters.
314  * Note that on many X servers this value will not be correct.
315  * 
316  * Return value: the width of the default screen in millimeters,
317  * though it is not always correct.
318  **/
319 gint
320 gdk_screen_width_mm (void)
321 {
322   return gdk_screen_get_width_mm (gdk_screen_get_default());
323 }
324
325 /**
326  * gdk_screen_height_mm:
327  * 
328  * Returns the height of the default screen in millimeters.
329  * Note that on many X servers this value will not be correct.
330  * 
331  * Return value: the height of the default screen in millimeters,
332  * though it is not always correct.
333  **/
334 gint
335 gdk_screen_height_mm (void)
336 {
337   return gdk_screen_get_height_mm (gdk_screen_get_default ());
338 }
339
340 /**
341  * gdk_screen_set_font_options_libgtk_only:
342  * @screen: a #GdkScreen
343  * @options: a #cairo_font_options_t, or %NULL to unset any
344  *   previously set default font options.
345  *
346  * Sets the default font options for the screen. These
347  * options will be set on any #PangoContext's newly created
348  * with gdk_pango_context_get_for_screen(). Changing the
349  * default set of font options does not affect contexts that
350  * have already been created.
351  * 
352  * This function is not part of the GDK public API and is only
353  * for use by GTK+.
354  **/
355 void
356 gdk_screen_set_font_options_libgtk_only (GdkScreen                  *screen,
357                                          const cairo_font_options_t *options)
358 {
359     g_return_if_fail (GDK_IS_SCREEN (screen));
360
361     if (screen->font_options)
362         cairo_font_options_destroy (screen->font_options);
363
364     if (options)
365         screen->font_options = cairo_font_options_copy (options);
366     else
367         screen->font_options = NULL;
368 }
369
370 /**
371  * gdk_screen_get_font_options_libgtk_only:
372  * @screen: a #GdkScreen
373  * 
374  * Gets any options previously set with gdk_screen_set_font_options_libgtk_only().
375  * 
376  * Return value: the current font options, or %NULL if no default
377  *  font options have been set.
378  **/
379 const cairo_font_options_t *
380 gdk_screen_get_font_options_libgtk_only (GdkScreen *screen)
381 {
382     g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
383
384     return screen->font_options;
385 }
386
387 /**
388  * gdk_screen_set_resolution_libgtk_only:
389  * @screen: a #GdkScreen
390  * @dpi: the resolution in "dots per inch". (Physical inches aren't actually
391  *   involved; the terminology is conventional.)
392  
393  * Sets the resolution for font handling on the screen. This is a
394  * scale factor between points specified in a #PangoFontDescription
395  * and cairo units. The default value is 96, meaning that a 10 point
396  * font will be 13 units high. (10 * 96. / 72. = 13.3).
397  *
398  * This function is not part of the GDK public API and is only
399  * for use by GTK+.
400  **/
401 void
402 gdk_screen_set_resolution_libgtk_only (GdkScreen *screen,
403                                        gdouble    dpi)
404 {
405     g_return_if_fail (GDK_IS_SCREEN (screen));
406
407     if (dpi >= 0)
408         screen->resolution = dpi;
409     else
410         screen->resolution = -1;
411 }
412
413 /**
414  * gdk_screen_get_resolution_libgtk_only:
415  * @screen: a #GdkScreen
416  * 
417  * Gets the resolution for font handling on the screen; see
418  * gdk_screen_set_resolution_libgtk_only() for full details.
419  * 
420  * Return value: the current resolution, or -1 if no resolution
421  * has been set.
422  **/
423 gdouble
424 gdk_screen_get_resolution_libgtk_only (GdkScreen *screen)
425 {
426     g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
427
428     return screen->resolution;
429 }
430
431 #define __GDK_SCREEN_C__
432 #include "gdkaliasdef.c"