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