]> Pileus Git - ~andy/gtk/blob - gdk/gdkscreen.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~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
30 static void gdk_screen_class_init  (GdkScreenClass *klass);
31 static void gdk_screen_dispose     (GObject        *object);
32
33 enum
34 {
35   SIZE_CHANGED,
36   LAST_SIGNAL
37 };
38
39 static guint signals[LAST_SIGNAL] = { 0 };
40
41 static gpointer parent_class = NULL;
42
43 GType
44 gdk_screen_get_type (void)
45 {
46   static GType object_type = 0;
47
48   if (!object_type)
49     {
50       static const GTypeInfo object_info =
51         {
52           sizeof (GdkScreenClass),
53           (GBaseInitFunc) NULL,
54           (GBaseFinalizeFunc) NULL,
55           (GClassInitFunc) gdk_screen_class_init,
56           NULL,                 /* class_finalize */
57           NULL,                 /* class_data */
58           sizeof (GdkScreen),
59           0,                    /* n_preallocs */
60           (GInstanceInitFunc) NULL,
61         };
62       
63       object_type = g_type_register_static (G_TYPE_OBJECT,
64                                             "GdkScreen", &object_info, 0);
65     }
66
67   return object_type;
68 }
69
70 static void
71 gdk_screen_class_init (GdkScreenClass *klass)
72 {
73   GObjectClass *object_class = G_OBJECT_CLASS (klass);
74
75   parent_class = g_type_class_peek_parent (klass);
76   
77   object_class->dispose = gdk_screen_dispose;
78   
79   /**
80    * GdkScreen::size-changed:
81    * @screen: the object on which the signal is emitted
82    * 
83    * The ::size_changed signal is emitted when the pixel width or 
84    * height of a screen changes.
85    *
86    * Since: 2.2
87    */
88   signals[SIZE_CHANGED] =
89     g_signal_new ("size_changed",
90                   G_OBJECT_CLASS_TYPE (klass),
91                   G_SIGNAL_RUN_LAST,
92                   G_STRUCT_OFFSET (GdkScreenClass, size_changed),
93                   NULL, NULL,
94                   g_cclosure_marshal_VOID__VOID,
95                   G_TYPE_NONE,
96                   0);
97 }
98
99 static void
100 gdk_screen_dispose (GObject *object)
101 {
102   GdkScreen *screen = GDK_SCREEN (object);
103   gint i;
104
105   for (i = 0; i < 32; ++i)
106     {
107       if (screen->exposure_gcs[i])
108         g_object_unref (screen->exposure_gcs[i]);
109
110       if (screen->normal_gcs[i])
111         g_object_unref (screen->normal_gcs[i]);
112     }
113
114   G_OBJECT_CLASS (parent_class)->dispose (object);
115 }
116
117 void 
118 _gdk_screen_close (GdkScreen *screen)
119 {
120   g_return_if_fail (GDK_IS_SCREEN (screen));
121
122   if (!screen->closed)
123     {
124       screen->closed = TRUE;
125       g_object_run_dispose (G_OBJECT (screen));
126     }
127 }
128
129 /* Fallback used when the monitor "at" a point or window
130  * doesn't exist.
131  */
132 static gint
133 get_nearest_monitor (GdkScreen *screen,
134                      gint       x,
135                      gint       y)
136 {
137   gint num_monitors, i;
138   gint nearest_dist = G_MAXINT;
139   gint nearest_monitor = 0;
140   
141   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
142
143   num_monitors = gdk_screen_get_n_monitors (screen);
144   
145   for (i = 0; i < num_monitors; i++)
146     {
147       GdkRectangle monitor;
148       gint dist_x, dist_y;
149       
150       gdk_screen_get_monitor_geometry (screen, i, &monitor);
151
152       if (x < monitor.x)
153         dist_x = monitor.x - x;
154       else if (x >= monitor.x + monitor.width)
155         dist_x = x - (monitor.x + monitor.width) + 1;
156       else
157         dist_x = 0;
158
159       if (y < monitor.y)
160         dist_y = monitor.y - y;
161       else if (y >= monitor.y + monitor.height)
162         dist_y = y - (monitor.y + monitor.height) + 1;
163       else
164         dist_y = 0;
165
166       if (MIN (dist_x, dist_y) < nearest_dist)
167         {
168           nearest_dist = MIN (dist_x, dist_y);
169           nearest_monitor = i;
170         }
171     }
172
173   return nearest_monitor;
174 }
175
176 /**
177  * gdk_screen_get_monitor_at_point:
178  * @screen: a #GdkScreen.
179  * @x: the x coordinate in the virtual screen.
180  * @y: the y coordinate in the virtual screen.
181  *
182  * Returns the monitor number in which the point (@x,@y) is located.
183  *
184  * Returns: the monitor number in which the point (@x,@y) lies, or
185  *   a monitor close to (@x,@y) if the point is not in any monitor.
186  *
187  * Since: 2.2
188  **/
189 gint 
190 gdk_screen_get_monitor_at_point (GdkScreen *screen,
191                                  gint       x,
192                                  gint       y)
193 {
194   gint num_monitors, i;
195   
196   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
197
198   num_monitors = gdk_screen_get_n_monitors (screen);
199   
200   for (i=0;i<num_monitors;i++)
201     {
202       GdkRectangle monitor;
203       
204       gdk_screen_get_monitor_geometry (screen, i, &monitor);
205
206       if (x >= monitor.x &&
207           x < monitor.x + monitor.width &&
208           y >= monitor.y &&
209           y < (monitor.y + monitor.height))
210         return i;
211     }
212
213   return get_nearest_monitor (screen, x, y);
214 }
215
216 /**
217  * gdk_screen_get_monitor_at_window:
218  * @screen: a #GdkScreen.
219  * @window: a #GdkWindow
220  * @returns: the monitor number in which most of @window is located,
221  *           or if @window does not intersect any monitors, a monitor,
222  *           close to @window.
223  *
224  * Returns the number of the monitor in which the largest area of the 
225  * bounding rectangle of @window resides.
226  *
227  * Since: 2.2
228  **/
229 gint 
230 gdk_screen_get_monitor_at_window (GdkScreen      *screen,
231                                   GdkWindow      *window)
232 {
233   gint num_monitors, i, area = 0, screen_num = -1;
234   GdkRectangle win_rect;
235   g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
236   
237   gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width,
238                            &win_rect.height, NULL);
239   gdk_window_get_origin (window, &win_rect.x, &win_rect.y);
240   num_monitors = gdk_screen_get_n_monitors (screen);
241   
242   for (i=0;i<num_monitors;i++)
243     {
244       GdkRectangle tmp_monitor, intersect;
245       
246       gdk_screen_get_monitor_geometry (screen, i, &tmp_monitor);
247       gdk_rectangle_intersect (&win_rect, &tmp_monitor, &intersect);
248       
249       if (intersect.width * intersect.height > area)
250         { 
251           area = intersect.width * intersect.height;
252           screen_num = i;
253         }
254     }
255   if (screen_num >= 0)
256     return screen_num;
257   else
258     return get_nearest_monitor (screen,
259                                 win_rect.x + win_rect.width / 2,
260                                 win_rect.y + win_rect.height / 2);
261 }
262
263 /**
264  * gdk_screen_width:
265  * 
266  * Returns the width of the default screen in pixels.
267  * 
268  * Return value: the width of the default screen in pixels.
269  **/
270 gint
271 gdk_screen_width (void)
272 {
273   return gdk_screen_get_width (gdk_screen_get_default());
274 }
275
276 /**
277  * gdk_screen_height:
278  * 
279  * Returns the height of the default screen in pixels.
280  * 
281  * Return value: the height of the default screen in pixels.
282  **/
283 gint
284 gdk_screen_height (void)
285 {
286   return gdk_screen_get_height (gdk_screen_get_default());
287 }
288
289 /**
290  * gdk_screen_width_mm:
291  * 
292  * Returns the width of the default screen in millimeters.
293  * Note that on many X servers this value will not be correct.
294  * 
295  * Return value: the width of the default screen in millimeters,
296  * though it is not always correct.
297  **/
298 gint
299 gdk_screen_width_mm (void)
300 {
301   return gdk_screen_get_width_mm (gdk_screen_get_default());
302 }
303
304 /**
305  * gdk_screen_height_mm:
306  * 
307  * Returns the height of the default screen in millimeters.
308  * Note that on many X servers this value will not be correct.
309  * 
310  * Return value: the height of the default screen in millimeters,
311  * though it is not always correct.
312  **/
313 gint
314 gdk_screen_height_mm (void)
315 {
316   return gdk_screen_get_height_mm (gdk_screen_get_default ());
317 }