]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkscreen-quartz.c
Register and handle a display reconfiguration callback
[~andy/gtk] / gdk / quartz / gdkscreen-quartz.c
1 /* gdkscreen-quartz.c
2  *
3  * Copyright (C) 2005 Imendio AB
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22 #include "gdk.h"
23 #include "gdkprivate-quartz.h"
24  
25 /* FIXME: If we want to do it properly, this should be stored
26  * in a proper GdkScreen subclass.
27  */
28 static GdkColormap *default_colormap = NULL;
29 static int n_screens = 0;
30 static GdkRectangle *screen_rects = NULL;
31
32 static guint screen_changed_id = 0;
33
34
35 static void
36 screen_rects_init (void)
37 {
38   NSArray *array;
39   NSRect largest_rect;
40   int i;
41
42   GDK_QUARTZ_ALLOC_POOL;
43
44   array = [NSScreen screens];
45
46   n_screens = [array count];
47   screen_rects = g_new0 (GdkRectangle, n_screens);
48
49   /* FIXME: as stated above the get_width() and get_height() functions
50    * in this file, we only support horizontal screen layouts for now.
51    */
52
53   /* Find the monitor with the largest height.  All monitors should be
54    * offset to this one in the GDK screen space instead of offset to
55    * the screen with the menu bar.
56    */
57   largest_rect = [[array objectAtIndex:0] frame];
58   for (i = 1; i < [array count]; i++)
59     {
60       NSRect rect = [[array objectAtIndex:i] frame];
61
62       if (rect.size.height > largest_rect.size.height)
63         largest_rect = [[array objectAtIndex:i] frame];
64     }
65
66   for (i = 0; i < n_screens; i++)
67     {
68       NSScreen *nsscreen;
69       NSRect rect;
70
71       nsscreen = [array objectAtIndex:i];
72       rect = [nsscreen frame];
73
74       screen_rects[i].x = rect.origin.x;
75       screen_rects[i].width = rect.size.width;
76       screen_rects[i].height = rect.size.height;
77
78       if (largest_rect.size.height - rect.size.height == 0)
79         screen_rects[i].y = 0;
80       else
81         screen_rects[i].y = largest_rect.size.height - rect.size.height + largest_rect.origin.y;
82     }
83
84   GDK_QUARTZ_RELEASE_POOL;
85 }
86
87 static void
88 screen_rects_free (void)
89 {
90   n_screens = 0;
91
92   g_free (screen_rects);
93   screen_rects = NULL;
94 }
95
96
97 static void
98 process_display_reconfiguration (void)
99 {
100   screen_rects_free ();
101   screen_rects_init ();
102
103   /* FIXME: We should only emit this when the size of screen really
104    * has changed.  We need to start bookkeeping width, height once
105    * we have a proper GdkScreen subclass.
106    */
107   g_signal_emit_by_name (_gdk_screen, "size-changed");
108 }
109
110 static gboolean
111 screen_changed_idle (gpointer data)
112 {
113   process_display_reconfiguration ();
114
115   screen_changed_id = 0;
116
117   return FALSE;
118 }
119
120 static void
121 screen_changed (CGDirectDisplayID            display,
122                 CGDisplayChangeSummaryFlags  flags,
123                 void                        *userInfo)
124 {
125   if (flags & kCGDisplayBeginConfigurationFlag)
126     {
127       /* Ignore the begin configuration signal. */
128
129       /* FIXME: We can most probably use this flag to properly
130        * emit monitors-changed.
131        */
132       return;
133     }
134   else
135     {
136       /* At this point Cocoa does not know about the new screen data
137        * yet, so we delay our refresh into an idle handler.
138        */
139
140       if (!screen_changed_id)
141         screen_changed_id = gdk_threads_add_idle (screen_changed_idle, NULL);
142     }
143 }
144
145 void
146 _gdk_quartz_screen_init (void)
147 {
148   gdk_screen_set_default_colormap (_gdk_screen,
149                                    gdk_screen_get_system_colormap (_gdk_screen));
150
151   screen_rects_init ();
152
153   CGDisplayRegisterReconfigurationCallback (screen_changed,
154                                             _gdk_screen);
155 }
156
157 GdkDisplay *
158 gdk_screen_get_display (GdkScreen *screen)
159 {
160   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
161
162   return _gdk_display;
163 }
164
165
166 GdkWindow *
167 gdk_screen_get_root_window (GdkScreen *screen)
168 {
169   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
170
171   return _gdk_root;
172 }
173
174 gint
175 gdk_screen_get_number (GdkScreen *screen)
176 {
177   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
178
179   return 0;
180 }
181
182 gchar * 
183 _gdk_windowing_substitute_screen_number (const gchar *display_name,
184                                          int          screen_number)
185 {
186   if (screen_number != 0)
187     return NULL;
188
189   return g_strdup (display_name);
190 }
191
192 GdkColormap*
193 gdk_screen_get_default_colormap (GdkScreen *screen)
194 {
195   return default_colormap;
196 }
197
198 void
199 gdk_screen_set_default_colormap (GdkScreen   *screen,
200                                  GdkColormap *colormap)
201 {
202   GdkColormap *old_colormap;
203   
204   g_return_if_fail (GDK_IS_SCREEN (screen));
205   g_return_if_fail (GDK_IS_COLORMAP (colormap));
206
207   old_colormap = default_colormap;
208
209   default_colormap = g_object_ref (colormap);
210   
211   if (old_colormap)
212     g_object_unref (old_colormap);
213 }
214
215 /* FIXME: note on the get_width() and the get_height() methods.  For
216  * now we only support screen layouts where the screens are laid out
217  * horizontally.  Mac OS X also supports laying out the screens vertically
218  * and the screens having "non-standard" offsets from eachother.  In the
219  * future we need a much more sophiscated algorithm to translate these
220  * layouts to GDK coordinate space and GDK screen layout.
221  */
222 gint
223 gdk_screen_get_width (GdkScreen *screen)
224 {
225   int i;
226   int width;
227   NSArray *array;
228
229   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
230
231   GDK_QUARTZ_ALLOC_POOL;
232   array = [NSScreen screens];
233
234   width = 0;
235   for (i = 0; i < [array count]; i++) 
236     {
237       NSRect rect = [[array objectAtIndex:i] frame];
238       width += rect.size.width;
239     }
240
241   GDK_QUARTZ_RELEASE_POOL;
242
243   return width;
244 }
245
246 gint
247 gdk_screen_get_height (GdkScreen *screen)
248 {
249   int i;
250   int height;
251   NSArray *array;
252
253   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
254
255   GDK_QUARTZ_ALLOC_POOL;
256   array = [NSScreen screens];
257
258   height = 0;
259   for (i = 0; i < [array count]; i++) 
260     {
261       NSRect rect = [[array objectAtIndex:i] frame];
262       height = MAX (height, rect.size.height);
263     }
264
265   GDK_QUARTZ_RELEASE_POOL;
266
267   return height;
268 }
269
270 static gint
271 get_mm_from_pixels (NSScreen *screen, int pixels)
272 {
273   /* userSpaceScaleFactor is in "pixels per point", 
274    * 72 is the number of points per inch, 
275    * and 25.4 is the number of millimeters per inch.
276    */
277 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_3
278   float dpi = [screen userSpaceScaleFactor] * 72.0;
279 #else
280   float dpi = 96.0 / 72.0;
281 #endif
282
283   return (pixels / dpi) * 25.4;
284 }
285
286 gint
287 gdk_screen_get_width_mm (GdkScreen *screen)
288 {
289   int i;
290   gint width;
291   NSArray *array;
292
293   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
294
295   GDK_QUARTZ_ALLOC_POOL;
296   array = [NSScreen screens];
297
298   width = 0;
299   for (i = 0; i < [array count]; i++)
300     {
301       NSScreen *screen = [array objectAtIndex:i];
302       NSRect rect = [screen frame];
303       width += get_mm_from_pixels (screen, rect.size.width);
304     }
305
306   GDK_QUARTZ_RELEASE_POOL;
307
308   return width;
309 }
310
311 gint
312 gdk_screen_get_height_mm (GdkScreen *screen)
313 {
314   int i;
315   gint height;
316   NSArray *array;
317
318   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
319
320   GDK_QUARTZ_ALLOC_POOL;
321   array = [NSScreen screens];
322
323   height = 0;
324   for (i = 0; i < [array count]; i++)
325     {
326       NSScreen *screen = [array objectAtIndex:i];
327       NSRect rect = [screen frame];
328       gint h = get_mm_from_pixels (screen, rect.size.height);
329       height = MAX (height, h);
330     }
331
332   GDK_QUARTZ_RELEASE_POOL;
333
334   return height;
335 }
336
337 int
338 gdk_screen_get_n_monitors (GdkScreen *screen)
339 {
340   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
341
342   return n_screens;
343 }
344
345 static NSScreen *
346 get_nsscreen_for_monitor (gint monitor_num)
347 {
348   NSArray *array;
349   NSScreen *screen;
350
351   GDK_QUARTZ_ALLOC_POOL;
352
353   array = [NSScreen screens];
354   screen = [array objectAtIndex:monitor_num];
355
356   GDK_QUARTZ_RELEASE_POOL;
357
358   return screen;
359 }
360
361 gint
362 gdk_screen_get_monitor_width_mm (GdkScreen *screen,
363                                  gint       monitor_num)
364 {
365   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
366   g_return_val_if_fail (monitor_num < gdk_screen_get_n_monitors (screen), 0);
367   g_return_val_if_fail (monitor_num >= 0, 0);
368
369   return get_mm_from_pixels (get_nsscreen_for_monitor (monitor_num),
370                              screen_rects[monitor_num].width);
371 }
372
373 gint
374 gdk_screen_get_monitor_height_mm (GdkScreen *screen,
375                                   gint       monitor_num)
376 {
377   g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
378   g_return_val_if_fail (monitor_num < gdk_screen_get_n_monitors (screen), 0);
379   g_return_val_if_fail (monitor_num >= 0, 0);
380
381   return get_mm_from_pixels (get_nsscreen_for_monitor (monitor_num),
382                              screen_rects[monitor_num].height);
383 }
384
385 gchar *
386 gdk_screen_get_monitor_plug_name (GdkScreen *screen,
387                                   gint       monitor_num)
388 {
389   /* FIXME: Is there some useful name we could use here? */
390   return NULL;
391 }
392
393 void
394 gdk_screen_get_monitor_geometry (GdkScreen    *screen, 
395                                  gint          monitor_num,
396                                  GdkRectangle *dest)
397 {
398   g_return_if_fail (GDK_IS_SCREEN (screen));
399   g_return_if_fail (monitor_num < gdk_screen_get_n_monitors (screen));
400   g_return_if_fail (monitor_num >= 0);
401
402   *dest = screen_rects[monitor_num];
403 }
404
405 gchar *
406 gdk_screen_make_display_name (GdkScreen *screen)
407 {
408   return g_strdup (gdk_display_get_name (_gdk_display));
409 }
410
411 GdkWindow *
412 gdk_screen_get_active_window (GdkScreen *screen)
413 {
414   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
415
416   return NULL;
417 }
418
419 GList *
420 gdk_screen_get_window_stack (GdkScreen *screen)
421 {
422   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
423
424   return NULL;
425 }
426
427 gboolean
428 gdk_screen_is_composited (GdkScreen *screen)
429 {
430   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
431
432   return TRUE;
433 }