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