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