1 /* gdkwindow-quartz.c
2 *
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * Copyright (C) 2005-2007 Imendio AB
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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "config.h"
21
22 #include <gdk/gdk.h>
23 #include <gdk/gdkdeviceprivate.h>
24 #include <gdk/gdkdisplayprivate.h>
25
26 #include "gdkwindowimpl.h"
27 #include "gdkwindow-quartz.h"
28 #include "gdkprivate-quartz.h"
29 #include "gdkglcontext-quartz.h"
30 #include "gdkquartzglcontext.h"
31 #include "gdkquartzscreen.h"
32 #include "gdkquartzcursor.h"
33 #include "gdkquartz-cocoa-access.h"
34 #include "gdkinternal-quartz.h"
35
36 #include <Carbon/Carbon.h>
37 #include <AvailabilityMacros.h>
38
39 #include <sys/time.h>
40 #include <cairo-quartz.h>
41
42 static gpointer parent_class;
43 static gpointer root_window_parent_class;
44
45 static GSList *update_nswindows;
46 static gboolean in_process_all_updates = FALSE;
47
48 static GSList *main_window_stack;
49
50 void _gdk_quartz_window_flush (GdkWindowImplQuartz *window_impl);
51
52 typedef struct
53 {
54 gint x, y;
55 gint width, height;
56 GdkWMDecoration decor;
57 } FullscreenSavedGeometry;
58
59 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
60 typedef enum
61 {
62 GDK_QUARTZ_BORDERLESS_WINDOW = NSBorderlessWindowMask,
63 GDK_QUARTZ_CLOSABLE_WINDOW = NSClosableWindowMask,
64 #if MAC_OS_X_VERSION_MIN_REQUIRED > 1060
65 /* Added in 10.7. Apple's docs are wrong to say it's from earlier. */
66 GDK_QUARTZ_FULLSCREEN_WINDOW = NSFullScreenWindowMask,
67 #endif
68 GDK_QUARTZ_MINIATURIZABLE_WINDOW = NSMiniaturizableWindowMask,
69 GDK_QUARTZ_RESIZABLE_WINDOW = NSResizableWindowMask,
70 GDK_QUARTZ_TITLED_WINDOW = NSTitledWindowMask,
71 } GdkQuartzWindowMask;
72 #else
73 typedef enum
74 {
75 GDK_QUARTZ_BORDERLESS_WINDOW = NSWindowStyleMaskBorderless,
76 GDK_QUARTZ_CLOSABLE_WINDOW = NSWindowStyleMaskClosable,
77 GDK_QUARTZ_FULLSCREEN_WINDOW = NSWindowStyleMaskFullScreen,
78 GDK_QUARTZ_MINIATURIZABLE_WINDOW = NSWindowStyleMaskMiniaturizable,
79 GDK_QUARTZ_RESIZABLE_WINDOW = NSWindowStyleMaskResizable,
80 GDK_QUARTZ_TITLED_WINDOW = NSWindowStyleMaskTitled,
81 } GdkQuartzWindowMask;
82 #endif
83
84 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
85 static FullscreenSavedGeometry *get_fullscreen_geometry (GdkWindow *window);
86 #endif
87
88 #define FULLSCREEN_DATA "fullscreen-data"
89
90 static void update_toplevel_order (void);
91 static void clear_toplevel_order (void);
92
93 #define WINDOW_IS_TOPLEVEL(window) \
94 (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
95 GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \
96 GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
97
98 /*
99 * GdkQuartzWindow
100 */
101
102 struct _GdkQuartzWindow
103 {
104 GdkWindow parent;
105 };
106
107 struct _GdkQuartzWindowClass
108 {
109 GdkWindowClass parent_class;
110 };
111
112 G_DEFINE_TYPE (GdkQuartzWindow, gdk_quartz_window, GDK_TYPE_WINDOW);
113
114 static void
gdk_quartz_window_class_init(GdkQuartzWindowClass * quartz_window_class)115 gdk_quartz_window_class_init (GdkQuartzWindowClass *quartz_window_class)
116 {
117 }
118
119 static void
gdk_quartz_window_init(GdkQuartzWindow * quartz_window)120 gdk_quartz_window_init (GdkQuartzWindow *quartz_window)
121 {
122 }
123
124
125 /*
126 * GdkQuartzWindowImpl
127 */
128
129 NSView *
gdk_quartz_window_get_nsview(GdkWindow * window)130 gdk_quartz_window_get_nsview (GdkWindow *window)
131 {
132 if (GDK_WINDOW_DESTROYED (window))
133 return NULL;
134
135 return ((GdkWindowImplQuartz *)window->impl)->view;
136 }
137
138 NSWindow *
gdk_quartz_window_get_nswindow(GdkWindow * window)139 gdk_quartz_window_get_nswindow (GdkWindow *window)
140 {
141 if (GDK_WINDOW_DESTROYED (window))
142 return NULL;
143
144 return ((GdkWindowImplQuartz *)window->impl)->toplevel;
145 }
146
147 static CGContextRef
gdk_window_impl_quartz_get_context(GdkWindowImplQuartz * window_impl,gboolean antialias)148 gdk_window_impl_quartz_get_context (GdkWindowImplQuartz *window_impl,
149 gboolean antialias)
150 {
151 CGContextRef cg_context = NULL;
152 CGSize scale;
153
154 if (GDK_WINDOW_DESTROYED (window_impl->wrapper))
155 return NULL;
156
157 /* Lock focus when not called as part of a drawRect call. This
158 * is needed when called from outside "real" expose events, for
159 * example for synthesized expose events when realizing windows
160 * and for widgets that send fake expose events like the arrow
161 * buttons in spinbuttons or the position marker in rulers.
162 */
163 if (window_impl->in_paint_rect_count == 0)
164 {
165 /* The NSView focus-locking API set was deprecated in MacOS 10.14 and
166 * has a significant cost in MacOS 11 - every lock/unlock seems to
167 * trigger a drawRect: call for the entire window. To return the
168 * lost performance, do not use the locking API in MacOS 11+
169 */
170 if(gdk_quartz_osx_version() < GDK_OSX_BIGSUR)
171 {
172 if (![window_impl->view lockFocusIfCanDraw])
173 return NULL;
174 }
175 }
176 #if MAC_OS_X_VERSION_MAX_ALLOWED < 101000
177 cg_context = [[NSGraphicsContext currentContext] graphicsPort];
178 #else
179 if (gdk_quartz_osx_version () < GDK_OSX_YOSEMITE)
180 cg_context = [[NSGraphicsContext currentContext] graphicsPort];
181 else
182 cg_context = [[NSGraphicsContext currentContext] CGContext];
183 #endif
184
185 if (!cg_context)
186 return NULL;
187 CGContextSaveGState (cg_context);
188 CGContextSetAllowsAntialiasing (cg_context, antialias);
189
190 /* Undo the default scaling transform, since we apply our own
191 * in gdk_quartz_ref_cairo_surface () */
192 scale = CGContextConvertSizeToDeviceSpace (cg_context,
193 CGSizeMake (1.0, 1.0));
194 CGContextScaleCTM (cg_context, 1.0 / fabs(scale.width), 1.0 / fabs(scale.height));
195 return cg_context;
196 }
197
198 static void
gdk_window_impl_quartz_release_context(GdkWindowImplQuartz * window_impl,CGContextRef cg_context)199 gdk_window_impl_quartz_release_context (GdkWindowImplQuartz *window_impl,
200 CGContextRef cg_context)
201 {
202 if (cg_context)
203 {
204 CGContextRestoreGState (cg_context);
205 CGContextSetAllowsAntialiasing (cg_context, TRUE);
206 }
207
208 /* See comment in gdk_quartz_window_get_context(). */
209 if (window_impl->in_paint_rect_count == 0)
210 {
211 _gdk_quartz_window_flush (window_impl);
212
213 /* As per gdk_window_impl_quartz_get_context(), the NSView
214 * focus-locking API set was deprecated in MacOS 10.14 and has
215 * a significant cost in MacOS 11 - every lock/unlock seems to
216 * trigger a drawRect: call for the entire window. To return the
217 * lost performance, do not use the locking API in MacOS 11+
218 */
219 if(gdk_quartz_osx_version() < GDK_OSX_BIGSUR)
220 [window_impl->view unlockFocus];
221 }
222 }
223
224 static void
gdk_window_impl_quartz_finalize(GObject * object)225 gdk_window_impl_quartz_finalize (GObject *object)
226 {
227 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (object);
228 GdkDisplay *display = gdk_window_get_display (impl->wrapper);
229 GdkSeat *seat = gdk_display_get_default_seat (display);
230
231 gdk_seat_ungrab (seat);
232
233 if (impl->transient_for)
234 g_object_unref (impl->transient_for);
235
236 if (impl->view)
237 [[NSNotificationCenter defaultCenter] removeObserver: impl->toplevel
238 name: @"NSViewFrameDidChangeNotification"
239 object: impl->view];
240
241 G_OBJECT_CLASS (parent_class)->finalize (object);
242 }
243
244 /* Help preventing "beam sync penalty" where CG makes all graphics code
245 * block until the next vsync if we try to flush (including call display on
246 * a view) too often. We do this by limiting the manual flushing done
247 * outside of expose calls to less than some frequency when measured over
248 * the last 4 flushes. This is a bit arbitray, but seems to make it possible
249 * for some quick manual flushes (such as gtkruler or gimp’s marching ants)
250 * without hitting the max flush frequency.
251 *
252 * If drawable NULL, no flushing is done, only registering that a flush was
253 * done externally.
254 *
255 * Note: As of MacOS 10.14 NSWindow flushWindow is deprecated because
256 * Quartz has the ability to handle deferred drawing on its own.
257 */
258 void
_gdk_quartz_window_flush(GdkWindowImplQuartz * window_impl)259 _gdk_quartz_window_flush (GdkWindowImplQuartz *window_impl)
260 {
261 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
262 static struct timeval prev_tv;
263 static gint intervals[4];
264 static gint index;
265 struct timeval tv;
266 gint ms;
267
268 gettimeofday (&tv, NULL);
269 ms = (tv.tv_sec - prev_tv.tv_sec) * 1000 + (tv.tv_usec - prev_tv.tv_usec) / 1000;
270 intervals[index++ % 4] = ms;
271
272 if (window_impl)
273 {
274 ms = intervals[0] + intervals[1] + intervals[2] + intervals[3];
275
276 /* ~25Hz on average. */
277 if (ms > 4*40)
278 {
279 if (window_impl)
280 [window_impl->toplevel flushWindow];
281
282 prev_tv = tv;
283 }
284 }
285 else
286 prev_tv = tv;
287 #endif
288 }
289
290 static cairo_user_data_key_t gdk_quartz_cairo_key;
291
292 typedef struct {
293 GdkWindowImplQuartz *window_impl;
294 CGContextRef cg_context;
295 } GdkQuartzCairoSurfaceData;
296
297 static void
gdk_quartz_cairo_surface_destroy(void * data)298 gdk_quartz_cairo_surface_destroy (void *data)
299 {
300 GdkQuartzCairoSurfaceData *surface_data = data;
301
302 surface_data->window_impl->cairo_surface = NULL;
303
304 gdk_quartz_window_release_context (surface_data->window_impl,
305 surface_data->cg_context);
306
307 g_free (surface_data);
308 }
309
310 static cairo_surface_t *
gdk_quartz_create_cairo_surface(GdkWindowImplQuartz * impl,int width,int height)311 gdk_quartz_create_cairo_surface (GdkWindowImplQuartz *impl,
312 int width,
313 int height)
314 {
315 CGContextRef cg_context;
316 GdkQuartzCairoSurfaceData *surface_data;
317 cairo_surface_t *surface;
318
319 cg_context = gdk_quartz_window_get_context (impl, TRUE);
320
321 surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
322 surface_data->window_impl = impl;
323 surface_data->cg_context = cg_context;
324
325 if (cg_context)
326 surface = cairo_quartz_surface_create_for_cg_context (cg_context,
327 width, height);
328 else
329 surface = cairo_quartz_surface_create(CAIRO_FORMAT_ARGB32, width, height);
330
331 cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
332 surface_data,
333 gdk_quartz_cairo_surface_destroy);
334
335 return surface;
336 }
337
338 static cairo_surface_t *
gdk_quartz_ref_cairo_surface(GdkWindow * window)339 gdk_quartz_ref_cairo_surface (GdkWindow *window)
340 {
341 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
342
343 if (GDK_WINDOW_DESTROYED (window))
344 return NULL;
345
346 if (!impl->cairo_surface)
347 {
348 gint scale = gdk_window_get_scale_factor (impl->wrapper);
349
350 impl->cairo_surface =
351 gdk_quartz_create_cairo_surface (impl,
352 gdk_window_get_width (impl->wrapper) * scale,
353 gdk_window_get_height (impl->wrapper) * scale);
354
355 cairo_surface_set_device_scale (impl->cairo_surface, scale, scale);
356 }
357 else
358 cairo_surface_reference (impl->cairo_surface);
359
360 return impl->cairo_surface;
361 }
362
363 static void
gdk_window_impl_quartz_init(GdkWindowImplQuartz * impl)364 gdk_window_impl_quartz_init (GdkWindowImplQuartz *impl)
365 {
366 impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
367 }
368
369 static gboolean
gdk_window_impl_quartz_begin_paint(GdkWindow * window)370 gdk_window_impl_quartz_begin_paint (GdkWindow *window)
371 {
372 return FALSE;
373 }
374
375 static void
gdk_quartz_window_set_needs_display_in_region(GdkWindow * window,cairo_region_t * region)376 gdk_quartz_window_set_needs_display_in_region (GdkWindow *window,
377 cairo_region_t *region)
378 {
379 GdkWindowImplQuartz *impl;
380 int i, n_rects;
381
382 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
383
384 if (!impl->needs_display_region)
385 impl->needs_display_region = cairo_region_create ();
386
387 cairo_region_union (impl->needs_display_region, region);
388
389 n_rects = cairo_region_num_rectangles (region);
390 for (i = 0; i < n_rects; i++)
391 {
392 cairo_rectangle_int_t rect;
393 cairo_region_get_rectangle (region, i, &rect);
394 [impl->view setNeedsDisplayInRect:NSMakeRect (rect.x, rect.y,
395 rect.width, rect.height)];
396 }
397 }
398
399 void
_gdk_quartz_window_process_updates_recurse(GdkWindow * window,cairo_region_t * region)400 _gdk_quartz_window_process_updates_recurse (GdkWindow *window,
401 cairo_region_t *region)
402 {
403 /* Make sure to only flush each toplevel at most once if we're called
404 * from process_all_updates.
405 */
406 if (in_process_all_updates)
407 {
408 GdkWindow *toplevel;
409
410 toplevel = gdk_window_get_effective_toplevel (window);
411 if (toplevel && WINDOW_IS_TOPLEVEL (toplevel))
412 {
413 GdkWindowImplQuartz *toplevel_impl;
414 NSWindow *nswindow;
415
416 toplevel_impl = (GdkWindowImplQuartz *)toplevel->impl;
417 nswindow = toplevel_impl->toplevel;
418 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
419 /* In theory, we could skip the flush disabling, since we only
420 * have one NSView.
421 */
422 if (nswindow && ![nswindow isFlushWindowDisabled])
423 {
424 [nswindow retain];
425 [nswindow disableFlushWindow];
426 update_nswindows = g_slist_prepend (update_nswindows, nswindow);
427 }
428 #endif
429 }
430 }
431
432 if (WINDOW_IS_TOPLEVEL (window))
433 gdk_quartz_window_set_needs_display_in_region (window, region);
434 else
435 _gdk_window_process_updates_recurse (window, region);
436
437 /* NOTE: I'm not sure if we should displayIfNeeded here. It slows down a
438 * lot (since it triggers the beam syncing) and things seem to work
439 * without it.
440 */
441 }
442
443 void
_gdk_quartz_display_before_process_all_updates(GdkDisplay * display)444 _gdk_quartz_display_before_process_all_updates (GdkDisplay *display)
445 {
446 in_process_all_updates = TRUE;
447
448 if (gdk_quartz_osx_version () >= GDK_OSX_EL_CAPITAN)
449 {
450 [NSAnimationContext endGrouping];
451 }
452 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
453 else
454 {
455 NSDisableScreenUpdates ();
456 }
457 #endif
458 }
459
460 void
_gdk_quartz_display_after_process_all_updates(GdkDisplay * display)461 _gdk_quartz_display_after_process_all_updates (GdkDisplay *display)
462 {
463 GSList *tmp_list = update_nswindows;
464
465 update_nswindows = NULL;
466
467 while (tmp_list)
468 {
469 NSWindow *nswindow = tmp_list->data;
470
471 [[nswindow contentView] displayIfNeeded];
472
473 _gdk_quartz_window_flush (NULL);
474 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
475 [nswindow enableFlushWindow];
476 [nswindow flushWindow];
477 #endif
478 [nswindow release];
479
480 tmp_list = g_slist_remove_link (tmp_list, tmp_list);
481 }
482
483 in_process_all_updates = FALSE;
484
485 if (gdk_quartz_osx_version() >= GDK_OSX_EL_CAPITAN)
486 {
487 [NSAnimationContext beginGrouping];
488 }
489 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
490 else
491 {
492 NSEnableScreenUpdates ();
493 }
494 #endif
495 }
496
497 static const gchar *
get_default_title(void)498 get_default_title (void)
499 {
500 const char *title;
501
502 title = g_get_application_name ();
503 if (!title)
504 title = g_get_prgname ();
505
506 return title;
507 }
508
509 static void
get_ancestor_coordinates_from_child(GdkWindow * child_window,gint child_x,gint child_y,GdkWindow * ancestor_window,gint * ancestor_x,gint * ancestor_y)510 get_ancestor_coordinates_from_child (GdkWindow *child_window,
511 gint child_x,
512 gint child_y,
513 GdkWindow *ancestor_window,
514 gint *ancestor_x,
515 gint *ancestor_y)
516 {
517 while (child_window != ancestor_window)
518 {
519 child_x += child_window->x;
520 child_y += child_window->y;
521
522 child_window = child_window->parent;
523 }
524
525 *ancestor_x = child_x;
526 *ancestor_y = child_y;
527 }
528
529 void
_gdk_quartz_window_debug_highlight(GdkWindow * window,gint number)530 _gdk_quartz_window_debug_highlight (GdkWindow *window, gint number)
531 {
532 gint x, y;
533 gint gx, gy;
534 GdkWindow *toplevel;
535 gint tx, ty;
536 static NSWindow *debug_window[10];
537 static NSRect old_rect[10];
538 NSRect rect;
539 NSColor *color;
540
541 g_return_if_fail (number >= 0 && number <= 9);
542
543 if (window == _gdk_root)
544 return;
545
546 if (window == NULL)
547 {
548 if (debug_window[number])
549 [debug_window[number] close];
550 debug_window[number] = NULL;
551
552 return;
553 }
554
555 toplevel = gdk_window_get_toplevel (window);
556 get_ancestor_coordinates_from_child (window, 0, 0, toplevel, &x, &y);
557
558 gdk_window_get_origin (toplevel, &tx, &ty);
559 x += tx;
560 y += ty;
561
562 _gdk_quartz_window_gdk_xy_to_xy (x, y + window->height,
563 &gx, &gy);
564
565 rect = NSMakeRect (gx, gy, window->width, window->height);
566
567 if (debug_window[number] && NSEqualRects (rect, old_rect[number]))
568 return;
569
570 old_rect[number] = rect;
571
572 if (debug_window[number])
573 [debug_window[number] close];
574
575 debug_window[number] = [[NSWindow alloc] initWithContentRect:rect
576 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
577 styleMask:(NSUInteger)GDK_QUARTZ_BORDERLESS_WINDOW
578 #else
579 styleMask:(NSWindowStyleMask)GDK_QUARTZ_BORDERLESS_WINDOW
580 #endif
581 backing:NSBackingStoreBuffered
582 defer:NO];
583
584 switch (number)
585 {
586 case 0:
587 color = [NSColor redColor];
588 break;
589 case 1:
590 color = [NSColor blueColor];
591 break;
592 case 2:
593 color = [NSColor greenColor];
594 break;
595 case 3:
596 color = [NSColor yellowColor];
597 break;
598 case 4:
599 color = [NSColor brownColor];
600 break;
601 case 5:
602 color = [NSColor purpleColor];
603 break;
604 default:
605 color = [NSColor blackColor];
606 break;
607 }
608
609 [debug_window[number] setBackgroundColor:color];
610 [debug_window[number] setAlphaValue:0.4];
611 [debug_window[number] setOpaque:NO];
612 [debug_window[number] setReleasedWhenClosed:YES];
613 [debug_window[number] setIgnoresMouseEvents:YES];
614 [debug_window[number] setLevel:NSFloatingWindowLevel];
615
616 [debug_window[number] orderFront:nil];
617 }
618
619 gboolean
_gdk_quartz_window_is_ancestor(GdkWindow * ancestor,GdkWindow * window)620 _gdk_quartz_window_is_ancestor (GdkWindow *ancestor,
621 GdkWindow *window)
622 {
623 if (ancestor == NULL || window == NULL)
624 return FALSE;
625
626 return (gdk_window_get_parent (window) == ancestor ||
627 _gdk_quartz_window_is_ancestor (ancestor,
628 gdk_window_get_parent (window)));
629 }
630
631
632 /* See notes on top of gdkscreen-quartz.c */
633 void
_gdk_quartz_window_gdk_xy_to_xy(gint gdk_x,gint gdk_y,gint * ns_x,gint * ns_y)634 _gdk_quartz_window_gdk_xy_to_xy (gint gdk_x,
635 gint gdk_y,
636 gint *ns_x,
637 gint *ns_y)
638 {
639 GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
640
641 if (ns_y)
642 *ns_y = screen_quartz->orig_y - gdk_y;
643
644 if (ns_x)
645 *ns_x = gdk_x + screen_quartz->orig_x;
646 }
647
648 void
_gdk_quartz_window_xy_to_gdk_xy(gint ns_x,gint ns_y,gint * gdk_x,gint * gdk_y)649 _gdk_quartz_window_xy_to_gdk_xy (gint ns_x,
650 gint ns_y,
651 gint *gdk_x,
652 gint *gdk_y)
653 {
654 GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
655
656 if (gdk_y)
657 *gdk_y = screen_quartz->orig_y - ns_y;
658
659 if (gdk_x)
660 *gdk_x = ns_x - screen_quartz->orig_x;
661 }
662
663 void
_gdk_quartz_window_nspoint_to_gdk_xy(NSPoint point,gint * x,gint * y)664 _gdk_quartz_window_nspoint_to_gdk_xy (NSPoint point,
665 gint *x,
666 gint *y)
667 {
668 _gdk_quartz_window_xy_to_gdk_xy (point.x, point.y,
669 x, y);
670 }
671
672 static GdkWindow *
find_child_window_helper(GdkWindow * window,gint x,gint y,gint x_offset,gint y_offset,gboolean get_toplevel)673 find_child_window_helper (GdkWindow *window,
674 gint x,
675 gint y,
676 gint x_offset,
677 gint y_offset,
678 gboolean get_toplevel)
679 {
680 GdkWindowImplQuartz *impl;
681 GList *l;
682
683 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
684
685 if (window == _gdk_root)
686 update_toplevel_order ();
687
688 for (l = impl->sorted_children; l; l = l->next)
689 {
690 GdkWindow *child = l->data;
691 GdkWindowImplQuartz *child_impl = GDK_WINDOW_IMPL_QUARTZ (child->impl);
692 int temp_x, temp_y;
693
694 if (!GDK_WINDOW_IS_MAPPED (child))
695 continue;
696
697 temp_x = x_offset + child->x;
698 temp_y = y_offset + child->y;
699
700 /* Special-case the root window. We have to include the title
701 * bar in the checks, otherwise the window below the title bar
702 * will be found i.e. events punch through. (If we can find a
703 * better way to deal with the events in gdkevents-quartz, this
704 * might not be needed.)
705 */
706 if (window == _gdk_root)
707 {
708 NSRect frame = NSMakeRect (0, 0, 100, 100);
709 NSRect content;
710 NSUInteger mask;
711 int titlebar_height;
712
713 mask = [child_impl->toplevel styleMask];
714
715 /* Get the title bar height. */
716 content = [NSWindow contentRectForFrameRect:frame
717 styleMask:mask];
718 titlebar_height = frame.size.height - content.size.height;
719
720 if (titlebar_height > 0 &&
721 x >= temp_x && y >= temp_y - titlebar_height &&
722 x < temp_x + child->width && y < temp_y)
723 {
724 /* The root means "unknown" i.e. a window not managed by
725 * GDK.
726 */
727 return (GdkWindow *)_gdk_root;
728 }
729 }
730
731 if ((!get_toplevel || (get_toplevel && window == _gdk_root)) &&
732 x >= temp_x && y >= temp_y &&
733 x < temp_x + child->width && y < temp_y + child->height)
734 {
735 /* Look for child windows. */
736 return find_child_window_helper (l->data,
737 x, y,
738 temp_x, temp_y,
739 get_toplevel);
740 }
741 }
742
743 return window;
744 }
745
746 /* Given a GdkWindow and coordinates relative to it, returns the
747 * innermost subwindow that contains the point. If the coordinates are
748 * outside the passed in window, NULL is returned.
749 */
750 GdkWindow *
_gdk_quartz_window_find_child(GdkWindow * window,gint x,gint y,gboolean get_toplevel)751 _gdk_quartz_window_find_child (GdkWindow *window,
752 gint x,
753 gint y,
754 gboolean get_toplevel)
755 {
756 if (x >= 0 && y >= 0 && x < window->width && y < window->height)
757 return find_child_window_helper (window, x, y, 0, 0, get_toplevel);
758
759 return NULL;
760 }
761
762 /* Raises a transient window.
763 */
764 static void
raise_transient(GdkWindowImplQuartz * impl)765 raise_transient (GdkWindowImplQuartz *impl)
766 {
767 /* In quartz the transient-for behavior is implemented by
768 * attaching the transient-for GdkNSWindows to the parent's
769 * GdkNSWindow. Stacking is managed by Quartz and the order
770 * is that of the parent's childWindows array. The only way
771 * to change that order is to remove the child from the
772 * parent and then add it back in.
773 */
774 GdkWindowImplQuartz *parent_impl =
775 GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
776 [parent_impl->toplevel removeChildWindow:impl->toplevel];
777 [parent_impl->toplevel addChildWindow:impl->toplevel
778 ordered:NSWindowAbove];
779 }
780
781 void
_gdk_quartz_window_did_become_main(GdkWindow * window)782 _gdk_quartz_window_did_become_main (GdkWindow *window)
783 {
784 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
785
786 main_window_stack = g_slist_remove (main_window_stack, window);
787
788 if (window->window_type != GDK_WINDOW_TEMP)
789 main_window_stack = g_slist_prepend (main_window_stack, window);
790
791 if (impl->transient_for)
792 raise_transient (impl);
793
794 clear_toplevel_order ();
795 }
796
797 void
_gdk_quartz_window_did_resign_main(GdkWindow * window)798 _gdk_quartz_window_did_resign_main (GdkWindow *window)
799 {
800 GdkWindow *new_window = NULL;
801
802 if (main_window_stack)
803 new_window = main_window_stack->data;
804 else
805 {
806 GList *toplevels;
807
808 toplevels = gdk_screen_get_toplevel_windows (gdk_screen_get_default ());
809 if (toplevels)
810 new_window = toplevels->data;
811 g_list_free (toplevels);
812 }
813
814 if (new_window &&
815 new_window != window &&
816 GDK_WINDOW_IS_MAPPED (new_window) &&
817 WINDOW_IS_TOPLEVEL (new_window))
818 {
819 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (new_window->impl);
820
821 [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
822 }
823
824 clear_toplevel_order ();
825 }
826
827 static NSScreen *
get_nsscreen_for_point(gint x,gint y)828 get_nsscreen_for_point (gint x, gint y)
829 {
830 int i;
831 NSArray *screens;
832 NSScreen *screen = NULL;
833
834 GDK_QUARTZ_ALLOC_POOL;
835
836 screens = [NSScreen screens];
837
838 for (i = 0; i < [screens count]; i++)
839 {
840 NSRect rect = [[screens objectAtIndex:i] frame];
841
842 if (x >= rect.origin.x && x <= rect.origin.x + rect.size.width &&
843 y >= rect.origin.y && y <= rect.origin.y + rect.size.height)
844 {
845 screen = [screens objectAtIndex:i];
846 break;
847 }
848 }
849
850 GDK_QUARTZ_RELEASE_POOL;
851
852 return screen;
853 }
854
855 void
_gdk_quartz_display_create_window_impl(GdkDisplay * display,GdkWindow * window,GdkWindow * real_parent,GdkScreen * screen,GdkEventMask event_mask,GdkWindowAttr * attributes,gint attributes_mask)856 _gdk_quartz_display_create_window_impl (GdkDisplay *display,
857 GdkWindow *window,
858 GdkWindow *real_parent,
859 GdkScreen *screen,
860 GdkEventMask event_mask,
861 GdkWindowAttr *attributes,
862 gint attributes_mask)
863 {
864 GdkWindowImplQuartz *impl;
865 GdkWindowImplQuartz *parent_impl;
866 GdkWindowTypeHint type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
867
868 GDK_QUARTZ_ALLOC_POOL;
869
870 impl = g_object_new (GDK_TYPE_WINDOW_IMPL_QUARTZ, NULL);
871 window->impl = GDK_WINDOW_IMPL (impl);
872 impl->wrapper = window;
873
874 parent_impl = GDK_WINDOW_IMPL_QUARTZ (window->parent->impl);
875
876 switch (window->window_type)
877 {
878 case GDK_WINDOW_TOPLEVEL:
879 case GDK_WINDOW_TEMP:
880 if (GDK_WINDOW_TYPE (window->parent) != GDK_WINDOW_ROOT)
881 {
882 /* The common code warns for this case */
883 parent_impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
884 }
885 }
886
887 /* Maintain the z-ordered list of children. */
888 if (window->parent != _gdk_root)
889 parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window);
890 else
891 clear_toplevel_order ();
892
893 gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
894 (attributes->cursor) :
895 NULL));
896
897 impl->view = NULL;
898 impl->toplevel = NULL;
899
900 if (attributes_mask & GDK_WA_TYPE_HINT)
901 {
902 type_hint = attributes->type_hint;
903 gdk_window_set_type_hint (window, type_hint);
904 }
905
906 switch (window->window_type)
907 {
908 case GDK_WINDOW_TOPLEVEL:
909 case GDK_WINDOW_TEMP:
910 {
911 NSScreen *screen;
912 NSRect screen_rect;
913 NSRect content_rect;
914 NSUInteger style_mask;
915 int nx, ny;
916 const char *title;
917
918 /* initWithContentRect will place on the mainScreen by default.
919 * We want to select the screen to place on ourselves. We need
920 * to find the screen the window will be on and correct the
921 * content_rect coordinates to be relative to that screen.
922 */
923 _gdk_quartz_window_gdk_xy_to_xy (window->x, window->y, &nx, &ny);
924
925 screen = get_nsscreen_for_point (nx, ny);
926 screen_rect = [screen frame];
927 nx -= screen_rect.origin.x;
928 ny -= screen_rect.origin.y;
929
930 content_rect = NSMakeRect (nx, ny - window->height,
931 window->width,
932 window->height);
933
934 if (window->window_type == GDK_WINDOW_TEMP ||
935 type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN)
936 {
937 style_mask = GDK_QUARTZ_BORDERLESS_WINDOW;
938 }
939 else
940 {
941 style_mask = (GDK_QUARTZ_TITLED_WINDOW |
942 GDK_QUARTZ_CLOSABLE_WINDOW |
943 GDK_QUARTZ_MINIATURIZABLE_WINDOW |
944 GDK_QUARTZ_RESIZABLE_WINDOW);
945 }
946
947 impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:content_rect
948 styleMask:style_mask
949 backing:NSBackingStoreBuffered
950 defer:NO
951 screen:screen];
952
953 if (type_hint != GDK_WINDOW_TYPE_HINT_NORMAL)
954 impl->toplevel.excludedFromWindowsMenu = true;
955
956 if (attributes_mask & GDK_WA_TITLE)
957 title = attributes->title;
958 else
959 title = get_default_title ();
960
961 gdk_window_set_title (window, title);
962
963 if (gdk_window_get_visual (window) == gdk_screen_get_rgba_visual (_gdk_screen))
964 {
965 [impl->toplevel setOpaque:NO];
966 [impl->toplevel setBackgroundColor:[NSColor clearColor]];
967 }
968
969 content_rect.origin.x = 0;
970 content_rect.origin.y = 0;
971
972 impl->view = [[GdkQuartzView alloc] initWithFrame:content_rect];
973 [impl->view setGdkWindow:window];
974 [impl->toplevel setContentView:impl->view];
975 [[NSNotificationCenter defaultCenter] addObserver: impl->toplevel
976 selector: @selector (windowDidResize:)
977 name: @"NSViewFrameDidChangeNotification"
978 object: impl->view];
979 [impl->view release];
980 }
981 break;
982
983 case GDK_WINDOW_CHILD:
984 {
985 GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (window->parent->impl);
986
987 if (!window->input_only)
988 {
989 NSRect frame_rect = NSMakeRect (window->x + window->parent->abs_x,
990 window->y + window->parent->abs_y,
991 window->width,
992 window->height);
993
994 impl->view = [[GdkQuartzView alloc] initWithFrame:frame_rect];
995
996 [impl->view setGdkWindow:window];
997
998 /* GdkWindows should be hidden by default */
999 [impl->view setHidden:YES];
1000 [parent_impl->view addSubview:impl->view];
1001 [impl->view release];
1002 }
1003 }
1004 break;
1005
1006 default:
1007 g_assert_not_reached ();
1008 }
1009
1010 GDK_QUARTZ_RELEASE_POOL;
1011 }
1012
1013 void
_gdk_quartz_window_update_position(GdkWindow * window)1014 _gdk_quartz_window_update_position (GdkWindow *window)
1015 {
1016 NSRect frame_rect;
1017 NSRect content_rect;
1018 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1019
1020 GDK_QUARTZ_ALLOC_POOL;
1021
1022 frame_rect = [impl->toplevel frame];
1023 content_rect = [impl->toplevel contentRectForFrameRect:frame_rect];
1024
1025 _gdk_quartz_window_xy_to_gdk_xy (content_rect.origin.x,
1026 content_rect.origin.y + content_rect.size.height,
1027 &window->x, &window->y);
1028
1029
1030 GDK_QUARTZ_RELEASE_POOL;
1031 }
1032
1033 void
_gdk_quartz_window_init_windowing(GdkDisplay * display,GdkScreen * screen)1034 _gdk_quartz_window_init_windowing (GdkDisplay *display,
1035 GdkScreen *screen)
1036 {
1037 GdkWindowImplQuartz *impl;
1038
1039 g_assert (_gdk_root == NULL);
1040
1041 _gdk_root = _gdk_display_create_window (display);
1042
1043 _gdk_root->impl = g_object_new (_gdk_root_window_impl_quartz_get_type (), NULL);
1044 _gdk_root->impl_window = _gdk_root;
1045 _gdk_root->visual = gdk_screen_get_system_visual (screen);
1046
1047 impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
1048
1049 _gdk_quartz_screen_update_window_sizes (screen);
1050
1051 _gdk_root->state = 0; /* We don't want GDK_WINDOW_STATE_WITHDRAWN here */
1052 _gdk_root->window_type = GDK_WINDOW_ROOT;
1053 _gdk_root->depth = 24;
1054 _gdk_root->viewable = TRUE;
1055
1056 impl->wrapper = _gdk_root;
1057 }
1058
1059 static void
gdk_quartz_window_destroy(GdkWindow * window,gboolean recursing,gboolean foreign_destroy)1060 gdk_quartz_window_destroy (GdkWindow *window,
1061 gboolean recursing,
1062 gboolean foreign_destroy)
1063 {
1064 GdkWindowImplQuartz *impl;
1065 GdkWindow *parent;
1066
1067 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1068
1069 main_window_stack = g_slist_remove (main_window_stack, window);
1070
1071 g_list_free (impl->sorted_children);
1072 impl->sorted_children = NULL;
1073
1074 parent = window->parent;
1075 if (parent)
1076 {
1077 GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
1078
1079 parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window);
1080 }
1081
1082 if (impl->cairo_surface)
1083 {
1084 cairo_surface_finish (impl->cairo_surface);
1085 cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
1086 NULL, NULL);
1087 impl->cairo_surface = NULL;
1088 }
1089
1090 if (!recursing && !foreign_destroy)
1091 {
1092 GDK_QUARTZ_ALLOC_POOL;
1093
1094 if (impl->toplevel)
1095 [impl->toplevel close];
1096 else if (impl->view)
1097 [impl->view removeFromSuperview];
1098
1099 GDK_QUARTZ_RELEASE_POOL;
1100 }
1101 }
1102
1103 static void
gdk_quartz_window_destroy_foreign(GdkWindow * window)1104 gdk_quartz_window_destroy_foreign (GdkWindow *window)
1105 {
1106 /* Foreign windows aren't supported in OSX. */
1107 }
1108
1109 /* FIXME: This might be possible to simplify with client-side windows. Also
1110 * note that already_mapped is not used yet, see the x11 backend.
1111 */
1112 static void
gdk_window_quartz_show(GdkWindow * window,gboolean already_mapped)1113 gdk_window_quartz_show (GdkWindow *window, gboolean already_mapped)
1114 {
1115 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1116 gboolean focus_on_map;
1117
1118 GDK_QUARTZ_ALLOC_POOL;
1119
1120 if (!GDK_WINDOW_IS_MAPPED (window))
1121 focus_on_map = window->focus_on_map;
1122 else
1123 focus_on_map = TRUE;
1124
1125 if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel)
1126 {
1127 gboolean make_key;
1128
1129 make_key = (window->accept_focus && focus_on_map &&
1130 window->window_type != GDK_WINDOW_TEMP);
1131
1132 [(GdkQuartzNSWindow*)impl->toplevel showAndMakeKey:make_key];
1133 clear_toplevel_order ();
1134
1135 _gdk_quartz_events_send_map_event (window);
1136 }
1137 else
1138 {
1139 [impl->view setHidden:NO];
1140 }
1141
1142 [impl->view setNeedsDisplay:YES];
1143
1144 gdk_synthesize_window_state (window, GDK_WINDOW_STATE_WITHDRAWN, 0);
1145
1146 if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
1147 gdk_window_maximize (window);
1148
1149 if (window->state & GDK_WINDOW_STATE_ICONIFIED)
1150 gdk_window_iconify (window);
1151
1152 if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
1153 _gdk_quartz_window_attach_to_parent (window);
1154
1155 GDK_QUARTZ_RELEASE_POOL;
1156 }
1157
1158 /* Temporarily unsets the parent window, if the window is a
1159 * transient.
1160 */
1161 void
_gdk_quartz_window_detach_from_parent(GdkWindow * window)1162 _gdk_quartz_window_detach_from_parent (GdkWindow *window)
1163 {
1164 GdkWindowImplQuartz *impl;
1165
1166 g_return_if_fail (GDK_IS_WINDOW (window));
1167
1168 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1169
1170 g_return_if_fail (impl->toplevel != NULL);
1171
1172 if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
1173 {
1174 GdkWindowImplQuartz *parent_impl;
1175
1176 parent_impl = GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
1177 [parent_impl->toplevel removeChildWindow:impl->toplevel];
1178 clear_toplevel_order ();
1179 }
1180 }
1181
1182 /* Re-sets the parent window, if the window is a transient. */
1183 void
_gdk_quartz_window_attach_to_parent(GdkWindow * window)1184 _gdk_quartz_window_attach_to_parent (GdkWindow *window)
1185 {
1186 GdkWindowImplQuartz *impl;
1187
1188 g_return_if_fail (GDK_IS_WINDOW (window));
1189
1190 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1191
1192 g_return_if_fail (impl->toplevel != NULL);
1193
1194 if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
1195 {
1196 GdkWindowImplQuartz *parent_impl;
1197
1198 parent_impl = GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
1199 [parent_impl->toplevel addChildWindow:impl->toplevel ordered:NSWindowAbove];
1200 clear_toplevel_order ();
1201 }
1202 }
1203
1204 void
gdk_window_quartz_hide(GdkWindow * window)1205 gdk_window_quartz_hide (GdkWindow *window)
1206 {
1207 GdkWindowImplQuartz *impl;
1208 GdkDisplay *display = gdk_window_get_display (window);
1209 GdkSeat *seat = gdk_display_get_default_seat (display);
1210 gdk_seat_ungrab (seat);
1211
1212 /* Make sure we're not stuck in fullscreen mode. */
1213 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
1214 if (get_fullscreen_geometry (window))
1215 SetSystemUIMode (kUIModeNormal, 0);
1216 #endif
1217
1218 _gdk_window_clear_update_area (window);
1219
1220 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1221
1222 if (WINDOW_IS_TOPLEVEL (window))
1223 {
1224 /* Update main window. */
1225 main_window_stack = g_slist_remove (main_window_stack, window);
1226 if ([NSApp mainWindow] == impl->toplevel)
1227 _gdk_quartz_window_did_resign_main (window);
1228
1229 if (impl->transient_for)
1230 _gdk_quartz_window_detach_from_parent (window);
1231
1232 [(GdkQuartzNSWindow*)impl->toplevel hide];
1233 }
1234 else if (impl->view)
1235 {
1236 [impl->view setHidden:YES];
1237 }
1238 }
1239
1240 void
gdk_window_quartz_withdraw(GdkWindow * window)1241 gdk_window_quartz_withdraw (GdkWindow *window)
1242 {
1243 gdk_window_hide (window);
1244 }
1245
1246 static void
move_resize_window_internal(GdkWindow * window,gint x,gint y,gint width,gint height)1247 move_resize_window_internal (GdkWindow *window,
1248 gint x,
1249 gint y,
1250 gint width,
1251 gint height)
1252 {
1253 GdkWindowImplQuartz *impl;
1254 GdkRectangle old_visible;
1255 GdkRectangle new_visible;
1256 GdkRectangle scroll_rect;
1257 cairo_region_t *old_region;
1258 cairo_region_t *expose_region;
1259 NSSize delta;
1260
1261 if (GDK_WINDOW_DESTROYED (window))
1262 return;
1263
1264 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1265
1266 if ((x == -1 || (x == window->x)) &&
1267 (y == -1 || (y == window->y)) &&
1268 (width == -1 || (width == window->width)) &&
1269 (height == -1 || (height == window->height)))
1270 {
1271 return;
1272 }
1273
1274 if (!impl->toplevel)
1275 {
1276 /* The previously visible area of this window in a coordinate
1277 * system rooted at the origin of this window.
1278 */
1279 old_visible.x = -window->x;
1280 old_visible.y = -window->y;
1281
1282 old_visible.width = window->width;
1283 old_visible.height = window->height;
1284 }
1285
1286 if (x != -1)
1287 {
1288 delta.width = x - window->x;
1289 window->x = x;
1290 }
1291 else
1292 {
1293 delta.width = 0;
1294 }
1295
1296 if (y != -1)
1297 {
1298 delta.height = y - window->y;
1299 window->y = y;
1300 }
1301 else
1302 {
1303 delta.height = 0;
1304 }
1305
1306 if (width != -1)
1307 window->width = width;
1308
1309 if (height != -1)
1310 window->height = height;
1311
1312 GDK_QUARTZ_ALLOC_POOL;
1313
1314 if (impl->toplevel)
1315 {
1316 NSRect content_rect;
1317 NSRect frame_rect;
1318 gint gx, gy;
1319
1320 _gdk_quartz_window_gdk_xy_to_xy (window->x, window->y + window->height,
1321 &gx, &gy);
1322
1323 content_rect = NSMakeRect (gx, gy, window->width, window->height);
1324
1325 frame_rect = [impl->toplevel frameRectForContentRect:content_rect];
1326 [impl->toplevel setFrame:frame_rect display:YES];
1327 }
1328 else
1329 {
1330 if (!window->input_only)
1331 {
1332 NSRect nsrect;
1333
1334 nsrect = NSMakeRect (window->x, window->y, window->width, window->height);
1335
1336 /* The newly visible area of this window in a coordinate
1337 * system rooted at the origin of this window.
1338 */
1339 new_visible.x = -window->x;
1340 new_visible.y = -window->y;
1341 new_visible.width = old_visible.width; /* parent has not changed size */
1342 new_visible.height = old_visible.height; /* parent has not changed size */
1343
1344 expose_region = cairo_region_create_rectangle (&new_visible);
1345 old_region = cairo_region_create_rectangle (&old_visible);
1346 cairo_region_subtract (expose_region, old_region);
1347
1348 /* Determine what (if any) part of the previously visible
1349 * part of the window can be copied without a redraw
1350 */
1351 scroll_rect = old_visible;
1352 scroll_rect.x -= delta.width;
1353 scroll_rect.y -= delta.height;
1354 gdk_rectangle_intersect (&scroll_rect, &old_visible, &scroll_rect);
1355
1356 if (!cairo_region_is_empty (expose_region))
1357 {
1358 if (scroll_rect.width != 0 && scroll_rect.height != 0)
1359 {
1360 [impl->view scrollRect:NSMakeRect (scroll_rect.x,
1361 scroll_rect.y,
1362 scroll_rect.width,
1363 scroll_rect.height)
1364 by:delta];
1365 }
1366
1367 [impl->view setFrame:nsrect];
1368
1369 gdk_quartz_window_set_needs_display_in_region (window, expose_region);
1370 }
1371 else
1372 {
1373 [impl->view setFrame:nsrect];
1374 [impl->view setNeedsDisplay:YES];
1375 }
1376
1377 cairo_region_destroy (expose_region);
1378 cairo_region_destroy (old_region);
1379 }
1380 }
1381
1382 if (window->gl_paint_context != NULL)
1383 [GDK_QUARTZ_GL_CONTEXT (window->gl_paint_context)->gl_context update];
1384
1385 GDK_QUARTZ_RELEASE_POOL;
1386 }
1387
1388 static inline void
window_quartz_move(GdkWindow * window,gint x,gint y)1389 window_quartz_move (GdkWindow *window,
1390 gint x,
1391 gint y)
1392 {
1393 g_return_if_fail (GDK_IS_WINDOW (window));
1394
1395 if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1396 return;
1397
1398 move_resize_window_internal (window, x, y, -1, -1);
1399 }
1400
1401 static inline void
window_quartz_resize(GdkWindow * window,gint width,gint height)1402 window_quartz_resize (GdkWindow *window,
1403 gint width,
1404 gint height)
1405 {
1406 g_return_if_fail (GDK_IS_WINDOW (window));
1407
1408 if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1409 return;
1410
1411 if (width < 1)
1412 width = 1;
1413 if (height < 1)
1414 height = 1;
1415
1416 move_resize_window_internal (window, -1, -1, width, height);
1417 }
1418
1419 static inline void
window_quartz_move_resize(GdkWindow * window,gint x,gint y,gint width,gint height)1420 window_quartz_move_resize (GdkWindow *window,
1421 gint x,
1422 gint y,
1423 gint width,
1424 gint height)
1425 {
1426 if (width < 1)
1427 width = 1;
1428 if (height < 1)
1429 height = 1;
1430
1431 move_resize_window_internal (window, x, y, width, height);
1432 }
1433
1434 static void
gdk_window_quartz_move_resize(GdkWindow * window,gboolean with_move,gint x,gint y,gint width,gint height)1435 gdk_window_quartz_move_resize (GdkWindow *window,
1436 gboolean with_move,
1437 gint x,
1438 gint y,
1439 gint width,
1440 gint height)
1441 {
1442 if (with_move && (width < 0 && height < 0))
1443 window_quartz_move (window, x, y);
1444 else
1445 {
1446 if (with_move)
1447 window_quartz_move_resize (window, x, y, width, height);
1448 else
1449 window_quartz_resize (window, width, height);
1450 }
1451 }
1452
1453 /* FIXME: This might need fixing (reparenting didn't work before client-side
1454 * windows either).
1455 */
1456 static gboolean
gdk_window_quartz_reparent(GdkWindow * window,GdkWindow * new_parent,gint x,gint y)1457 gdk_window_quartz_reparent (GdkWindow *window,
1458 GdkWindow *new_parent,
1459 gint x,
1460 gint y)
1461 {
1462 GdkWindow *old_parent;
1463 GdkWindowImplQuartz *impl, *old_parent_impl, *new_parent_impl;
1464 NSView *view, *new_parent_view;
1465
1466 if (new_parent == _gdk_root)
1467 {
1468 /* Could be added, just needs implementing. */
1469 g_warning ("Reparenting to root window is not supported yet in the Mac OS X backend");
1470 return FALSE;
1471 }
1472
1473 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1474 view = impl->view;
1475
1476 new_parent_impl = GDK_WINDOW_IMPL_QUARTZ (new_parent->impl);
1477 new_parent_view = new_parent_impl->view;
1478
1479 old_parent = window->parent;
1480 old_parent_impl = GDK_WINDOW_IMPL_QUARTZ (old_parent->impl);
1481
1482 [view retain];
1483
1484 [view removeFromSuperview];
1485 [new_parent_view addSubview:view];
1486
1487 [view release];
1488
1489 window->parent = new_parent;
1490
1491 if (old_parent)
1492 {
1493 old_parent_impl->sorted_children = g_list_remove (old_parent_impl->sorted_children, window);
1494 }
1495
1496 new_parent_impl->sorted_children = g_list_prepend (new_parent_impl->sorted_children, window);
1497
1498 return FALSE;
1499 }
1500
1501 /* Get the toplevel ordering from NSApp and update our own list. We do
1502 * this on demand since the NSApp’s list is not up to date directly
1503 * after we get windowDidBecomeMain.
1504 */
1505 static void
update_toplevel_order(void)1506 update_toplevel_order (void)
1507 {
1508 GdkWindowImplQuartz *root_impl;
1509 NSEnumerator *enumerator;
1510 id nswindow;
1511 GList *toplevels = NULL;
1512
1513 root_impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
1514
1515 if (root_impl->sorted_children)
1516 return;
1517
1518 GDK_QUARTZ_ALLOC_POOL;
1519
1520 enumerator = [[NSApp orderedWindows] objectEnumerator];
1521 while ((nswindow = [enumerator nextObject]))
1522 {
1523 GdkWindow *window;
1524
1525 if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
1526 continue;
1527
1528 window = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
1529 toplevels = g_list_prepend (toplevels, window);
1530 }
1531
1532 GDK_QUARTZ_RELEASE_POOL;
1533
1534 root_impl->sorted_children = g_list_reverse (toplevels);
1535 }
1536
1537 static void
clear_toplevel_order(void)1538 clear_toplevel_order (void)
1539 {
1540 GdkWindowImplQuartz *root_impl;
1541
1542 root_impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
1543
1544 g_list_free (root_impl->sorted_children);
1545 root_impl->sorted_children = NULL;
1546 }
1547
1548 static void
gdk_window_quartz_raise(GdkWindow * window)1549 gdk_window_quartz_raise (GdkWindow *window)
1550 {
1551 if (GDK_WINDOW_DESTROYED (window))
1552 return;
1553
1554 if (WINDOW_IS_TOPLEVEL (window))
1555 {
1556 GdkWindowImplQuartz *impl;
1557
1558 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1559
1560 if (impl->transient_for)
1561 raise_transient (impl);
1562 else
1563 [impl->toplevel orderFront:impl->toplevel];
1564
1565 clear_toplevel_order ();
1566 }
1567 else
1568 {
1569 GdkWindow *parent = window->parent;
1570
1571 if (parent)
1572 {
1573 GdkWindowImplQuartz *impl;
1574
1575 impl = (GdkWindowImplQuartz *)parent->impl;
1576
1577 impl->sorted_children = g_list_remove (impl->sorted_children, window);
1578 impl->sorted_children = g_list_prepend (impl->sorted_children, window);
1579 }
1580 }
1581 }
1582
1583 static void
gdk_window_quartz_lower(GdkWindow * window)1584 gdk_window_quartz_lower (GdkWindow *window)
1585 {
1586 if (GDK_WINDOW_DESTROYED (window))
1587 return;
1588
1589 if (WINDOW_IS_TOPLEVEL (window))
1590 {
1591 GdkWindowImplQuartz *impl;
1592
1593 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1594 [impl->toplevel orderBack:impl->toplevel];
1595
1596 clear_toplevel_order ();
1597 }
1598 else
1599 {
1600 GdkWindow *parent = window->parent;
1601
1602 if (parent)
1603 {
1604 GdkWindowImplQuartz *impl;
1605
1606 impl = (GdkWindowImplQuartz *)parent->impl;
1607
1608 impl->sorted_children = g_list_remove (impl->sorted_children, window);
1609 impl->sorted_children = g_list_append (impl->sorted_children, window);
1610 }
1611 }
1612 }
1613
1614 static void
gdk_window_quartz_restack_toplevel(GdkWindow * window,GdkWindow * sibling,gboolean above)1615 gdk_window_quartz_restack_toplevel (GdkWindow *window,
1616 GdkWindow *sibling,
1617 gboolean above)
1618 {
1619 GdkWindowImplQuartz *impl;
1620 gint sibling_num;
1621
1622 impl = GDK_WINDOW_IMPL_QUARTZ (sibling->impl);
1623 sibling_num = [impl->toplevel windowNumber];
1624
1625 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1626
1627 if (above)
1628 [impl->toplevel orderWindow:NSWindowAbove relativeTo:sibling_num];
1629 else
1630 [impl->toplevel orderWindow:NSWindowBelow relativeTo:sibling_num];
1631 }
1632
1633 static void
gdk_window_quartz_set_background(GdkWindow * window,cairo_pattern_t * pattern)1634 gdk_window_quartz_set_background (GdkWindow *window,
1635 cairo_pattern_t *pattern)
1636 {
1637 /* FIXME: We could theoretically set the background color for toplevels
1638 * here. (Currently we draw the background before emitting expose events)
1639 */
1640 }
1641
1642 static void
gdk_window_quartz_set_device_cursor(GdkWindow * window,GdkDevice * device,GdkCursor * cursor)1643 gdk_window_quartz_set_device_cursor (GdkWindow *window,
1644 GdkDevice *device,
1645 GdkCursor *cursor)
1646 {
1647 NSCursor *nscursor;
1648
1649 if (GDK_WINDOW_DESTROYED (window))
1650 return;
1651
1652 nscursor = _gdk_quartz_cursor_get_ns_cursor (cursor);
1653
1654 [nscursor set];
1655 }
1656
1657 static void
gdk_window_quartz_get_geometry(GdkWindow * window,gint * x,gint * y,gint * width,gint * height)1658 gdk_window_quartz_get_geometry (GdkWindow *window,
1659 gint *x,
1660 gint *y,
1661 gint *width,
1662 gint *height)
1663 {
1664 GdkWindowImplQuartz *impl;
1665 NSRect ns_rect;
1666
1667 if (GDK_WINDOW_DESTROYED (window))
1668 return;
1669
1670 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1671 if (window == _gdk_root)
1672 {
1673 if (x)
1674 *x = 0;
1675 if (y)
1676 *y = 0;
1677
1678 if (width)
1679 *width = window->width;
1680 if (height)
1681 *height = window->height;
1682 }
1683 else if (WINDOW_IS_TOPLEVEL (window))
1684 {
1685 ns_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
1686
1687 /* This doesn't work exactly as in X. There doesn't seem to be a
1688 * way to get the coords relative to the parent window (usually
1689 * the window frame), but that seems useless except for
1690 * borderless windows where it's relative to the root window. So
1691 * we return (0, 0) (should be something like (0, 22)) for
1692 * windows with borders and the root relative coordinates
1693 * otherwise.
1694 */
1695 if ([impl->toplevel styleMask] == GDK_QUARTZ_BORDERLESS_WINDOW)
1696 {
1697 _gdk_quartz_window_xy_to_gdk_xy (ns_rect.origin.x,
1698 ns_rect.origin.y + ns_rect.size.height,
1699 x, y);
1700 }
1701 else
1702 {
1703 if (x)
1704 *x = 0;
1705 if (y)
1706 *y = 0;
1707 }
1708
1709 if (width)
1710 *width = ns_rect.size.width;
1711 if (height)
1712 *height = ns_rect.size.height;
1713 }
1714 else
1715 {
1716 ns_rect = [impl->view frame];
1717
1718 if (x)
1719 *x = ns_rect.origin.x;
1720 if (y)
1721 *y = ns_rect.origin.y;
1722 if (width)
1723 *width = ns_rect.size.width;
1724 if (height)
1725 *height = ns_rect.size.height;
1726 }
1727 }
1728
1729 static void
gdk_window_quartz_get_root_coords(GdkWindow * window,gint x,gint y,gint * root_x,gint * root_y)1730 gdk_window_quartz_get_root_coords (GdkWindow *window,
1731 gint x,
1732 gint y,
1733 gint *root_x,
1734 gint *root_y)
1735 {
1736 int tmp_x = 0, tmp_y = 0;
1737 GdkWindow *toplevel;
1738 NSRect content_rect;
1739 GdkWindowImplQuartz *impl;
1740
1741 if (GDK_WINDOW_DESTROYED (window))
1742 {
1743 if (root_x)
1744 *root_x = 0;
1745 if (root_y)
1746 *root_y = 0;
1747
1748 return;
1749 }
1750
1751 if (window == _gdk_root)
1752 {
1753 if (root_x)
1754 *root_x = x;
1755 if (root_y)
1756 *root_y = y;
1757
1758 return;
1759 }
1760
1761 toplevel = gdk_window_get_toplevel (window);
1762 impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
1763
1764 content_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
1765
1766 _gdk_quartz_window_xy_to_gdk_xy (content_rect.origin.x,
1767 content_rect.origin.y + content_rect.size.height,
1768 &tmp_x, &tmp_y);
1769
1770 tmp_x += x;
1771 tmp_y += y;
1772
1773 while (window != toplevel)
1774 {
1775 if (_gdk_window_has_impl ((GdkWindow *)window))
1776 {
1777 tmp_x += window->x;
1778 tmp_y += window->y;
1779 }
1780
1781 window = window->parent;
1782 }
1783
1784 if (root_x)
1785 *root_x = tmp_x;
1786 if (root_y)
1787 *root_y = tmp_y;
1788 }
1789
1790 /* Returns coordinates relative to the passed in window. */
1791 static GdkWindow *
gdk_window_quartz_get_device_state_helper(GdkWindow * window,GdkDevice * device,gdouble * x,gdouble * y,GdkModifierType * mask)1792 gdk_window_quartz_get_device_state_helper (GdkWindow *window,
1793 GdkDevice *device,
1794 gdouble *x,
1795 gdouble *y,
1796 GdkModifierType *mask)
1797 {
1798 NSPoint point;
1799 gint x_tmp, y_tmp;
1800 GdkWindow *toplevel;
1801 GdkWindow *found_window;
1802
1803 g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
1804
1805 if (GDK_WINDOW_DESTROYED (window))
1806 {
1807 *x = 0;
1808 *y = 0;
1809 *mask = 0;
1810 return NULL;
1811 }
1812
1813 toplevel = gdk_window_get_toplevel (window);
1814
1815 *mask = _gdk_quartz_events_get_current_keyboard_modifiers () |
1816 _gdk_quartz_events_get_current_mouse_modifiers ();
1817
1818 /* Get the y coordinate, needs to be flipped. */
1819 if (window == _gdk_root)
1820 {
1821 point = [NSEvent mouseLocation];
1822 _gdk_quartz_window_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
1823 }
1824 else
1825 {
1826 GdkWindowImplQuartz *impl;
1827 NSWindow *nswindow;
1828
1829 impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
1830 nswindow = impl->toplevel;
1831
1832 point = [nswindow mouseLocationOutsideOfEventStream];
1833
1834 x_tmp = point.x;
1835 y_tmp = toplevel->height - point.y;
1836
1837 window = (GdkWindow *)toplevel;
1838 }
1839
1840 found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp,
1841 FALSE);
1842
1843 /* We never return the root window. */
1844 if (found_window == _gdk_root)
1845 found_window = NULL;
1846
1847 *x = x_tmp;
1848 *y = y_tmp;
1849
1850 return found_window;
1851 }
1852
1853 static gboolean
gdk_window_quartz_get_device_state(GdkWindow * window,GdkDevice * device,gdouble * x,gdouble * y,GdkModifierType * mask)1854 gdk_window_quartz_get_device_state (GdkWindow *window,
1855 GdkDevice *device,
1856 gdouble *x,
1857 gdouble *y,
1858 GdkModifierType *mask)
1859 {
1860 return gdk_window_quartz_get_device_state_helper (window,
1861 device,
1862 x, y, mask) != NULL;
1863 }
1864
1865 static GdkEventMask
gdk_window_quartz_get_events(GdkWindow * window)1866 gdk_window_quartz_get_events (GdkWindow *window)
1867 {
1868 if (GDK_WINDOW_DESTROYED (window))
1869 return 0;
1870 else
1871 return window->event_mask;
1872 }
1873
1874 static void
gdk_window_quartz_set_events(GdkWindow * window,GdkEventMask event_mask)1875 gdk_window_quartz_set_events (GdkWindow *window,
1876 GdkEventMask event_mask)
1877 {
1878 /* The mask is set in the common code. */
1879 }
1880
1881 static void
gdk_quartz_window_set_urgency_hint(GdkWindow * window,gboolean urgent)1882 gdk_quartz_window_set_urgency_hint (GdkWindow *window,
1883 gboolean urgent)
1884 {
1885 if (GDK_WINDOW_DESTROYED (window) ||
1886 !WINDOW_IS_TOPLEVEL (window))
1887 return;
1888
1889 /* FIXME: Implement */
1890 }
1891
1892 static void
gdk_quartz_window_set_geometry_hints(GdkWindow * window,const GdkGeometry * geometry,GdkWindowHints geom_mask)1893 gdk_quartz_window_set_geometry_hints (GdkWindow *window,
1894 const GdkGeometry *geometry,
1895 GdkWindowHints geom_mask)
1896 {
1897 GdkWindowImplQuartz *impl;
1898
1899 g_return_if_fail (geometry != NULL);
1900
1901 if (GDK_WINDOW_DESTROYED (window) ||
1902 !WINDOW_IS_TOPLEVEL (window))
1903 return;
1904
1905 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1906 if (!impl->toplevel)
1907 return;
1908
1909 if (geom_mask & GDK_HINT_POS)
1910 {
1911 /* FIXME: Implement */
1912 }
1913
1914 if (geom_mask & GDK_HINT_USER_POS)
1915 {
1916 /* FIXME: Implement */
1917 }
1918
1919 if (geom_mask & GDK_HINT_USER_SIZE)
1920 {
1921 /* FIXME: Implement */
1922 }
1923
1924 if (geom_mask & GDK_HINT_MIN_SIZE)
1925 {
1926 NSSize size;
1927
1928 size.width = geometry->min_width;
1929 size.height = geometry->min_height;
1930
1931 [impl->toplevel setContentMinSize:size];
1932 }
1933
1934 if (geom_mask & GDK_HINT_MAX_SIZE)
1935 {
1936 NSSize size;
1937
1938 size.width = geometry->max_width;
1939 size.height = geometry->max_height;
1940
1941 [impl->toplevel setContentMaxSize:size];
1942 }
1943
1944 if (geom_mask & GDK_HINT_BASE_SIZE)
1945 {
1946 /* FIXME: Implement */
1947 }
1948
1949 if (geom_mask & GDK_HINT_RESIZE_INC)
1950 {
1951 NSSize size;
1952
1953 size.width = geometry->width_inc;
1954 size.height = geometry->height_inc;
1955
1956 [impl->toplevel setContentResizeIncrements:size];
1957 }
1958
1959 if (geom_mask & GDK_HINT_ASPECT)
1960 {
1961 NSSize size;
1962
1963 if (geometry->min_aspect != geometry->max_aspect)
1964 {
1965 g_warning ("Only equal minimum and maximum aspect ratios are supported on Mac OS. Using minimum aspect ratio...");
1966 }
1967
1968 size.width = geometry->min_aspect;
1969 size.height = 1.0;
1970
1971 [impl->toplevel setContentAspectRatio:size];
1972 }
1973
1974 if (geom_mask & GDK_HINT_WIN_GRAVITY)
1975 {
1976 /* FIXME: Implement */
1977 }
1978 }
1979
1980 static void
gdk_quartz_window_set_title(GdkWindow * window,const gchar * title)1981 gdk_quartz_window_set_title (GdkWindow *window,
1982 const gchar *title)
1983 {
1984 GdkWindowImplQuartz *impl;
1985
1986 g_return_if_fail (title != NULL);
1987
1988 if (GDK_WINDOW_DESTROYED (window) ||
1989 !WINDOW_IS_TOPLEVEL (window))
1990 return;
1991
1992 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1993
1994 if (impl->toplevel)
1995 {
1996 GDK_QUARTZ_ALLOC_POOL;
1997 [impl->toplevel setTitle:[NSString stringWithUTF8String:title]];
1998 GDK_QUARTZ_RELEASE_POOL;
1999 }
2000 }
2001
2002 static void
gdk_quartz_window_set_role(GdkWindow * window,const gchar * role)2003 gdk_quartz_window_set_role (GdkWindow *window,
2004 const gchar *role)
2005 {
2006 if (GDK_WINDOW_DESTROYED (window) ||
2007 WINDOW_IS_TOPLEVEL (window))
2008 return;
2009
2010 /* FIXME: Implement */
2011 }
2012
2013 static void
gdk_quartz_window_set_startup_id(GdkWindow * window,const gchar * startup_id)2014 gdk_quartz_window_set_startup_id (GdkWindow *window,
2015 const gchar *startup_id)
2016 {
2017 /* FIXME: Implement? */
2018 }
2019
2020 static void
gdk_quartz_window_set_transient_for(GdkWindow * window,GdkWindow * parent)2021 gdk_quartz_window_set_transient_for (GdkWindow *window,
2022 GdkWindow *parent)
2023 {
2024 GdkWindowImplQuartz *window_impl;
2025 GdkWindowImplQuartz *parent_impl;
2026
2027 if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (parent) ||
2028 !WINDOW_IS_TOPLEVEL (window))
2029 return;
2030
2031 window_impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2032 if (!window_impl->toplevel)
2033 return;
2034
2035 GDK_QUARTZ_ALLOC_POOL;
2036
2037 if (window_impl->transient_for)
2038 {
2039 _gdk_quartz_window_detach_from_parent (window);
2040
2041 g_object_unref (window_impl->transient_for);
2042 window_impl->transient_for = NULL;
2043 }
2044
2045 parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
2046 if (parent_impl->toplevel)
2047 {
2048 /* We save the parent because it needs to be unset/reset when
2049 * hiding and showing the window.
2050 */
2051
2052 /* We don't set transients for tooltips, they are already
2053 * handled by the window level being the top one. If we do, then
2054 * the parent window will be brought to the top just because the
2055 * tooltip is, which is not what we want.
2056 */
2057 if (gdk_window_get_type_hint (window) != GDK_WINDOW_TYPE_HINT_TOOLTIP)
2058 {
2059 window_impl->transient_for = g_object_ref (parent);
2060
2061 /* We only add the window if it is shown, otherwise it will
2062 * be shown unconditionally here. If it is not shown, the
2063 * window will be added in show() instead.
2064 */
2065 if (!(window->state & GDK_WINDOW_STATE_WITHDRAWN))
2066 _gdk_quartz_window_attach_to_parent (window);
2067 }
2068 }
2069
2070 GDK_QUARTZ_RELEASE_POOL;
2071 }
2072
2073 static void
gdk_window_quartz_shape_combine_region(GdkWindow * window,const cairo_region_t * shape,gint x,gint y)2074 gdk_window_quartz_shape_combine_region (GdkWindow *window,
2075 const cairo_region_t *shape,
2076 gint x,
2077 gint y)
2078 {
2079 /* FIXME: Implement */
2080 }
2081
2082 static void
gdk_window_quartz_input_shape_combine_region(GdkWindow * window,const cairo_region_t * shape_region,gint offset_x,gint offset_y)2083 gdk_window_quartz_input_shape_combine_region (GdkWindow *window,
2084 const cairo_region_t *shape_region,
2085 gint offset_x,
2086 gint offset_y)
2087 {
2088 /* FIXME: Implement */
2089 }
2090
2091 static void
gdk_quartz_window_set_override_redirect(GdkWindow * window,gboolean override_redirect)2092 gdk_quartz_window_set_override_redirect (GdkWindow *window,
2093 gboolean override_redirect)
2094 {
2095 /* FIXME: Implement */
2096 }
2097
2098 static void
gdk_quartz_window_set_accept_focus(GdkWindow * window,gboolean accept_focus)2099 gdk_quartz_window_set_accept_focus (GdkWindow *window,
2100 gboolean accept_focus)
2101 {
2102 window->accept_focus = accept_focus != FALSE;
2103 }
2104
2105 static void
gdk_quartz_window_set_focus_on_map(GdkWindow * window,gboolean focus_on_map)2106 gdk_quartz_window_set_focus_on_map (GdkWindow *window,
2107 gboolean focus_on_map)
2108 {
2109 window->focus_on_map = focus_on_map != FALSE;
2110 }
2111
2112 static void
gdk_quartz_window_set_icon_name(GdkWindow * window,const gchar * name)2113 gdk_quartz_window_set_icon_name (GdkWindow *window,
2114 const gchar *name)
2115 {
2116 /* FIXME: Implement */
2117 }
2118
2119 static void
gdk_quartz_window_focus(GdkWindow * window,guint32 timestamp)2120 gdk_quartz_window_focus (GdkWindow *window,
2121 guint32 timestamp)
2122 {
2123 GdkWindowImplQuartz *impl;
2124
2125 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2126
2127 if (GDK_WINDOW_DESTROYED (window) ||
2128 !WINDOW_IS_TOPLEVEL (window))
2129 return;
2130
2131 if (window->accept_focus && window->window_type != GDK_WINDOW_TEMP)
2132 {
2133 GDK_QUARTZ_ALLOC_POOL;
2134 [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
2135 clear_toplevel_order ();
2136 GDK_QUARTZ_RELEASE_POOL;
2137 }
2138 }
2139
2140 static gint
window_type_hint_to_level(GdkWindowTypeHint hint)2141 window_type_hint_to_level (GdkWindowTypeHint hint)
2142 {
2143 /* the order in this switch statement corresponds to the actual
2144 * stacking order: the first group is top, the last group is bottom
2145 */
2146 switch (hint)
2147 {
2148 case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
2149 case GDK_WINDOW_TYPE_HINT_COMBO:
2150 case GDK_WINDOW_TYPE_HINT_DND:
2151 case GDK_WINDOW_TYPE_HINT_TOOLTIP:
2152 return NSPopUpMenuWindowLevel;
2153
2154 case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
2155 case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2156 return NSStatusWindowLevel;
2157
2158 case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
2159 case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
2160 return NSTornOffMenuWindowLevel;
2161
2162 case GDK_WINDOW_TYPE_HINT_DOCK:
2163 return NSFloatingWindowLevel; /* NSDockWindowLevel is deprecated, and not replaced */
2164
2165 case GDK_WINDOW_TYPE_HINT_UTILITY:
2166 case GDK_WINDOW_TYPE_HINT_DIALOG: /* Dialog window */
2167 case GDK_WINDOW_TYPE_HINT_NORMAL: /* Normal toplevel window */
2168 case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
2169 return NSNormalWindowLevel;
2170
2171 case GDK_WINDOW_TYPE_HINT_DESKTOP:
2172 return kCGDesktopWindowLevelKey; /* doesn't map to any real Cocoa model */
2173
2174 default:
2175 break;
2176 }
2177
2178 return NSNormalWindowLevel;
2179 }
2180
2181 static gboolean
window_type_hint_to_shadow(GdkWindowTypeHint hint)2182 window_type_hint_to_shadow (GdkWindowTypeHint hint)
2183 {
2184 switch (hint)
2185 {
2186 case GDK_WINDOW_TYPE_HINT_NORMAL: /* Normal toplevel window */
2187 case GDK_WINDOW_TYPE_HINT_DIALOG: /* Dialog window */
2188 case GDK_WINDOW_TYPE_HINT_DOCK:
2189 case GDK_WINDOW_TYPE_HINT_UTILITY:
2190 case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
2191 case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
2192 case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2193 case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
2194 case GDK_WINDOW_TYPE_HINT_COMBO:
2195 case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
2196 case GDK_WINDOW_TYPE_HINT_TOOLTIP:
2197 return TRUE;
2198
2199 case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
2200 case GDK_WINDOW_TYPE_HINT_DESKTOP: /* N/A */
2201 case GDK_WINDOW_TYPE_HINT_DND:
2202 break;
2203
2204 default:
2205 break;
2206 }
2207
2208 return FALSE;
2209 }
2210
2211 static gboolean
window_type_hint_to_hides_on_deactivate(GdkWindowTypeHint hint)2212 window_type_hint_to_hides_on_deactivate (GdkWindowTypeHint hint)
2213 {
2214 switch (hint)
2215 {
2216 case GDK_WINDOW_TYPE_HINT_UTILITY:
2217 case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
2218 case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2219 case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
2220 case GDK_WINDOW_TYPE_HINT_TOOLTIP:
2221 return TRUE;
2222
2223 default:
2224 break;
2225 }
2226
2227 return FALSE;
2228 }
2229
2230 static void
_gdk_quartz_window_update_has_shadow(GdkWindowImplQuartz * impl)2231 _gdk_quartz_window_update_has_shadow (GdkWindowImplQuartz *impl)
2232 {
2233 gboolean has_shadow;
2234
2235 /* In case there is any shadow set we have to turn off the
2236 * NSWindow setHasShadow as the system drawn ones wont match our
2237 * window boundary anymore */
2238 has_shadow = (window_type_hint_to_shadow (impl->type_hint) && !impl->shadow_max);
2239
2240 [impl->toplevel setHasShadow: has_shadow];
2241 }
2242
2243 static void
_gdk_quartz_window_set_collection_behavior(NSWindow * nswindow,GdkWindowTypeHint hint)2244 _gdk_quartz_window_set_collection_behavior (NSWindow *nswindow,
2245 GdkWindowTypeHint hint)
2246 {
2247 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2248 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
2249 #define GDK_QUARTZ_ALLOWS_TILING NSWindowCollectionBehaviorFullScreenAllowsTiling
2250 #define GDK_QUARTZ_DISALLOWS_TILING NSWindowCollectionBehaviorFullScreenDisallowsTiling
2251 #else
2252 #define GDK_QUARTZ_ALLOWS_TILING 1 << 11
2253 #define GDK_QUARTZ_DISALLOWS_TILING 1 << 12
2254 #endif
2255 if (gdk_quartz_osx_version() >= GDK_OSX_LION)
2256 {
2257 /* Fullscreen Collection Behavior */
2258 NSWindowCollectionBehavior behavior = [nswindow collectionBehavior];
2259 switch (hint)
2260 {
2261 case GDK_WINDOW_TYPE_HINT_NORMAL:
2262 case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2263 behavior &= ~(NSWindowCollectionBehaviorFullScreenAuxiliary &
2264 GDK_QUARTZ_DISALLOWS_TILING);
2265 behavior |= (NSWindowCollectionBehaviorFullScreenPrimary |
2266 GDK_QUARTZ_ALLOWS_TILING);
2267
2268 break;
2269 default:
2270 behavior &= ~(NSWindowCollectionBehaviorFullScreenPrimary &
2271 GDK_QUARTZ_ALLOWS_TILING);
2272 behavior |= (NSWindowCollectionBehaviorFullScreenAuxiliary |
2273 GDK_QUARTZ_DISALLOWS_TILING);
2274 break;
2275 }
2276 [nswindow setCollectionBehavior:behavior];
2277 }
2278 #undef GDK_QUARTZ_ALLOWS_TILING
2279 #undef GDK_QUARTZ_DISALLOWS_TILING
2280 #endif
2281 }
2282
2283 static void
gdk_quartz_window_set_type_hint(GdkWindow * window,GdkWindowTypeHint hint)2284 gdk_quartz_window_set_type_hint (GdkWindow *window,
2285 GdkWindowTypeHint hint)
2286 {
2287 GdkWindowImplQuartz *impl;
2288
2289 if (GDK_WINDOW_DESTROYED (window) ||
2290 !WINDOW_IS_TOPLEVEL (window))
2291 return;
2292
2293 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2294
2295 impl->type_hint = hint;
2296
2297 /* Match the documentation, only do something if we're not mapped yet. */
2298 if (GDK_WINDOW_IS_MAPPED (window))
2299 return;
2300
2301 _gdk_quartz_window_update_has_shadow (impl);
2302 if (impl->toplevel)
2303 _gdk_quartz_window_set_collection_behavior (impl->toplevel, hint);
2304 [impl->toplevel setLevel: window_type_hint_to_level (hint)];
2305 [impl->toplevel setHidesOnDeactivate: window_type_hint_to_hides_on_deactivate (hint)];
2306 }
2307
2308 static GdkWindowTypeHint
gdk_quartz_window_get_type_hint(GdkWindow * window)2309 gdk_quartz_window_get_type_hint (GdkWindow *window)
2310 {
2311 if (GDK_WINDOW_DESTROYED (window) ||
2312 !WINDOW_IS_TOPLEVEL (window))
2313 return GDK_WINDOW_TYPE_HINT_NORMAL;
2314
2315 return GDK_WINDOW_IMPL_QUARTZ (window->impl)->type_hint;
2316 }
2317
2318 static void
gdk_quartz_window_set_modal_hint(GdkWindow * window,gboolean modal)2319 gdk_quartz_window_set_modal_hint (GdkWindow *window,
2320 gboolean modal)
2321 {
2322 if (GDK_WINDOW_DESTROYED (window) ||
2323 !WINDOW_IS_TOPLEVEL (window))
2324 return;
2325
2326 /* FIXME: Implement */
2327 }
2328
2329 static void
gdk_quartz_window_set_skip_taskbar_hint(GdkWindow * window,gboolean skips_taskbar)2330 gdk_quartz_window_set_skip_taskbar_hint (GdkWindow *window,
2331 gboolean skips_taskbar)
2332 {
2333 if (GDK_WINDOW_DESTROYED (window) ||
2334 !WINDOW_IS_TOPLEVEL (window))
2335 return;
2336
2337 /* FIXME: Implement */
2338 }
2339
2340 static void
gdk_quartz_window_set_skip_pager_hint(GdkWindow * window,gboolean skips_pager)2341 gdk_quartz_window_set_skip_pager_hint (GdkWindow *window,
2342 gboolean skips_pager)
2343 {
2344 if (GDK_WINDOW_DESTROYED (window) ||
2345 !WINDOW_IS_TOPLEVEL (window))
2346 return;
2347
2348 /* FIXME: Implement */
2349 }
2350
2351 static void
gdk_quartz_window_begin_resize_drag(GdkWindow * window,GdkWindowEdge edge,GdkDevice * device,gint button,gint root_x,gint root_y,guint32 timestamp)2352 gdk_quartz_window_begin_resize_drag (GdkWindow *window,
2353 GdkWindowEdge edge,
2354 GdkDevice *device,
2355 gint button,
2356 gint root_x,
2357 gint root_y,
2358 guint32 timestamp)
2359 {
2360 GdkWindowImplQuartz *impl;
2361
2362 g_return_if_fail (GDK_IS_WINDOW (window));
2363
2364 if (GDK_WINDOW_DESTROYED (window))
2365 return;
2366
2367 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2368
2369 if (!impl->toplevel)
2370 {
2371 g_warning ("Can't call gdk_window_begin_resize_drag on non-toplevel window");
2372 return;
2373 }
2374
2375 [(GdkQuartzNSWindow *)impl->toplevel beginManualResize:edge];
2376 }
2377
2378 static void
gdk_quartz_window_begin_move_drag(GdkWindow * window,GdkDevice * device,gint button,gint root_x,gint root_y,guint32 timestamp)2379 gdk_quartz_window_begin_move_drag (GdkWindow *window,
2380 GdkDevice *device,
2381 gint button,
2382 gint root_x,
2383 gint root_y,
2384 guint32 timestamp)
2385 {
2386 GdkWindowImplQuartz *impl;
2387
2388 if (GDK_WINDOW_DESTROYED (window) ||
2389 !WINDOW_IS_TOPLEVEL (window))
2390 return;
2391
2392 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2393
2394 if (!impl->toplevel)
2395 {
2396 g_warning ("Can't call gdk_window_begin_move_drag on non-toplevel window");
2397 return;
2398 }
2399
2400 [(GdkQuartzNSWindow *)impl->toplevel beginManualMove];
2401 }
2402
2403 static void
gdk_quartz_window_set_icon_list(GdkWindow * window,GList * pixbufs)2404 gdk_quartz_window_set_icon_list (GdkWindow *window,
2405 GList *pixbufs)
2406 {
2407 /* FIXME: Implement */
2408 }
2409
2410 static void
gdk_quartz_window_get_frame_extents(GdkWindow * window,GdkRectangle * rect)2411 gdk_quartz_window_get_frame_extents (GdkWindow *window,
2412 GdkRectangle *rect)
2413 {
2414 GdkWindow *toplevel;
2415 GdkWindowImplQuartz *impl;
2416 NSRect ns_rect;
2417
2418 g_return_if_fail (rect != NULL);
2419
2420
2421 rect->x = 0;
2422 rect->y = 0;
2423 rect->width = 1;
2424 rect->height = 1;
2425
2426 toplevel = gdk_window_get_effective_toplevel (window);
2427 impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
2428
2429 ns_rect = [impl->toplevel frame];
2430
2431 _gdk_quartz_window_xy_to_gdk_xy (ns_rect.origin.x,
2432 ns_rect.origin.y + ns_rect.size.height,
2433 &rect->x, &rect->y);
2434
2435 rect->width = ns_rect.size.width;
2436 rect->height = ns_rect.size.height;
2437 }
2438
2439 /* Fake protocol to make gcc think that it's OK to call setStyleMask
2440 even if it isn't. We check to make sure before actually calling
2441 it. */
2442
2443 @protocol CanSetStyleMask
2444 - (void)setStyleMask:(int)mask;
2445 @end
2446
2447 static void
gdk_quartz_window_set_decorations(GdkWindow * window,GdkWMDecoration decorations)2448 gdk_quartz_window_set_decorations (GdkWindow *window,
2449 GdkWMDecoration decorations)
2450 {
2451 GdkWindowImplQuartz *impl;
2452 NSUInteger old_mask, new_mask;
2453 NSView *old_view;
2454
2455 if (GDK_WINDOW_DESTROYED (window) ||
2456 !WINDOW_IS_TOPLEVEL (window))
2457 return;
2458
2459 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2460
2461 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP ||
2462 impl->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN )
2463 {
2464 new_mask = GDK_QUARTZ_BORDERLESS_WINDOW;
2465 }
2466 else if (decorations == 0) {
2467 new_mask = GDK_QUARTZ_BORDERLESS_WINDOW | GDK_QUARTZ_MINIATURIZABLE_WINDOW;
2468 }
2469 else
2470 {
2471 /* FIXME: Honor other GDK_DECOR_* flags. */
2472 new_mask = (GDK_QUARTZ_TITLED_WINDOW | GDK_QUARTZ_CLOSABLE_WINDOW |
2473 GDK_QUARTZ_MINIATURIZABLE_WINDOW |
2474 GDK_QUARTZ_RESIZABLE_WINDOW);
2475 }
2476
2477 GDK_QUARTZ_ALLOC_POOL;
2478
2479 old_mask = [impl->toplevel styleMask];
2480
2481 if (old_mask != new_mask)
2482 {
2483 NSRect rect;
2484
2485 old_view = [[impl->toplevel contentView] retain];
2486
2487 rect = [impl->toplevel frame];
2488
2489 /* Properly update the size of the window when the titlebar is
2490 * added or removed.
2491 */
2492 if (old_mask == GDK_QUARTZ_BORDERLESS_WINDOW &&
2493 new_mask != GDK_QUARTZ_BORDERLESS_WINDOW)
2494 {
2495 rect = [NSWindow frameRectForContentRect:rect styleMask:new_mask];
2496
2497 }
2498 else if (old_mask != GDK_QUARTZ_BORDERLESS_WINDOW &&
2499 new_mask == GDK_QUARTZ_BORDERLESS_WINDOW)
2500 {
2501 rect = [NSWindow contentRectForFrameRect:rect styleMask:old_mask];
2502 }
2503
2504 /* Note, before OS 10.6 there doesn't seem to be a way to change this
2505 * without recreating the toplevel. From 10.6 onward, a simple call to
2506 * setStyleMask takes care of most of this, except for ensuring that the
2507 * title is set.
2508 */
2509 if ([impl->toplevel respondsToSelector:@selector(setStyleMask:)])
2510 {
2511 NSString *title = [impl->toplevel title];
2512
2513 [(id<CanSetStyleMask>)impl->toplevel setStyleMask:new_mask];
2514
2515 /* It appears that unsetting and then resetting
2516 * GDK_QUARTZ_TITLED_WINDOW does not reset the title in the
2517 * title bar as might be expected.
2518 *
2519 * In theory we only need to set this if new_mask includes
2520 * GDK_QUARTZ_TITLED_WINDOW. This behaved extremely oddly when
2521 * conditionalized upon that and since it has no side effects (i.e.
2522 * if GDK_QUARTZ_TITLED_WINDOW is not requested, the title will not be
2523 * displayed) just do it unconditionally. We also must null check
2524 * 'title' before setting it to avoid crashing.
2525 */
2526 if (title)
2527 [impl->toplevel setTitle:title];
2528 }
2529 else
2530 {
2531 NSString *title = [impl->toplevel title];
2532 NSColor *bg = [impl->toplevel backgroundColor];
2533 NSScreen *screen = [impl->toplevel screen];
2534
2535 /* Make sure the old window is closed, recall that releasedWhenClosed
2536 * is set on GdkQuartzWindows.
2537 */
2538 [impl->toplevel close];
2539
2540 impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:rect
2541 styleMask:new_mask
2542 backing:NSBackingStoreBuffered
2543 defer:NO
2544 screen:screen];
2545 _gdk_quartz_window_update_has_shadow (impl);
2546
2547 [impl->toplevel setLevel: window_type_hint_to_level (impl->type_hint)];
2548 if (title)
2549 [impl->toplevel setTitle:title];
2550 [impl->toplevel setBackgroundColor:bg];
2551 [impl->toplevel setHidesOnDeactivate: window_type_hint_to_hides_on_deactivate (impl->type_hint)];
2552 [impl->toplevel setContentView:old_view];
2553 }
2554
2555 if (new_mask == GDK_QUARTZ_BORDERLESS_WINDOW)
2556 {
2557 [impl->toplevel setContentSize:rect.size];
2558 }
2559 else
2560 [impl->toplevel setFrame:rect display:YES];
2561
2562 /* Invalidate the window shadow for non-opaque views that have shadow
2563 * enabled, to get the shadow shape updated.
2564 */
2565 if (![old_view isOpaque] && [impl->toplevel hasShadow])
2566 [(GdkQuartzView*)old_view setNeedsInvalidateShadow:YES];
2567
2568 [old_view release];
2569 }
2570
2571 GDK_QUARTZ_RELEASE_POOL;
2572 }
2573
2574 static gboolean
gdk_quartz_window_get_decorations(GdkWindow * window,GdkWMDecoration * decorations)2575 gdk_quartz_window_get_decorations (GdkWindow *window,
2576 GdkWMDecoration *decorations)
2577 {
2578 GdkWindowImplQuartz *impl;
2579
2580 if (GDK_WINDOW_DESTROYED (window) ||
2581 !WINDOW_IS_TOPLEVEL (window))
2582 return FALSE;
2583
2584 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2585
2586 if (decorations)
2587 {
2588 /* Borderless is 0, so we can't check it as a bit being set. */
2589 if ([impl->toplevel styleMask] == GDK_QUARTZ_BORDERLESS_WINDOW)
2590 {
2591 *decorations = 0;
2592 }
2593 else
2594 {
2595 /* FIXME: Honor the other GDK_DECOR_* flags. */
2596 *decorations = GDK_DECOR_ALL;
2597 }
2598 }
2599
2600 return TRUE;
2601 }
2602
2603 static void
gdk_quartz_window_set_functions(GdkWindow * window,GdkWMFunction functions)2604 gdk_quartz_window_set_functions (GdkWindow *window,
2605 GdkWMFunction functions)
2606 {
2607 GdkWindowImplQuartz *impl;
2608 gboolean min, max, close;
2609
2610 g_return_if_fail (GDK_IS_WINDOW (window));
2611
2612 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2613
2614 if (functions & GDK_FUNC_ALL)
2615 {
2616 min = !(functions & GDK_FUNC_MINIMIZE);
2617 max = !(functions & GDK_FUNC_MAXIMIZE);
2618 close = !(functions & GDK_FUNC_CLOSE);
2619 }
2620 else
2621 {
2622 min = (functions & GDK_FUNC_MINIMIZE);
2623 max = (functions & GDK_FUNC_MAXIMIZE);
2624 close = (functions & GDK_FUNC_CLOSE);
2625 }
2626
2627 if (impl->toplevel)
2628 {
2629 NSUInteger mask = [impl->toplevel styleMask];
2630
2631 if (min)
2632 mask = mask | GDK_QUARTZ_MINIATURIZABLE_WINDOW;
2633 else
2634 mask = mask & ~GDK_QUARTZ_MINIATURIZABLE_WINDOW;
2635
2636 if (max)
2637 mask = mask | GDK_QUARTZ_RESIZABLE_WINDOW;
2638 else
2639 mask = mask & ~GDK_QUARTZ_RESIZABLE_WINDOW;
2640
2641 if (close)
2642 mask = mask | GDK_QUARTZ_CLOSABLE_WINDOW;
2643 else
2644 mask = mask & ~GDK_QUARTZ_CLOSABLE_WINDOW;
2645
2646 [impl->toplevel setStyleMask:mask];
2647 }
2648 }
2649
2650 static void
gdk_quartz_window_stick(GdkWindow * window)2651 gdk_quartz_window_stick (GdkWindow *window)
2652 {
2653 if (GDK_WINDOW_DESTROYED (window) ||
2654 !WINDOW_IS_TOPLEVEL (window))
2655 return;
2656 }
2657
2658 static void
gdk_quartz_window_unstick(GdkWindow * window)2659 gdk_quartz_window_unstick (GdkWindow *window)
2660 {
2661 if (GDK_WINDOW_DESTROYED (window) ||
2662 !WINDOW_IS_TOPLEVEL (window))
2663 return;
2664 }
2665
2666 static void
gdk_quartz_window_maximize(GdkWindow * window)2667 gdk_quartz_window_maximize (GdkWindow *window)
2668 {
2669 GdkWindowImplQuartz *impl;
2670 gboolean maximized;
2671
2672 if (GDK_WINDOW_DESTROYED (window) ||
2673 !WINDOW_IS_TOPLEVEL (window))
2674 return;
2675
2676 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2677 maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
2678
2679 if (GDK_WINDOW_IS_MAPPED (window))
2680 {
2681 GDK_QUARTZ_ALLOC_POOL;
2682
2683 if (impl->toplevel && !maximized)
2684 [impl->toplevel zoom:nil];
2685
2686 GDK_QUARTZ_RELEASE_POOL;
2687 }
2688 }
2689
2690 static void
gdk_quartz_window_unmaximize(GdkWindow * window)2691 gdk_quartz_window_unmaximize (GdkWindow *window)
2692 {
2693 GdkWindowImplQuartz *impl;
2694 gboolean maximized;
2695
2696 if (GDK_WINDOW_DESTROYED (window) ||
2697 !WINDOW_IS_TOPLEVEL (window))
2698 return;
2699
2700 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2701 maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
2702
2703 if (GDK_WINDOW_IS_MAPPED (window))
2704 {
2705 GDK_QUARTZ_ALLOC_POOL;
2706
2707 if (impl->toplevel && maximized)
2708 [impl->toplevel zoom:nil];
2709
2710 GDK_QUARTZ_RELEASE_POOL;
2711 }
2712 }
2713
2714 static void
gdk_quartz_window_iconify(GdkWindow * window)2715 gdk_quartz_window_iconify (GdkWindow *window)
2716 {
2717 GdkWindowImplQuartz *impl;
2718
2719 if (GDK_WINDOW_DESTROYED (window) ||
2720 !WINDOW_IS_TOPLEVEL (window))
2721 return;
2722
2723 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2724
2725 if (GDK_WINDOW_IS_MAPPED (window))
2726 {
2727 GDK_QUARTZ_ALLOC_POOL;
2728
2729 if (impl->toplevel)
2730 [impl->toplevel miniaturize:nil];
2731
2732 GDK_QUARTZ_RELEASE_POOL;
2733 }
2734 else
2735 {
2736 gdk_synthesize_window_state (window,
2737 0,
2738 GDK_WINDOW_STATE_ICONIFIED);
2739 }
2740 }
2741
2742 static void
gdk_quartz_window_deiconify(GdkWindow * window)2743 gdk_quartz_window_deiconify (GdkWindow *window)
2744 {
2745 GdkWindowImplQuartz *impl;
2746
2747 if (GDK_WINDOW_DESTROYED (window) ||
2748 !WINDOW_IS_TOPLEVEL (window))
2749 return;
2750
2751 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2752
2753 if (GDK_WINDOW_IS_MAPPED (window))
2754 {
2755 GDK_QUARTZ_ALLOC_POOL;
2756
2757 if (impl->toplevel)
2758 [impl->toplevel deminiaturize:nil];
2759
2760 GDK_QUARTZ_RELEASE_POOL;
2761 }
2762 else
2763 {
2764 gdk_synthesize_window_state (window,
2765 GDK_WINDOW_STATE_ICONIFIED,
2766 0);
2767 }
2768 }
2769
2770 static gboolean
window_is_fullscreen(GdkWindow * window)2771 window_is_fullscreen (GdkWindow *window)
2772 {
2773 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2774
2775 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2776 if (gdk_quartz_osx_version() >= GDK_OSX_LION)
2777 return ([impl->toplevel styleMask] & GDK_QUARTZ_FULLSCREEN_WINDOW) != 0;
2778 else
2779 #endif
2780 return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA) != NULL;
2781 }
2782
2783 static void
gdk_quartz_window_fullscreen(GdkWindow * window)2784 gdk_quartz_window_fullscreen (GdkWindow *window)
2785 {
2786 GdkWindowImplQuartz *impl;
2787
2788 if (GDK_WINDOW_DESTROYED (window) ||
2789 !WINDOW_IS_TOPLEVEL (window))
2790 return;
2791
2792 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2793
2794 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2795 if (gdk_quartz_osx_version() >= GDK_OSX_LION)
2796 {
2797 if (!window_is_fullscreen (window))
2798 [impl->toplevel toggleFullScreen:nil];
2799 }
2800 else
2801 {
2802 #endif
2803 FullscreenSavedGeometry *geometry;
2804 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2805 NSRect frame;
2806
2807 if (GDK_WINDOW_DESTROYED (window) ||
2808 !WINDOW_IS_TOPLEVEL (window))
2809 return;
2810
2811 geometry = get_fullscreen_geometry (window);
2812 if (!geometry)
2813 {
2814 geometry = g_new (FullscreenSavedGeometry, 1);
2815
2816 geometry->x = window->x;
2817 geometry->y = window->y;
2818 geometry->width = window->width;
2819 geometry->height = window->height;
2820
2821 if (!gdk_window_get_decorations (window, &geometry->decor))
2822 geometry->decor = GDK_DECOR_ALL;
2823
2824 g_object_set_data_full (G_OBJECT (window),
2825 FULLSCREEN_DATA, geometry,
2826 g_free);
2827
2828 gdk_window_set_decorations (window, 0);
2829
2830 frame = [[impl->toplevel screen] frame];
2831 move_resize_window_internal (window,
2832 0, 0,
2833 frame.size.width, frame.size.height);
2834 [impl->toplevel setContentSize:frame.size];
2835 [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
2836
2837 clear_toplevel_order ();
2838 }
2839
2840 SetSystemUIMode (kUIModeAllHidden, kUIOptionAutoShowMenuBar);
2841
2842 gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
2843 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2844 }
2845 #endif
2846 }
2847
2848 static void
gdk_quartz_window_unfullscreen(GdkWindow * window)2849 gdk_quartz_window_unfullscreen (GdkWindow *window)
2850 {
2851 GdkWindowImplQuartz *impl;
2852
2853 if (GDK_WINDOW_DESTROYED (window) ||
2854 !WINDOW_IS_TOPLEVEL (window))
2855 return;
2856
2857 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2858 if (gdk_quartz_osx_version() >= GDK_OSX_LION)
2859 {
2860 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2861
2862 if (window_is_fullscreen (window))
2863 [impl->toplevel toggleFullScreen:nil];
2864 }
2865 else
2866 {
2867 #endif
2868 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2869 FullscreenSavedGeometry *geometry;
2870
2871 if (GDK_WINDOW_DESTROYED (window) ||
2872 !WINDOW_IS_TOPLEVEL (window))
2873 return;
2874
2875 geometry = get_fullscreen_geometry (window);
2876 if (geometry)
2877 {
2878 SetSystemUIMode (kUIModeNormal, 0);
2879
2880 move_resize_window_internal (window,
2881 geometry->x,
2882 geometry->y,
2883 geometry->width,
2884 geometry->height);
2885
2886 gdk_window_set_decorations (window, geometry->decor);
2887
2888 g_object_set_data (G_OBJECT (window), FULLSCREEN_DATA, NULL);
2889
2890 [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
2891 clear_toplevel_order ();
2892
2893 gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
2894 }
2895
2896 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2897 }
2898 #endif
2899 }
2900
2901 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2902 static FullscreenSavedGeometry *
get_fullscreen_geometry(GdkWindow * window)2903 get_fullscreen_geometry (GdkWindow *window)
2904 {
2905 return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA);
2906 }
2907 #endif
2908
2909 void
_gdk_quartz_window_update_fullscreen_state(GdkWindow * window)2910 _gdk_quartz_window_update_fullscreen_state (GdkWindow *window)
2911 {
2912 if (GDK_WINDOW_DESTROYED (window) || !WINDOW_IS_TOPLEVEL (window))
2913 return;
2914
2915 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2916 if (gdk_quartz_osx_version() >= GDK_OSX_LION)
2917 {
2918 gboolean is_fullscreen = window_is_fullscreen (window);
2919 gboolean was_fullscreen = (gdk_window_get_state (window) &
2920 GDK_WINDOW_STATE_FULLSCREEN) != 0;
2921
2922 if (is_fullscreen != was_fullscreen)
2923 {
2924 if (is_fullscreen)
2925 gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
2926 else
2927 gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
2928 }
2929 }
2930 #endif
2931 }
2932
2933 static void
gdk_quartz_window_set_keep_above(GdkWindow * window,gboolean setting)2934 gdk_quartz_window_set_keep_above (GdkWindow *window,
2935 gboolean setting)
2936 {
2937 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2938 gint level;
2939
2940 g_return_if_fail (GDK_IS_WINDOW (window));
2941
2942 if (GDK_WINDOW_DESTROYED (window) ||
2943 !WINDOW_IS_TOPLEVEL (window))
2944 return;
2945
2946 level = window_type_hint_to_level (gdk_window_get_type_hint (window));
2947
2948 /* Adjust normal window level by one if necessary. */
2949 [impl->toplevel setLevel: level + (setting ? 1 : 0)];
2950 }
2951
2952 static void
gdk_quartz_window_set_keep_below(GdkWindow * window,gboolean setting)2953 gdk_quartz_window_set_keep_below (GdkWindow *window,
2954 gboolean setting)
2955 {
2956 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2957 gint level;
2958
2959 g_return_if_fail (GDK_IS_WINDOW (window));
2960
2961 if (GDK_WINDOW_DESTROYED (window) ||
2962 !WINDOW_IS_TOPLEVEL (window))
2963 return;
2964
2965 level = window_type_hint_to_level (gdk_window_get_type_hint (window));
2966
2967 /* Adjust normal window level by one if necessary. */
2968 [impl->toplevel setLevel: level - (setting ? 1 : 0)];
2969 }
2970
2971 /* X11 "feature" not useful in other backends. */
2972 static GdkWindow *
gdk_quartz_window_get_group(GdkWindow * window)2973 gdk_quartz_window_get_group (GdkWindow *window)
2974 {
2975 return NULL;
2976 }
2977
2978 /* X11 "feature" not useful in other backends. */
2979 static void
gdk_quartz_window_set_group(GdkWindow * window,GdkWindow * leader)2980 gdk_quartz_window_set_group (GdkWindow *window,
2981 GdkWindow *leader)
2982 {
2983 }
2984
2985 static void
gdk_quartz_window_destroy_notify(GdkWindow * window)2986 gdk_quartz_window_destroy_notify (GdkWindow *window)
2987 {
2988 GdkDisplay *display = gdk_window_get_display (window);
2989 GdkSeat *seat = gdk_display_get_default_seat (display);
2990 gdk_seat_ungrab (seat);
2991 }
2992
2993 static void
gdk_quartz_window_set_opacity(GdkWindow * window,gdouble opacity)2994 gdk_quartz_window_set_opacity (GdkWindow *window,
2995 gdouble opacity)
2996 {
2997 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2998
2999 g_return_if_fail (GDK_IS_WINDOW (window));
3000 g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
3001
3002 if (GDK_WINDOW_DESTROYED (window) ||
3003 !WINDOW_IS_TOPLEVEL (window))
3004 return;
3005
3006 if (opacity < 0)
3007 opacity = 0;
3008 else if (opacity > 1)
3009 opacity = 1;
3010
3011 [impl->toplevel setAlphaValue: opacity];
3012 }
3013
3014 static void
gdk_quartz_window_set_shadow_width(GdkWindow * window,gint left,gint right,gint top,gint bottom)3015 gdk_quartz_window_set_shadow_width (GdkWindow *window,
3016 gint left,
3017 gint right,
3018 gint top,
3019 gint bottom)
3020 {
3021 GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
3022
3023 g_return_if_fail (GDK_IS_WINDOW (window));
3024 g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
3025
3026 if (GDK_WINDOW_DESTROYED (window) ||
3027 !WINDOW_IS_TOPLEVEL (window))
3028 return;
3029
3030 impl->shadow_top = top;
3031 impl->shadow_max = MAX (MAX (left, right), MAX (top, bottom));
3032 _gdk_quartz_window_update_has_shadow (impl);
3033 }
3034
3035 static cairo_region_t *
gdk_quartz_window_get_shape(GdkWindow * window)3036 gdk_quartz_window_get_shape (GdkWindow *window)
3037 {
3038 /* FIXME: implement */
3039 return NULL;
3040 }
3041
3042 static cairo_region_t *
gdk_quartz_window_get_input_shape(GdkWindow * window)3043 gdk_quartz_window_get_input_shape (GdkWindow *window)
3044 {
3045 /* FIXME: implement */
3046 return NULL;
3047 }
3048
3049 /* Protocol to build cleanly for OSX < 10.7 */
3050 @protocol ScaleFactor
3051 - (CGFloat) backingScaleFactor;
3052 @end
3053
3054 static gint
gdk_quartz_window_get_scale_factor(GdkWindow * window)3055 gdk_quartz_window_get_scale_factor (GdkWindow *window)
3056 {
3057 GdkWindowImplQuartz *impl;
3058
3059 if (GDK_WINDOW_DESTROYED (window))
3060 return 1;
3061
3062 impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
3063
3064 if (impl->toplevel != NULL && gdk_quartz_osx_version() >= GDK_OSX_LION)
3065 return [(id <ScaleFactor>) impl->toplevel backingScaleFactor];
3066
3067 return 1;
3068 }
3069
3070 static void
gdk_window_impl_quartz_class_init(GdkWindowImplQuartzClass * klass)3071 gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass)
3072 {
3073 GObjectClass *object_class = G_OBJECT_CLASS (klass);
3074 GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
3075 GdkWindowImplQuartzClass *impl_quartz_class = GDK_WINDOW_IMPL_QUARTZ_CLASS (klass);
3076
3077 parent_class = g_type_class_peek_parent (klass);
3078
3079 object_class->finalize = gdk_window_impl_quartz_finalize;
3080
3081 impl_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
3082 impl_class->show = gdk_window_quartz_show;
3083 impl_class->hide = gdk_window_quartz_hide;
3084 impl_class->withdraw = gdk_window_quartz_withdraw;
3085 impl_class->set_events = gdk_window_quartz_set_events;
3086 impl_class->get_events = gdk_window_quartz_get_events;
3087 impl_class->raise = gdk_window_quartz_raise;
3088 impl_class->lower = gdk_window_quartz_lower;
3089 impl_class->restack_toplevel = gdk_window_quartz_restack_toplevel;
3090 impl_class->move_resize = gdk_window_quartz_move_resize;
3091 impl_class->set_background = gdk_window_quartz_set_background;
3092 impl_class->reparent = gdk_window_quartz_reparent;
3093 impl_class->set_device_cursor = gdk_window_quartz_set_device_cursor;
3094 impl_class->get_geometry = gdk_window_quartz_get_geometry;
3095 impl_class->get_root_coords = gdk_window_quartz_get_root_coords;
3096 impl_class->get_device_state = gdk_window_quartz_get_device_state;
3097 impl_class->shape_combine_region = gdk_window_quartz_shape_combine_region;
3098 impl_class->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
3099 impl_class->destroy = gdk_quartz_window_destroy;
3100 impl_class->destroy_foreign = gdk_quartz_window_destroy_foreign;
3101 impl_class->get_shape = gdk_quartz_window_get_shape;
3102 impl_class->get_input_shape = gdk_quartz_window_get_input_shape;
3103 impl_class->begin_paint = gdk_window_impl_quartz_begin_paint;
3104 impl_class->get_scale_factor = gdk_quartz_window_get_scale_factor;
3105
3106 impl_class->focus = gdk_quartz_window_focus;
3107 impl_class->set_type_hint = gdk_quartz_window_set_type_hint;
3108 impl_class->get_type_hint = gdk_quartz_window_get_type_hint;
3109 impl_class->set_modal_hint = gdk_quartz_window_set_modal_hint;
3110 impl_class->set_skip_taskbar_hint = gdk_quartz_window_set_skip_taskbar_hint;
3111 impl_class->set_skip_pager_hint = gdk_quartz_window_set_skip_pager_hint;
3112 impl_class->set_urgency_hint = gdk_quartz_window_set_urgency_hint;
3113 impl_class->set_geometry_hints = gdk_quartz_window_set_geometry_hints;
3114 impl_class->set_title = gdk_quartz_window_set_title;
3115 impl_class->set_role = gdk_quartz_window_set_role;
3116 impl_class->set_startup_id = gdk_quartz_window_set_startup_id;
3117 impl_class->set_transient_for = gdk_quartz_window_set_transient_for;
3118 impl_class->get_frame_extents = gdk_quartz_window_get_frame_extents;
3119 impl_class->set_override_redirect = gdk_quartz_window_set_override_redirect;
3120 impl_class->set_accept_focus = gdk_quartz_window_set_accept_focus;
3121 impl_class->set_focus_on_map = gdk_quartz_window_set_focus_on_map;
3122 impl_class->set_icon_list = gdk_quartz_window_set_icon_list;
3123 impl_class->set_icon_name = gdk_quartz_window_set_icon_name;
3124 impl_class->iconify = gdk_quartz_window_iconify;
3125 impl_class->deiconify = gdk_quartz_window_deiconify;
3126 impl_class->stick = gdk_quartz_window_stick;
3127 impl_class->unstick = gdk_quartz_window_unstick;
3128 impl_class->maximize = gdk_quartz_window_maximize;
3129 impl_class->unmaximize = gdk_quartz_window_unmaximize;
3130 impl_class->fullscreen = gdk_quartz_window_fullscreen;
3131 impl_class->unfullscreen = gdk_quartz_window_unfullscreen;
3132 impl_class->set_keep_above = gdk_quartz_window_set_keep_above;
3133 impl_class->set_keep_below = gdk_quartz_window_set_keep_below;
3134 impl_class->get_group = gdk_quartz_window_get_group;
3135 impl_class->set_group = gdk_quartz_window_set_group;
3136 impl_class->set_decorations = gdk_quartz_window_set_decorations;
3137 impl_class->get_decorations = gdk_quartz_window_get_decorations;
3138 impl_class->set_functions = gdk_quartz_window_set_functions;
3139 impl_class->begin_resize_drag = gdk_quartz_window_begin_resize_drag;
3140 impl_class->begin_move_drag = gdk_quartz_window_begin_move_drag;
3141 impl_class->set_opacity = gdk_quartz_window_set_opacity;
3142 impl_class->set_shadow_width = gdk_quartz_window_set_shadow_width;
3143 impl_class->destroy_notify = gdk_quartz_window_destroy_notify;
3144 impl_class->register_dnd = _gdk_quartz_window_register_dnd;
3145 impl_class->drag_begin = _gdk_quartz_window_drag_begin;
3146 impl_class->process_updates_recurse = _gdk_quartz_window_process_updates_recurse;
3147 impl_class->sync_rendering = _gdk_quartz_window_sync_rendering;
3148 impl_class->simulate_key = _gdk_quartz_window_simulate_key;
3149 impl_class->simulate_button = _gdk_quartz_window_simulate_button;
3150 impl_class->get_property = _gdk_quartz_window_get_property;
3151 impl_class->change_property = _gdk_quartz_window_change_property;
3152 impl_class->delete_property = _gdk_quartz_window_delete_property;
3153
3154 impl_class->create_gl_context = gdk_quartz_window_create_gl_context;
3155 impl_class->invalidate_for_new_frame = gdk_quartz_window_invalidate_for_new_frame;
3156
3157 impl_quartz_class->get_context = gdk_window_impl_quartz_get_context;
3158 impl_quartz_class->release_context = gdk_window_impl_quartz_release_context;
3159 }
3160
3161 GType
_gdk_window_impl_quartz_get_type(void)3162 _gdk_window_impl_quartz_get_type (void)
3163 {
3164 static GType object_type = 0;
3165
3166 if (!object_type)
3167 {
3168 const GTypeInfo object_info =
3169 {
3170 sizeof (GdkWindowImplQuartzClass),
3171 (GBaseInitFunc) NULL,
3172 (GBaseFinalizeFunc) NULL,
3173 (GClassInitFunc) gdk_window_impl_quartz_class_init,
3174 NULL, /* class_finalize */
3175 NULL, /* class_data */
3176 sizeof (GdkWindowImplQuartz),
3177 0, /* n_preallocs */
3178 (GInstanceInitFunc) gdk_window_impl_quartz_init,
3179 };
3180
3181 object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL,
3182 "GdkWindowImplQuartz",
3183 &object_info, 0);
3184 }
3185
3186 return object_type;
3187 }
3188
3189 CGContextRef
gdk_quartz_window_get_context(GdkWindowImplQuartz * window,gboolean antialias)3190 gdk_quartz_window_get_context (GdkWindowImplQuartz *window,
3191 gboolean antialias)
3192 {
3193 if (!GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->get_context)
3194 {
3195 g_warning ("%s doesn't implement GdkWindowImplQuartzClass::get_context()",
3196 G_OBJECT_TYPE_NAME (window));
3197 return NULL;
3198 }
3199
3200 return GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->get_context (window, antialias);
3201 }
3202
3203 void
gdk_quartz_window_release_context(GdkWindowImplQuartz * window,CGContextRef cg_context)3204 gdk_quartz_window_release_context (GdkWindowImplQuartz *window,
3205 CGContextRef cg_context)
3206 {
3207 if (!GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->release_context)
3208 {
3209 g_warning ("%s doesn't implement GdkWindowImplQuartzClass::release_context()",
3210 G_OBJECT_TYPE_NAME (window));
3211 return;
3212 }
3213
3214 GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->release_context (window, cg_context);
3215 }
3216
3217
3218
3219 static CGContextRef
gdk_root_window_impl_quartz_get_context(GdkWindowImplQuartz * window,gboolean antialias)3220 gdk_root_window_impl_quartz_get_context (GdkWindowImplQuartz *window,
3221 gboolean antialias)
3222 {
3223 CGColorSpaceRef colorspace;
3224 CGContextRef cg_context;
3225 GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (window);
3226
3227 if (GDK_WINDOW_DESTROYED (window_impl->wrapper))
3228 return NULL;
3229
3230 /* We do not have the notion of a root window on OS X. We fake this
3231 * by creating a 1x1 bitmap and return a context to that.
3232 */
3233 colorspace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
3234 cg_context = CGBitmapContextCreate (NULL,
3235 1, 1, 8, 4, colorspace,
3236 (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
3237 CGColorSpaceRelease (colorspace);
3238
3239 return cg_context;
3240 }
3241
3242 static void
gdk_root_window_impl_quartz_release_context(GdkWindowImplQuartz * window,CGContextRef cg_context)3243 gdk_root_window_impl_quartz_release_context (GdkWindowImplQuartz *window,
3244 CGContextRef cg_context)
3245 {
3246 CGContextRelease (cg_context);
3247 }
3248
3249 static void
gdk_root_window_impl_quartz_class_init(GdkRootWindowImplQuartzClass * klass)3250 gdk_root_window_impl_quartz_class_init (GdkRootWindowImplQuartzClass *klass)
3251 {
3252 GdkWindowImplQuartzClass *window_quartz_class = GDK_WINDOW_IMPL_QUARTZ_CLASS (klass);
3253
3254 root_window_parent_class = g_type_class_peek_parent (klass);
3255
3256 window_quartz_class->get_context = gdk_root_window_impl_quartz_get_context;
3257 window_quartz_class->release_context = gdk_root_window_impl_quartz_release_context;
3258 }
3259
3260 static void
gdk_root_window_impl_quartz_init(GdkRootWindowImplQuartz * impl)3261 gdk_root_window_impl_quartz_init (GdkRootWindowImplQuartz *impl)
3262 {
3263 }
3264
3265 GType
_gdk_root_window_impl_quartz_get_type(void)3266 _gdk_root_window_impl_quartz_get_type (void)
3267 {
3268 static GType object_type = 0;
3269
3270 if (!object_type)
3271 {
3272 const GTypeInfo object_info =
3273 {
3274 sizeof (GdkRootWindowImplQuartzClass),
3275 (GBaseInitFunc) NULL,
3276 (GBaseFinalizeFunc) NULL,
3277 (GClassInitFunc) gdk_root_window_impl_quartz_class_init,
3278 NULL, /* class_finalize */
3279 NULL, /* class_data */
3280 sizeof (GdkRootWindowImplQuartz),
3281 0, /* n_preallocs */
3282 (GInstanceInitFunc) gdk_root_window_impl_quartz_init,
3283 };
3284
3285 object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL_QUARTZ,
3286 "GdkRootWindowQuartz",
3287 &object_info, 0);
3288 }
3289
3290 return object_type;
3291 }
3292