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