]> Pileus Git - ~andy/gtk/blob - gdk/quartz/gdkwindow-quartz.c
Add stubs for missing GDK windowing functions to Quartz backend
[~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   private->viewable = TRUE;
973
974   drawable_impl = GDK_DRAWABLE_IMPL_QUARTZ (private->impl);
975   
976   drawable_impl->wrapper = GDK_DRAWABLE (private);
977   drawable_impl->colormap = gdk_screen_get_system_colormap (_gdk_screen);
978   g_object_ref (drawable_impl->colormap);
979 }
980
981 static void
982 _gdk_quartz_window_destroy (GdkWindow *window,
983                             gboolean   recursing,
984                             gboolean   foreign_destroy)
985 {
986   GdkWindowObject *private;
987   GdkWindowImplQuartz *impl;
988   GdkWindowObject *parent;
989
990   private = GDK_WINDOW_OBJECT (window);
991   impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
992
993   main_window_stack = g_slist_remove (main_window_stack, window);
994
995   g_list_free (impl->sorted_children);
996   impl->sorted_children = NULL;
997
998   parent = private->parent;
999   if (parent)
1000     {
1001       GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
1002
1003       parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window);
1004     }
1005
1006   _gdk_quartz_drawable_finish (GDK_DRAWABLE (impl));
1007
1008   if (!recursing && !foreign_destroy)
1009     {
1010       GDK_QUARTZ_ALLOC_POOL;
1011
1012       if (impl->toplevel)
1013         [impl->toplevel close];
1014       else if (impl->view)
1015         [impl->view removeFromSuperview];
1016
1017       GDK_QUARTZ_RELEASE_POOL;
1018     }
1019 }
1020
1021 void
1022 _gdk_windowing_window_destroy_foreign (GdkWindow *window)
1023 {
1024   /* Foreign windows aren't supported in OSX. */
1025 }
1026
1027 /* FIXME: This might be possible to simplify with client-side windows. Also
1028  * note that already_mapped is not used yet, see the x11 backend.
1029 */
1030 static void
1031 gdk_window_quartz_show (GdkWindow *window, gboolean already_mapped)
1032 {
1033   GdkWindowObject *private = (GdkWindowObject *)window;
1034   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
1035   gboolean focus_on_map;
1036
1037   GDK_QUARTZ_ALLOC_POOL;
1038
1039   if (!GDK_WINDOW_IS_MAPPED (window))
1040     focus_on_map = private->focus_on_map;
1041   else
1042     focus_on_map = TRUE;
1043
1044   if (impl->toplevel)
1045     {
1046       gboolean make_key;
1047
1048       make_key = (private->accept_focus && focus_on_map &&
1049                   private->window_type != GDK_WINDOW_TEMP);
1050
1051       [(GdkQuartzWindow*)impl->toplevel showAndMakeKey:make_key];
1052       clear_toplevel_order ();
1053
1054       _gdk_quartz_events_send_map_event (window);
1055     }
1056   else
1057     {
1058       [impl->view setHidden:NO];
1059     }
1060
1061   [impl->view setNeedsDisplay:YES];
1062
1063   gdk_synthesize_window_state (window, GDK_WINDOW_STATE_WITHDRAWN, 0);
1064
1065   if (private->state & GDK_WINDOW_STATE_MAXIMIZED)
1066     gdk_window_maximize (window);
1067
1068   if (private->state & GDK_WINDOW_STATE_ICONIFIED)
1069     gdk_window_iconify (window);
1070
1071   if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
1072     _gdk_quartz_window_attach_to_parent (window);
1073
1074   GDK_QUARTZ_RELEASE_POOL;
1075 }
1076
1077 /* Temporarily unsets the parent window, if the window is a
1078  * transient. 
1079  */
1080 void
1081 _gdk_quartz_window_detach_from_parent (GdkWindow *window)
1082 {
1083   GdkWindowImplQuartz *impl;
1084
1085   g_return_if_fail (GDK_IS_WINDOW (window));
1086
1087   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
1088   
1089   g_return_if_fail (impl->toplevel != NULL);
1090
1091   if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
1092     {
1093       GdkWindowImplQuartz *parent_impl;
1094
1095       parent_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (impl->transient_for)->impl);
1096       [parent_impl->toplevel removeChildWindow:impl->toplevel];
1097       clear_toplevel_order ();
1098     }
1099 }
1100
1101 /* Re-sets the parent window, if the window is a transient. */
1102 void
1103 _gdk_quartz_window_attach_to_parent (GdkWindow *window)
1104 {
1105   GdkWindowImplQuartz *impl;
1106
1107   g_return_if_fail (GDK_IS_WINDOW (window));
1108
1109   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
1110   
1111   g_return_if_fail (impl->toplevel != NULL);
1112
1113   if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
1114     {
1115       GdkWindowImplQuartz *parent_impl;
1116
1117       parent_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (impl->transient_for)->impl);
1118       [parent_impl->toplevel addChildWindow:impl->toplevel ordered:NSWindowAbove];
1119       clear_toplevel_order ();
1120     }
1121 }
1122
1123 void
1124 gdk_window_quartz_hide (GdkWindow *window)
1125 {
1126   GdkWindowObject *private = (GdkWindowObject *)window;
1127   GdkWindowImplQuartz *impl;
1128
1129   /* Make sure we're not stuck in fullscreen mode. */
1130   if (get_fullscreen_geometry (window))
1131     SetSystemUIMode (kUIModeNormal, 0);
1132
1133   check_grab_unmap (window);
1134
1135   _gdk_window_clear_update_area (window);
1136
1137   impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
1138
1139   if (impl->toplevel) 
1140     {
1141      /* Update main window. */
1142       main_window_stack = g_slist_remove (main_window_stack, window);
1143       if ([NSApp mainWindow] == impl->toplevel)
1144         _gdk_quartz_window_did_resign_main (window);
1145
1146       if (impl->transient_for)
1147         _gdk_quartz_window_detach_from_parent (window);
1148
1149       [(GdkQuartzWindow*)impl->toplevel hide];
1150     }
1151   else if (impl->view)
1152     {
1153       [impl->view setHidden:YES];
1154     }
1155 }
1156
1157 void
1158 gdk_window_quartz_withdraw (GdkWindow *window)
1159 {
1160   gdk_window_hide (window);
1161 }
1162
1163 static void
1164 move_resize_window_internal (GdkWindow *window,
1165                              gint       x,
1166                              gint       y,
1167                              gint       width,
1168                              gint       height)
1169 {
1170   GdkWindowObject *private = (GdkWindowObject *)window;
1171   GdkWindowImplQuartz *impl;
1172   GdkRectangle old_visible;
1173   GdkRectangle new_visible;
1174   GdkRectangle scroll_rect;
1175   GdkRegion *old_region;
1176   GdkRegion *expose_region;
1177   NSSize delta;
1178
1179   if (GDK_WINDOW_DESTROYED (window))
1180     return;
1181
1182   impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
1183
1184   if ((x == -1 || (x == private->x)) &&
1185       (y == -1 || (y == private->y)) &&
1186       (width == -1 || (width == private->width)) &&
1187       (height == -1 || (height == private->height)))
1188     {
1189       return;
1190     }
1191
1192   if (!impl->toplevel)
1193     {
1194       /* The previously visible area of this window in a coordinate
1195        * system rooted at the origin of this window.
1196        */
1197       old_visible.x = -private->x;
1198       old_visible.y = -private->y;
1199
1200       gdk_window_get_size (GDK_DRAWABLE (private->parent), 
1201                            &old_visible.width, 
1202                            &old_visible.height);
1203     }
1204
1205   if (x != -1)
1206     {
1207       delta.width = x - private->x;
1208       private->x = x;
1209     }
1210   else
1211     {
1212       delta.width = 0;
1213     }
1214
1215   if (y != -1)
1216     {
1217       delta.height = y - private->y;
1218       private->y = y;
1219     }
1220   else
1221     {
1222       delta.height = 0;
1223     }
1224
1225   if (width != -1)
1226     private->width = width;
1227
1228   if (height != -1)
1229     private->height = height;
1230
1231   GDK_QUARTZ_ALLOC_POOL;
1232
1233   if (impl->toplevel)
1234     {
1235       NSRect content_rect;
1236       NSRect frame_rect;
1237
1238       content_rect =  NSMakeRect (private->x,
1239                                   _gdk_quartz_window_get_inverted_screen_y (private->y + private->height),
1240                                   private->width, private->height);
1241
1242       frame_rect = [impl->toplevel frameRectForContentRect:content_rect];
1243       [impl->toplevel setFrame:frame_rect display:YES];
1244     }
1245   else 
1246     {
1247       if (!private->input_only)
1248         {
1249           NSRect nsrect;
1250
1251           nsrect = NSMakeRect (private->x, private->y, private->width, private->height);
1252
1253           /* The newly visible area of this window in a coordinate
1254            * system rooted at the origin of this window.
1255            */
1256           new_visible.x = -private->x;
1257           new_visible.y = -private->y;
1258           new_visible.width = old_visible.width;   /* parent has not changed size */
1259           new_visible.height = old_visible.height; /* parent has not changed size */
1260
1261           expose_region = gdk_region_rectangle (&new_visible);
1262           old_region = gdk_region_rectangle (&old_visible);
1263           gdk_region_subtract (expose_region, old_region);
1264
1265           /* Determine what (if any) part of the previously visible
1266            * part of the window can be copied without a redraw
1267            */
1268           scroll_rect = old_visible;
1269           scroll_rect.x -= delta.width;
1270           scroll_rect.y -= delta.height;
1271           gdk_rectangle_intersect (&scroll_rect, &old_visible, &scroll_rect);
1272
1273           if (!gdk_region_empty (expose_region))
1274             {
1275               GdkRectangle* rects;
1276               gint n_rects;
1277               gint n;
1278
1279               if (scroll_rect.width != 0 && scroll_rect.height != 0)
1280                 {
1281                   [impl->view scrollRect:NSMakeRect (scroll_rect.x,
1282                                                      scroll_rect.y,
1283                                                      scroll_rect.width,
1284                                                      scroll_rect.height)
1285                                       by:delta];
1286                 }
1287
1288               [impl->view setFrame:nsrect];
1289
1290               gdk_region_get_rectangles (expose_region, &rects, &n_rects);
1291
1292               for (n = 0; n < n_rects; ++n)
1293                 {
1294                   [impl->view setNeedsDisplayInRect:NSMakeRect (rects[n].x,
1295                                                                 rects[n].y,
1296                                                                 rects[n].width,
1297                                                                 rects[n].height)];
1298                 }
1299
1300               g_free (rects);
1301             }
1302           else
1303             {
1304               [impl->view setFrame:nsrect];
1305               [impl->view setNeedsDisplay:YES];
1306             }
1307
1308           gdk_region_destroy (expose_region);
1309           gdk_region_destroy (old_region);
1310         }
1311     }
1312
1313   GDK_QUARTZ_RELEASE_POOL;
1314 }
1315
1316 static inline void
1317 window_quartz_move (GdkWindow *window,
1318                     gint       x,
1319                     gint       y)
1320 {
1321   g_return_if_fail (GDK_IS_WINDOW (window));
1322
1323   if (((GdkWindowObject *)window)->state & GDK_WINDOW_STATE_FULLSCREEN)
1324     return;
1325
1326   move_resize_window_internal (window, x, y, -1, -1);
1327 }
1328
1329 static inline void
1330 window_quartz_resize (GdkWindow *window,
1331                       gint       width,
1332                       gint       height)
1333 {
1334   g_return_if_fail (GDK_IS_WINDOW (window));
1335
1336   if (((GdkWindowObject *)window)->state & GDK_WINDOW_STATE_FULLSCREEN)
1337     return;
1338
1339   if (width < 1)
1340     width = 1;
1341   if (height < 1)
1342     height = 1;
1343
1344   move_resize_window_internal (window, -1, -1, width, height);
1345 }
1346
1347 static inline void
1348 window_quartz_move_resize (GdkWindow *window,
1349                            gint       x,
1350                            gint       y,
1351                            gint       width,
1352                            gint       height)
1353 {
1354   if (width < 1)
1355     width = 1;
1356   if (height < 1)
1357     height = 1;
1358
1359   move_resize_window_internal (window, x, y, width, height);
1360 }
1361
1362 static void
1363 gdk_window_quartz_move_resize (GdkWindow *window,
1364                                gboolean   with_move,
1365                                gint       x,
1366                                gint       y,
1367                                gint       width,
1368                                gint       height)
1369 {
1370   if (with_move && (width < 0 && height < 0))
1371     window_quartz_move (window, x, y);
1372   else
1373     {
1374       if (with_move)
1375         window_quartz_move_resize (window, x, y, width, height);
1376       else
1377         window_quartz_resize (window, width, height);
1378     }
1379 }
1380
1381 /* FIXME: This might need fixing (reparenting didn't work before client-side
1382  * windows either).
1383  */
1384 static gboolean
1385 gdk_window_quartz_reparent (GdkWindow *window,
1386                             GdkWindow *new_parent,
1387                             gint       x,
1388                             gint       y)
1389 {
1390   GdkWindowObject *private, *old_parent_private, *new_parent_private;
1391   GdkWindowImplQuartz *impl, *old_parent_impl, *new_parent_impl;
1392   NSView *view, *new_parent_view;
1393
1394   if (new_parent == _gdk_root)
1395     {
1396       /* Could be added, just needs implementing. */
1397       g_warning ("Reparenting to root window is not supported yet in the Mac OS X backend");
1398       return FALSE;
1399     }
1400
1401   private = GDK_WINDOW_OBJECT (window);
1402   impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
1403   view = impl->view;
1404
1405   new_parent_private = GDK_WINDOW_OBJECT (new_parent);
1406   new_parent_impl = GDK_WINDOW_IMPL_QUARTZ (new_parent_private->impl);
1407   new_parent_view = new_parent_impl->view;
1408
1409   old_parent_private = GDK_WINDOW_OBJECT (private->parent);
1410   old_parent_impl = GDK_WINDOW_IMPL_QUARTZ (old_parent_private->impl);
1411
1412   [view retain];
1413
1414   [view removeFromSuperview];
1415   [new_parent_view addSubview:view];
1416
1417   [view release];
1418
1419   private->parent = new_parent_private;
1420
1421   if (old_parent_private)
1422     {
1423       old_parent_impl->sorted_children = g_list_remove (old_parent_impl->sorted_children, window);
1424     }
1425
1426   new_parent_impl->sorted_children = g_list_prepend (new_parent_impl->sorted_children, window);
1427
1428   return FALSE;
1429 }
1430
1431 /* Get the toplevel ordering from NSApp and update our own list. We do
1432  * this on demand since the NSApp's list is not up to date directly
1433  * after we get windowDidBecomeMain.
1434  */
1435 static void
1436 update_toplevel_order (void)
1437 {
1438   GdkWindowObject *root;
1439   GdkWindowImplQuartz *root_impl;
1440   NSEnumerator *enumerator;
1441   id nswindow;
1442   GList *toplevels = NULL;
1443
1444   root = GDK_WINDOW_OBJECT (_gdk_root);
1445   root_impl = GDK_WINDOW_IMPL_QUARTZ (root->impl);
1446
1447   if (root_impl->sorted_children)
1448     return;
1449
1450   GDK_QUARTZ_ALLOC_POOL;
1451
1452   enumerator = [[NSApp orderedWindows] objectEnumerator];
1453   while ((nswindow = [enumerator nextObject]))
1454     {
1455       GdkWindow *window;
1456
1457       if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
1458         continue;
1459
1460       window = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
1461       toplevels = g_list_prepend (toplevels, window);
1462     }
1463
1464   GDK_QUARTZ_RELEASE_POOL;
1465
1466   root_impl->sorted_children = g_list_reverse (toplevels);
1467 }
1468
1469 static void
1470 clear_toplevel_order (void)
1471 {
1472   GdkWindowObject *root;
1473   GdkWindowImplQuartz *root_impl;
1474
1475   root = GDK_WINDOW_OBJECT (_gdk_root);
1476   root_impl = GDK_WINDOW_IMPL_QUARTZ (root->impl);
1477
1478   g_list_free (root_impl->sorted_children);
1479   root_impl->sorted_children = NULL;
1480 }
1481
1482 static void
1483 gdk_window_quartz_raise (GdkWindow *window)
1484 {
1485   if (GDK_WINDOW_DESTROYED (window))
1486     return;
1487
1488   if (WINDOW_IS_TOPLEVEL (window))
1489     {
1490       GdkWindowImplQuartz *impl;
1491
1492       impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
1493       [impl->toplevel orderFront:impl->toplevel];
1494
1495       clear_toplevel_order ();
1496     }
1497   else
1498     {
1499       GdkWindowObject *parent = GDK_WINDOW_OBJECT (window)->parent;
1500
1501       if (parent)
1502         {
1503           GdkWindowImplQuartz *impl;
1504
1505           impl = (GdkWindowImplQuartz *)parent->impl;
1506
1507           impl->sorted_children = g_list_remove (impl->sorted_children, window);
1508           impl->sorted_children = g_list_prepend (impl->sorted_children, window);
1509         }
1510     }
1511 }
1512
1513 static void
1514 gdk_window_quartz_lower (GdkWindow *window)
1515 {
1516   if (GDK_WINDOW_DESTROYED (window))
1517     return;
1518
1519   if (WINDOW_IS_TOPLEVEL (window))
1520     {
1521       GdkWindowImplQuartz *impl;
1522
1523       impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
1524       [impl->toplevel orderBack:impl->toplevel];
1525
1526       clear_toplevel_order ();
1527     }
1528   else
1529     {
1530       GdkWindowObject *parent = GDK_WINDOW_OBJECT (window)->parent;
1531
1532       if (parent)
1533         {
1534           GdkWindowImplQuartz *impl;
1535
1536           impl = (GdkWindowImplQuartz *)parent->impl;
1537
1538           impl->sorted_children = g_list_remove (impl->sorted_children, window);
1539           impl->sorted_children = g_list_append (impl->sorted_children, window);
1540         }
1541     }
1542 }
1543
1544 static void
1545 gdk_window_quartz_set_background (GdkWindow      *window,
1546                                   const GdkColor *color)
1547 {
1548   /* FIXME: We could theoretically set the background color for toplevels
1549    * here. (Currently we draw the background before emitting expose events)
1550    */
1551 }
1552
1553 static void
1554 gdk_window_quartz_set_back_pixmap (GdkWindow *window,
1555                                    GdkPixmap *pixmap)
1556 {
1557   /* FIXME: Could theoretically set some background image here. (Currently
1558    * the back pixmap is drawn before emitting expose events.
1559    */
1560 }
1561
1562 static void
1563 gdk_window_quartz_set_cursor (GdkWindow *window,
1564                               GdkCursor *cursor)
1565 {
1566   GdkCursorPrivate *cursor_private;
1567   NSCursor *nscursor;
1568
1569   cursor_private = (GdkCursorPrivate *)cursor;
1570
1571   if (GDK_WINDOW_DESTROYED (window))
1572     return;
1573
1574   if (!cursor)
1575     nscursor = [NSCursor arrowCursor];
1576   else 
1577     nscursor = cursor_private->nscursor;
1578
1579   [nscursor set];
1580 }
1581
1582 static void
1583 gdk_window_quartz_get_geometry (GdkWindow *window,
1584                                 gint      *x,
1585                                 gint      *y,
1586                                 gint      *width,
1587                                 gint      *height,
1588                                 gint      *depth)
1589 {
1590   GdkWindowImplQuartz *impl;
1591   GdkWindowObject *private;
1592   NSRect ns_rect;
1593
1594   if (GDK_WINDOW_DESTROYED (window))
1595     return;
1596
1597   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
1598   private = GDK_WINDOW_OBJECT (window);
1599   if (window == _gdk_root)
1600     {
1601       if (x) 
1602         *x = 0;
1603       if (y) 
1604         *y = 0;
1605
1606       if (width) 
1607         *width = private->width;
1608       if (height)
1609         *height = private->height;
1610     }
1611   else if (WINDOW_IS_TOPLEVEL (window))
1612     {
1613       ns_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
1614
1615       /* This doesn't work exactly as in X. There doesn't seem to be a
1616        * way to get the coords relative to the parent window (usually
1617        * the window frame), but that seems useless except for
1618        * borderless windows where it's relative to the root window. So
1619        * we return (0, 0) (should be something like (0, 22)) for
1620        * windows with borders and the root relative coordinates
1621        * otherwise.
1622        */
1623       if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
1624         {
1625           if (x)
1626             *x = ns_rect.origin.x;
1627           if (y)
1628             *y = _gdk_quartz_window_get_inverted_screen_y (ns_rect.origin.y + ns_rect.size.height);
1629         }
1630       else 
1631         {
1632           if (x)
1633             *x = 0;
1634           if (y)
1635             *y = 0;
1636         }
1637
1638       if (width)
1639         *width = ns_rect.size.width;
1640       if (height)
1641         *height = ns_rect.size.height;
1642     }
1643   else
1644     {
1645       ns_rect = [impl->view frame];
1646       
1647       if (x)
1648         *x = ns_rect.origin.x;
1649       if (y)
1650         *y = ns_rect.origin.y;
1651       if (width)
1652         *width  = ns_rect.size.width;
1653       if (height)
1654         *height = ns_rect.size.height;
1655     }
1656     
1657   if (depth)
1658       *depth = gdk_drawable_get_depth (window);
1659 }
1660
1661 static gint
1662 gdk_window_quartz_get_root_coords (GdkWindow *window,
1663                                    gint       x,
1664                                    gint       y,
1665                                    gint      *root_x,
1666                                    gint      *root_y)
1667 {
1668   GdkWindowObject *private;
1669   int tmp_x = 0, tmp_y = 0;
1670   GdkWindow *toplevel;
1671   NSRect content_rect;
1672   GdkWindowImplQuartz *impl;
1673
1674   if (GDK_WINDOW_DESTROYED (window)) 
1675     {
1676       if (root_x)
1677         *root_x = 0;
1678       if (root_y)
1679         *root_y = 0;
1680       
1681       return 0;
1682     }
1683
1684   if (window == _gdk_root)
1685     {
1686       if (root_x)
1687         *root_x = x;
1688       if (root_y)
1689         *root_y = y;
1690
1691       return 1;
1692     }
1693   
1694   private = GDK_WINDOW_OBJECT (window);
1695
1696   toplevel = gdk_window_get_toplevel (window);
1697   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
1698
1699   content_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
1700
1701   tmp_x = x + content_rect.origin.x;
1702   tmp_y = y + _gdk_quartz_window_get_inverted_screen_y (content_rect.origin.y + content_rect.size.height);
1703
1704   while (private != GDK_WINDOW_OBJECT (toplevel))
1705     {
1706       if (_gdk_window_has_impl ((GdkWindow *)private))
1707         {
1708           tmp_x += private->x;
1709           tmp_y += private->y;
1710         }
1711
1712       private = private->parent;
1713     }
1714
1715   if (root_x)
1716     *root_x = tmp_x;
1717   if (root_y)
1718     *root_y = tmp_y;
1719
1720   return TRUE;
1721 }
1722
1723 static gboolean
1724 gdk_window_quartz_get_deskrelative_origin (GdkWindow *window,
1725                                            gint      *x,
1726                                            gint      *y)
1727 {
1728   return gdk_window_get_origin (window, x, y);
1729 }
1730
1731 void
1732 gdk_window_get_root_origin (GdkWindow *window,
1733                             gint      *x,
1734                             gint      *y)
1735 {
1736   GdkRectangle rect;
1737
1738   rect.x = 0;
1739   rect.y = 0;
1740   
1741   gdk_window_get_frame_extents (window, &rect);
1742
1743   if (x)
1744     *x = rect.x;
1745
1746   if (y)
1747     *y = rect.y;
1748 }
1749
1750 /* Returns coordinates relative to the passed in window. */
1751 static GdkWindow *
1752 gdk_window_quartz_get_pointer_helper (GdkWindow       *window,
1753                                       gint            *x,
1754                                       gint            *y,
1755                                       GdkModifierType *mask)
1756 {
1757   GdkWindowObject *toplevel;
1758   GdkWindowObject *private;
1759   NSPoint point;
1760   gint x_tmp, y_tmp;
1761   GdkWindow *found_window;
1762
1763   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
1764
1765   if (GDK_WINDOW_DESTROYED (window))
1766     {
1767       *x = 0;
1768       *y = 0;
1769       *mask = 0;
1770       return NULL;
1771     }
1772   
1773   toplevel = GDK_WINDOW_OBJECT (gdk_window_get_toplevel (window));
1774
1775   *mask = _gdk_quartz_events_get_current_event_mask ();
1776
1777   /* Get the y coordinate, needs to be flipped. */
1778   if (window == _gdk_root)
1779     {
1780       point = [NSEvent mouseLocation];
1781       x_tmp = point.x;
1782       y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
1783     }
1784   else
1785     {
1786       GdkWindowImplQuartz *impl;
1787       NSWindow *nswindow;
1788
1789       impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
1790       private = GDK_WINDOW_OBJECT (toplevel);
1791       nswindow = impl->toplevel;
1792
1793       point = [nswindow mouseLocationOutsideOfEventStream];
1794
1795       x_tmp = point.x;
1796       y_tmp = private->height - point.y;
1797
1798       window = (GdkWindow *)toplevel;
1799     }
1800
1801   found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp);
1802
1803   /* We never return the root window. */
1804   if (found_window == _gdk_root)
1805     found_window = NULL;
1806
1807   *x = x_tmp;
1808   *y = y_tmp;
1809
1810   return found_window;
1811 }
1812
1813 static gboolean
1814 gdk_window_quartz_get_pointer (GdkWindow       *window,
1815                                gint            *x,
1816                                gint            *y,
1817                                GdkModifierType *mask)
1818 {
1819   return gdk_window_quartz_get_pointer_helper (window, x, y, mask) != NULL;
1820 }
1821
1822 /* Returns coordinates relative to the root. */
1823 void
1824 _gdk_windowing_get_pointer (GdkDisplay       *display,
1825                             GdkScreen       **screen,
1826                             gint             *x,
1827                             gint             *y,
1828                             GdkModifierType  *mask)
1829 {
1830   g_return_if_fail (display == _gdk_display);
1831   
1832   *screen = _gdk_screen;
1833   gdk_window_quartz_get_pointer_helper (_gdk_root, x, y, mask);
1834 }
1835
1836 void
1837 gdk_display_warp_pointer (GdkDisplay *display,
1838                           GdkScreen  *screen,
1839                           gint        x,
1840                           gint        y)
1841 {
1842   CGDisplayMoveCursorToPoint (CGMainDisplayID (), CGPointMake (x, y));
1843 }
1844
1845 /* Returns coordinates relative to the found window. */
1846 GdkWindow *
1847 _gdk_windowing_window_at_pointer (GdkDisplay      *display,
1848                                   gint            *win_x,
1849                                   gint            *win_y,
1850                                   GdkModifierType *mask)
1851 {
1852   GdkWindow *found_window;
1853   gint x, y;
1854   GdkModifierType tmp_mask = 0;
1855
1856   found_window = gdk_window_quartz_get_pointer_helper (_gdk_root,
1857                                                        &x, &y,
1858                                                        &tmp_mask);
1859   if (found_window)
1860     {
1861       GdkWindowObject *private;
1862
1863       /* The coordinates returned above are relative the root, we want
1864        * coordinates relative the window here. 
1865        */
1866       private = GDK_WINDOW_OBJECT (found_window);
1867       while (private != GDK_WINDOW_OBJECT (_gdk_root))
1868         {
1869           x -= private->x;
1870           y -= private->y;
1871           
1872           private = private->parent;
1873         }
1874
1875       *win_x = x;
1876       *win_y = y;
1877     }
1878   else
1879     {
1880       /* Mimic the X backend here, -1,-1 for unknown windows. */
1881       *win_x = -1;
1882       *win_y = -1;
1883     }
1884
1885   if (mask)
1886     *mask = tmp_mask;
1887
1888   return found_window;
1889 }
1890
1891 static GdkEventMask  
1892 gdk_window_quartz_get_events (GdkWindow *window)
1893 {
1894   if (GDK_WINDOW_DESTROYED (window))
1895     return 0;
1896   else
1897     return GDK_WINDOW_OBJECT (window)->event_mask;
1898 }
1899
1900 static void
1901 gdk_window_quartz_set_events (GdkWindow       *window,
1902                               GdkEventMask     event_mask)
1903 {
1904   /* The mask is set in the common code. */
1905 }
1906
1907 void
1908 gdk_window_set_urgency_hint (GdkWindow *window,
1909                              gboolean   urgent)
1910 {
1911   if (GDK_WINDOW_DESTROYED (window) ||
1912       !WINDOW_IS_TOPLEVEL (window))
1913     return;
1914
1915   /* FIXME: Implement */
1916 }
1917
1918 void 
1919 gdk_window_set_geometry_hints (GdkWindow         *window,
1920                                const GdkGeometry *geometry,
1921                                GdkWindowHints     geom_mask)
1922 {
1923   GdkWindowImplQuartz *impl;
1924
1925   g_return_if_fail (geometry != NULL);
1926
1927   if (GDK_WINDOW_DESTROYED (window) ||
1928       !WINDOW_IS_TOPLEVEL (window))
1929     return;
1930   
1931   impl = GDK_WINDOW_IMPL_QUARTZ (((GdkWindowObject *) window)->impl);
1932   if (!impl->toplevel)
1933     return;
1934
1935   if (geom_mask & GDK_HINT_POS)
1936     {
1937       /* FIXME: Implement */
1938     }
1939
1940   if (geom_mask & GDK_HINT_USER_POS)
1941     {
1942       /* FIXME: Implement */
1943     }
1944
1945   if (geom_mask & GDK_HINT_USER_SIZE)
1946     {
1947       /* FIXME: Implement */
1948     }
1949   
1950   if (geom_mask & GDK_HINT_MIN_SIZE)
1951     {
1952       NSSize size;
1953
1954       size.width = geometry->min_width;
1955       size.height = geometry->min_height;
1956
1957       [impl->toplevel setContentMinSize:size];
1958     }
1959   
1960   if (geom_mask & GDK_HINT_MAX_SIZE)
1961     {
1962       NSSize size;
1963
1964       size.width = geometry->max_width;
1965       size.height = geometry->max_height;
1966
1967       [impl->toplevel setContentMaxSize:size];
1968     }
1969   
1970   if (geom_mask & GDK_HINT_BASE_SIZE)
1971     {
1972       /* FIXME: Implement */
1973     }
1974   
1975   if (geom_mask & GDK_HINT_RESIZE_INC)
1976     {
1977       NSSize size;
1978
1979       size.width = geometry->width_inc;
1980       size.height = geometry->height_inc;
1981
1982       [impl->toplevel setContentResizeIncrements:size];
1983     }
1984   
1985   if (geom_mask & GDK_HINT_ASPECT)
1986     {
1987       /* FIXME: Implement */
1988     }
1989
1990   if (geom_mask & GDK_HINT_WIN_GRAVITY)
1991     {
1992       /* FIXME: Implement */
1993     }
1994 }
1995
1996 void
1997 gdk_window_set_title (GdkWindow   *window,
1998                       const gchar *title)
1999 {
2000   GdkWindowImplQuartz *impl;
2001
2002   g_return_if_fail (title != NULL);
2003
2004   if (GDK_WINDOW_DESTROYED (window) ||
2005       WINDOW_IS_TOPLEVEL (window))
2006     return;
2007
2008   impl = GDK_WINDOW_IMPL_QUARTZ (((GdkWindowObject *)window)->impl);
2009
2010   if (impl->toplevel)
2011     {
2012       GDK_QUARTZ_ALLOC_POOL;
2013       [impl->toplevel setTitle:[NSString stringWithUTF8String:title]];
2014       GDK_QUARTZ_RELEASE_POOL;
2015     }
2016 }
2017
2018 void          
2019 gdk_window_set_role (GdkWindow   *window,
2020                      const gchar *role)
2021 {
2022   if (GDK_WINDOW_DESTROYED (window) ||
2023       WINDOW_IS_TOPLEVEL (window))
2024     return;
2025
2026   /* FIXME: Implement */
2027 }
2028
2029 void
2030 gdk_window_set_transient_for (GdkWindow *window, 
2031                               GdkWindow *parent)
2032 {
2033   GdkWindowImplQuartz *window_impl;
2034   GdkWindowImplQuartz *parent_impl;
2035
2036   if (!GDK_WINDOW_DESTROYED (window) && !GDK_WINDOW_DESTROYED (parent) &&
2037       WINDOW_IS_TOPLEVEL (window))
2038     return;
2039
2040   window_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
2041   if (!window_impl->toplevel)
2042     return;
2043
2044   GDK_QUARTZ_ALLOC_POOL;
2045
2046   if (window_impl->transient_for)
2047     {
2048       _gdk_quartz_window_detach_from_parent (window);
2049
2050       g_object_unref (window_impl->transient_for);
2051       window_impl->transient_for = NULL;
2052     }
2053
2054   parent_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (parent)->impl);
2055   if (parent_impl->toplevel)
2056     {
2057       /* We save the parent because it needs to be unset/reset when
2058        * hiding and showing the window. 
2059        */
2060
2061       /* We don't set transients for tooltips, they are already
2062        * handled by the window level being the top one. If we do, then
2063        * the parent window will be brought to the top just because the
2064        * tooltip is, which is not what we want.
2065        */
2066       if (gdk_window_get_type_hint (window) != GDK_WINDOW_TYPE_HINT_TOOLTIP)
2067         {
2068           window_impl->transient_for = g_object_ref (parent);
2069
2070           /* We only add the window if it is shown, otherwise it will
2071            * be shown unconditionally here. If it is not shown, the
2072            * window will be added in show() instead.
2073            */
2074           if (!(GDK_WINDOW_OBJECT (window)->state & GDK_WINDOW_STATE_WITHDRAWN))
2075             _gdk_quartz_window_attach_to_parent (window);
2076         }
2077     }
2078   
2079   GDK_QUARTZ_RELEASE_POOL;
2080 }
2081
2082 static void
2083 gdk_window_quartz_shape_combine_region (GdkWindow       *window,
2084                                         const GdkRegion *shape,
2085                                         gint             x,
2086                                         gint             y)
2087 {
2088   /* FIXME: Implement */
2089 }
2090
2091 static void
2092 gdk_window_quartz_input_shape_combine_region (GdkWindow       *window,
2093                                               const GdkRegion *shape_region,
2094                                               gint             offset_x,
2095                                               gint             offset_y)
2096 {
2097   /* FIXME: Implement */
2098 }
2099
2100 void
2101 gdk_window_set_override_redirect (GdkWindow *window,
2102                                   gboolean override_redirect)
2103 {
2104   /* FIXME: Implement */
2105 }
2106
2107 void
2108 gdk_window_set_accept_focus (GdkWindow *window,
2109                              gboolean accept_focus)
2110 {
2111   GdkWindowObject *private;
2112
2113   private = (GdkWindowObject *)window;  
2114
2115   private->accept_focus = accept_focus != FALSE;
2116 }
2117
2118 static gboolean 
2119 gdk_window_quartz_set_static_gravities (GdkWindow *window,
2120                                         gboolean   use_static)
2121 {
2122   if (GDK_WINDOW_DESTROYED (window) ||
2123       !WINDOW_IS_TOPLEVEL (window))
2124     return FALSE;
2125
2126   /* FIXME: Implement */
2127   return FALSE;
2128 }
2129
2130 void
2131 gdk_window_set_focus_on_map (GdkWindow *window,
2132                              gboolean focus_on_map)
2133 {
2134   GdkWindowObject *private;
2135
2136   private = (GdkWindowObject *)window;  
2137   
2138   private->focus_on_map = focus_on_map != FALSE;
2139 }
2140
2141 void          
2142 gdk_window_set_icon (GdkWindow *window, 
2143                      GdkWindow *icon_window,
2144                      GdkPixmap *pixmap,
2145                      GdkBitmap *mask)
2146 {
2147   /* FIXME: Implement */
2148 }
2149
2150 void          
2151 gdk_window_set_icon_name (GdkWindow   *window, 
2152                           const gchar *name)
2153 {
2154   /* FIXME: Implement */
2155 }
2156
2157 void
2158 gdk_window_focus (GdkWindow *window,
2159                   guint32    timestamp)
2160 {
2161   GdkWindowObject *private;
2162   GdkWindowImplQuartz *impl;
2163         
2164   private = (GdkWindowObject*) window;
2165   impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
2166
2167   if (GDK_WINDOW_DESTROYED (window) ||
2168       !WINDOW_IS_TOPLEVEL (window))
2169     return;
2170
2171   if (private->accept_focus && private->window_type != GDK_WINDOW_TEMP)
2172     {
2173       GDK_QUARTZ_ALLOC_POOL;
2174       [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
2175       clear_toplevel_order ();
2176       GDK_QUARTZ_RELEASE_POOL;
2177     }
2178 }
2179
2180 void
2181 gdk_window_set_hints (GdkWindow *window,
2182                       gint       x,
2183                       gint       y,
2184                       gint       min_width,
2185                       gint       min_height,
2186                       gint       max_width,
2187                       gint       max_height,
2188                       gint       flags)
2189 {
2190   /* FIXME: Implement */
2191 }
2192
2193 static
2194 gint window_type_hint_to_level (GdkWindowTypeHint hint)
2195 {
2196   switch (hint)
2197     {
2198     case GDK_WINDOW_TYPE_HINT_DOCK:
2199     case GDK_WINDOW_TYPE_HINT_UTILITY:
2200       return NSFloatingWindowLevel;
2201
2202     case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
2203     case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
2204       return NSTornOffMenuWindowLevel;
2205
2206     case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
2207     case GDK_WINDOW_TYPE_HINT_TOOLTIP:
2208       return NSStatusWindowLevel;
2209
2210     case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2211     case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
2212     case GDK_WINDOW_TYPE_HINT_COMBO:
2213     case GDK_WINDOW_TYPE_HINT_DND:
2214       return NSPopUpMenuWindowLevel;
2215
2216     case GDK_WINDOW_TYPE_HINT_NORMAL:  /* Normal toplevel window */
2217     case GDK_WINDOW_TYPE_HINT_DIALOG:  /* Dialog window */
2218     case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
2219     case GDK_WINDOW_TYPE_HINT_DESKTOP: /* N/A */
2220       break;
2221
2222     default:
2223       break;
2224     }
2225
2226   return NSNormalWindowLevel;
2227 }
2228
2229 static gboolean 
2230 window_type_hint_to_shadow (GdkWindowTypeHint hint)
2231 {
2232   switch (hint)
2233     {
2234     case GDK_WINDOW_TYPE_HINT_NORMAL:  /* Normal toplevel window */
2235     case GDK_WINDOW_TYPE_HINT_DIALOG:  /* Dialog window */
2236     case GDK_WINDOW_TYPE_HINT_DOCK:
2237     case GDK_WINDOW_TYPE_HINT_UTILITY:
2238     case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
2239     case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
2240     case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
2241     case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
2242     case GDK_WINDOW_TYPE_HINT_COMBO:
2243     case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
2244     case GDK_WINDOW_TYPE_HINT_TOOLTIP:
2245       return TRUE;
2246
2247     case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
2248     case GDK_WINDOW_TYPE_HINT_DESKTOP: /* N/A */
2249     case GDK_WINDOW_TYPE_HINT_DND:
2250       break;
2251
2252     default:
2253       break;
2254     }
2255
2256   return FALSE;
2257 }
2258
2259
2260 void
2261 gdk_window_set_type_hint (GdkWindow        *window,
2262                           GdkWindowTypeHint hint)
2263 {
2264   GdkWindowImplQuartz *impl;
2265   
2266   if (GDK_WINDOW_DESTROYED (window) ||
2267       !WINDOW_IS_TOPLEVEL (window))
2268     return;
2269
2270   impl = GDK_WINDOW_IMPL_QUARTZ (((GdkWindowObject *) window)->impl);
2271
2272   impl->type_hint = hint;
2273
2274   /* Match the documentation, only do something if we're not mapped yet. */
2275   if (GDK_WINDOW_IS_MAPPED (window))
2276     return;
2277
2278   [impl->toplevel setHasShadow: window_type_hint_to_shadow (hint)];
2279   [impl->toplevel setLevel: window_type_hint_to_level (hint)];
2280 }
2281
2282 GdkWindowTypeHint
2283 gdk_window_get_type_hint (GdkWindow *window)
2284 {
2285   if (GDK_WINDOW_DESTROYED (window) ||
2286       !WINDOW_IS_TOPLEVEL (window))
2287     return GDK_WINDOW_TYPE_HINT_NORMAL;
2288   
2289   return GDK_WINDOW_IMPL_QUARTZ (((GdkWindowObject *) window)->impl)->type_hint;
2290 }
2291
2292 void
2293 gdk_window_set_modal_hint (GdkWindow *window,
2294                            gboolean   modal)
2295 {
2296   if (GDK_WINDOW_DESTROYED (window) ||
2297       !WINDOW_IS_TOPLEVEL (window))
2298     return;
2299
2300   /* FIXME: Implement */
2301 }
2302
2303 void
2304 gdk_window_set_skip_taskbar_hint (GdkWindow *window,
2305                                   gboolean   skips_taskbar)
2306 {
2307   if (GDK_WINDOW_DESTROYED (window) ||
2308       !WINDOW_IS_TOPLEVEL (window))
2309     return;
2310
2311   /* FIXME: Implement */
2312 }
2313
2314 void
2315 gdk_window_set_skip_pager_hint (GdkWindow *window,
2316                                 gboolean   skips_pager)
2317 {
2318   if (GDK_WINDOW_DESTROYED (window) ||
2319       !WINDOW_IS_TOPLEVEL (window))
2320     return;
2321
2322   /* FIXME: Implement */
2323 }
2324
2325 void
2326 gdk_window_begin_resize_drag (GdkWindow     *window,
2327                               GdkWindowEdge  edge,
2328                               gint           button,
2329                               gint           root_x,
2330                               gint           root_y,
2331                               guint32        timestamp)
2332 {
2333   GdkWindowObject *private;
2334   GdkWindowImplQuartz *impl;
2335
2336   g_return_if_fail (GDK_IS_WINDOW (window));
2337
2338   if (edge != GDK_WINDOW_EDGE_SOUTH_EAST)
2339     {
2340       g_warning ("Resizing is only implemented for GDK_WINDOW_EDGE_SOUTH_EAST on Mac OS");
2341       return;
2342     }
2343
2344   if (GDK_WINDOW_DESTROYED (window))
2345     return;
2346
2347   private = GDK_WINDOW_OBJECT (window);
2348   impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
2349
2350   if (!impl->toplevel)
2351     {
2352       g_warning ("Can't call gdk_window_begin_resize_drag on non-toplevel window");
2353       return;
2354     }
2355
2356   [(GdkQuartzWindow *)impl->toplevel beginManualResize];
2357 }
2358
2359 void
2360 gdk_window_begin_move_drag (GdkWindow *window,
2361                             gint       button,
2362                             gint       root_x,
2363                             gint       root_y,
2364                             guint32    timestamp)
2365 {
2366   GdkWindowObject *private;
2367   GdkWindowImplQuartz *impl;
2368
2369   if (GDK_WINDOW_DESTROYED (window) ||
2370       !WINDOW_IS_TOPLEVEL (window))
2371     return;
2372
2373   private = GDK_WINDOW_OBJECT (window);
2374   impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
2375
2376   if (!impl->toplevel)
2377     {
2378       g_warning ("Can't call gdk_window_begin_move_drag on non-toplevel window");
2379       return;
2380     }
2381
2382   [(GdkQuartzWindow *)impl->toplevel beginManualMove];
2383 }
2384
2385 void
2386 gdk_window_set_icon_list (GdkWindow *window,
2387                           GList     *pixbufs)
2388 {
2389   /* FIXME: Implement */
2390 }
2391
2392 void
2393 gdk_window_get_frame_extents (GdkWindow    *window,
2394                               GdkRectangle *rect)
2395 {
2396   GdkWindowObject *private;
2397   GdkWindow *toplevel;
2398   GdkWindowImplQuartz *impl;
2399   NSRect ns_rect;
2400
2401   g_return_if_fail (rect != NULL);
2402
2403   private = GDK_WINDOW_OBJECT (window);
2404
2405   rect->x = 0;
2406   rect->y = 0;
2407   rect->width = 1;
2408   rect->height = 1;
2409   
2410   toplevel = gdk_window_get_toplevel (window);
2411   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
2412
2413   ns_rect = [impl->toplevel frame];
2414
2415   rect->x = ns_rect.origin.x;
2416   rect->y = _gdk_quartz_window_get_inverted_screen_y (ns_rect.origin.y + ns_rect.size.height);
2417   rect->width = ns_rect.size.width;
2418   rect->height = ns_rect.size.height;
2419 }
2420
2421 void
2422 gdk_window_set_decorations (GdkWindow       *window,
2423                             GdkWMDecoration  decorations)
2424 {
2425   GdkWindowImplQuartz *impl;
2426   int old_mask, new_mask;
2427   NSView *old_view;
2428
2429   if (GDK_WINDOW_DESTROYED (window) ||
2430       !WINDOW_IS_TOPLEVEL (window))
2431     return;
2432
2433   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
2434
2435   if (decorations == 0 || GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP ||
2436       impl->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN )
2437     {
2438       new_mask = NSBorderlessWindowMask;
2439     }
2440   else
2441     {
2442       /* FIXME: Honor other GDK_DECOR_* flags. */
2443       new_mask = (NSTitledWindowMask | NSClosableWindowMask |
2444                     NSMiniaturizableWindowMask | NSResizableWindowMask);
2445     }
2446
2447   GDK_QUARTZ_ALLOC_POOL;
2448
2449   old_mask = [impl->toplevel styleMask];
2450
2451   /* Note, there doesn't seem to be a way to change this without
2452    * recreating the toplevel. There might be bad side-effects of doing
2453    * that, but it seems alright.
2454    */
2455   if (old_mask != new_mask)
2456     {
2457       NSRect rect;
2458
2459       old_view = [impl->toplevel contentView];
2460
2461       rect = [impl->toplevel frame];
2462
2463       /* Properly update the size of the window when the titlebar is
2464        * added or removed.
2465        */
2466       if (old_mask == NSBorderlessWindowMask &&
2467           new_mask != NSBorderlessWindowMask)
2468         {
2469           rect = [NSWindow frameRectForContentRect:rect styleMask:new_mask];
2470
2471         }
2472       else if (old_mask != NSBorderlessWindowMask &&
2473                new_mask == NSBorderlessWindowMask)
2474         {
2475           rect = [NSWindow contentRectForFrameRect:rect styleMask:old_mask];
2476         }
2477
2478       impl->toplevel = [impl->toplevel initWithContentRect:rect
2479                                                  styleMask:new_mask
2480                                                    backing:NSBackingStoreBuffered
2481                                                      defer:NO];
2482
2483       [impl->toplevel setHasShadow: window_type_hint_to_shadow (impl->type_hint)];
2484       [impl->toplevel setLevel: window_type_hint_to_level (impl->type_hint)];
2485
2486       [impl->toplevel setContentView:old_view];
2487       [impl->toplevel setFrame:rect display:YES];
2488
2489       /* Invalidate the window shadow for non-opaque views that have shadow
2490        * enabled, to get the shadow shape updated.
2491        */
2492       if (![old_view isOpaque] && [impl->toplevel hasShadow])
2493         [(GdkQuartzView*)old_view setNeedsInvalidateShadow:YES];
2494     }
2495
2496   GDK_QUARTZ_RELEASE_POOL;
2497 }
2498
2499 gboolean
2500 gdk_window_get_decorations (GdkWindow       *window,
2501                             GdkWMDecoration *decorations)
2502 {
2503   GdkWindowImplQuartz *impl;
2504
2505   if (GDK_WINDOW_DESTROYED (window) ||
2506       !WINDOW_IS_TOPLEVEL (window))
2507     return FALSE;
2508
2509   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
2510
2511   if (decorations)
2512     {
2513       /* Borderless is 0, so we can't check it as a bit being set. */
2514       if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
2515         {
2516           *decorations = 0;
2517         }
2518       else
2519         {
2520           /* FIXME: Honor the other GDK_DECOR_* flags. */
2521           *decorations = GDK_DECOR_ALL;
2522         }
2523     }
2524
2525   return TRUE;
2526 }
2527
2528 void
2529 gdk_window_set_functions (GdkWindow    *window,
2530                           GdkWMFunction functions)
2531 {
2532   g_return_if_fail (GDK_IS_WINDOW (window));
2533
2534   /* FIXME: Implement */
2535 }
2536
2537 gboolean
2538 _gdk_windowing_window_queue_antiexpose (GdkWindow  *window,
2539                                         GdkRegion  *area)
2540 {
2541   return FALSE;
2542 }
2543
2544 void
2545 gdk_window_stick (GdkWindow *window)
2546 {
2547   if (GDK_WINDOW_DESTROYED (window) ||
2548       !WINDOW_IS_TOPLEVEL (window))
2549     return;
2550 }
2551
2552 void
2553 gdk_window_unstick (GdkWindow *window)
2554 {
2555   if (GDK_WINDOW_DESTROYED (window) ||
2556       !WINDOW_IS_TOPLEVEL (window))
2557     return;
2558 }
2559
2560 void
2561 gdk_window_maximize (GdkWindow *window)
2562 {
2563   GdkWindowImplQuartz *impl;
2564
2565   if (GDK_WINDOW_DESTROYED (window) ||
2566       !WINDOW_IS_TOPLEVEL (window))
2567     return;
2568
2569   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
2570
2571   if (GDK_WINDOW_IS_MAPPED (window))
2572     {
2573       GDK_QUARTZ_ALLOC_POOL;
2574
2575       if (impl->toplevel && ![impl->toplevel isZoomed])
2576         [impl->toplevel zoom:nil];
2577
2578       GDK_QUARTZ_RELEASE_POOL;
2579     }
2580   else
2581     {
2582       gdk_synthesize_window_state (window,
2583                                    0,
2584                                    GDK_WINDOW_STATE_MAXIMIZED);
2585     }
2586 }
2587
2588 void
2589 gdk_window_unmaximize (GdkWindow *window)
2590 {
2591   GdkWindowImplQuartz *impl;
2592
2593   if (GDK_WINDOW_DESTROYED (window) ||
2594       !WINDOW_IS_TOPLEVEL (window))
2595     return;
2596
2597   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
2598
2599   if (GDK_WINDOW_IS_MAPPED (window))
2600     {
2601       GDK_QUARTZ_ALLOC_POOL;
2602
2603       if (impl->toplevel && [impl->toplevel isZoomed])
2604         [impl->toplevel zoom:nil];
2605
2606       GDK_QUARTZ_RELEASE_POOL;
2607     }
2608   else
2609     {
2610       gdk_synthesize_window_state (window,
2611                                    GDK_WINDOW_STATE_MAXIMIZED,
2612                                    0);
2613     }
2614 }
2615
2616 void
2617 gdk_window_iconify (GdkWindow *window)
2618 {
2619   GdkWindowImplQuartz *impl;
2620
2621   if (GDK_WINDOW_DESTROYED (window) ||
2622       !WINDOW_IS_TOPLEVEL (window))
2623     return;
2624
2625   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
2626
2627   if (GDK_WINDOW_IS_MAPPED (window))
2628     {
2629       GDK_QUARTZ_ALLOC_POOL;
2630
2631       if (impl->toplevel)
2632         [impl->toplevel miniaturize:nil];
2633
2634       GDK_QUARTZ_RELEASE_POOL;
2635     }
2636   else
2637     {
2638       gdk_synthesize_window_state (window,
2639                                    0,
2640                                    GDK_WINDOW_STATE_ICONIFIED);
2641     }
2642 }
2643
2644 void
2645 gdk_window_deiconify (GdkWindow *window)
2646 {
2647   GdkWindowImplQuartz *impl;
2648
2649   if (GDK_WINDOW_DESTROYED (window) ||
2650       !WINDOW_IS_TOPLEVEL (window))
2651     return;
2652
2653   impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
2654
2655   if (GDK_WINDOW_IS_MAPPED (window))
2656     {
2657       GDK_QUARTZ_ALLOC_POOL;
2658
2659       if (impl->toplevel)
2660         [impl->toplevel deminiaturize:nil];
2661
2662       GDK_QUARTZ_RELEASE_POOL;
2663     }
2664   else
2665     {
2666       gdk_synthesize_window_state (window,
2667                                    GDK_WINDOW_STATE_ICONIFIED,
2668                                    0);
2669     }
2670 }
2671
2672 static FullscreenSavedGeometry *
2673 get_fullscreen_geometry (GdkWindow *window)
2674 {
2675   return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA);
2676 }
2677
2678 void
2679 gdk_window_fullscreen (GdkWindow *window)
2680 {
2681   FullscreenSavedGeometry *geometry;
2682   GdkWindowObject *private = (GdkWindowObject *) window;
2683   NSRect frame;
2684
2685   if (GDK_WINDOW_DESTROYED (window) ||
2686       !WINDOW_IS_TOPLEVEL (window))
2687     return;
2688
2689   geometry = get_fullscreen_geometry (window);
2690   if (!geometry)
2691     {
2692       geometry = g_new (FullscreenSavedGeometry, 1);
2693
2694       geometry->x = private->x;
2695       geometry->y = private->y;
2696       geometry->width = private->width;
2697       geometry->height = private->height;
2698
2699       if (!gdk_window_get_decorations (window, &geometry->decor))
2700         geometry->decor = GDK_DECOR_ALL;
2701
2702       g_object_set_data_full (G_OBJECT (window),
2703                               FULLSCREEN_DATA, geometry, 
2704                               g_free);
2705
2706       gdk_window_set_decorations (window, 0);
2707
2708       frame = [[NSScreen mainScreen] frame];
2709       move_resize_window_internal (window,
2710                                    0, 0, 
2711                                    frame.size.width, frame.size.height);
2712     }
2713
2714   SetSystemUIMode (kUIModeAllHidden, kUIOptionAutoShowMenuBar);
2715
2716   gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
2717 }
2718
2719 void
2720 gdk_window_unfullscreen (GdkWindow *window)
2721 {
2722   FullscreenSavedGeometry *geometry;
2723
2724   if (GDK_WINDOW_DESTROYED (window) ||
2725       !WINDOW_IS_TOPLEVEL (window))
2726     return;
2727
2728   geometry = get_fullscreen_geometry (window);
2729   if (geometry)
2730     {
2731       SetSystemUIMode (kUIModeNormal, 0);
2732
2733       move_resize_window_internal (window,
2734                                    geometry->x,
2735                                    geometry->y,
2736                                    geometry->width,
2737                                    geometry->height);
2738       
2739       gdk_window_set_decorations (window, geometry->decor);
2740
2741       g_object_set_data (G_OBJECT (window), FULLSCREEN_DATA, NULL);
2742
2743       gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
2744     }
2745 }
2746
2747 void
2748 gdk_window_set_keep_above (GdkWindow *window, gboolean setting)
2749 {
2750   GdkWindowObject *private = (GdkWindowObject *) window;
2751   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
2752   gint level;
2753
2754   g_return_if_fail (GDK_IS_WINDOW (window));
2755
2756   if (GDK_WINDOW_DESTROYED (window) ||
2757       !WINDOW_IS_TOPLEVEL (window))
2758     return;
2759
2760   level = window_type_hint_to_level (gdk_window_get_type_hint (window));
2761   
2762   /* Adjust normal window level by one if necessary. */
2763   [impl->toplevel setLevel: level + (setting ? 1 : 0)];
2764 }
2765
2766 void
2767 gdk_window_set_keep_below (GdkWindow *window, gboolean setting)
2768 {
2769   GdkWindowObject *private = (GdkWindowObject *) window;
2770   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
2771   gint level;
2772
2773   g_return_if_fail (GDK_IS_WINDOW (window));
2774
2775   if (GDK_WINDOW_DESTROYED (window) ||
2776       !WINDOW_IS_TOPLEVEL (window))
2777     return;
2778   
2779   level = window_type_hint_to_level (gdk_window_get_type_hint (window));
2780   
2781   /* Adjust normal window level by one if necessary. */
2782   [impl->toplevel setLevel: level - (setting ? 1 : 0)];
2783 }
2784
2785 GdkWindow *
2786 gdk_window_get_group (GdkWindow *window)
2787 {
2788   g_return_val_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD, NULL);
2789
2790   if (GDK_WINDOW_DESTROYED (window) ||
2791       !WINDOW_IS_TOPLEVEL (window))
2792     return NULL;
2793
2794   /* FIXME: Implement */
2795
2796   return NULL;
2797 }
2798
2799 void          
2800 gdk_window_set_group (GdkWindow *window, 
2801                       GdkWindow *leader)
2802 {
2803   /* FIXME: Implement */        
2804 }
2805
2806 GdkWindow*
2807 gdk_window_foreign_new_for_display (GdkDisplay      *display,
2808                                     GdkNativeWindow  anid)
2809 {
2810   /* Foreign windows aren't supported in Mac OS X */
2811   return NULL;
2812 }
2813
2814 GdkWindow*
2815 gdk_window_lookup (GdkNativeWindow anid)
2816 {
2817   /* Foreign windows aren't supported in Mac OS X */
2818   return NULL;
2819 }
2820
2821 GdkWindow *
2822 gdk_window_lookup_for_display (GdkDisplay *display, GdkNativeWindow anid)
2823 {
2824   /* Foreign windows aren't supported in Mac OS X */
2825   return NULL;
2826 }
2827
2828 void
2829 gdk_window_enable_synchronized_configure (GdkWindow *window)
2830 {
2831 }
2832
2833 void
2834 gdk_window_configure_finished (GdkWindow *window)
2835 {
2836 }
2837
2838 void
2839 gdk_window_destroy_notify (GdkWindow *window)
2840 {
2841   check_grab_destroy (window);
2842 }
2843
2844 void 
2845 _gdk_windowing_window_beep (GdkWindow *window)
2846 {
2847   g_return_if_fail (GDK_IS_WINDOW (window));
2848
2849   gdk_display_beep (_gdk_display);
2850 }
2851
2852 void
2853 gdk_window_set_opacity (GdkWindow *window,
2854                         gdouble    opacity)
2855 {
2856   GdkWindowObject *private = (GdkWindowObject *) window;
2857   GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
2858
2859   g_return_if_fail (GDK_IS_WINDOW (window));
2860   g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
2861
2862   if (GDK_WINDOW_DESTROYED (window) ||
2863       !WINDOW_IS_TOPLEVEL (window))
2864     return;
2865
2866   if (opacity < 0)
2867     opacity = 0;
2868   else if (opacity > 1)
2869     opacity = 1;
2870
2871   [impl->toplevel setAlphaValue: opacity];
2872 }
2873
2874 void
2875 _gdk_windowing_window_set_composited (GdkWindow *window, gboolean composited)
2876 {
2877 }
2878
2879 GdkRegion *
2880 _gdk_windowing_get_shape_for_mask (GdkBitmap *mask)
2881 {
2882   /* FIXME: implement */
2883   return NULL;
2884 }
2885
2886 GdkRegion *
2887 _gdk_windowing_window_get_shape (GdkWindow *window)
2888 {
2889   /* FIXME: implement */
2890   return NULL;
2891 }
2892
2893 GdkRegion *
2894 _gdk_windowing_window_get_input_shape (GdkWindow *window)
2895 {
2896   /* FIXME: implement */
2897   return NULL;
2898 }
2899
2900 static void
2901 gdk_window_impl_iface_init (GdkWindowImplIface *iface)
2902 {
2903   iface->show = gdk_window_quartz_show;
2904   iface->hide = gdk_window_quartz_hide;
2905   iface->withdraw = gdk_window_quartz_withdraw;
2906   iface->set_events = gdk_window_quartz_set_events;
2907   iface->get_events = gdk_window_quartz_get_events;
2908   iface->raise = gdk_window_quartz_raise;
2909   iface->lower = gdk_window_quartz_lower;
2910   iface->move_resize = gdk_window_quartz_move_resize;
2911   iface->set_background = gdk_window_quartz_set_background;
2912   iface->set_back_pixmap = gdk_window_quartz_set_back_pixmap;
2913   iface->reparent = gdk_window_quartz_reparent;
2914   iface->set_cursor = gdk_window_quartz_set_cursor;
2915   iface->get_geometry = gdk_window_quartz_get_geometry;
2916   iface->get_root_coords = gdk_window_quartz_get_root_coords;
2917   iface->get_pointer = gdk_window_quartz_get_pointer;
2918   iface->get_deskrelative_origin = gdk_window_quartz_get_deskrelative_origin;
2919   iface->shape_combine_region = gdk_window_quartz_shape_combine_region;
2920   iface->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
2921   iface->set_static_gravities = gdk_window_quartz_set_static_gravities;
2922   iface->queue_antiexpose = _gdk_quartz_window_queue_antiexpose;
2923   iface->queue_translation = _gdk_quartz_window_queue_translation;
2924   iface->destroy = _gdk_quartz_window_destroy;
2925 }