]> 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_keyboard_modifiers () |
1840       _gdk_quartz_events_get_current_mouse_modifiers ();
1841
1842   /* Get the y coordinate, needs to be flipped. */
1843   if (window == _gdk_root)
1844     {
1845       point = [NSEvent mouseLocation];
1846       _gdk_quartz_window_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
1847     }
1848   else
1849     {
1850       GdkWindowImplQuartz *impl;
1851       NSWindow *nswindow;
1852
1853       impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
1854       nswindow = impl->toplevel;
1855
1856       point = [nswindow mouseLocationOutsideOfEventStream];
1857
1858       x_tmp = point.x;
1859       y_tmp = toplevel->height - point.y;
1860
1861       window = (GdkWindow *)toplevel;
1862     }
1863
1864   found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp,
1865                                                 FALSE);
1866
1867   /* We never return the root window. */
1868   if (found_window == _gdk_root)
1869     found_window = NULL;
1870
1871   *x = x_tmp;
1872   *y = y_tmp;
1873
1874   return found_window;
1875 }
1876
1877 static gboolean
1878 gdk_window_quartz_get_device_state (GdkWindow       *window,
1879                                     GdkDevice       *device,
1880                                     gint            *x,
1881                                     gint            *y,
1882                                     GdkModifierType *mask)
1883 {
1884   return gdk_window_quartz_get_device_state_helper (window,
1885                                                     device,
1886                                                     x, y, mask) != NULL;
1887 }
1888
1889 /* Returns coordinates relative to the root. */
1890 void
1891 _gdk_windowing_get_device_state (GdkDisplay       *display,
1892                                  GdkDevice        *device,
1893                                  GdkScreen       **screen,
1894                                  gint             *x,
1895                                  gint             *y,
1896                                  GdkModifierType  *mask)
1897 {
1898   g_return_if_fail (display == _gdk_display);
1899   
1900   *screen = _gdk_screen;
1901   gdk_window_quartz_get_device_state_helper (_gdk_root, device, x, y, mask);
1902 }
1903
1904 /* Returns coordinates relative to the found window. */
1905 GdkWindow *
1906 _gdk_windowing_window_at_pointer (GdkDisplay      *display,
1907                                   gint            *win_x,
1908                                   gint            *win_y,
1909                                   GdkModifierType *mask,
1910                                   gboolean         get_toplevel)
1911 {
1912   GdkWindow *found_window;
1913   gint x, y;
1914   GdkModifierType tmp_mask = 0;
1915
1916   found_window = gdk_window_quartz_get_device_state_helper (_gdk_root,
1917                                                             display->core_pointer,
1918                                                             &x, &y,
1919                                                             &tmp_mask);
1920   if (found_window)
1921     {
1922       /* The coordinates returned above are relative the root, we want
1923        * coordinates relative the window here. 
1924        */
1925       while (found_window != _gdk_root)
1926         {
1927           x -= found_window->x;
1928           y -= found_window->y;
1929           
1930           found_window = found_window->parent;
1931         }
1932
1933       *win_x = x;
1934       *win_y = y;
1935     }
1936   else
1937     {
1938       /* Mimic the X backend here, -1,-1 for unknown windows. */
1939       *win_x = -1;
1940       *win_y = -1;
1941     }
1942
1943   if (mask)
1944     *mask = tmp_mask;
1945
1946   if (get_toplevel)
1947     {
1948       /* Requested toplevel, find it. */
1949       /* TODO: This can be implemented more efficient by never
1950          recursing into children in the first place */
1951       if (found_window)
1952         {
1953           /* Convert to toplevel */
1954           while (found_window->parent != NULL &&
1955                  found_window->parent->window_type != GDK_WINDOW_ROOT)
1956             {
1957               *win_x += found_window->x;
1958               *win_y += found_window->y;
1959               found_window = found_window->parent;
1960             }
1961         }
1962     }
1963
1964   return found_window;
1965 }
1966
1967 GdkWindow*
1968 _gdk_windowing_window_at_device_position (GdkDisplay      *display,
1969                                           GdkDevice       *device,
1970                                           gint            *win_x,
1971                                           gint            *win_y,
1972                                           GdkModifierType *mask,
1973                                           gboolean         get_toplevel)
1974 {
1975   return GDK_DEVICE_GET_CLASS (device)->window_at_position (device,
1976                                                             win_x, win_y,
1977                                                             mask,
1978                                                             get_toplevel);
1979 }
1980
1981
1982 static GdkEventMask  
1983 gdk_window_quartz_get_events (GdkWindow *window)
1984 {
1985   if (GDK_WINDOW_DESTROYED (window))
1986     return 0;
1987   else
1988     return window->event_mask;
1989 }
1990
1991 static void
1992 gdk_window_quartz_set_events (GdkWindow       *window,
1993                               GdkEventMask     event_mask)
1994 {
1995   /* The mask is set in the common code. */
1996 }
1997
1998 static void
1999 gdk_quartz_window_set_urgency_hint (GdkWindow *window,
2000                                     gboolean   urgent)
2001 {
2002   if (GDK_WINDOW_DESTROYED (window) ||
2003       !WINDOW_IS_TOPLEVEL (window))
2004     return;
2005
2006   /* FIXME: Implement */
2007 }
2008
2009 static void
2010 gdk_quartz_window_set_geometry_hints (GdkWindow         *window,
2011                                       const GdkGeometry *geometry,
2012                                       GdkWindowHints     geom_mask)
2013 {
2014   GdkWindowImplQuartz *impl;
2015
2016   g_return_if_fail (geometry != NULL);
2017
2018   if (GDK_WINDOW_DESTROYED (window) ||
2019       !WINDOW_IS_TOPLEVEL (window))
2020     return;
2021   
2022   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2023   if (!impl->toplevel)
2024     return;
2025
2026   if (geom_mask & GDK_HINT_POS)
2027     {
2028       /* FIXME: Implement */
2029     }
2030
2031   if (geom_mask & GDK_HINT_USER_POS)
2032     {
2033       /* FIXME: Implement */
2034     }
2035
2036   if (geom_mask & GDK_HINT_USER_SIZE)
2037     {
2038       /* FIXME: Implement */
2039     }
2040   
2041   if (geom_mask & GDK_HINT_MIN_SIZE)
2042     {
2043       NSSize size;
2044
2045       size.width = geometry->min_width;
2046       size.height = geometry->min_height;
2047
2048       [impl->toplevel setContentMinSize:size];
2049     }
2050   
2051   if (geom_mask & GDK_HINT_MAX_SIZE)
2052     {
2053       NSSize size;
2054
2055       size.width = geometry->max_width;
2056       size.height = geometry->max_height;
2057
2058       [impl->toplevel setContentMaxSize:size];
2059     }
2060   
2061   if (geom_mask & GDK_HINT_BASE_SIZE)
2062     {
2063       /* FIXME: Implement */
2064     }
2065   
2066   if (geom_mask & GDK_HINT_RESIZE_INC)
2067     {
2068       NSSize size;
2069
2070       size.width = geometry->width_inc;
2071       size.height = geometry->height_inc;
2072
2073       [impl->toplevel setContentResizeIncrements:size];
2074     }
2075   
2076   if (geom_mask & GDK_HINT_ASPECT)
2077     {
2078       /* FIXME: Implement */
2079     }
2080
2081   if (geom_mask & GDK_HINT_WIN_GRAVITY)
2082     {
2083       /* FIXME: Implement */
2084     }
2085 }
2086
2087 static void
2088 gdk_quartz_window_set_title (GdkWindow   *window,
2089                              const gchar *title)
2090 {
2091   GdkWindowImplQuartz *impl;
2092
2093   g_return_if_fail (title != NULL);
2094
2095   if (GDK_WINDOW_DESTROYED (window) ||
2096       !WINDOW_IS_TOPLEVEL (window))
2097     return;
2098
2099   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2100
2101   if (impl->toplevel)
2102     {
2103       GDK_QUARTZ_ALLOC_POOL;
2104       [impl->toplevel setTitle:[NSString stringWithUTF8String:title]];
2105       GDK_QUARTZ_RELEASE_POOL;
2106     }
2107 }
2108
2109 static void
2110 gdk_quartz_window_set_role (GdkWindow   *window,
2111                             const gchar *role)
2112 {
2113   if (GDK_WINDOW_DESTROYED (window) ||
2114       WINDOW_IS_TOPLEVEL (window))
2115     return;
2116
2117   /* FIXME: Implement */
2118 }
2119
2120 static void
2121 gdk_quartz_window_set_startup_id (GdkWindow   *window,
2122                                   const gchar *startup_id)
2123 {
2124   /* FIXME: Implement? */
2125 }
2126
2127 static void
2128 gdk_quartz_window_set_transient_for (GdkWindow *window,
2129                                      GdkWindow *parent)
2130 {
2131   GdkWindowImplQuartz *window_impl;
2132   GdkWindowImplQuartz *parent_impl;
2133
2134   if (GDK_WINDOW_DESTROYED (window)  || GDK_WINDOW_DESTROYED (parent) ||
2135       !WINDOW_IS_TOPLEVEL (window))
2136     return;
2137
2138   window_impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2139   if (!window_impl->toplevel)
2140     return;
2141
2142   GDK_QUARTZ_ALLOC_POOL;
2143
2144   if (window_impl->transient_for)
2145     {
2146       _gdk_quartz_window_detach_from_parent (window);
2147
2148       g_object_unref (window_impl->transient_for);
2149       window_impl->transient_for = NULL;
2150     }
2151
2152   parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
2153   if (parent_impl->toplevel)
2154     {
2155       /* We save the parent because it needs to be unset/reset when
2156        * hiding and showing the window. 
2157        */
2158
2159       /* We don't set transients for tooltips, they are already
2160        * handled by the window level being the top one. If we do, then
2161        * the parent window will be brought to the top just because the
2162        * tooltip is, which is not what we want.
2163        */
2164       if (gdk_window_get_type_hint (window) != GDK_WINDOW_TYPE_HINT_TOOLTIP)
2165         {
2166           window_impl->transient_for = g_object_ref (parent);
2167
2168           /* We only add the window if it is shown, otherwise it will
2169            * be shown unconditionally here. If it is not shown, the
2170            * window will be added in show() instead.
2171            */
2172           if (!(window->state & GDK_WINDOW_STATE_WITHDRAWN))
2173             _gdk_quartz_window_attach_to_parent (window);
2174         }
2175     }
2176   
2177   GDK_QUARTZ_RELEASE_POOL;
2178 }
2179
2180 static void
2181 gdk_window_quartz_shape_combine_region (GdkWindow       *window,
2182                                         const cairo_region_t *shape,
2183                                         gint             x,
2184                                         gint             y)
2185 {
2186   /* FIXME: Implement */
2187 }
2188
2189 static void
2190 gdk_window_quartz_input_shape_combine_region (GdkWindow       *window,
2191                                               const cairo_region_t *shape_region,
2192                                               gint             offset_x,
2193                                               gint             offset_y)
2194 {
2195   /* FIXME: Implement */
2196 }
2197
2198 static void
2199 gdk_quartz_window_set_override_redirect (GdkWindow *window,
2200                                          gboolean override_redirect)
2201 {
2202   /* FIXME: Implement */
2203 }
2204
2205 static void
2206 gdk_quartz_window_set_accept_focus (GdkWindow *window,
2207                                     gboolean accept_focus)
2208 {
2209   window->accept_focus = accept_focus != FALSE;
2210 }
2211
2212 static gboolean 
2213 gdk_window_quartz_set_static_gravities (GdkWindow *window,
2214                                         gboolean   use_static)
2215 {
2216   if (GDK_WINDOW_DESTROYED (window) ||
2217       !WINDOW_IS_TOPLEVEL (window))
2218     return FALSE;
2219
2220   /* FIXME: Implement */
2221   return FALSE;
2222 }
2223
2224 static gboolean
2225 gdk_quartz_window_queue_antiexpose (GdkWindow *window,
2226                                     cairo_region_t *area)
2227 {
2228   return FALSE;
2229 }
2230
2231 static void
2232 gdk_quartz_window_translate (GdkWindow      *window,
2233                              cairo_region_t *area,
2234                              gint            dx,
2235                              gint            dy)
2236 {
2237   cairo_region_t *invalidate, *scrolled;
2238   GdkWindowImplQuartz *impl = (GdkWindowImplQuartz *)window->impl;
2239   GdkRectangle extents;
2240
2241   cairo_region_get_extents (area, &extents);
2242
2243   [impl->view scrollRect:NSMakeRect (extents.x - dx, extents.y - dy,
2244                                      extents.width, extents.height)
2245               by:NSMakeSize (dx, dy)];
2246
2247   if (impl->needs_display_region)
2248     {
2249       cairo_region_t *intersection;
2250
2251       /* Invalidate already invalidated area that was moved at new
2252        * location.
2253        */
2254       intersection = cairo_region_copy (impl->needs_display_region);
2255       cairo_region_intersect (intersection, area);
2256       cairo_region_translate (intersection, dx, dy);
2257
2258       gdk_quartz_window_set_needs_display_in_region (window, intersection);
2259       cairo_region_destroy (intersection);
2260     }
2261
2262   /* Calculate newly exposed area that needs invalidation */
2263   scrolled = cairo_region_copy (area);
2264   cairo_region_translate (scrolled, dx, dy);
2265
2266   invalidate = cairo_region_copy (area);
2267   cairo_region_subtract (invalidate, scrolled);
2268   cairo_region_destroy (scrolled);
2269
2270   gdk_quartz_window_set_needs_display_in_region (window, invalidate);
2271   cairo_region_destroy (invalidate);
2272 }
2273
2274 static void
2275 gdk_quartz_window_set_focus_on_map (GdkWindow *window,
2276                                     gboolean focus_on_map)
2277 {
2278   window->focus_on_map = focus_on_map != FALSE;
2279 }
2280
2281 static void
2282 gdk_quartz_window_set_icon_name (GdkWindow   *window,
2283                                  const gchar *name)
2284 {
2285   /* FIXME: Implement */
2286 }
2287
2288 static void
2289 gdk_quartz_window_focus (GdkWindow *window,
2290                          guint32    timestamp)
2291 {
2292   GdkWindowImplQuartz *impl;
2293         
2294   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2295
2296   if (GDK_WINDOW_DESTROYED (window) ||
2297       !WINDOW_IS_TOPLEVEL (window))
2298     return;
2299
2300   if (window->accept_focus && window->window_type != GDK_WINDOW_TEMP)
2301     {
2302       GDK_QUARTZ_ALLOC_POOL;
2303       [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
2304       clear_toplevel_order ();
2305       GDK_QUARTZ_RELEASE_POOL;
2306     }
2307 }
2308
2309 static
2310 gint window_type_hint_to_level (GdkWindowTypeHint hint)
2311 {
2312   switch (hint)
2313     {
2314     case GDK_WINDOW_TYPE_HINT_DOCK:
2315     case GDK_WINDOW_TYPE_HINT_UTILITY:
2316       return NSFloatingWindowLevel;
2317
2318     case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
2319     case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
2320       return NSTornOffMenuWindowLevel;
2321
2322     case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
2323     case GDK_WINDOW_TYPE_HINT_TOOLTIP:
2324       return NSStatusWindowLevel;
2325
2326     case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2327     case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
2328     case GDK_WINDOW_TYPE_HINT_COMBO:
2329     case GDK_WINDOW_TYPE_HINT_DND:
2330       return NSPopUpMenuWindowLevel;
2331
2332     case GDK_WINDOW_TYPE_HINT_NORMAL:  /* Normal toplevel window */
2333     case GDK_WINDOW_TYPE_HINT_DIALOG:  /* Dialog window */
2334     case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
2335     case GDK_WINDOW_TYPE_HINT_DESKTOP: /* N/A */
2336       break;
2337
2338     default:
2339       break;
2340     }
2341
2342   return NSNormalWindowLevel;
2343 }
2344
2345 static gboolean 
2346 window_type_hint_to_shadow (GdkWindowTypeHint hint)
2347 {
2348   switch (hint)
2349     {
2350     case GDK_WINDOW_TYPE_HINT_NORMAL:  /* Normal toplevel window */
2351     case GDK_WINDOW_TYPE_HINT_DIALOG:  /* Dialog window */
2352     case GDK_WINDOW_TYPE_HINT_DOCK:
2353     case GDK_WINDOW_TYPE_HINT_UTILITY:
2354     case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
2355     case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
2356     case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2357     case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
2358     case GDK_WINDOW_TYPE_HINT_COMBO:
2359     case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
2360     case GDK_WINDOW_TYPE_HINT_TOOLTIP:
2361       return TRUE;
2362
2363     case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
2364     case GDK_WINDOW_TYPE_HINT_DESKTOP: /* N/A */
2365     case GDK_WINDOW_TYPE_HINT_DND:
2366       break;
2367
2368     default:
2369       break;
2370     }
2371
2372   return FALSE;
2373 }
2374
2375
2376 static void
2377 gdk_quartz_window_set_type_hint (GdkWindow        *window,
2378                                  GdkWindowTypeHint hint)
2379 {
2380   GdkWindowImplQuartz *impl;
2381   
2382   if (GDK_WINDOW_DESTROYED (window) ||
2383       !WINDOW_IS_TOPLEVEL (window))
2384     return;
2385
2386   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2387
2388   impl->type_hint = hint;
2389
2390   /* Match the documentation, only do something if we're not mapped yet. */
2391   if (GDK_WINDOW_IS_MAPPED (window))
2392     return;
2393
2394   [impl->toplevel setHasShadow: window_type_hint_to_shadow (hint)];
2395   [impl->toplevel setLevel: window_type_hint_to_level (hint)];
2396 }
2397
2398 static GdkWindowTypeHint
2399 gdk_quartz_window_get_type_hint (GdkWindow *window)
2400 {
2401   if (GDK_WINDOW_DESTROYED (window) ||
2402       !WINDOW_IS_TOPLEVEL (window))
2403     return GDK_WINDOW_TYPE_HINT_NORMAL;
2404   
2405   return GDK_WINDOW_IMPL_QUARTZ (window->impl)->type_hint;
2406 }
2407
2408 static void
2409 gdk_quartz_window_set_modal_hint (GdkWindow *window,
2410                                   gboolean   modal)
2411 {
2412   if (GDK_WINDOW_DESTROYED (window) ||
2413       !WINDOW_IS_TOPLEVEL (window))
2414     return;
2415
2416   /* FIXME: Implement */
2417 }
2418
2419 static void
2420 gdk_quartz_window_set_skip_taskbar_hint (GdkWindow *window,
2421                                          gboolean   skips_taskbar)
2422 {
2423   if (GDK_WINDOW_DESTROYED (window) ||
2424       !WINDOW_IS_TOPLEVEL (window))
2425     return;
2426
2427   /* FIXME: Implement */
2428 }
2429
2430 static void
2431 gdk_quartz_window_set_skip_pager_hint (GdkWindow *window,
2432                                        gboolean   skips_pager)
2433 {
2434   if (GDK_WINDOW_DESTROYED (window) ||
2435       !WINDOW_IS_TOPLEVEL (window))
2436     return;
2437
2438   /* FIXME: Implement */
2439 }
2440
2441 static void
2442 gdk_quartz_window_begin_resize_drag (GdkWindow     *window,
2443                                      GdkWindowEdge  edge,
2444                                      gint           button,
2445                                      gint           root_x,
2446                                      gint           root_y,
2447                                      guint32        timestamp)
2448 {
2449   GdkWindowImplQuartz *impl;
2450
2451   g_return_if_fail (GDK_IS_WINDOW (window));
2452
2453   if (edge != GDK_WINDOW_EDGE_SOUTH_EAST)
2454     {
2455       g_warning ("Resizing is only implemented for GDK_WINDOW_EDGE_SOUTH_EAST on Mac OS");
2456       return;
2457     }
2458
2459   if (GDK_WINDOW_DESTROYED (window))
2460     return;
2461
2462   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2463
2464   if (!impl->toplevel)
2465     {
2466       g_warning ("Can't call gdk_window_begin_resize_drag on non-toplevel window");
2467       return;
2468     }
2469
2470   [(GdkQuartzNSWindow *)impl->toplevel beginManualResize];
2471 }
2472
2473 static void
2474 gdk_quartz_window_begin_move_drag (GdkWindow *window,
2475                                    gint       button,
2476                                    gint       root_x,
2477                                    gint       root_y,
2478                                    guint32    timestamp)
2479 {
2480   GdkWindowImplQuartz *impl;
2481
2482   if (GDK_WINDOW_DESTROYED (window) ||
2483       !WINDOW_IS_TOPLEVEL (window))
2484     return;
2485
2486   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2487
2488   if (!impl->toplevel)
2489     {
2490       g_warning ("Can't call gdk_window_begin_move_drag on non-toplevel window");
2491       return;
2492     }
2493
2494   [(GdkQuartzNSWindow *)impl->toplevel beginManualMove];
2495 }
2496
2497 static void
2498 gdk_quartz_window_set_icon_list (GdkWindow *window,
2499                                  GList     *pixbufs)
2500 {
2501   /* FIXME: Implement */
2502 }
2503
2504 static void
2505 gdk_quartz_window_get_frame_extents (GdkWindow    *window,
2506                                      GdkRectangle *rect)
2507 {
2508   GdkWindow *toplevel;
2509   GdkWindowImplQuartz *impl;
2510   NSRect ns_rect;
2511
2512   g_return_if_fail (rect != NULL);
2513
2514
2515   rect->x = 0;
2516   rect->y = 0;
2517   rect->width = 1;
2518   rect->height = 1;
2519   
2520   toplevel = gdk_window_get_effective_toplevel (window);
2521   impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
2522
2523   ns_rect = [impl->toplevel frame];
2524
2525   _gdk_quartz_window_xy_to_gdk_xy (ns_rect.origin.x,
2526                                    ns_rect.origin.y + ns_rect.size.height,
2527                                    &rect->x, &rect->y);
2528
2529   rect->width = ns_rect.size.width;
2530   rect->height = ns_rect.size.height;
2531 }
2532
2533 static void
2534 gdk_quartz_window_set_decorations (GdkWindow       *window,
2535                                    GdkWMDecoration  decorations)
2536 {
2537   GdkWindowImplQuartz *impl;
2538   NSUInteger old_mask, new_mask;
2539   NSView *old_view;
2540
2541   if (GDK_WINDOW_DESTROYED (window) ||
2542       !WINDOW_IS_TOPLEVEL (window))
2543     return;
2544
2545   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2546
2547   if (decorations == 0 || GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP ||
2548       impl->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN )
2549     {
2550       new_mask = NSBorderlessWindowMask;
2551     }
2552   else
2553     {
2554       /* FIXME: Honor other GDK_DECOR_* flags. */
2555       new_mask = (NSTitledWindowMask | NSClosableWindowMask |
2556                     NSMiniaturizableWindowMask | NSResizableWindowMask);
2557     }
2558
2559   GDK_QUARTZ_ALLOC_POOL;
2560
2561   old_mask = [impl->toplevel styleMask];
2562
2563   if (old_mask != new_mask)
2564     {
2565       NSRect rect;
2566
2567       old_view = [impl->toplevel contentView];
2568
2569       rect = [impl->toplevel frame];
2570
2571       /* Properly update the size of the window when the titlebar is
2572        * added or removed.
2573        */
2574       if (old_mask == NSBorderlessWindowMask &&
2575           new_mask != NSBorderlessWindowMask)
2576         {
2577           rect = [NSWindow frameRectForContentRect:rect styleMask:new_mask];
2578
2579         }
2580       else if (old_mask != NSBorderlessWindowMask &&
2581                new_mask == NSBorderlessWindowMask)
2582         {
2583           rect = [NSWindow contentRectForFrameRect:rect styleMask:old_mask];
2584         }
2585
2586       /* Note, before OS 10.6 there doesn't seem to be a way to change this without
2587        * recreating the toplevel. There might be bad side-effects of doing
2588        * that, but it seems alright.
2589        */
2590       if ([impl->toplevel respondsToSelector:@selector(setStyleMask:)])
2591         {
2592           [impl->toplevel setStyleMask:new_mask];
2593         }
2594       else
2595         {
2596           [impl->toplevel release];
2597           impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:rect
2598                                                                 styleMask:new_mask
2599                                                                   backing:NSBackingStoreBuffered
2600                                                                     defer:NO];
2601           [impl->toplevel setHasShadow: window_type_hint_to_shadow (impl->type_hint)];
2602           [impl->toplevel setLevel: window_type_hint_to_level (impl->type_hint)];
2603           [impl->toplevel setContentView:old_view];
2604         }
2605
2606       [impl->toplevel setFrame:rect display:YES];
2607
2608       /* Invalidate the window shadow for non-opaque views that have shadow
2609        * enabled, to get the shadow shape updated.
2610        */
2611       if (![old_view isOpaque] && [impl->toplevel hasShadow])
2612         [(GdkQuartzView*)old_view setNeedsInvalidateShadow:YES];
2613     }
2614
2615   GDK_QUARTZ_RELEASE_POOL;
2616 }
2617
2618 static gboolean
2619 gdk_quartz_window_get_decorations (GdkWindow       *window,
2620                                    GdkWMDecoration *decorations)
2621 {
2622   GdkWindowImplQuartz *impl;
2623
2624   if (GDK_WINDOW_DESTROYED (window) ||
2625       !WINDOW_IS_TOPLEVEL (window))
2626     return FALSE;
2627
2628   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2629
2630   if (decorations)
2631     {
2632       /* Borderless is 0, so we can't check it as a bit being set. */
2633       if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
2634         {
2635           *decorations = 0;
2636         }
2637       else
2638         {
2639           /* FIXME: Honor the other GDK_DECOR_* flags. */
2640           *decorations = GDK_DECOR_ALL;
2641         }
2642     }
2643
2644   return TRUE;
2645 }
2646
2647 static void
2648 gdk_quartz_window_set_functions (GdkWindow    *window,
2649                                  GdkWMFunction functions)
2650 {
2651   g_return_if_fail (GDK_IS_WINDOW (window));
2652
2653   /* FIXME: Implement */
2654 }
2655
2656 gboolean
2657 _gdk_windowing_window_queue_antiexpose (GdkWindow  *window,
2658                                         cairo_region_t  *area)
2659 {
2660   return FALSE;
2661 }
2662
2663 static void
2664 gdk_quartz_window_stick (GdkWindow *window)
2665 {
2666   if (GDK_WINDOW_DESTROYED (window) ||
2667       !WINDOW_IS_TOPLEVEL (window))
2668     return;
2669 }
2670
2671 static void
2672 gdk_quartz_window_unstick (GdkWindow *window)
2673 {
2674   if (GDK_WINDOW_DESTROYED (window) ||
2675       !WINDOW_IS_TOPLEVEL (window))
2676     return;
2677 }
2678
2679 static void
2680 gdk_quartz_window_maximize (GdkWindow *window)
2681 {
2682   GdkWindowImplQuartz *impl;
2683
2684   if (GDK_WINDOW_DESTROYED (window) ||
2685       !WINDOW_IS_TOPLEVEL (window))
2686     return;
2687
2688   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2689
2690   if (GDK_WINDOW_IS_MAPPED (window))
2691     {
2692       GDK_QUARTZ_ALLOC_POOL;
2693
2694       if (impl->toplevel && ![impl->toplevel isZoomed])
2695         [impl->toplevel zoom:nil];
2696
2697       GDK_QUARTZ_RELEASE_POOL;
2698     }
2699   else
2700     {
2701       gdk_synthesize_window_state (window,
2702                                    0,
2703                                    GDK_WINDOW_STATE_MAXIMIZED);
2704     }
2705 }
2706
2707 static void
2708 gdk_quartz_window_unmaximize (GdkWindow *window)
2709 {
2710   GdkWindowImplQuartz *impl;
2711
2712   if (GDK_WINDOW_DESTROYED (window) ||
2713       !WINDOW_IS_TOPLEVEL (window))
2714     return;
2715
2716   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2717
2718   if (GDK_WINDOW_IS_MAPPED (window))
2719     {
2720       GDK_QUARTZ_ALLOC_POOL;
2721
2722       if (impl->toplevel && [impl->toplevel isZoomed])
2723         [impl->toplevel zoom:nil];
2724
2725       GDK_QUARTZ_RELEASE_POOL;
2726     }
2727   else
2728     {
2729       gdk_synthesize_window_state (window,
2730                                    GDK_WINDOW_STATE_MAXIMIZED,
2731                                    0);
2732     }
2733 }
2734
2735 static void
2736 gdk_quartz_window_iconify (GdkWindow *window)
2737 {
2738   GdkWindowImplQuartz *impl;
2739
2740   if (GDK_WINDOW_DESTROYED (window) ||
2741       !WINDOW_IS_TOPLEVEL (window))
2742     return;
2743
2744   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2745
2746   if (GDK_WINDOW_IS_MAPPED (window))
2747     {
2748       GDK_QUARTZ_ALLOC_POOL;
2749
2750       if (impl->toplevel)
2751         [impl->toplevel miniaturize:nil];
2752
2753       GDK_QUARTZ_RELEASE_POOL;
2754     }
2755   else
2756     {
2757       gdk_synthesize_window_state (window,
2758                                    0,
2759                                    GDK_WINDOW_STATE_ICONIFIED);
2760     }
2761 }
2762
2763 static void
2764 gdk_quartz_window_deiconify (GdkWindow *window)
2765 {
2766   GdkWindowImplQuartz *impl;
2767
2768   if (GDK_WINDOW_DESTROYED (window) ||
2769       !WINDOW_IS_TOPLEVEL (window))
2770     return;
2771
2772   impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2773
2774   if (GDK_WINDOW_IS_MAPPED (window))
2775     {
2776       GDK_QUARTZ_ALLOC_POOL;
2777
2778       if (impl->toplevel)
2779         [impl->toplevel deminiaturize:nil];
2780
2781       GDK_QUARTZ_RELEASE_POOL;
2782     }
2783   else
2784     {
2785       gdk_synthesize_window_state (window,
2786                                    GDK_WINDOW_STATE_ICONIFIED,
2787                                    0);
2788     }
2789 }
2790
2791 static FullscreenSavedGeometry *
2792 get_fullscreen_geometry (GdkWindow *window)
2793 {
2794   return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA);
2795 }
2796
2797 static void
2798 gdk_quartz_window_fullscreen (GdkWindow *window)
2799 {
2800   FullscreenSavedGeometry *geometry;
2801   NSRect frame;
2802
2803   if (GDK_WINDOW_DESTROYED (window) ||
2804       !WINDOW_IS_TOPLEVEL (window))
2805     return;
2806
2807   geometry = get_fullscreen_geometry (window);
2808   if (!geometry)
2809     {
2810       geometry = g_new (FullscreenSavedGeometry, 1);
2811
2812       geometry->x = window->x;
2813       geometry->y = window->y;
2814       geometry->width = window->width;
2815       geometry->height = window->height;
2816
2817       if (!gdk_window_get_decorations (window, &geometry->decor))
2818         geometry->decor = GDK_DECOR_ALL;
2819
2820       g_object_set_data_full (G_OBJECT (window),
2821                               FULLSCREEN_DATA, geometry, 
2822                               g_free);
2823
2824       gdk_window_set_decorations (window, 0);
2825
2826       frame = [[NSScreen mainScreen] frame];
2827       move_resize_window_internal (window,
2828                                    0, 0, 
2829                                    frame.size.width, frame.size.height);
2830     }
2831
2832   SetSystemUIMode (kUIModeAllHidden, kUIOptionAutoShowMenuBar);
2833
2834   gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
2835 }
2836
2837 static void
2838 gdk_quartz_window_unfullscreen (GdkWindow *window)
2839 {
2840   FullscreenSavedGeometry *geometry;
2841
2842   if (GDK_WINDOW_DESTROYED (window) ||
2843       !WINDOW_IS_TOPLEVEL (window))
2844     return;
2845
2846   geometry = get_fullscreen_geometry (window);
2847   if (geometry)
2848     {
2849       SetSystemUIMode (kUIModeNormal, 0);
2850
2851       move_resize_window_internal (window,
2852                                    geometry->x,
2853                                    geometry->y,
2854                                    geometry->width,
2855                                    geometry->height);
2856       
2857       gdk_window_set_decorations (window, geometry->decor);
2858
2859       g_object_set_data (G_OBJECT (window), FULLSCREEN_DATA, NULL);
2860
2861       gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
2862     }
2863 }
2864
2865 static void
2866 gdk_quartz_window_set_keep_above (GdkWindow *window,
2867                                   gboolean   setting)
2868 {
2869   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2870   gint level;
2871
2872   g_return_if_fail (GDK_IS_WINDOW (window));
2873
2874   if (GDK_WINDOW_DESTROYED (window) ||
2875       !WINDOW_IS_TOPLEVEL (window))
2876     return;
2877
2878   level = window_type_hint_to_level (gdk_window_get_type_hint (window));
2879   
2880   /* Adjust normal window level by one if necessary. */
2881   [impl->toplevel setLevel: level + (setting ? 1 : 0)];
2882 }
2883
2884 static void
2885 gdk_quartz_window_set_keep_below (GdkWindow *window,
2886                                   gboolean   setting)
2887 {
2888   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2889   gint level;
2890
2891   g_return_if_fail (GDK_IS_WINDOW (window));
2892
2893   if (GDK_WINDOW_DESTROYED (window) ||
2894       !WINDOW_IS_TOPLEVEL (window))
2895     return;
2896   
2897   level = window_type_hint_to_level (gdk_window_get_type_hint (window));
2898   
2899   /* Adjust normal window level by one if necessary. */
2900   [impl->toplevel setLevel: level - (setting ? 1 : 0)];
2901 }
2902
2903 static GdkWindow *
2904 gdk_quartz_window_get_group (GdkWindow *window)
2905 {
2906   g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL);
2907
2908   if (GDK_WINDOW_DESTROYED (window) ||
2909       !WINDOW_IS_TOPLEVEL (window))
2910     return NULL;
2911
2912   /* FIXME: Implement */
2913
2914   return NULL;
2915 }
2916
2917 static void
2918 gdk_quartz_window_set_group (GdkWindow *window,
2919                              GdkWindow *leader)
2920 {
2921   /* FIXME: Implement */        
2922 }
2923
2924 static void
2925 gdk_quartz_window_enable_synchronized_configure (GdkWindow *window)
2926 {
2927 }
2928
2929 static void
2930 gdk_quartz_window_configure_finished (GdkWindow *window)
2931 {
2932 }
2933
2934 static void
2935 gdk_quartz_window_destroy_notify (GdkWindow *window)
2936 {
2937   check_grab_destroy (window);
2938 }
2939
2940 static void
2941 gdk_quartz_window_set_opacity (GdkWindow *window,
2942                                gdouble    opacity)
2943 {
2944   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
2945
2946   g_return_if_fail (GDK_IS_WINDOW (window));
2947   g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
2948
2949   if (GDK_WINDOW_DESTROYED (window) ||
2950       !WINDOW_IS_TOPLEVEL (window))
2951     return;
2952
2953   if (opacity < 0)
2954     opacity = 0;
2955   else if (opacity > 1)
2956     opacity = 1;
2957
2958   [impl->toplevel setAlphaValue: opacity];
2959 }
2960
2961 static cairo_region_t *
2962 gdk_quartz_window_get_shape (GdkWindow *window)
2963 {
2964   /* FIXME: implement */
2965   return NULL;
2966 }
2967
2968 static cairo_region_t *
2969 gdk_quartz_window_get_input_shape (GdkWindow *window)
2970 {
2971   /* FIXME: implement */
2972   return NULL;
2973 }
2974
2975
2976 static void
2977 gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass)
2978 {
2979   GObjectClass *object_class = G_OBJECT_CLASS (klass);
2980   GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
2981   GdkWindowImplQuartzClass *impl_quartz_class = GDK_WINDOW_IMPL_QUARTZ_CLASS (klass);
2982
2983   parent_class = g_type_class_peek_parent (klass);
2984
2985   object_class->finalize = gdk_window_impl_quartz_finalize;
2986
2987   impl_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
2988   impl_class->show = gdk_window_quartz_show;
2989   impl_class->hide = gdk_window_quartz_hide;
2990   impl_class->withdraw = gdk_window_quartz_withdraw;
2991   impl_class->set_events = gdk_window_quartz_set_events;
2992   impl_class->get_events = gdk_window_quartz_get_events;
2993   impl_class->raise = gdk_window_quartz_raise;
2994   impl_class->lower = gdk_window_quartz_lower;
2995   impl_class->restack_toplevel = gdk_window_quartz_restack_toplevel;
2996   impl_class->move_resize = gdk_window_quartz_move_resize;
2997   impl_class->set_background = gdk_window_quartz_set_background;
2998   impl_class->reparent = gdk_window_quartz_reparent;
2999   impl_class->set_device_cursor = gdk_window_quartz_set_device_cursor;
3000   impl_class->get_geometry = gdk_window_quartz_get_geometry;
3001   impl_class->get_root_coords = gdk_window_quartz_get_root_coords;
3002   impl_class->get_device_state = gdk_window_quartz_get_device_state;
3003   impl_class->shape_combine_region = gdk_window_quartz_shape_combine_region;
3004   impl_class->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
3005   impl_class->set_static_gravities = gdk_window_quartz_set_static_gravities;
3006   impl_class->queue_antiexpose = gdk_quartz_window_queue_antiexpose;
3007   impl_class->translate = gdk_quartz_window_translate;
3008   impl_class->destroy = gdk_quartz_window_destroy;
3009   impl_class->destroy_foreign = gdk_quartz_window_destroy_foreign;
3010   impl_class->resize_cairo_surface = gdk_window_quartz_resize_cairo_surface;
3011   impl_class->get_shape = gdk_quartz_window_get_shape;
3012   impl_class->get_input_shape = gdk_quartz_window_get_input_shape;
3013
3014   impl_class->focus = gdk_quartz_window_focus;
3015   impl_class->set_type_hint = gdk_quartz_window_set_type_hint;
3016   impl_class->get_type_hint = gdk_quartz_window_get_type_hint;
3017   impl_class->set_modal_hint = gdk_quartz_window_set_modal_hint;
3018   impl_class->set_skip_taskbar_hint = gdk_quartz_window_set_skip_taskbar_hint;
3019   impl_class->set_skip_pager_hint = gdk_quartz_window_set_skip_pager_hint;
3020   impl_class->set_urgency_hint = gdk_quartz_window_set_urgency_hint;
3021   impl_class->set_geometry_hints = gdk_quartz_window_set_geometry_hints;
3022   impl_class->set_title = gdk_quartz_window_set_title;
3023   impl_class->set_role = gdk_quartz_window_set_role;
3024   impl_class->set_startup_id = gdk_quartz_window_set_startup_id;
3025   impl_class->set_transient_for = gdk_quartz_window_set_transient_for;
3026   impl_class->get_root_origin = gdk_quartz_window_get_root_origin;
3027   impl_class->get_frame_extents = gdk_quartz_window_get_frame_extents;
3028   impl_class->set_override_redirect = gdk_quartz_window_set_override_redirect;
3029   impl_class->set_accept_focus = gdk_quartz_window_set_accept_focus;
3030   impl_class->set_focus_on_map = gdk_quartz_window_set_focus_on_map;
3031   impl_class->set_icon_list = gdk_quartz_window_set_icon_list;
3032   impl_class->set_icon_name = gdk_quartz_window_set_icon_name;
3033   impl_class->iconify = gdk_quartz_window_iconify;
3034   impl_class->deiconify = gdk_quartz_window_deiconify;
3035   impl_class->stick = gdk_quartz_window_stick;
3036   impl_class->unstick = gdk_quartz_window_unstick;
3037   impl_class->maximize = gdk_quartz_window_maximize;
3038   impl_class->unmaximize = gdk_quartz_window_unmaximize;
3039   impl_class->fullscreen = gdk_quartz_window_fullscreen;
3040   impl_class->unfullscreen = gdk_quartz_window_unfullscreen;
3041   impl_class->set_keep_above = gdk_quartz_window_set_keep_above;
3042   impl_class->set_keep_below = gdk_quartz_window_set_keep_below;
3043   impl_class->get_group = gdk_quartz_window_get_group;
3044   impl_class->set_group = gdk_quartz_window_set_group;
3045   impl_class->set_decorations = gdk_quartz_window_set_decorations;
3046   impl_class->get_decorations = gdk_quartz_window_get_decorations;
3047   impl_class->set_functions = gdk_quartz_window_set_functions;
3048   impl_class->set_functions = gdk_quartz_window_set_functions;
3049   impl_class->begin_resize_drag = gdk_quartz_window_begin_resize_drag;
3050   impl_class->begin_move_drag = gdk_quartz_window_begin_move_drag;
3051   impl_class->enable_synchronized_configure = gdk_quartz_window_enable_synchronized_configure;
3052   impl_class->configure_finished = gdk_quartz_window_configure_finished;
3053   impl_class->set_opacity = gdk_quartz_window_set_opacity;
3054   impl_class->destroy_notify = gdk_quartz_window_destroy_notify;
3055   impl_class->register_dnd = _gdk_quartz_window_register_dnd;
3056   impl_class->drag_begin = _gdk_quartz_window_drag_begin;
3057   impl_class->process_updates_recurse = _gdk_quartz_window_process_updates_recurse;
3058   impl_class->sync_rendering = _gdk_quartz_window_sync_rendering;
3059   impl_class->simulate_key = _gdk_quartz_window_simulate_key;
3060   impl_class->simulate_button = _gdk_quartz_window_simulate_button;
3061   impl_class->get_property = _gdk_quartz_window_get_property;
3062   impl_class->change_property = _gdk_quartz_window_change_property;
3063   impl_class->delete_property = _gdk_quartz_window_delete_property;
3064
3065
3066   impl_quartz_class->get_context = gdk_window_impl_quartz_get_context;
3067   impl_quartz_class->release_context = gdk_window_impl_quartz_release_context;
3068 }
3069
3070 GType
3071 _gdk_window_impl_quartz_get_type (void)
3072 {
3073   static GType object_type = 0;
3074
3075   if (!object_type)
3076     {
3077       const GTypeInfo object_info =
3078         {
3079           sizeof (GdkWindowImplQuartzClass),
3080           (GBaseInitFunc) NULL,
3081           (GBaseFinalizeFunc) NULL,
3082           (GClassInitFunc) gdk_window_impl_quartz_class_init,
3083           NULL,           /* class_finalize */
3084           NULL,           /* class_data */
3085           sizeof (GdkWindowImplQuartz),
3086           0,              /* n_preallocs */
3087           (GInstanceInitFunc) gdk_window_impl_quartz_init,
3088         };
3089
3090       const GInterfaceInfo paintable_info = 
3091         {
3092           (GInterfaceInitFunc) gdk_window_impl_quartz_paintable_init,
3093           NULL,
3094           NULL
3095         };
3096
3097       object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL,
3098                                             "GdkWindowImplQuartz",
3099                                             &object_info, 0);
3100       g_type_add_interface_static (object_type,
3101                                    GDK_TYPE_PAINTABLE,
3102                                    &paintable_info);
3103     }
3104
3105   return object_type;
3106 }
3107
3108 CGContextRef
3109 gdk_quartz_window_get_context (GdkWindowImplQuartz  *window,
3110                                gboolean             antialias)
3111 {
3112   if (!GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->get_context)
3113     {
3114       g_warning ("%s doesn't implement GdkWindowImplQuartzClass::get_context()",
3115                  G_OBJECT_TYPE_NAME (window));
3116       return NULL;
3117     }
3118
3119   return GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->get_context (window, antialias);
3120 }
3121
3122 void
3123 gdk_quartz_window_release_context (GdkWindowImplQuartz  *window,
3124                                    CGContextRef          cg_context)
3125 {
3126   if (!GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->release_context)
3127     {
3128       g_warning ("%s doesn't implement GdkWindowImplQuartzClass::release_context()",
3129                  G_OBJECT_TYPE_NAME (window));
3130       return;
3131     }
3132
3133   GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->release_context (window, cg_context);
3134 }
3135
3136
3137
3138 static CGContextRef
3139 gdk_root_window_impl_quartz_get_context (GdkWindowImplQuartz *window,
3140                                          gboolean             antialias)
3141 {
3142   CGColorSpaceRef colorspace;
3143   CGContextRef cg_context;
3144   GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (window);
3145
3146   if (GDK_WINDOW_DESTROYED (window_impl->wrapper))
3147     return NULL;
3148
3149   /* We do not have the notion of a root window on OS X.  We fake this
3150    * by creating a 1x1 bitmap and return a context to that.
3151    */
3152   colorspace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
3153   cg_context = CGBitmapContextCreate (NULL,
3154                                       1, 1, 8, 4, colorspace,
3155                                       kCGImageAlphaPremultipliedLast);
3156   CGColorSpaceRelease (colorspace);
3157
3158   return cg_context;
3159 }
3160
3161 static void
3162 gdk_root_window_impl_quartz_release_context (GdkWindowImplQuartz *window,
3163                                              CGContextRef         cg_context)
3164 {
3165   CGContextRelease (cg_context);
3166 }
3167
3168 static void
3169 gdk_root_window_impl_quartz_class_init (GdkRootWindowImplQuartzClass *klass)
3170 {
3171   GdkWindowImplQuartzClass *window_quartz_class = GDK_WINDOW_IMPL_QUARTZ_CLASS (klass);
3172
3173   root_window_parent_class = g_type_class_peek_parent (klass);
3174
3175   window_quartz_class->get_context = gdk_root_window_impl_quartz_get_context;
3176   window_quartz_class->release_context = gdk_root_window_impl_quartz_release_context;
3177 }
3178
3179 static void
3180 gdk_root_window_impl_quartz_init (GdkRootWindowImplQuartz *impl)
3181 {
3182 }
3183
3184 GType
3185 _gdk_root_window_impl_quartz_get_type (void)
3186 {
3187   static GType object_type = 0;
3188
3189   if (!object_type)
3190     {
3191       const GTypeInfo object_info =
3192         {
3193           sizeof (GdkRootWindowImplQuartzClass),
3194           (GBaseInitFunc) NULL,
3195           (GBaseFinalizeFunc) NULL,
3196           (GClassInitFunc) gdk_root_window_impl_quartz_class_init,
3197           NULL,           /* class_finalize */
3198           NULL,           /* class_data */
3199           sizeof (GdkRootWindowImplQuartz),
3200           0,              /* n_preallocs */
3201           (GInstanceInitFunc) gdk_root_window_impl_quartz_init,
3202         };
3203
3204       object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL_QUARTZ,
3205                                             "GdkRootWindowQuartz",
3206                                             &object_info, 0);
3207     }
3208
3209   return object_type;
3210 }