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