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