]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkwindow-quartz.c
Merge branch 'bgo593793-filechooser-recent-folders-master'
[~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 static 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_quartz_window_init_windowing (GdkDisplay *display,
1047                                    GdkScreen  *screen)
1048 {
1049   GdkWindowImplQuartz *impl;
1050
1051   g_assert (_gdk_root == NULL);
1052
1053   _gdk_root = _gdk_display_create_window (display);
1054
1055   _gdk_root->impl = g_object_new (_gdk_root_window_impl_quartz_get_type (), NULL);
1056   _gdk_root->impl_window = _gdk_root;
1057   _gdk_root->visual = gdk_screen_get_system_visual (screen);
1058
1059   impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
1060
1061   _gdk_quartz_screen_update_window_sizes (screen);
1062
1063   _gdk_root->state = 0; /* We don't want GDK_WINDOW_STATE_WITHDRAWN here */
1064   _gdk_root->window_type = GDK_WINDOW_ROOT;
1065   _gdk_root->depth = 24;
1066   _gdk_root->viewable = TRUE;
1067
1068   impl->wrapper = _gdk_root;
1069 }
1070
1071 static void
1072 gdk_quartz_window_destroy (GdkWindow *window,
1073                            gboolean   recursing,
1074                            gboolean   foreign_destroy)
1075 {
1076   GdkWindowImplQuartz *impl;
1077   GdkWindow *parent;
1078
1079   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1080
1081   main_window_stack = g_slist_remove (main_window_stack, window);
1082
1083   g_list_free (impl->sorted_children);
1084   impl->sorted_children = NULL;
1085
1086   parent = window->parent;
1087   if (parent)
1088     {
1089       GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
1090
1091       parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window);
1092     }
1093
1094   if (impl->cairo_surface)
1095     {
1096       cairo_surface_finish (impl->cairo_surface);
1097       cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
1098                                    NULL, NULL);
1099       impl->cairo_surface = NULL;
1100     }
1101
1102   if (!recursing && !foreign_destroy)
1103     {
1104       GDK_QUARTZ_ALLOC_POOL;
1105
1106       if (impl->toplevel)
1107         [impl->toplevel close];
1108       else if (impl->view)
1109         [impl->view removeFromSuperview];
1110
1111       GDK_QUARTZ_RELEASE_POOL;
1112     }
1113 }
1114
1115 static cairo_surface_t *
1116 gdk_window_quartz_resize_cairo_surface (GdkWindow       *window,
1117                                         cairo_surface_t *surface,
1118                                         gint             width,
1119                                         gint             height)
1120 {
1121   /* Quartz surfaces cannot be resized */
1122   cairo_surface_destroy (surface);
1123
1124   return NULL;
1125 }
1126
1127 static void
1128 gdk_quartz_window_destroy_foreign (GdkWindow *window)
1129 {
1130   /* Foreign windows aren't supported in OSX. */
1131 }
1132
1133 /* FIXME: This might be possible to simplify with client-side windows. Also
1134  * note that already_mapped is not used yet, see the x11 backend.
1135 */
1136 static void
1137 gdk_window_quartz_show (GdkWindow *window, gboolean already_mapped)
1138 {
1139   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1140   gboolean focus_on_map;
1141
1142   GDK_QUARTZ_ALLOC_POOL;
1143
1144   if (!GDK_WINDOW_IS_MAPPED (window))
1145     focus_on_map = window->focus_on_map;
1146   else
1147     focus_on_map = TRUE;
1148
1149   if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel)
1150     {
1151       gboolean make_key;
1152
1153       make_key = (window->accept_focus && focus_on_map &&
1154                   window->window_type != GDK_WINDOW_TEMP);
1155
1156       [(GdkQuartzNSWindow*)impl->toplevel showAndMakeKey:make_key];
1157       clear_toplevel_order ();
1158
1159       _gdk_quartz_events_send_map_event (window);
1160     }
1161   else
1162     {
1163       [impl->view setHidden:NO];
1164     }
1165
1166   [impl->view setNeedsDisplay:YES];
1167
1168   gdk_synthesize_window_state (window, GDK_WINDOW_STATE_WITHDRAWN, 0);
1169
1170   if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
1171     gdk_window_maximize (window);
1172
1173   if (window->state & GDK_WINDOW_STATE_ICONIFIED)
1174     gdk_window_iconify (window);
1175
1176   if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
1177     _gdk_quartz_window_attach_to_parent (window);
1178
1179   GDK_QUARTZ_RELEASE_POOL;
1180 }
1181
1182 /* Temporarily unsets the parent window, if the window is a
1183  * transient. 
1184  */
1185 void
1186 _gdk_quartz_window_detach_from_parent (GdkWindow *window)
1187 {
1188   GdkWindowImplQuartz *impl;
1189
1190   g_return_if_fail (GDK_IS_WINDOW (window));
1191
1192   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1193   
1194   g_return_if_fail (impl->toplevel != NULL);
1195
1196   if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
1197     {
1198       GdkWindowImplQuartz *parent_impl;
1199
1200       parent_impl = GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
1201       [parent_impl->toplevel removeChildWindow:impl->toplevel];
1202       clear_toplevel_order ();
1203     }
1204 }
1205
1206 /* Re-sets the parent window, if the window is a transient. */
1207 void
1208 _gdk_quartz_window_attach_to_parent (GdkWindow *window)
1209 {
1210   GdkWindowImplQuartz *impl;
1211
1212   g_return_if_fail (GDK_IS_WINDOW (window));
1213
1214   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1215   
1216   g_return_if_fail (impl->toplevel != NULL);
1217
1218   if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
1219     {
1220       GdkWindowImplQuartz *parent_impl;
1221
1222       parent_impl = GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
1223       [parent_impl->toplevel addChildWindow:impl->toplevel ordered:NSWindowAbove];
1224       clear_toplevel_order ();
1225     }
1226 }
1227
1228 void
1229 gdk_window_quartz_hide (GdkWindow *window)
1230 {
1231   GdkWindowImplQuartz *impl;
1232
1233   /* Make sure we're not stuck in fullscreen mode. */
1234   if (get_fullscreen_geometry (window))
1235     SetSystemUIMode (kUIModeNormal, 0);
1236
1237   check_grab_unmap (window);
1238
1239   _gdk_window_clear_update_area (window);
1240
1241   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1242
1243   if (WINDOW_IS_TOPLEVEL (window)) 
1244     {
1245      /* Update main window. */
1246       main_window_stack = g_slist_remove (main_window_stack, window);
1247       if ([NSApp mainWindow] == impl->toplevel)
1248         _gdk_quartz_window_did_resign_main (window);
1249
1250       if (impl->transient_for)
1251         _gdk_quartz_window_detach_from_parent (window);
1252
1253       [(GdkQuartzNSWindow*)impl->toplevel hide];
1254     }
1255   else if (impl->view)
1256     {
1257       [impl->view setHidden:YES];
1258     }
1259 }
1260
1261 void
1262 gdk_window_quartz_withdraw (GdkWindow *window)
1263 {
1264   gdk_window_hide (window);
1265 }
1266
1267 static void
1268 move_resize_window_internal (GdkWindow *window,
1269                              gint       x,
1270                              gint       y,
1271                              gint       width,
1272                              gint       height)
1273 {
1274   GdkWindowImplQuartz *impl;
1275   GdkRectangle old_visible;
1276   GdkRectangle new_visible;
1277   GdkRectangle scroll_rect;
1278   cairo_region_t *old_region;
1279   cairo_region_t *expose_region;
1280   NSSize delta;
1281
1282   if (GDK_WINDOW_DESTROYED (window))
1283     return;
1284
1285   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1286
1287   if ((x == -1 || (x == window->x)) &&
1288       (y == -1 || (y == window->y)) &&
1289       (width == -1 || (width == window->width)) &&
1290       (height == -1 || (height == window->height)))
1291     {
1292       return;
1293     }
1294
1295   if (!impl->toplevel)
1296     {
1297       /* The previously visible area of this window in a coordinate
1298        * system rooted at the origin of this window.
1299        */
1300       old_visible.x = -window->x;
1301       old_visible.y = -window->y;
1302
1303       old_visible.width = window->width;
1304       old_visible.height = window->height;
1305     }
1306
1307   if (x != -1)
1308     {
1309       delta.width = x - window->x;
1310       window->x = x;
1311     }
1312   else
1313     {
1314       delta.width = 0;
1315     }
1316
1317   if (y != -1)
1318     {
1319       delta.height = y - window->y;
1320       window->y = y;
1321     }
1322   else
1323     {
1324       delta.height = 0;
1325     }
1326
1327   if (width != -1)
1328     window->width = width;
1329
1330   if (height != -1)
1331     window->height = height;
1332
1333   GDK_QUARTZ_ALLOC_POOL;
1334
1335   if (impl->toplevel)
1336     {
1337       NSRect content_rect;
1338       NSRect frame_rect;
1339       gint gx, gy;
1340
1341       _gdk_quartz_window_gdk_xy_to_xy (window->x, window->y + window->height,
1342                                        &gx, &gy);
1343
1344       content_rect = NSMakeRect (gx, gy, window->width, window->height);
1345
1346       frame_rect = [impl->toplevel frameRectForContentRect:content_rect];
1347       [impl->toplevel setFrame:frame_rect display:YES];
1348     }
1349   else 
1350     {
1351       if (!window->input_only)
1352         {
1353           NSRect nsrect;
1354
1355           nsrect = NSMakeRect (window->x, window->y, window->width, window->height);
1356
1357           /* The newly visible area of this window in a coordinate
1358            * system rooted at the origin of this window.
1359            */
1360           new_visible.x = -window->x;
1361           new_visible.y = -window->y;
1362           new_visible.width = old_visible.width;   /* parent has not changed size */
1363           new_visible.height = old_visible.height; /* parent has not changed size */
1364
1365           expose_region = cairo_region_create_rectangle (&new_visible);
1366           old_region = cairo_region_create_rectangle (&old_visible);
1367           cairo_region_subtract (expose_region, old_region);
1368
1369           /* Determine what (if any) part of the previously visible
1370            * part of the window can be copied without a redraw
1371            */
1372           scroll_rect = old_visible;
1373           scroll_rect.x -= delta.width;
1374           scroll_rect.y -= delta.height;
1375           gdk_rectangle_intersect (&scroll_rect, &old_visible, &scroll_rect);
1376
1377           if (!cairo_region_is_empty (expose_region))
1378             {
1379               if (scroll_rect.width != 0 && scroll_rect.height != 0)
1380                 {
1381                   [impl->view scrollRect:NSMakeRect (scroll_rect.x,
1382                                                      scroll_rect.y,
1383                                                      scroll_rect.width,
1384                                                      scroll_rect.height)
1385                                       by:delta];
1386                 }
1387
1388               [impl->view setFrame:nsrect];
1389
1390               gdk_quartz_window_set_needs_display_in_region (window, expose_region);
1391             }
1392           else
1393             {
1394               [impl->view setFrame:nsrect];
1395               [impl->view setNeedsDisplay:YES];
1396             }
1397
1398           cairo_region_destroy (expose_region);
1399           cairo_region_destroy (old_region);
1400         }
1401     }
1402
1403   GDK_QUARTZ_RELEASE_POOL;
1404 }
1405
1406 static inline void
1407 window_quartz_move (GdkWindow *window,
1408                     gint       x,
1409                     gint       y)
1410 {
1411   g_return_if_fail (GDK_IS_WINDOW (window));
1412
1413   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1414     return;
1415
1416   move_resize_window_internal (window, x, y, -1, -1);
1417 }
1418
1419 static inline void
1420 window_quartz_resize (GdkWindow *window,
1421                       gint       width,
1422                       gint       height)
1423 {
1424   g_return_if_fail (GDK_IS_WINDOW (window));
1425
1426   if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1427     return;
1428
1429   if (width < 1)
1430     width = 1;
1431   if (height < 1)
1432     height = 1;
1433
1434   move_resize_window_internal (window, -1, -1, width, height);
1435 }
1436
1437 static inline void
1438 window_quartz_move_resize (GdkWindow *window,
1439                            gint       x,
1440                            gint       y,
1441                            gint       width,
1442                            gint       height)
1443 {
1444   if (width < 1)
1445     width = 1;
1446   if (height < 1)
1447     height = 1;
1448
1449   move_resize_window_internal (window, x, y, width, height);
1450 }
1451
1452 static void
1453 gdk_window_quartz_move_resize (GdkWindow *window,
1454                                gboolean   with_move,
1455                                gint       x,
1456                                gint       y,
1457                                gint       width,
1458                                gint       height)
1459 {
1460   if (with_move && (width < 0 && height < 0))
1461     window_quartz_move (window, x, y);
1462   else
1463     {
1464       if (with_move)
1465         window_quartz_move_resize (window, x, y, width, height);
1466       else
1467         window_quartz_resize (window, width, height);
1468     }
1469 }
1470
1471 /* FIXME: This might need fixing (reparenting didn't work before client-side
1472  * windows either).
1473  */
1474 static gboolean
1475 gdk_window_quartz_reparent (GdkWindow *window,
1476                             GdkWindow *new_parent,
1477                             gint       x,
1478                             gint       y)
1479 {
1480   GdkWindow *old_parent;
1481   GdkWindowImplQuartz *impl, *old_parent_impl, *new_parent_impl;
1482   NSView *view, *new_parent_view;
1483
1484   if (new_parent == _gdk_root)
1485     {
1486       /* Could be added, just needs implementing. */
1487       g_warning ("Reparenting to root window is not supported yet in the Mac OS X backend");
1488       return FALSE;
1489     }
1490
1491   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1492   view = impl->view;
1493
1494   new_parent_impl = GDK_WINDOW_IMPL_QUARTZ (new_parent->impl);
1495   new_parent_view = new_parent_impl->view;
1496
1497   old_parent = window->parent;
1498   old_parent_impl = GDK_WINDOW_IMPL_QUARTZ (old_parent->impl);
1499
1500   [view retain];
1501
1502   [view removeFromSuperview];
1503   [new_parent_view addSubview:view];
1504
1505   [view release];
1506
1507   window->parent = new_parent;
1508
1509   if (old_parent)
1510     {
1511       old_parent_impl->sorted_children = g_list_remove (old_parent_impl->sorted_children, window);
1512     }
1513
1514   new_parent_impl->sorted_children = g_list_prepend (new_parent_impl->sorted_children, window);
1515
1516   return FALSE;
1517 }
1518
1519 /* Get the toplevel ordering from NSApp and update our own list. We do
1520  * this on demand since the NSApp's list is not up to date directly
1521  * after we get windowDidBecomeMain.
1522  */
1523 static void
1524 update_toplevel_order (void)
1525 {
1526   GdkWindowImplQuartz *root_impl;
1527   NSEnumerator *enumerator;
1528   id nswindow;
1529   GList *toplevels = NULL;
1530
1531   root_impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
1532
1533   if (root_impl->sorted_children)
1534     return;
1535
1536   GDK_QUARTZ_ALLOC_POOL;
1537
1538   enumerator = [[NSApp orderedWindows] objectEnumerator];
1539   while ((nswindow = [enumerator nextObject]))
1540     {
1541       GdkWindow *window;
1542
1543       if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
1544         continue;
1545
1546       window = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
1547       toplevels = g_list_prepend (toplevels, window);
1548     }
1549
1550   GDK_QUARTZ_RELEASE_POOL;
1551
1552   root_impl->sorted_children = g_list_reverse (toplevels);
1553 }
1554
1555 static void
1556 clear_toplevel_order (void)
1557 {
1558   GdkWindowImplQuartz *root_impl;
1559
1560   root_impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
1561
1562   g_list_free (root_impl->sorted_children);
1563   root_impl->sorted_children = NULL;
1564 }
1565
1566 static void
1567 gdk_window_quartz_raise (GdkWindow *window)
1568 {
1569   if (GDK_WINDOW_DESTROYED (window))
1570     return;
1571
1572   if (WINDOW_IS_TOPLEVEL (window))
1573     {
1574       GdkWindowImplQuartz *impl;
1575
1576       impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1577       [impl->toplevel orderFront:impl->toplevel];
1578
1579       clear_toplevel_order ();
1580     }
1581   else
1582     {
1583       GdkWindow *parent = window->parent;
1584
1585       if (parent)
1586         {
1587           GdkWindowImplQuartz *impl;
1588
1589           impl = (GdkWindowImplQuartz *)parent->impl;
1590
1591           impl->sorted_children = g_list_remove (impl->sorted_children, window);
1592           impl->sorted_children = g_list_prepend (impl->sorted_children, window);
1593         }
1594     }
1595 }
1596
1597 static void
1598 gdk_window_quartz_lower (GdkWindow *window)
1599 {
1600   if (GDK_WINDOW_DESTROYED (window))
1601     return;
1602
1603   if (WINDOW_IS_TOPLEVEL (window))
1604     {
1605       GdkWindowImplQuartz *impl;
1606
1607       impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1608       [impl->toplevel orderBack:impl->toplevel];
1609
1610       clear_toplevel_order ();
1611     }
1612   else
1613     {
1614       GdkWindow *parent = window->parent;
1615
1616       if (parent)
1617         {
1618           GdkWindowImplQuartz *impl;
1619
1620           impl = (GdkWindowImplQuartz *)parent->impl;
1621
1622           impl->sorted_children = g_list_remove (impl->sorted_children, window);
1623           impl->sorted_children = g_list_append (impl->sorted_children, window);
1624         }
1625     }
1626 }
1627
1628 static void
1629 gdk_window_quartz_restack_toplevel (GdkWindow *window,
1630                                     GdkWindow *sibling,
1631                                     gboolean   above)
1632 {
1633   /* FIXME: Implement this */
1634 }
1635
1636 static void
1637 gdk_window_quartz_set_background (GdkWindow       *window,
1638                                   cairo_pattern_t *pattern)
1639 {
1640   /* FIXME: We could theoretically set the background color for toplevels
1641    * here. (Currently we draw the background before emitting expose events)
1642    */
1643 }
1644
1645 static void
1646 gdk_window_quartz_set_device_cursor (GdkWindow *window,
1647                                      GdkDevice *device,
1648                                      GdkCursor *cursor)
1649 {
1650   NSCursor *nscursor;
1651
1652   if (GDK_WINDOW_DESTROYED (window))
1653     return;
1654
1655   nscursor = _gdk_quartz_cursor_get_ns_cursor (cursor);
1656
1657   [nscursor set];
1658 }
1659
1660 static void
1661 gdk_window_quartz_get_geometry (GdkWindow *window,
1662                                 gint      *x,
1663                                 gint      *y,
1664                                 gint      *width,
1665                                 gint      *height)
1666 {
1667   GdkWindowImplQuartz *impl;
1668   NSRect ns_rect;
1669
1670   if (GDK_WINDOW_DESTROYED (window))
1671     return;
1672
1673   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1674   if (window == _gdk_root)
1675     {
1676       if (x) 
1677         *x = 0;
1678       if (y) 
1679         *y = 0;
1680
1681       if (width) 
1682         *width = window->width;
1683       if (height)
1684         *height = window->height;
1685     }
1686   else if (WINDOW_IS_TOPLEVEL (window))
1687     {
1688       ns_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
1689
1690       /* This doesn't work exactly as in X. There doesn't seem to be a
1691        * way to get the coords relative to the parent window (usually
1692        * the window frame), but that seems useless except for
1693        * borderless windows where it's relative to the root window. So
1694        * we return (0, 0) (should be something like (0, 22)) for
1695        * windows with borders and the root relative coordinates
1696        * otherwise.
1697        */
1698       if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
1699         {
1700           _gdk_quartz_window_xy_to_gdk_xy (ns_rect.origin.x,
1701                                            ns_rect.origin.y + ns_rect.size.height,
1702                                            x, y);
1703         }
1704       else 
1705         {
1706           if (x)
1707             *x = 0;
1708           if (y)
1709             *y = 0;
1710         }
1711
1712       if (width)
1713         *width = ns_rect.size.width;
1714       if (height)
1715         *height = ns_rect.size.height;
1716     }
1717   else
1718     {
1719       ns_rect = [impl->view frame];
1720       
1721       if (x)
1722         *x = ns_rect.origin.x;
1723       if (y)
1724         *y = ns_rect.origin.y;
1725       if (width)
1726         *width  = ns_rect.size.width;
1727       if (height)
1728         *height = ns_rect.size.height;
1729     }
1730 }
1731
1732 static gint
1733 gdk_window_quartz_get_root_coords (GdkWindow *window,
1734                                    gint       x,
1735                                    gint       y,
1736                                    gint      *root_x,
1737                                    gint      *root_y)
1738 {
1739   int tmp_x = 0, tmp_y = 0;
1740   GdkWindow *toplevel;
1741   NSRect content_rect;
1742   GdkWindowImplQuartz *impl;
1743
1744   if (GDK_WINDOW_DESTROYED (window)) 
1745     {
1746       if (root_x)
1747         *root_x = 0;
1748       if (root_y)
1749         *root_y = 0;
1750       
1751       return 0;
1752     }
1753
1754   if (window == _gdk_root)
1755     {
1756       if (root_x)
1757         *root_x = x;
1758       if (root_y)
1759         *root_y = y;
1760
1761       return 1;
1762     }
1763   
1764   toplevel = gdk_window_get_toplevel (window);
1765   impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
1766
1767   content_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
1768
1769   _gdk_quartz_window_xy_to_gdk_xy (content_rect.origin.x,
1770                                    content_rect.origin.y + content_rect.size.height,
1771                                    &tmp_x, &tmp_y);
1772
1773   tmp_x += x;
1774   tmp_y += y;
1775
1776   while (window != toplevel)
1777     {
1778       if (_gdk_window_has_impl ((GdkWindow *)window))
1779         {
1780           tmp_x += window->x;
1781           tmp_y += window->y;
1782         }
1783
1784       window = window->parent;
1785     }
1786
1787   if (root_x)
1788     *root_x = tmp_x;
1789   if (root_y)
1790     *root_y = tmp_y;
1791
1792   return TRUE;
1793 }
1794
1795 static void
1796 gdk_quartz_window_get_root_origin (GdkWindow *window,
1797                                    gint      *x,
1798                                    gint      *y)
1799 {
1800   GdkRectangle rect;
1801
1802   rect.x = 0;
1803   rect.y = 0;
1804   
1805   gdk_window_get_frame_extents (window, &rect);
1806
1807   if (x)
1808     *x = rect.x;
1809
1810   if (y)
1811     *y = rect.y;
1812 }
1813
1814 /* Returns coordinates relative to the passed in window. */
1815 static GdkWindow *
1816 gdk_window_quartz_get_device_state_helper (GdkWindow       *window,
1817                                            GdkDevice       *device,
1818                                            gint            *x,
1819                                            gint            *y,
1820                                            GdkModifierType *mask)
1821 {
1822   NSPoint point;
1823   gint x_tmp, y_tmp;
1824   GdkWindow *toplevel;
1825   GdkWindow *found_window;
1826
1827   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
1828
1829   if (GDK_WINDOW_DESTROYED (window))
1830     {
1831       *x = 0;
1832       *y = 0;
1833       *mask = 0;
1834       return NULL;
1835     }
1836   
1837   toplevel = gdk_window_get_toplevel (window);
1838
1839   *mask = _gdk_quartz_events_get_current_event_mask ();
1840
1841   /* Get the y coordinate, needs to be flipped. */
1842   if (window == _gdk_root)
1843     {
1844       point = [NSEvent mouseLocation];
1845       _gdk_quartz_window_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
1846     }
1847   else
1848     {
1849       GdkWindowImplQuartz *impl;
1850       NSWindow *nswindow;
1851
1852       impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
1853       nswindow = impl->toplevel;
1854
1855       point = [nswindow mouseLocationOutsideOfEventStream];
1856
1857       x_tmp = point.x;
1858       y_tmp = toplevel->height - point.y;
1859
1860       window = (GdkWindow *)toplevel;
1861     }
1862
1863   found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp,
1864                                                 FALSE);
1865
1866   /* We never return the root window. */
1867   if (found_window == _gdk_root)
1868     found_window = NULL;
1869
1870   *x = x_tmp;
1871   *y = y_tmp;
1872
1873   return found_window;
1874 }
1875
1876 static gboolean
1877 gdk_window_quartz_get_device_state (GdkWindow       *window,
1878                                     GdkDevice       *device,
1879                                     gint            *x,
1880                                     gint            *y,
1881                                     GdkModifierType *mask)
1882 {
1883   return gdk_window_quartz_get_device_state_helper (window,
1884                                                     device,
1885                                                     x, y, mask) != NULL;
1886 }
1887
1888 /* Returns coordinates relative to the root. */
1889 void
1890 _gdk_windowing_get_device_state (GdkDisplay       *display,
1891                                  GdkDevice        *device,
1892                                  GdkScreen       **screen,
1893                                  gint             *x,
1894                                  gint             *y,
1895                                  GdkModifierType  *mask)
1896 {
1897   g_return_if_fail (display == _gdk_display);
1898   
1899   *screen = _gdk_screen;
1900   gdk_window_quartz_get_device_state_helper (_gdk_root, device, x, y, mask);
1901 }
1902
1903 /* Returns coordinates relative to the found window. */
1904 GdkWindow *
1905 _gdk_windowing_window_at_pointer (GdkDisplay      *display,
1906                                   gint            *win_x,
1907                                   gint            *win_y,
1908                                   GdkModifierType *mask,
1909                                   gboolean         get_toplevel)
1910 {
1911   GdkWindow *found_window;
1912   gint x, y;
1913   GdkModifierType tmp_mask = 0;
1914
1915   found_window = gdk_window_quartz_get_device_state_helper (_gdk_root,
1916                                                             display->core_pointer,
1917                                                             &x, &y,
1918                                                             &tmp_mask);
1919   if (found_window)
1920     {
1921       /* The coordinates returned above are relative the root, we want
1922        * coordinates relative the window here. 
1923        */
1924       while (found_window != _gdk_root)
1925         {
1926           x -= found_window->x;
1927           y -= found_window->y;
1928           
1929           found_window = found_window->parent;
1930         }
1931
1932       *win_x = x;
1933       *win_y = y;
1934     }
1935   else
1936     {
1937       /* Mimic the X backend here, -1,-1 for unknown windows. */
1938       *win_x = -1;
1939       *win_y = -1;
1940     }
1941
1942   if (mask)
1943     *mask = tmp_mask;
1944
1945   if (get_toplevel)
1946     {
1947       /* Requested toplevel, find it. */
1948       /* TODO: This can be implemented more efficient by never
1949          recursing into children in the first place */
1950       if (found_window)
1951         {
1952           /* Convert to toplevel */
1953           while (found_window->parent != NULL &&
1954                  found_window->parent->window_type != GDK_WINDOW_ROOT)
1955             {
1956               *win_x += found_window->x;
1957               *win_y += found_window->y;
1958               found_window = found_window->parent;
1959             }
1960         }
1961     }
1962
1963   return found_window;
1964 }
1965
1966 GdkWindow*
1967 _gdk_windowing_window_at_device_position (GdkDisplay      *display,
1968                                           GdkDevice       *device,
1969                                           gint            *win_x,
1970                                           gint            *win_y,
1971                                           GdkModifierType *mask,
1972                                           gboolean         get_toplevel)
1973 {
1974   return GDK_DEVICE_GET_CLASS (device)->window_at_position (device,
1975                                                             win_x, win_y,
1976                                                             mask,
1977                                                             get_toplevel);
1978 }
1979
1980
1981 static GdkEventMask  
1982 gdk_window_quartz_get_events (GdkWindow *window)
1983 {
1984   if (GDK_WINDOW_DESTROYED (window))
1985     return 0;
1986   else
1987     return window->event_mask;
1988 }
1989
1990 static void
1991 gdk_window_quartz_set_events (GdkWindow       *window,
1992                               GdkEventMask     event_mask)
1993 {
1994   /* The mask is set in the common code. */
1995 }
1996
1997 static void
1998 gdk_quartz_window_set_urgency_hint (GdkWindow *window,
1999                                     gboolean   urgent)
2000 {
2001   if (GDK_WINDOW_DESTROYED (window) ||
2002       !WINDOW_IS_TOPLEVEL (window))
2003     return;
2004
2005   /* FIXME: Implement */
2006 }
2007
2008 static void
2009 gdk_quartz_window_set_geometry_hints (GdkWindow         *window,
2010                                       const GdkGeometry *geometry,
2011                                       GdkWindowHints     geom_mask)
2012 {
2013   GdkWindowImplQuartz *impl;
2014
2015   g_return_if_fail (geometry != NULL);
2016
2017   if (GDK_WINDOW_DESTROYED (window) ||
2018       !WINDOW_IS_TOPLEVEL (window))
2019     return;
2020   
2021   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2022   if (!impl->toplevel)
2023     return;
2024
2025   if (geom_mask & GDK_HINT_POS)
2026     {
2027       /* FIXME: Implement */
2028     }
2029
2030   if (geom_mask & GDK_HINT_USER_POS)
2031     {
2032       /* FIXME: Implement */
2033     }
2034
2035   if (geom_mask & GDK_HINT_USER_SIZE)
2036     {
2037       /* FIXME: Implement */
2038     }
2039   
2040   if (geom_mask & GDK_HINT_MIN_SIZE)
2041     {
2042       NSSize size;
2043
2044       size.width = geometry->min_width;
2045       size.height = geometry->min_height;
2046
2047       [impl->toplevel setContentMinSize:size];
2048     }
2049   
2050   if (geom_mask & GDK_HINT_MAX_SIZE)
2051     {
2052       NSSize size;
2053
2054       size.width = geometry->max_width;
2055       size.height = geometry->max_height;
2056
2057       [impl->toplevel setContentMaxSize:size];
2058     }
2059   
2060   if (geom_mask & GDK_HINT_BASE_SIZE)
2061     {
2062       /* FIXME: Implement */
2063     }
2064   
2065   if (geom_mask & GDK_HINT_RESIZE_INC)
2066     {
2067       NSSize size;
2068
2069       size.width = geometry->width_inc;
2070       size.height = geometry->height_inc;
2071
2072       [impl->toplevel setContentResizeIncrements:size];
2073     }
2074   
2075   if (geom_mask & GDK_HINT_ASPECT)
2076     {
2077       /* FIXME: Implement */
2078     }
2079
2080   if (geom_mask & GDK_HINT_WIN_GRAVITY)
2081     {
2082       /* FIXME: Implement */
2083     }
2084 }
2085
2086 static void
2087 gdk_quartz_window_set_title (GdkWindow   *window,
2088                              const gchar *title)
2089 {
2090   GdkWindowImplQuartz *impl;
2091
2092   g_return_if_fail (title != NULL);
2093
2094   if (GDK_WINDOW_DESTROYED (window) ||
2095       !WINDOW_IS_TOPLEVEL (window))
2096     return;
2097
2098   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2099
2100   if (impl->toplevel)
2101     {
2102       GDK_QUARTZ_ALLOC_POOL;
2103       [impl->toplevel setTitle:[NSString stringWithUTF8String:title]];
2104       GDK_QUARTZ_RELEASE_POOL;
2105     }
2106 }
2107
2108 static void
2109 gdk_quartz_window_set_role (GdkWindow   *window,
2110                             const gchar *role)
2111 {
2112   if (GDK_WINDOW_DESTROYED (window) ||
2113       WINDOW_IS_TOPLEVEL (window))
2114     return;
2115
2116   /* FIXME: Implement */
2117 }
2118
2119 static void
2120 gdk_quartz_window_set_startup_id (GdkWindow   *window,
2121                                   const gchar *startup_id)
2122 {
2123   /* FIXME: Implement? */
2124 }
2125
2126 static void
2127 gdk_quartz_window_set_transient_for (GdkWindow *window,
2128                                      GdkWindow *parent)
2129 {
2130   GdkWindowImplQuartz *window_impl;
2131   GdkWindowImplQuartz *parent_impl;
2132
2133   if (GDK_WINDOW_DESTROYED (window)  || GDK_WINDOW_DESTROYED (parent) ||
2134       !WINDOW_IS_TOPLEVEL (window))
2135     return;
2136
2137   window_impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2138   if (!window_impl->toplevel)
2139     return;
2140
2141   GDK_QUARTZ_ALLOC_POOL;
2142
2143   if (window_impl->transient_for)
2144     {
2145       _gdk_quartz_window_detach_from_parent (window);
2146
2147       g_object_unref (window_impl->transient_for);
2148       window_impl->transient_for = NULL;
2149     }
2150
2151   parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
2152   if (parent_impl->toplevel)
2153     {
2154       /* We save the parent because it needs to be unset/reset when
2155        * hiding and showing the window. 
2156        */
2157
2158       /* We don't set transients for tooltips, they are already
2159        * handled by the window level being the top one. If we do, then
2160        * the parent window will be brought to the top just because the
2161        * tooltip is, which is not what we want.
2162        */
2163       if (gdk_window_get_type_hint (window) != GDK_WINDOW_TYPE_HINT_TOOLTIP)
2164         {
2165           window_impl->transient_for = g_object_ref (parent);
2166
2167           /* We only add the window if it is shown, otherwise it will
2168            * be shown unconditionally here. If it is not shown, the
2169            * window will be added in show() instead.
2170            */
2171           if (!(window->state & GDK_WINDOW_STATE_WITHDRAWN))
2172             _gdk_quartz_window_attach_to_parent (window);
2173         }
2174     }
2175   
2176   GDK_QUARTZ_RELEASE_POOL;
2177 }
2178
2179 static void
2180 gdk_window_quartz_shape_combine_region (GdkWindow       *window,
2181                                         const cairo_region_t *shape,
2182                                         gint             x,
2183                                         gint             y)
2184 {
2185   /* FIXME: Implement */
2186 }
2187
2188 static void
2189 gdk_window_quartz_input_shape_combine_region (GdkWindow       *window,
2190                                               const cairo_region_t *shape_region,
2191                                               gint             offset_x,
2192                                               gint             offset_y)
2193 {
2194   /* FIXME: Implement */
2195 }
2196
2197 static void
2198 gdk_quartz_window_set_override_redirect (GdkWindow *window,
2199                                          gboolean override_redirect)
2200 {
2201   /* FIXME: Implement */
2202 }
2203
2204 static void
2205 gdk_quartz_window_set_accept_focus (GdkWindow *window,
2206                                     gboolean accept_focus)
2207 {
2208   window->accept_focus = accept_focus != FALSE;
2209 }
2210
2211 static gboolean 
2212 gdk_window_quartz_set_static_gravities (GdkWindow *window,
2213                                         gboolean   use_static)
2214 {
2215   if (GDK_WINDOW_DESTROYED (window) ||
2216       !WINDOW_IS_TOPLEVEL (window))
2217     return FALSE;
2218
2219   /* FIXME: Implement */
2220   return FALSE;
2221 }
2222
2223 static gboolean
2224 gdk_quartz_window_queue_antiexpose (GdkWindow *window,
2225                                     cairo_region_t *area)
2226 {
2227   return FALSE;
2228 }
2229
2230 static void
2231 gdk_quartz_window_translate (GdkWindow      *window,
2232                              cairo_region_t *area,
2233                              gint            dx,
2234                              gint            dy)
2235 {
2236   cairo_region_t *invalidate, *scrolled;
2237   GdkWindowImplQuartz *impl = (GdkWindowImplQuartz *)window->impl;
2238   GdkRectangle extents;
2239
2240   cairo_region_get_extents (area, &extents);
2241
2242   [impl->view scrollRect:NSMakeRect (extents.x - dx, extents.y - dy,
2243                                      extents.width, extents.height)
2244               by:NSMakeSize (dx, dy)];
2245
2246   if (impl->needs_display_region)
2247     {
2248       cairo_region_t *intersection;
2249
2250       /* Invalidate already invalidated area that was moved at new
2251        * location.
2252        */
2253       intersection = cairo_region_copy (impl->needs_display_region);
2254       cairo_region_intersect (intersection, area);
2255       cairo_region_translate (intersection, dx, dy);
2256
2257       gdk_quartz_window_set_needs_display_in_region (window, intersection);
2258       cairo_region_destroy (intersection);
2259     }
2260
2261   /* Calculate newly exposed area that needs invalidation */
2262   scrolled = cairo_region_copy (area);
2263   cairo_region_translate (scrolled, dx, dy);
2264
2265   invalidate = cairo_region_copy (area);
2266   cairo_region_subtract (invalidate, scrolled);
2267   cairo_region_destroy (scrolled);
2268
2269   gdk_quartz_window_set_needs_display_in_region (window, invalidate);
2270   cairo_region_destroy (invalidate);
2271 }
2272
2273 static void
2274 gdk_quartz_window_set_focus_on_map (GdkWindow *window,
2275                                     gboolean focus_on_map)
2276 {
2277   window->focus_on_map = focus_on_map != FALSE;
2278 }
2279
2280 static void
2281 gdk_quartz_window_set_icon_name (GdkWindow   *window,
2282                                  const gchar *name)
2283 {
2284   /* FIXME: Implement */
2285 }
2286
2287 static void
2288 gdk_quartz_window_focus (GdkWindow *window,
2289                          guint32    timestamp)
2290 {
2291   GdkWindowImplQuartz *impl;
2292         
2293   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2294
2295   if (GDK_WINDOW_DESTROYED (window) ||
2296       !WINDOW_IS_TOPLEVEL (window))
2297     return;
2298
2299   if (window->accept_focus && window->window_type != GDK_WINDOW_TEMP)
2300     {
2301       GDK_QUARTZ_ALLOC_POOL;
2302       [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
2303       clear_toplevel_order ();
2304       GDK_QUARTZ_RELEASE_POOL;
2305     }
2306 }
2307
2308 static
2309 gint window_type_hint_to_level (GdkWindowTypeHint hint)
2310 {
2311   switch (hint)
2312     {
2313     case GDK_WINDOW_TYPE_HINT_DOCK:
2314     case GDK_WINDOW_TYPE_HINT_UTILITY:
2315       return NSFloatingWindowLevel;
2316
2317     case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
2318     case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
2319       return NSTornOffMenuWindowLevel;
2320
2321     case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
2322     case GDK_WINDOW_TYPE_HINT_TOOLTIP:
2323       return NSStatusWindowLevel;
2324
2325     case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2326     case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
2327     case GDK_WINDOW_TYPE_HINT_COMBO:
2328     case GDK_WINDOW_TYPE_HINT_DND:
2329       return NSPopUpMenuWindowLevel;
2330
2331     case GDK_WINDOW_TYPE_HINT_NORMAL:  /* Normal toplevel window */
2332     case GDK_WINDOW_TYPE_HINT_DIALOG:  /* Dialog window */
2333     case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
2334     case GDK_WINDOW_TYPE_HINT_DESKTOP: /* N/A */
2335       break;
2336
2337     default:
2338       break;
2339     }
2340
2341   return NSNormalWindowLevel;
2342 }
2343
2344 static gboolean 
2345 window_type_hint_to_shadow (GdkWindowTypeHint hint)
2346 {
2347   switch (hint)
2348     {
2349     case GDK_WINDOW_TYPE_HINT_NORMAL:  /* Normal toplevel window */
2350     case GDK_WINDOW_TYPE_HINT_DIALOG:  /* Dialog window */
2351     case GDK_WINDOW_TYPE_HINT_DOCK:
2352     case GDK_WINDOW_TYPE_HINT_UTILITY:
2353     case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
2354     case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
2355     case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2356     case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
2357     case GDK_WINDOW_TYPE_HINT_COMBO:
2358     case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
2359     case GDK_WINDOW_TYPE_HINT_TOOLTIP:
2360       return TRUE;
2361
2362     case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
2363     case GDK_WINDOW_TYPE_HINT_DESKTOP: /* N/A */
2364     case GDK_WINDOW_TYPE_HINT_DND:
2365       break;
2366
2367     default:
2368       break;
2369     }
2370
2371   return FALSE;
2372 }
2373
2374
2375 static void
2376 gdk_quartz_window_set_type_hint (GdkWindow        *window,
2377                                  GdkWindowTypeHint hint)
2378 {
2379   GdkWindowImplQuartz *impl;
2380   
2381   if (GDK_WINDOW_DESTROYED (window) ||
2382       !WINDOW_IS_TOPLEVEL (window))
2383     return;
2384
2385   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2386
2387   impl->type_hint = hint;
2388
2389   /* Match the documentation, only do something if we're not mapped yet. */
2390   if (GDK_WINDOW_IS_MAPPED (window))
2391     return;
2392
2393   [impl->toplevel setHasShadow: window_type_hint_to_shadow (hint)];
2394   [impl->toplevel setLevel: window_type_hint_to_level (hint)];
2395 }
2396
2397 static GdkWindowTypeHint
2398 gdk_quartz_window_get_type_hint (GdkWindow *window)
2399 {
2400   if (GDK_WINDOW_DESTROYED (window) ||
2401       !WINDOW_IS_TOPLEVEL (window))
2402     return GDK_WINDOW_TYPE_HINT_NORMAL;
2403   
2404   return GDK_WINDOW_IMPL_QUARTZ (window->impl)->type_hint;
2405 }
2406
2407 static void
2408 gdk_quartz_window_set_modal_hint (GdkWindow *window,
2409                                   gboolean   modal)
2410 {
2411   if (GDK_WINDOW_DESTROYED (window) ||
2412       !WINDOW_IS_TOPLEVEL (window))
2413     return;
2414
2415   /* FIXME: Implement */
2416 }
2417
2418 static void
2419 gdk_quartz_window_set_skip_taskbar_hint (GdkWindow *window,
2420                                          gboolean   skips_taskbar)
2421 {
2422   if (GDK_WINDOW_DESTROYED (window) ||
2423       !WINDOW_IS_TOPLEVEL (window))
2424     return;
2425
2426   /* FIXME: Implement */
2427 }
2428
2429 static void
2430 gdk_quartz_window_set_skip_pager_hint (GdkWindow *window,
2431                                        gboolean   skips_pager)
2432 {
2433   if (GDK_WINDOW_DESTROYED (window) ||
2434       !WINDOW_IS_TOPLEVEL (window))
2435     return;
2436
2437   /* FIXME: Implement */
2438 }
2439
2440 static void
2441 gdk_quartz_window_begin_resize_drag (GdkWindow     *window,
2442                                      GdkWindowEdge  edge,
2443                                      gint           button,
2444                                      gint           root_x,
2445                                      gint           root_y,
2446                                      guint32        timestamp)
2447 {
2448   GdkWindowImplQuartz *impl;
2449
2450   g_return_if_fail (GDK_IS_WINDOW (window));
2451
2452   if (edge != GDK_WINDOW_EDGE_SOUTH_EAST)
2453     {
2454       g_warning ("Resizing is only implemented for GDK_WINDOW_EDGE_SOUTH_EAST on Mac OS");
2455       return;
2456     }
2457
2458   if (GDK_WINDOW_DESTROYED (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_resize_drag on non-toplevel window");
2466       return;
2467     }
2468
2469   [(GdkQuartzNSWindow *)impl->toplevel beginManualResize];
2470 }
2471
2472 static void
2473 gdk_quartz_window_begin_move_drag (GdkWindow *window,
2474                                    gint       button,
2475                                    gint       root_x,
2476                                    gint       root_y,
2477                                    guint32    timestamp)
2478 {
2479   GdkWindowImplQuartz *impl;
2480
2481   if (GDK_WINDOW_DESTROYED (window) ||
2482       !WINDOW_IS_TOPLEVEL (window))
2483     return;
2484
2485   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2486
2487   if (!impl->toplevel)
2488     {
2489       g_warning ("Can't call gdk_window_begin_move_drag on non-toplevel window");
2490       return;
2491     }
2492
2493   [(GdkQuartzNSWindow *)impl->toplevel beginManualMove];
2494 }
2495
2496 static void
2497 gdk_quartz_window_set_icon_list (GdkWindow *window,
2498                                  GList     *pixbufs)
2499 {
2500   /* FIXME: Implement */
2501 }
2502
2503 static void
2504 gdk_quartz_window_get_frame_extents (GdkWindow    *window,
2505                                      GdkRectangle *rect)
2506 {
2507   GdkWindow *toplevel;
2508   GdkWindowImplQuartz *impl;
2509   NSRect ns_rect;
2510
2511   g_return_if_fail (rect != NULL);
2512
2513
2514   rect->x = 0;
2515   rect->y = 0;
2516   rect->width = 1;
2517   rect->height = 1;
2518   
2519   toplevel = gdk_window_get_effective_toplevel (window);
2520   impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
2521
2522   ns_rect = [impl->toplevel frame];
2523
2524   _gdk_quartz_window_xy_to_gdk_xy (ns_rect.origin.x,
2525                                    ns_rect.origin.y + ns_rect.size.height,
2526                                    &rect->x, &rect->y);
2527
2528   rect->width = ns_rect.size.width;
2529   rect->height = ns_rect.size.height;
2530 }
2531
2532 static void
2533 gdk_quartz_window_set_decorations (GdkWindow       *window,
2534                                    GdkWMDecoration  decorations)
2535 {
2536   GdkWindowImplQuartz *impl;
2537   NSUInteger old_mask, new_mask;
2538   NSView *old_view;
2539
2540   if (GDK_WINDOW_DESTROYED (window) ||
2541       !WINDOW_IS_TOPLEVEL (window))
2542     return;
2543
2544   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2545
2546   if (decorations == 0 || GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP ||
2547       impl->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN )
2548     {
2549       new_mask = NSBorderlessWindowMask;
2550     }
2551   else
2552     {
2553       /* FIXME: Honor other GDK_DECOR_* flags. */
2554       new_mask = (NSTitledWindowMask | NSClosableWindowMask |
2555                     NSMiniaturizableWindowMask | NSResizableWindowMask);
2556     }
2557
2558   GDK_QUARTZ_ALLOC_POOL;
2559
2560   old_mask = [impl->toplevel styleMask];
2561
2562   if (old_mask != new_mask)
2563     {
2564       NSRect rect;
2565
2566       old_view = [impl->toplevel contentView];
2567
2568       rect = [impl->toplevel frame];
2569
2570       /* Properly update the size of the window when the titlebar is
2571        * added or removed.
2572        */
2573       if (old_mask == NSBorderlessWindowMask &&
2574           new_mask != NSBorderlessWindowMask)
2575         {
2576           rect = [NSWindow frameRectForContentRect:rect styleMask:new_mask];
2577
2578         }
2579       else if (old_mask != NSBorderlessWindowMask &&
2580                new_mask == NSBorderlessWindowMask)
2581         {
2582           rect = [NSWindow contentRectForFrameRect:rect styleMask:old_mask];
2583         }
2584
2585       /* Note, before OS 10.6 there doesn't seem to be a way to change this without
2586        * recreating the toplevel. There might be bad side-effects of doing
2587        * that, but it seems alright.
2588        */
2589 #if MAC_OS_X_VERSION_MIN_ALLOWED > MAC_OS_X_VERSION_10_5
2590       if ([impl->toplevel respondsToSelector:@selector(setStyleMask:)])
2591         {
2592           [impl->toplevel setStyleMask:new_mask];
2593         }
2594       else
2595 #endif
2596         {
2597           [impl->toplevel release];
2598           impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:rect
2599                                                                 styleMask:new_mask
2600                                                                   backing:NSBackingStoreBuffered
2601                                                                     defer:NO];
2602           [impl->toplevel setHasShadow: window_type_hint_to_shadow (impl->type_hint)];
2603           [impl->toplevel setLevel: window_type_hint_to_level (impl->type_hint)];
2604           [impl->toplevel setContentView:old_view];
2605         }
2606
2607       [impl->toplevel setFrame:rect display:YES];
2608
2609       /* Invalidate the window shadow for non-opaque views that have shadow
2610        * enabled, to get the shadow shape updated.
2611        */
2612       if (![old_view isOpaque] && [impl->toplevel hasShadow])
2613         [(GdkQuartzView*)old_view setNeedsInvalidateShadow:YES];
2614     }
2615
2616   GDK_QUARTZ_RELEASE_POOL;
2617 }
2618
2619 static gboolean
2620 gdk_quartz_window_get_decorations (GdkWindow       *window,
2621                                    GdkWMDecoration *decorations)
2622 {
2623   GdkWindowImplQuartz *impl;
2624
2625   if (GDK_WINDOW_DESTROYED (window) ||
2626       !WINDOW_IS_TOPLEVEL (window))
2627     return FALSE;
2628
2629   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2630
2631   if (decorations)
2632     {
2633       /* Borderless is 0, so we can't check it as a bit being set. */
2634       if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
2635         {
2636           *decorations = 0;
2637         }
2638       else
2639         {
2640           /* FIXME: Honor the other GDK_DECOR_* flags. */
2641           *decorations = GDK_DECOR_ALL;
2642         }
2643     }
2644
2645   return TRUE;
2646 }
2647
2648 static void
2649 gdk_quartz_window_set_functions (GdkWindow    *window,
2650                                  GdkWMFunction functions)
2651 {
2652   g_return_if_fail (GDK_IS_WINDOW (window));
2653
2654   /* FIXME: Implement */
2655 }
2656
2657 gboolean
2658 _gdk_windowing_window_queue_antiexpose (GdkWindow  *window,
2659                                         cairo_region_t  *area)
2660 {
2661   return FALSE;
2662 }
2663
2664 static void
2665 gdk_quartz_window_stick (GdkWindow *window)
2666 {
2667   if (GDK_WINDOW_DESTROYED (window) ||
2668       !WINDOW_IS_TOPLEVEL (window))
2669     return;
2670 }
2671
2672 static void
2673 gdk_quartz_window_unstick (GdkWindow *window)
2674 {
2675   if (GDK_WINDOW_DESTROYED (window) ||
2676       !WINDOW_IS_TOPLEVEL (window))
2677     return;
2678 }
2679
2680 static void
2681 gdk_quartz_window_maximize (GdkWindow *window)
2682 {
2683   GdkWindowImplQuartz *impl;
2684
2685   if (GDK_WINDOW_DESTROYED (window) ||
2686       !WINDOW_IS_TOPLEVEL (window))
2687     return;
2688
2689   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2690
2691   if (GDK_WINDOW_IS_MAPPED (window))
2692     {
2693       GDK_QUARTZ_ALLOC_POOL;
2694
2695       if (impl->toplevel && ![impl->toplevel isZoomed])
2696         [impl->toplevel zoom:nil];
2697
2698       GDK_QUARTZ_RELEASE_POOL;
2699     }
2700   else
2701     {
2702       gdk_synthesize_window_state (window,
2703                                    0,
2704                                    GDK_WINDOW_STATE_MAXIMIZED);
2705     }
2706 }
2707
2708 static void
2709 gdk_quartz_window_unmaximize (GdkWindow *window)
2710 {
2711   GdkWindowImplQuartz *impl;
2712
2713   if (GDK_WINDOW_DESTROYED (window) ||
2714       !WINDOW_IS_TOPLEVEL (window))
2715     return;
2716
2717   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2718
2719   if (GDK_WINDOW_IS_MAPPED (window))
2720     {
2721       GDK_QUARTZ_ALLOC_POOL;
2722
2723       if (impl->toplevel && [impl->toplevel isZoomed])
2724         [impl->toplevel zoom:nil];
2725
2726       GDK_QUARTZ_RELEASE_POOL;
2727     }
2728   else
2729     {
2730       gdk_synthesize_window_state (window,
2731                                    GDK_WINDOW_STATE_MAXIMIZED,
2732                                    0);
2733     }
2734 }
2735
2736 static void
2737 gdk_quartz_window_iconify (GdkWindow *window)
2738 {
2739   GdkWindowImplQuartz *impl;
2740
2741   if (GDK_WINDOW_DESTROYED (window) ||
2742       !WINDOW_IS_TOPLEVEL (window))
2743     return;
2744
2745   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2746
2747   if (GDK_WINDOW_IS_MAPPED (window))
2748     {
2749       GDK_QUARTZ_ALLOC_POOL;
2750
2751       if (impl->toplevel)
2752         [impl->toplevel miniaturize:nil];
2753
2754       GDK_QUARTZ_RELEASE_POOL;
2755     }
2756   else
2757     {
2758       gdk_synthesize_window_state (window,
2759                                    0,
2760                                    GDK_WINDOW_STATE_ICONIFIED);
2761     }
2762 }
2763
2764 static void
2765 gdk_quartz_window_deiconify (GdkWindow *window)
2766 {
2767   GdkWindowImplQuartz *impl;
2768
2769   if (GDK_WINDOW_DESTROYED (window) ||
2770       !WINDOW_IS_TOPLEVEL (window))
2771     return;
2772
2773   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2774
2775   if (GDK_WINDOW_IS_MAPPED (window))
2776     {
2777       GDK_QUARTZ_ALLOC_POOL;
2778
2779       if (impl->toplevel)
2780         [impl->toplevel deminiaturize:nil];
2781
2782       GDK_QUARTZ_RELEASE_POOL;
2783     }
2784   else
2785     {
2786       gdk_synthesize_window_state (window,
2787                                    GDK_WINDOW_STATE_ICONIFIED,
2788                                    0);
2789     }
2790 }
2791
2792 static FullscreenSavedGeometry *
2793 get_fullscreen_geometry (GdkWindow *window)
2794 {
2795   return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA);
2796 }
2797
2798 static void
2799 gdk_quartz_window_fullscreen (GdkWindow *window)
2800 {
2801   FullscreenSavedGeometry *geometry;
2802   NSRect frame;
2803
2804   if (GDK_WINDOW_DESTROYED (window) ||
2805       !WINDOW_IS_TOPLEVEL (window))
2806     return;
2807
2808   geometry = get_fullscreen_geometry (window);
2809   if (!geometry)
2810     {
2811       geometry = g_new (FullscreenSavedGeometry, 1);
2812
2813       geometry->x = window->x;
2814       geometry->y = window->y;
2815       geometry->width = window->width;
2816       geometry->height = window->height;
2817
2818       if (!gdk_window_get_decorations (window, &geometry->decor))
2819         geometry->decor = GDK_DECOR_ALL;
2820
2821       g_object_set_data_full (G_OBJECT (window),
2822                               FULLSCREEN_DATA, geometry, 
2823                               g_free);
2824
2825       gdk_window_set_decorations (window, 0);
2826
2827       frame = [[NSScreen mainScreen] frame];
2828       move_resize_window_internal (window,
2829                                    0, 0, 
2830                                    frame.size.width, frame.size.height);
2831     }
2832
2833   SetSystemUIMode (kUIModeAllHidden, kUIOptionAutoShowMenuBar);
2834
2835   gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
2836 }
2837
2838 static void
2839 gdk_quartz_window_unfullscreen (GdkWindow *window)
2840 {
2841   FullscreenSavedGeometry *geometry;
2842
2843   if (GDK_WINDOW_DESTROYED (window) ||
2844       !WINDOW_IS_TOPLEVEL (window))
2845     return;
2846
2847   geometry = get_fullscreen_geometry (window);
2848   if (geometry)
2849     {
2850       SetSystemUIMode (kUIModeNormal, 0);
2851
2852       move_resize_window_internal (window,
2853                                    geometry->x,
2854                                    geometry->y,
2855                                    geometry->width,
2856                                    geometry->height);
2857       
2858       gdk_window_set_decorations (window, geometry->decor);
2859
2860       g_object_set_data (G_OBJECT (window), FULLSCREEN_DATA, NULL);
2861
2862       gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
2863     }
2864 }
2865
2866 static void
2867 gdk_quartz_window_set_keep_above (GdkWindow *window,
2868                                   gboolean   setting)
2869 {
2870   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2871   gint level;
2872
2873   g_return_if_fail (GDK_IS_WINDOW (window));
2874
2875   if (GDK_WINDOW_DESTROYED (window) ||
2876       !WINDOW_IS_TOPLEVEL (window))
2877     return;
2878
2879   level = window_type_hint_to_level (gdk_window_get_type_hint (window));
2880   
2881   /* Adjust normal window level by one if necessary. */
2882   [impl->toplevel setLevel: level + (setting ? 1 : 0)];
2883 }
2884
2885 static void
2886 gdk_quartz_window_set_keep_below (GdkWindow *window,
2887                                   gboolean   setting)
2888 {
2889   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2890   gint level;
2891
2892   g_return_if_fail (GDK_IS_WINDOW (window));
2893
2894   if (GDK_WINDOW_DESTROYED (window) ||
2895       !WINDOW_IS_TOPLEVEL (window))
2896     return;
2897   
2898   level = window_type_hint_to_level (gdk_window_get_type_hint (window));
2899   
2900   /* Adjust normal window level by one if necessary. */
2901   [impl->toplevel setLevel: level - (setting ? 1 : 0)];
2902 }
2903
2904 static GdkWindow *
2905 gdk_quartz_window_get_group (GdkWindow *window)
2906 {
2907   g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL);
2908
2909   if (GDK_WINDOW_DESTROYED (window) ||
2910       !WINDOW_IS_TOPLEVEL (window))
2911     return NULL;
2912
2913   /* FIXME: Implement */
2914
2915   return NULL;
2916 }
2917
2918 static void
2919 gdk_quartz_window_set_group (GdkWindow *window,
2920                              GdkWindow *leader)
2921 {
2922   /* FIXME: Implement */        
2923 }
2924
2925 static void
2926 gdk_quartz_window_enable_synchronized_configure (GdkWindow *window)
2927 {
2928 }
2929
2930 static void
2931 gdk_quartz_window_configure_finished (GdkWindow *window)
2932 {
2933 }
2934
2935 static void
2936 gdk_quartz_window_destroy_notify (GdkWindow *window)
2937 {
2938   check_grab_destroy (window);
2939 }
2940
2941 static void
2942 gdk_quartz_window_set_opacity (GdkWindow *window,
2943                                gdouble    opacity)
2944 {
2945   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2946
2947   g_return_if_fail (GDK_IS_WINDOW (window));
2948   g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
2949
2950   if (GDK_WINDOW_DESTROYED (window) ||
2951       !WINDOW_IS_TOPLEVEL (window))
2952     return;
2953
2954   if (opacity < 0)
2955     opacity = 0;
2956   else if (opacity > 1)
2957     opacity = 1;
2958
2959   [impl->toplevel setAlphaValue: opacity];
2960 }
2961
2962 static cairo_region_t *
2963 gdk_quartz_window_get_shape (GdkWindow *window)
2964 {
2965   /* FIXME: implement */
2966   return NULL;
2967 }
2968
2969 static cairo_region_t *
2970 gdk_quartz_window_get_input_shape (GdkWindow *window)
2971 {
2972   /* FIXME: implement */
2973   return NULL;
2974 }
2975
2976
2977 static void
2978 gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass)
2979 {
2980   GObjectClass *object_class = G_OBJECT_CLASS (klass);
2981   GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
2982   GdkWindowImplQuartzClass *impl_quartz_class = GDK_WINDOW_IMPL_QUARTZ_CLASS (klass);
2983
2984   parent_class = g_type_class_peek_parent (klass);
2985
2986   object_class->finalize = gdk_window_impl_quartz_finalize;
2987
2988   impl_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
2989   impl_class->show = gdk_window_quartz_show;
2990   impl_class->hide = gdk_window_quartz_hide;
2991   impl_class->withdraw = gdk_window_quartz_withdraw;
2992   impl_class->set_events = gdk_window_quartz_set_events;
2993   impl_class->get_events = gdk_window_quartz_get_events;
2994   impl_class->raise = gdk_window_quartz_raise;
2995   impl_class->lower = gdk_window_quartz_lower;
2996   impl_class->restack_toplevel = gdk_window_quartz_restack_toplevel;
2997   impl_class->move_resize = gdk_window_quartz_move_resize;
2998   impl_class->set_background = gdk_window_quartz_set_background;
2999   impl_class->reparent = gdk_window_quartz_reparent;
3000   impl_class->set_device_cursor = gdk_window_quartz_set_device_cursor;
3001   impl_class->get_geometry = gdk_window_quartz_get_geometry;
3002   impl_class->get_root_coords = gdk_window_quartz_get_root_coords;
3003   impl_class->get_device_state = gdk_window_quartz_get_device_state;
3004   impl_class->shape_combine_region = gdk_window_quartz_shape_combine_region;
3005   impl_class->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
3006   impl_class->set_static_gravities = gdk_window_quartz_set_static_gravities;
3007   impl_class->queue_antiexpose = gdk_quartz_window_queue_antiexpose;
3008   impl_class->translate = gdk_quartz_window_translate;
3009   impl_class->destroy = gdk_quartz_window_destroy;
3010   impl_class->destroy_foreign = gdk_quartz_window_destroy_foreign;
3011   impl_class->resize_cairo_surface = gdk_window_quartz_resize_cairo_surface;
3012   impl_class->get_shape = gdk_quartz_window_get_shape;
3013   impl_class->get_input_shape = gdk_quartz_window_get_input_shape;
3014
3015   impl_class->focus = gdk_quartz_window_focus;
3016   impl_class->set_type_hint = gdk_quartz_window_set_type_hint;
3017   impl_class->get_type_hint = gdk_quartz_window_get_type_hint;
3018   impl_class->set_modal_hint = gdk_quartz_window_set_modal_hint;
3019   impl_class->set_skip_taskbar_hint = gdk_quartz_window_set_skip_taskbar_hint;
3020   impl_class->set_skip_pager_hint = gdk_quartz_window_set_skip_pager_hint;
3021   impl_class->set_urgency_hint = gdk_quartz_window_set_urgency_hint;
3022   impl_class->set_geometry_hints = gdk_quartz_window_set_geometry_hints;
3023   impl_class->set_title = gdk_quartz_window_set_title;
3024   impl_class->set_role = gdk_quartz_window_set_role;
3025   impl_class->set_startup_id = gdk_quartz_window_set_startup_id;
3026   impl_class->set_transient_for = gdk_quartz_window_set_transient_for;
3027   impl_class->get_root_origin = gdk_quartz_window_get_root_origin;
3028   impl_class->get_frame_extents = gdk_quartz_window_get_frame_extents;
3029   impl_class->set_override_redirect = gdk_quartz_window_set_override_redirect;
3030   impl_class->set_accept_focus = gdk_quartz_window_set_accept_focus;
3031   impl_class->set_focus_on_map = gdk_quartz_window_set_focus_on_map;
3032   impl_class->set_icon_list = gdk_quartz_window_set_icon_list;
3033   impl_class->set_icon_name = gdk_quartz_window_set_icon_name;
3034   impl_class->iconify = gdk_quartz_window_iconify;
3035   impl_class->deiconify = gdk_quartz_window_deiconify;
3036   impl_class->stick = gdk_quartz_window_stick;
3037   impl_class->unstick = gdk_quartz_window_unstick;
3038   impl_class->maximize = gdk_quartz_window_maximize;
3039   impl_class->unmaximize = gdk_quartz_window_unmaximize;
3040   impl_class->fullscreen = gdk_quartz_window_fullscreen;
3041   impl_class->unfullscreen = gdk_quartz_window_unfullscreen;
3042   impl_class->set_keep_above = gdk_quartz_window_set_keep_above;
3043   impl_class->set_keep_below = gdk_quartz_window_set_keep_below;
3044   impl_class->get_group = gdk_quartz_window_get_group;
3045   impl_class->set_group = gdk_quartz_window_set_group;
3046   impl_class->set_decorations = gdk_quartz_window_set_decorations;
3047   impl_class->get_decorations = gdk_quartz_window_get_decorations;
3048   impl_class->set_functions = gdk_quartz_window_set_functions;
3049   impl_class->set_functions = gdk_quartz_window_set_functions;
3050   impl_class->begin_resize_drag = gdk_quartz_window_begin_resize_drag;
3051   impl_class->begin_move_drag = gdk_quartz_window_begin_move_drag;
3052   impl_class->enable_synchronized_configure = gdk_quartz_window_enable_synchronized_configure;
3053   impl_class->configure_finished = gdk_quartz_window_configure_finished;
3054   impl_class->set_opacity = gdk_quartz_window_set_opacity;
3055   impl_class->destroy_notify = gdk_quartz_window_destroy_notify;
3056   impl_class->register_dnd = _gdk_quartz_window_register_dnd;
3057   impl_class->drag_begin = _gdk_quartz_window_drag_begin;
3058   impl_class->process_updates_recurse = _gdk_quartz_window_process_updates_recurse;
3059   impl_class->sync_rendering = _gdk_quartz_window_sync_rendering;
3060   impl_class->simulate_key = _gdk_quartz_window_simulate_key;
3061   impl_class->simulate_button = _gdk_quartz_window_simulate_button;
3062   impl_class->get_property = _gdk_quartz_window_get_property;
3063   impl_class->change_property = _gdk_quartz_window_change_property;
3064   impl_class->delete_property = _gdk_quartz_window_delete_property;
3065
3066
3067   impl_quartz_class->get_context = gdk_window_impl_quartz_get_context;
3068   impl_quartz_class->release_context = gdk_window_impl_quartz_release_context;
3069 }
3070
3071 GType
3072 _gdk_window_impl_quartz_get_type (void)
3073 {
3074   static GType object_type = 0;
3075
3076   if (!object_type)
3077     {
3078       const GTypeInfo object_info =
3079         {
3080           sizeof (GdkWindowImplQuartzClass),
3081           (GBaseInitFunc) NULL,
3082           (GBaseFinalizeFunc) NULL,
3083           (GClassInitFunc) gdk_window_impl_quartz_class_init,
3084           NULL,           /* class_finalize */
3085           NULL,           /* class_data */
3086           sizeof (GdkWindowImplQuartz),
3087           0,              /* n_preallocs */
3088           (GInstanceInitFunc) gdk_window_impl_quartz_init,
3089         };
3090
3091       const GInterfaceInfo paintable_info = 
3092         {
3093           (GInterfaceInitFunc) gdk_window_impl_quartz_paintable_init,
3094           NULL,
3095           NULL
3096         };
3097
3098       object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL,
3099                                             "GdkWindowImplQuartz",
3100                                             &object_info, 0);
3101       g_type_add_interface_static (object_type,
3102                                    GDK_TYPE_PAINTABLE,
3103                                    &paintable_info);
3104     }
3105
3106   return object_type;
3107 }
3108
3109 CGContextRef
3110 gdk_quartz_window_get_context (GdkWindowImplQuartz  *window,
3111                                gboolean             antialias)
3112 {
3113   if (!GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->get_context)
3114     {
3115       g_warning ("%s doesn't implement GdkWindowImplQuartzClass::get_context()",
3116                  G_OBJECT_TYPE_NAME (window));
3117       return NULL;
3118     }
3119
3120   return GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->get_context (window, antialias);
3121 }
3122
3123 void
3124 gdk_quartz_window_release_context (GdkWindowImplQuartz  *window,
3125                                    CGContextRef          cg_context)
3126 {
3127   if (!GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->release_context)
3128     {
3129       g_warning ("%s doesn't implement GdkWindowImplQuartzClass::release_context()",
3130                  G_OBJECT_TYPE_NAME (window));
3131       return;
3132     }
3133
3134   GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->release_context (window, cg_context);
3135 }
3136
3137
3138
3139 static CGContextRef
3140 gdk_root_window_impl_quartz_get_context (GdkWindowImplQuartz *window,
3141                                          gboolean             antialias)
3142 {
3143   CGColorSpaceRef colorspace;
3144   CGContextRef cg_context;
3145   GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (window);
3146
3147   if (GDK_WINDOW_DESTROYED (window_impl->wrapper))
3148     return NULL;
3149
3150   /* We do not have the notion of a root window on OS X.  We fake this
3151    * by creating a 1x1 bitmap and return a context to that.
3152    */
3153   colorspace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
3154   cg_context = CGBitmapContextCreate (NULL,
3155                                       1, 1, 8, 4, colorspace,
3156                                       kCGImageAlphaPremultipliedLast);
3157   CGColorSpaceRelease (colorspace);
3158
3159   return cg_context;
3160 }
3161
3162 static void
3163 gdk_root_window_impl_quartz_release_context (GdkWindowImplQuartz *window,
3164                                              CGContextRef         cg_context)
3165 {
3166   CGContextRelease (cg_context);
3167 }
3168
3169 static void
3170 gdk_root_window_impl_quartz_class_init (GdkRootWindowImplQuartzClass *klass)
3171 {
3172   GdkWindowImplQuartzClass *window_quartz_class = GDK_WINDOW_IMPL_QUARTZ_CLASS (klass);
3173
3174   root_window_parent_class = g_type_class_peek_parent (klass);
3175
3176   window_quartz_class->get_context = gdk_root_window_impl_quartz_get_context;
3177   window_quartz_class->release_context = gdk_root_window_impl_quartz_release_context;
3178 }
3179
3180 static void
3181 gdk_root_window_impl_quartz_init (GdkRootWindowImplQuartz *impl)
3182 {
3183 }
3184
3185 GType
3186 _gdk_root_window_impl_quartz_get_type (void)
3187 {
3188   static GType object_type = 0;
3189
3190   if (!object_type)
3191     {
3192       const GTypeInfo object_info =
3193         {
3194           sizeof (GdkRootWindowImplQuartzClass),
3195           (GBaseInitFunc) NULL,
3196           (GBaseFinalizeFunc) NULL,
3197           (GClassInitFunc) gdk_root_window_impl_quartz_class_init,
3198           NULL,           /* class_finalize */
3199           NULL,           /* class_data */
3200           sizeof (GdkRootWindowImplQuartz),
3201           0,              /* n_preallocs */
3202           (GInstanceInitFunc) gdk_root_window_impl_quartz_init,
3203         };
3204
3205       object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL_QUARTZ,
3206                                             "GdkRootWindowQuartz",
3207                                             &object_info, 0);
3208     }
3209
3210   return object_type;
3211 }