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