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