gdkwindow-quartz.c 79.9 KB
Newer Older
Anders Carlsson's avatar
Anders Carlsson committed
1
2
3
/* gdkwindow-quartz.c
 *
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4
 * Copyright (C) 2005-2007 Imendio AB
Anders Carlsson's avatar
Anders Carlsson committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

22
#include "config.h"
23
#include <Carbon/Carbon.h>
Anders Carlsson's avatar
Anders Carlsson committed
24
25

#include "gdk.h"
26
#include "gdkdeviceprivate.h"
27
#include "gdkwindowimpl.h"
Anders Carlsson's avatar
Anders Carlsson committed
28
#include "gdkprivate-quartz.h"
29
#include "gdkscreen-quartz.h"
30
#include "gdkinputprivate.h"
Anders Carlsson's avatar
Anders Carlsson committed
31
32
33

static gpointer parent_class;

34
35
static GSList   *update_nswindows;
static gboolean  in_process_all_updates = FALSE;
36
37

static GSList *main_window_stack;
38

39
40
41
42
43
44
45
46
47
48
#define FULLSCREEN_DATA "fullscreen-data"

typedef struct
{
  gint            x, y;
  gint            width, height;
  GdkWMDecoration decor;
} FullscreenSavedGeometry;


49
static void update_toplevel_order (void);
50
51
52
static void clear_toplevel_order  (void);

static FullscreenSavedGeometry *get_fullscreen_geometry (GdkWindow *window);
53

54
55
56
57
#define WINDOW_IS_TOPLEVEL(window)		     \
  (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&   \
   GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN && \
   GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)
58

59
60
static void gdk_window_impl_iface_init (GdkWindowImplIface *iface);

61
62
63
64
65
NSView *
gdk_quartz_window_get_nsview (GdkWindow *window)
{
  GdkWindowObject *private = (GdkWindowObject *)window;

66
67
68
  if (GDK_WINDOW_DESTROYED (window))
    return NULL;

69
70
71
  return ((GdkWindowImplQuartz *)private->impl)->view;
}

72
73
74
75
76
77
78
79
80
81
82
NSWindow *
gdk_quartz_window_get_nswindow (GdkWindow *window)
{
  GdkWindowObject *private = (GdkWindowObject *)window;

  if (GDK_WINDOW_DESTROYED (window))
    return NULL;

  return ((GdkWindowImplQuartz *)private->impl)->toplevel;
}

Sven Herzberg's avatar
Sven Herzberg committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
static CGContextRef
gdk_window_impl_quartz_get_context (GdkDrawable *drawable,
				    gboolean     antialias)
{
  GdkDrawableImplQuartz *drawable_impl = GDK_DRAWABLE_IMPL_QUARTZ (drawable);
  GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (drawable);
  CGContextRef cg_context;

  if (GDK_WINDOW_DESTROYED (drawable_impl->wrapper))
    return NULL;

  /* Lock focus when not called as part of a drawRect call. This
   * is needed when called from outside "real" expose events, for
   * example for synthesized expose events when realizing windows
   * and for widgets that send fake expose events like the arrow
98
   * buttons in spinbuttons or the position marker in rulers.
Sven Herzberg's avatar
Sven Herzberg committed
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
   */
  if (window_impl->in_paint_rect_count == 0)
    {
      if (![window_impl->view lockFocusIfCanDraw])
        return NULL;
    }

  cg_context = [[NSGraphicsContext currentContext] graphicsPort];
  CGContextSaveGState (cg_context);
  CGContextSetAllowsAntialiasing (cg_context, antialias);

  /* We'll emulate the clipping caused by double buffering here */
  if (window_impl->begin_paint_count != 0)
    {
      CGRect rect;
      CGRect *cg_rects;
      gint n_rects, i;

Benjamin Otte's avatar
Benjamin Otte committed
117
      n_rects = cairo_region_num_rectangles (window_impl->paint_clip_region);
Sven Herzberg's avatar
Sven Herzberg committed
118
119

      if (n_rects == 1)
Benjamin Otte's avatar
Benjamin Otte committed
120
	cg_rects = &rect;
Sven Herzberg's avatar
Sven Herzberg committed
121
      else
Benjamin Otte's avatar
Benjamin Otte committed
122
	cg_rects = g_new (CGRect, n_rects);
Sven Herzberg's avatar
Sven Herzberg committed
123
124

      for (i = 0; i < n_rects; i++)
Benjamin Otte's avatar
Benjamin Otte committed
125
126
127
128
129
130
131
132
133
	{
          cairo_rectangle_int_t cairo_rect;
          cairo_region_get_rectangle (window_impl->paint_clip_region,
                                      i, &cairo_rect);
	  cg_rects[i].origin.x = cairo_rect.x;
	  cg_rects[i].origin.y = cairo_rect.y;
	  cg_rects[i].size.width = cairo_rect.width;
	  cg_rects[i].size.height = cairo_rect.height;
	}
Sven Herzberg's avatar
Sven Herzberg committed
134

135
      CGContextClipToRects (cg_context, cg_rects, n_rects);
Sven Herzberg's avatar
Sven Herzberg committed
136
137
138
139
140
141
142
143

      if (cg_rects != &rect)
        g_free (cg_rects);
    }

  return cg_context;
}

144
145
146
static void
check_grab_unmap (GdkWindow *window)
{
147
  GList *list, *l;
148
  GdkDisplay *display = gdk_drawable_get_display (window);
149
  GdkDeviceManager *device_manager;
150

151
152
153
154
  device_manager = gdk_display_get_device_manager (display);
  list = gdk_device_manager_list_devices (device_manager,
                                          GDK_DEVICE_TYPE_FLOATING);
  for (l = list; l; l = l->next)
155
    {
156
      _gdk_display_end_device_grab (display, l->data, 0, window, TRUE);
157
    }
158
159

  g_list_free (list);
160
161
162
163
164
}

static void
check_grab_destroy (GdkWindow *window)
{
165
  GList *list, *l;
166
  GdkDisplay *display = gdk_drawable_get_display (window);
167
  GdkDeviceManager *device_manager;
168
169

  /* Make sure there is no lasting grab in this native window */
170
171
172
173
174
  device_manager = gdk_display_get_device_manager (display);
  list = gdk_device_manager_list_devices (device_manager,
                                          GDK_DEVICE_TYPE_MASTER);

  for (l = list; l; l = l->next)
175
    {
176
177
178
179
180
181
182
183
184
      GdkDeviceGrabInfo *grab;

      grab = _gdk_display_get_last_device_grab (display, l->data);
      if (grab && grab->native_window == window)
        {
          /* Serials are always 0 in quartz, but for clarity: */
          grab->serial_end = grab->serial_start;
          grab->implicit_ungrab = TRUE;
        }
185
186
    }

187
  g_list_free (list);
188
189
}

Anders Carlsson's avatar
Anders Carlsson committed
190
191
192
193
194
static void
gdk_window_impl_quartz_finalize (GObject *object)
{
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (object);

195
196
  check_grab_destroy (GDK_DRAWABLE_IMPL_QUARTZ (object)->wrapper);

197
  if (impl->paint_clip_region)
Benjamin Otte's avatar
Benjamin Otte committed
198
    cairo_region_destroy (impl->paint_clip_region);
199

200
201
202
  if (impl->transient_for)
    g_object_unref (impl->transient_for);

Anders Carlsson's avatar
Anders Carlsson committed
203
204
205
206
207
208
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass)
{
209
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
210
  GdkDrawableImplQuartzClass *drawable_quartz_class = GDK_DRAWABLE_IMPL_QUARTZ_CLASS (klass);
Anders Carlsson's avatar
Anders Carlsson committed
211
212
213

  parent_class = g_type_class_peek_parent (klass);

214
215
  object_class->finalize = gdk_window_impl_quartz_finalize;

Sven Herzberg's avatar
Sven Herzberg committed
216
  drawable_quartz_class->get_context = gdk_window_impl_quartz_get_context;
Anders Carlsson's avatar
Anders Carlsson committed
217
218
219
220
221
}

static void
gdk_window_impl_quartz_init (GdkWindowImplQuartz *impl)
{
222
  impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
Anders Carlsson's avatar
Anders Carlsson committed
223
224
}

225
static void
226
gdk_window_impl_quartz_begin_paint_region (GdkPaintable    *paintable,
227
                                           GdkWindow       *window,
228
					   const cairo_region_t *region)
229
230
{
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable);
231
  GdkWindowObject *private = (GdkWindowObject*)window;
232
233
  int n_rects;
  GdkPixmap *bg_pixmap;
234
  cairo_region_t *clipped_and_offset_region;
235
236
237
  gboolean free_clipped_and_offset_region = TRUE;

  bg_pixmap = private->bg_pixmap;
238

Benjamin Otte's avatar
Benjamin Otte committed
239
  clipped_and_offset_region = cairo_region_copy (region);
240

Benjamin Otte's avatar
Benjamin Otte committed
241
  cairo_region_intersect (clipped_and_offset_region,
242
                        private->clip_region_with_children);
Benjamin Otte's avatar
Benjamin Otte committed
243
  cairo_region_translate (clipped_and_offset_region,
244
                     private->abs_x, private->abs_y);
245
246

  if (impl->begin_paint_count == 0)
247
248
249
250
    {
      impl->paint_clip_region = clipped_and_offset_region;
      free_clipped_and_offset_region = FALSE;
    }
251
  else
Benjamin Otte's avatar
Benjamin Otte committed
252
    cairo_region_union (impl->paint_clip_region, clipped_and_offset_region);
253

254
  impl->begin_paint_count++;
255

256
  if (bg_pixmap == GDK_NO_BG)
257
    goto done;
258

Benjamin Otte's avatar
Benjamin Otte committed
259
  n_rects = cairo_region_num_rectangles (clipped_and_offset_region);
260

261
262
263
  if (n_rects == 0)
    goto done;

264
265
  if (bg_pixmap == NULL)
    {
266
      CGContextRef cg_context;
267
      CGColorRef color;
268
      gint i;
269
270

      cg_context = gdk_quartz_drawable_get_context (GDK_DRAWABLE (impl), FALSE);
271
272
273
274
      color = _gdk_quartz_colormap_get_cgcolor_from_pixel (window,
                                                           private->bg_color.pixel);
      CGContextSetFillColorWithColor (cg_context, color);
      CGColorRelease (color);
275
 
276
      for (i = 0; i < n_rects; i++)
277
        {
Benjamin Otte's avatar
Benjamin Otte committed
278
279
          cairo_rectangle_int_t rect;
          cairo_region_get_rectangle (clipped_and_offset_region, i, &rect);
280
          CGContextFillRect (cg_context,
Benjamin Otte's avatar
Benjamin Otte committed
281
282
                             CGRectMake (rect.x, rect.y,
                                         rect.width, rect.height));
283
        }
284
285

      gdk_quartz_drawable_release_context (GDK_DRAWABLE (impl), cg_context);
286
287
    }
  else
288
    {
289
290
291
      int x, y;
      int x_offset, y_offset;
      int width, height;
292
      cairo_rectangle_int_t rect;
293
      GdkGC *gc;
294

295
      x_offset = y_offset = 0;
296

297
      while (window && bg_pixmap == GDK_PARENT_RELATIVE_BG)
298
299
300
301
302
303
304
305
        {
          /* If this window should have the same background as the parent,
           * fetch the parent. (And if the same goes for the parent, fetch
           * the grandparent, etc.)
           */
          x_offset += ((GdkWindowObject *) window)->x;
          y_offset += ((GdkWindowObject *) window)->y;
          window = GDK_WINDOW (((GdkWindowObject *) window)->parent);
306
307
308
309
310
311
312
313
          bg_pixmap = ((GdkWindowObject *) window)->bg_pixmap;
        }

      if (bg_pixmap == NULL || bg_pixmap == GDK_NO_BG || bg_pixmap == GDK_PARENT_RELATIVE_BG)
        {
          /* Parent relative background but the parent doesn't have a
           * pixmap.
           */ 
314
          goto done;
315
316
317
318
319
320
        }

      /* Note: There should be a CG API to draw tiled images, we might
       * want to look into that for this. 
       */
      gc = gdk_gc_new (GDK_DRAWABLE (impl));
321

322
      gdk_drawable_get_size (GDK_DRAWABLE (bg_pixmap), &width, &height);
323

324
      x = -x_offset;
Benjamin Otte's avatar
Benjamin Otte committed
325
326
      cairo_region_get_rectangle (clipped_and_offset_region, 0, &rect);
      while (x < (rect.x + rect.width))
327
        {
Benjamin Otte's avatar
Benjamin Otte committed
328
          if (x + width >= rect.x)
329
330
	    {
              y = -y_offset;
Benjamin Otte's avatar
Benjamin Otte committed
331
              while (y < (rect.y + rect.height))
332
                {
Benjamin Otte's avatar
Benjamin Otte committed
333
                  if (y + height >= rect.y)
334
335
336
337
338
339
340
                    gdk_draw_drawable (GDK_DRAWABLE (impl), gc, bg_pixmap, 0, 0, x, y, width, height);
		  
                  y += height;
                }
            }
          x += width;
        }
341
342

      g_object_unref (gc);
343
    }
344

345
346
 done:
  if (free_clipped_and_offset_region)
Benjamin Otte's avatar
Benjamin Otte committed
347
    cairo_region_destroy (clipped_and_offset_region);
348
349
350
351
352
353
354
}

static void
gdk_window_impl_quartz_end_paint (GdkPaintable *paintable)
{
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (paintable);

355
  impl->begin_paint_count--;
356
357
358

  if (impl->begin_paint_count == 0)
    {
Benjamin Otte's avatar
Benjamin Otte committed
359
      cairo_region_destroy (impl->paint_clip_region);
360
361
      impl->paint_clip_region = NULL;
    }
362
363
}

364
void
Benjamin Otte's avatar
Benjamin Otte committed
365
_gdk_quartz_window_set_needs_display_in_region (GdkWindow    *window,
366
                                                cairo_region_t    *region)
367
368
369
{
  GdkWindowObject *private;
  GdkWindowImplQuartz *impl;
Benjamin Otte's avatar
Benjamin Otte committed
370
  int i, n_rects;
371
372
373
374
375

  private = GDK_WINDOW_OBJECT (window);
  impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);

  if (!impl->needs_display_region)
Benjamin Otte's avatar
Benjamin Otte committed
376
    impl->needs_display_region = cairo_region_create ();
377

Benjamin Otte's avatar
Benjamin Otte committed
378
  cairo_region_union (impl->needs_display_region, region);
379

Benjamin Otte's avatar
Benjamin Otte committed
380
381
382
383
384
385
386
387
  n_rects = cairo_region_num_rectangles (region);
  for (i = 0; i < n_rects; i++)
    {
      cairo_rectangle_int_t rect;
      cairo_region_get_rectangle (region, i, &rect);
      [impl->view setNeedsDisplayInRect:NSMakeRect (rect.x, rect.y,
                                                    rect.width, rect.height)];
    }
388
389
}

390
391
void
_gdk_windowing_window_process_updates_recurse (GdkWindow *window,
392
                                               cairo_region_t *region)
393
{
394
395
396
397
  /* Make sure to only flush each toplevel at most once if we're called
   * from process_all_updates.
   */
  if (in_process_all_updates)
398
    {
399
400
401
      GdkWindow *toplevel;

      toplevel = gdk_window_get_toplevel (window);
402
      if (toplevel)
403
        {
404
405
          GdkWindowObject *toplevel_private;
          GdkWindowImplQuartz *toplevel_impl;
406
407
          NSWindow *nswindow;

408
409
410
          toplevel_private = (GdkWindowObject *)toplevel;
          toplevel_impl = (GdkWindowImplQuartz *)toplevel_private->impl;
          nswindow = toplevel_impl->toplevel;
411

412
413
414
          /* In theory, we could skip the flush disabling, since we only
           * have one NSView.
           */
415
416
          if (nswindow && ![nswindow isFlushWindowDisabled]) 
            {
417
              [nswindow retain];
418
              [nswindow disableFlushWindow];
419
              update_nswindows = g_slist_prepend (update_nswindows, nswindow);
420
            }
421
        }
422
423
    }

Benjamin Otte's avatar
Benjamin Otte committed
424
  _gdk_quartz_window_set_needs_display_in_region (window, region);
425

426
427
428
429
  /* NOTE: I'm not sure if we should displayIfNeeded here. It slows down a
   * lot (since it triggers the beam syncing) and things seem to work
   * without it.
   */
430
431
}

432
433
void
_gdk_windowing_before_process_all_updates (void)
434
{
435
  in_process_all_updates = TRUE;
436
437

  NSDisableScreenUpdates ();
438
439
}

440
441
void
_gdk_windowing_after_process_all_updates (void)
442
{
443
444
  GSList *old_update_nswindows = update_nswindows;
  GSList *tmp_list = update_nswindows;
445

446
  update_nswindows = NULL;
447

448
  while (tmp_list)
449
    {
450
451
      NSWindow *nswindow = tmp_list->data;

452
453
      [[nswindow contentView] displayIfNeeded];

454
455
      _gdk_quartz_drawable_flush (NULL);

456
457
458
      [nswindow enableFlushWindow];
      [nswindow flushWindow];
      [nswindow release];
459

460
      tmp_list = tmp_list->next;
461
    }
462

463
  g_slist_free (old_update_nswindows);
464

465
  in_process_all_updates = FALSE;
466
467

  NSEnableScreenUpdates ();
468
469
470
471
472
473
474
475
476
}

static void
gdk_window_impl_quartz_paintable_init (GdkPaintableIface *iface)
{
  iface->begin_paint_region = gdk_window_impl_quartz_begin_paint_region;
  iface->end_paint = gdk_window_impl_quartz_end_paint;
}

Anders Carlsson's avatar
Anders Carlsson committed
477
478
479
480
481
482
483
GType
_gdk_window_impl_quartz_get_type (void)
{
  static GType object_type = 0;

  if (!object_type)
    {
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
      const GTypeInfo object_info =
	{
	  sizeof (GdkWindowImplQuartzClass),
	  (GBaseInitFunc) NULL,
	  (GBaseFinalizeFunc) NULL,
	  (GClassInitFunc) gdk_window_impl_quartz_class_init,
	  NULL,           /* class_finalize */
	  NULL,           /* class_data */
	  sizeof (GdkWindowImplQuartz),
	  0,              /* n_preallocs */
	  (GInstanceInitFunc) gdk_window_impl_quartz_init,
	};

      const GInterfaceInfo paintable_info = 
	{
	  (GInterfaceInitFunc) gdk_window_impl_quartz_paintable_init,
	  NULL,
	  NULL
	};
503

504
505
506
507
508
509
510
      const GInterfaceInfo window_impl_info = 
	{
	  (GInterfaceInitFunc) gdk_window_impl_iface_init,
	  NULL,
	  NULL
	};

Anders Carlsson's avatar
Anders Carlsson committed
511
512
513
      object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_QUARTZ,
                                            "GdkWindowImplQuartz",
                                            &object_info, 0);
514
515
516
      g_type_add_interface_static (object_type,
				   GDK_TYPE_PAINTABLE,
				   &paintable_info);
517
518
519
      g_type_add_interface_static (object_type,
				   GDK_TYPE_WINDOW_IMPL,
				   &window_impl_info);
Anders Carlsson's avatar
Anders Carlsson committed
520
    }
521

Anders Carlsson's avatar
Anders Carlsson committed
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  return object_type;
}

GType
_gdk_window_impl_get_type (void)
{
  return _gdk_window_impl_quartz_get_type ();
}

static const gchar *
get_default_title (void)
{
  const char *title;

  title = g_get_application_name ();
  if (!title)
    title = g_get_prgname ();

  return title;
}

543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
static void
get_ancestor_coordinates_from_child (GdkWindow *child_window,
				     gint       child_x,
				     gint       child_y,
				     GdkWindow *ancestor_window, 
				     gint      *ancestor_x, 
				     gint      *ancestor_y)
{
  GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window);
  GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window);

  while (child_private != ancestor_private)
    {
      child_x += child_private->x;
      child_y += child_private->y;

      child_private = child_private->parent;
    }

  *ancestor_x = child_x;
  *ancestor_y = child_y;
}

void
567
_gdk_quartz_window_debug_highlight (GdkWindow *window, gint number)
568
569
570
{
  GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
  gint x, y;
571
  gint gx, gy;
572
573
  GdkWindow *toplevel;
  gint tx, ty;
574
575
  static NSWindow *debug_window[10];
  static NSRect old_rect[10];
576
  NSRect rect;
577
578
579
  NSColor *color;

  g_return_if_fail (number >= 0 && number <= 9);
580
581
582
583
584

  if (window == _gdk_root)
    return;

  if (window == NULL)
585
586
587
588
589
590
591
    {
      if (debug_window[number])
        [debug_window[number] close];
      debug_window[number] = NULL;

      return;
    }
592
593
594
595
596
597
598
599

  toplevel = gdk_window_get_toplevel (window);
  get_ancestor_coordinates_from_child (window, 0, 0, toplevel, &x, &y);

  gdk_window_get_origin (toplevel, &tx, &ty);
  x += tx;
  y += ty;

600
601
602
603
  _gdk_quartz_window_gdk_xy_to_xy (x, y + private->height,
                                   &gx, &gy);

  rect = NSMakeRect (gx, gy, private->width, private->height);
604

605
606
607
608
  if (debug_window[number] && NSEqualRects (rect, old_rect[number]))
    return;

  old_rect[number] = rect;
609

610
611
  if (debug_window[number])
    [debug_window[number] close];
612

613
614
615
616
  debug_window[number] = [[NSWindow alloc] initWithContentRect:rect
                                                     styleMask:NSBorderlessWindowMask
			                               backing:NSBackingStoreBuffered
			                                 defer:NO];
617

618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
  switch (number)
    {
    case 0:
      color = [NSColor redColor];
      break;
    case 1:
      color = [NSColor blueColor];
      break;
    case 2:
      color = [NSColor greenColor];
      break;
    case 3:
      color = [NSColor yellowColor];
      break;
    case 4:
      color = [NSColor brownColor];
      break;
    case 5:
      color = [NSColor purpleColor];
      break;
    default:
      color = [NSColor blackColor];
      break;
    }
642

643
644
645
646
647
648
  [debug_window[number] setBackgroundColor:color];
  [debug_window[number] setAlphaValue:0.4];
  [debug_window[number] setOpaque:NO];
  [debug_window[number] setReleasedWhenClosed:YES];
  [debug_window[number] setIgnoresMouseEvents:YES];
  [debug_window[number] setLevel:NSFloatingWindowLevel];
649

650
  [debug_window[number] orderFront:nil];
651
652
}

653
654
655
656
657
658
659
660
661
662
663
664
gboolean
_gdk_quartz_window_is_ancestor (GdkWindow *ancestor,
                                GdkWindow *window)
{
  if (ancestor == NULL || window == NULL)
    return FALSE;

  return (gdk_window_get_parent (window) == ancestor ||
          _gdk_quartz_window_is_ancestor (ancestor, 
                                          gdk_window_get_parent (window)));
}

665

666
/* See notes on top of gdkscreen-quartz.c */
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
void
_gdk_quartz_window_gdk_xy_to_xy (gint  gdk_x,
                                 gint  gdk_y,
                                 gint *ns_x,
                                 gint *ns_y)
{
  GdkScreenQuartz *screen_quartz = GDK_SCREEN_QUARTZ (_gdk_screen);

  if (ns_y)
    *ns_y = screen_quartz->height - gdk_y + screen_quartz->min_y;

  if (ns_x)
    *ns_x = gdk_x + screen_quartz->min_x;
}

void
_gdk_quartz_window_xy_to_gdk_xy (gint  ns_x,
                                 gint  ns_y,
                                 gint *gdk_x,
                                 gint *gdk_y)
Anders Carlsson's avatar
Anders Carlsson committed
687
{
688
  GdkScreenQuartz *screen_quartz = GDK_SCREEN_QUARTZ (_gdk_screen);
Anders Carlsson's avatar
Anders Carlsson committed
689

690
691
  if (gdk_y)
    *gdk_y = screen_quartz->height - ns_y + screen_quartz->min_y;
692

693
694
695
  if (gdk_x)
    *gdk_x = ns_x - screen_quartz->min_x;
}
696

697
698
699
700
701
702
703
void
_gdk_quartz_window_nspoint_to_gdk_xy (NSPoint  point,
                                      gint    *x,
                                      gint    *y)
{
  _gdk_quartz_window_xy_to_gdk_xy (point.x, point.y,
                                   x, y);
Anders Carlsson's avatar
Anders Carlsson committed
704
705
}

706
707
708
709
710
static GdkWindow *
find_child_window_helper (GdkWindow *window,
			  gint       x,
			  gint       y,
			  gint       x_offset,
711
712
			  gint       y_offset,
                          gboolean   get_toplevel)
713
{
714
  GdkWindowImplQuartz *impl;
715
716
  GList *l;

717
718
719
720
721
722
  impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);

  if (window == _gdk_root)
    update_toplevel_order ();

  for (l = impl->sorted_children; l; l = l->next)
723
    {
724
725
      GdkWindowObject *child_private = l->data;
      GdkWindowImplQuartz *child_impl = GDK_WINDOW_IMPL_QUARTZ (child_private->impl);
726
727
      int temp_x, temp_y;

728
      if (!GDK_WINDOW_IS_MAPPED (child_private))
729
730
	continue;

731
732
733
734
735
736
737
738
739
740
741
742
743
      temp_x = x_offset + child_private->x;
      temp_y = y_offset + child_private->y;

      /* Special-case the root window. We have to include the title
       * bar in the checks, otherwise the window below the title bar
       * will be found i.e. events punch through. (If we can find a
       * better way to deal with the events in gdkevents-quartz, this
       * might not be needed.)
       */
      if (window == _gdk_root)
        {
          NSRect frame = NSMakeRect (0, 0, 100, 100);
          NSRect content;
744
          NSUInteger mask;
745
746
747
748
749
750
751
752
753
754
755
          int titlebar_height;

          mask = [child_impl->toplevel styleMask];

          /* Get the title bar height. */
          content = [NSWindow contentRectForFrameRect:frame
                                            styleMask:mask];
          titlebar_height = frame.size.height - content.size.height;

          if (titlebar_height > 0 &&
              x >= temp_x && y >= temp_y - titlebar_height &&
756
              x < temp_x + child_private->width && y < temp_y)
757
758
759
760
761
762
763
764
            {
              /* The root means "unknown" i.e. a window not managed by
               * GDK.
               */
              return (GdkWindow *)_gdk_root;
            }
        }

765
766
      if ((!get_toplevel || (get_toplevel && window == _gdk_root)) &&
          x >= temp_x && y >= temp_y &&
767
	  x < temp_x + child_private->width && y < temp_y + child_private->height)
768
769
770
771
	{
	  /* Look for child windows. */
	  return find_child_window_helper (l->data,
					   x, y,
772
773
					   temp_x, temp_y,
                                           get_toplevel);
774
775
776
777
778
779
780
	}
    }
  
  return window;
}

/* Given a GdkWindow and coordinates relative to it, returns the
781
782
 * innermost subwindow that contains the point. If the coordinates are
 * outside the passed in window, NULL is returned.
783
784
785
786
 */
GdkWindow *
_gdk_quartz_window_find_child (GdkWindow *window,
			       gint       x,
787
788
			       gint       y,
                               gboolean   get_toplevel)
789
790
791
{
  GdkWindowObject *private = GDK_WINDOW_OBJECT (window);

792
  if (x >= 0 && y >= 0 && x < private->width && y < private->height)
793
    return find_child_window_helper (window, x, y, 0, 0, get_toplevel);
794
795
796
797

  return NULL;
}

798

799
800
801
802
803
804
void
_gdk_quartz_window_did_become_main (GdkWindow *window)
{
  main_window_stack = g_slist_remove (main_window_stack, window);

  if (GDK_WINDOW_OBJECT (window)->window_type != GDK_WINDOW_TEMP)
805
    main_window_stack = g_slist_prepend (main_window_stack, window);
806
807

  clear_toplevel_order ();
808
809
810
811
812
813
814
815
816
817
818
819
820
}

void
_gdk_quartz_window_did_resign_main (GdkWindow *window)
{
  GdkWindow *new_window = NULL;

  if (main_window_stack)
    new_window = main_window_stack->data;
  else
    {
      GList *toplevels;

821
      toplevels = gdk_screen_get_toplevel_windows (gdk_screen_get_default ());
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
      if (toplevels)
        new_window = toplevels->data;
      g_list_free (toplevels);
    }

  if (new_window &&
      new_window != window &&
      GDK_WINDOW_IS_MAPPED (new_window) &&
      GDK_WINDOW_OBJECT (new_window)->window_type != GDK_WINDOW_TEMP)
    {
      GdkWindowObject *private = (GdkWindowObject *) new_window;
      GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);

      [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
    }
837
838

  clear_toplevel_order ();
839
840
}

841
static NSScreen *
Kristian Rietveld's avatar
Kristian Rietveld committed
842
get_nsscreen_for_point (gint x, gint y)
843
844
845
{
  int i;
  NSArray *screens;
846
  NSScreen *screen = NULL;
847
848
849
850
851
852
853
854
855

  GDK_QUARTZ_ALLOC_POOL;

  screens = [NSScreen screens];

  for (i = 0; i < [screens count]; i++)
    {
      NSRect rect = [[screens objectAtIndex:i] frame];

Kristian Rietveld's avatar
Kristian Rietveld committed
856
857
      if (x >= rect.origin.x && x <= rect.origin.x + rect.size.width &&
          y >= rect.origin.y && y <= rect.origin.y + rect.size.height)
858
859
860
861
        {
          screen = [screens objectAtIndex:i];
          break;
        }
862
863
864
865
    }

  GDK_QUARTZ_RELEASE_POOL;

866
  return screen;
867
868
}

869
870
871
872
873
874
875
876
void
_gdk_window_impl_new (GdkWindow     *window,
		      GdkWindow     *real_parent,
		      GdkScreen     *screen,
		      GdkVisual     *visual,
		      GdkEventMask   event_mask,
		      GdkWindowAttr *attributes,
		      gint           attributes_mask)
Anders Carlsson's avatar
Anders Carlsson committed
877
878
879
880
{
  GdkWindowObject *private;
  GdkWindowImplQuartz *impl;
  GdkDrawableImplQuartz *draw_impl;
881
  GdkWindowImplQuartz *parent_impl;
Anders Carlsson's avatar
Anders Carlsson committed
882

883
  GDK_QUARTZ_ALLOC_POOL;
Anders Carlsson's avatar
Anders Carlsson committed
884
885

  private = (GdkWindowObject *)window;
886

887
888
889
  impl = g_object_new (_gdk_window_impl_get_type (), NULL);
  private->impl = (GdkDrawable *)impl;
  draw_impl = GDK_DRAWABLE_IMPL_QUARTZ (impl);
Anders Carlsson's avatar
Anders Carlsson committed
890
891
  draw_impl->wrapper = GDK_DRAWABLE (window);

892
  parent_impl = GDK_WINDOW_IMPL_QUARTZ (private->parent->impl);
Anders Carlsson's avatar
Anders Carlsson committed
893
894
895
896
897
898

  switch (private->window_type)
    {
    case GDK_WINDOW_TOPLEVEL:
    case GDK_WINDOW_DIALOG:
    case GDK_WINDOW_TEMP:
899
      if (GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
Anders Carlsson's avatar
Anders Carlsson committed
900
	{
901
902
	  /* The common code warns for this case */
          parent_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (_gdk_root)->impl);
Anders Carlsson's avatar
Anders Carlsson committed
903
904
905
	}
    }

906
  if (!private->input_only)
Anders Carlsson's avatar
Anders Carlsson committed
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
    {
      if (attributes_mask & GDK_WA_COLORMAP)
	{
	  draw_impl->colormap = attributes->colormap;
	  g_object_ref (attributes->colormap);
	}
      else
	{
	  if (visual == gdk_screen_get_system_visual (_gdk_screen))
	    {
	      draw_impl->colormap = gdk_screen_get_system_colormap (_gdk_screen);
	      g_object_ref (draw_impl->colormap);
	    }
	  else if (visual == gdk_screen_get_rgba_visual (_gdk_screen))
	    {
	      draw_impl->colormap = gdk_screen_get_rgba_colormap (_gdk_screen);
	      g_object_ref (draw_impl->colormap);
	    }
	  else
	    {
	      draw_impl->colormap = gdk_colormap_new (visual, FALSE);
	    }
	}
    }
  else
    {
      draw_impl->colormap = gdk_screen_get_system_colormap (_gdk_screen);
Anders Carlsson's avatar
Anders Carlsson committed
934
      g_object_ref (draw_impl->colormap);
Anders Carlsson's avatar
Anders Carlsson committed
935
936
    }

937
  /* Maintain the z-ordered list of children. */
938
  if (private->parent != (GdkWindowObject *)_gdk_root)
939
940
941
    parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window);
  else
    clear_toplevel_order ();
Anders Carlsson's avatar
Anders Carlsson committed
942
943
944
945
946
947
948
949
950
951
952

  gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
				  (attributes->cursor) :
				  NULL));

  switch (attributes->window_type) 
    {
    case GDK_WINDOW_TOPLEVEL:
    case GDK_WINDOW_DIALOG:
    case GDK_WINDOW_TEMP:
      {
953
954
        NSScreen *screen;
        NSRect screen_rect;
955
        NSRect content_rect;
956
        NSUInteger style_mask;
957
        int nx, ny;
958
959
        const char *title;

960
961
962
963
964
965
966
        /* initWithContentRect will place on the mainScreen by default.
         * We want to select the screen to place on ourselves.  We need
         * to find the screen the window will be on and correct the
         * content_rect coordinates to be relative to that screen.
         */
        _gdk_quartz_window_gdk_xy_to_xy (private->x, private->y, &nx, &ny);

Kristian Rietveld's avatar
Kristian Rietveld committed
967
        screen = get_nsscreen_for_point (nx, ny);
968
969
970
971
972
        screen_rect = [screen frame];
        nx -= screen_rect.origin.x;
        ny -= screen_rect.origin.y;

        content_rect = NSMakeRect (nx, ny - private->height,
973
974
                                   private->width,
                                   private->height);
Anders Carlsson's avatar
Anders Carlsson committed
975

976
977
        if (attributes->window_type == GDK_WINDOW_TEMP ||
            attributes->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN)
978
979
          {
            style_mask = NSBorderlessWindowMask;
980
981
982
          }
        else
          {
983
984
985
986
987
            style_mask = (NSTitledWindowMask |
                          NSClosableWindowMask |
                          NSMiniaturizableWindowMask |
                          NSResizableWindowMask);
          }
Anders Carlsson's avatar
Anders Carlsson committed
988
989

	impl->toplevel = [[GdkQuartzWindow alloc] initWithContentRect:content_rect 
Anders Carlsson's avatar
Anders Carlsson committed
990
			                                    styleMask:style_mask
Michael Natterer's avatar
Michael Natterer committed
991
			                                      backing:NSBackingStoreBuffered
992
993
			                                        defer:NO
                                                                screen:screen];
Michael Natterer's avatar
Michael Natterer committed
994

Anders Carlsson's avatar
Anders Carlsson committed
995
996
997
998
999
1000
	if (attributes_mask & GDK_WA_TITLE)
	  title = attributes->title;
	else
	  title = get_default_title ();

	gdk_window_set_title (window, title);
1001
  
Anders Carlsson's avatar
Anders Carlsson committed
1002
1003
1004
1005
1006
1007
	if (draw_impl->colormap == gdk_screen_get_rgba_colormap (_gdk_screen))
	  {
	    [impl->toplevel setOpaque:NO];
	    [impl->toplevel setBackgroundColor:[NSColor clearColor]];
	  }

1008
1009
1010
        content_rect.origin.x = 0;
        content_rect.origin.y = 0;

Anders Carlsson's avatar
Anders Carlsson committed
1011
1012
1013
	impl->view = [[GdkQuartzView alloc] initWithFrame:content_rect];
	[impl->view setGdkWindow:window];
	[impl->toplevel setContentView:impl->view];
1014
	[impl->view release];
Anders Carlsson's avatar
Anders Carlsson committed
1015
1016
      }
      break;
1017

Anders Carlsson's avatar
Anders Carlsson committed
1018
1019
    case GDK_WINDOW_CHILD:
      {
1020
	GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (private->parent)->impl);
Anders Carlsson's avatar
Anders Carlsson committed
1021

1022
	if (!private->input_only)
Anders Carlsson's avatar
Anders Carlsson committed
1023
	  {
1024
1025
1026
1027
	    NSRect frame_rect = NSMakeRect (private->x + private->parent->abs_x,
                                            private->y + private->parent->abs_y,
                                            private->width,
                                            private->height);
Anders Carlsson's avatar
Anders Carlsson committed
1028
1029
1030
1031
1032
1033
1034
1035
	
	    impl->view = [[GdkQuartzView alloc] initWithFrame:frame_rect];
	    
	    [impl->view setGdkWindow:window];

	    /* GdkWindows should be hidden by default */
	    [impl->view setHidden:YES];
	    [parent_impl->view addSubview:impl->view];
1036
	    [impl->view release];
Anders Carlsson's avatar
Anders Carlsson committed
1037
1038
1039
	  }
      }
      break;
1040

Anders Carlsson's avatar
Anders Carlsson committed
1041
1042
1043
1044
1045
1046
    default:
      g_assert_not_reached ();
    }

  GDK_QUARTZ_RELEASE_POOL;

Cody Russell's avatar
Cody Russell committed
1047
1048
  if (attributes_mask & GDK_WA_TYPE_HINT)
    gdk_window_set_type_hint (window, attributes->type_hint);
Anders Carlsson's avatar
Anders Carlsson committed
1049
1050
}

1051
void
1052
_gdk_quartz_window_update_position (GdkWindow *window)
1053
{
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  NSRect frame_rect;
  NSRect content_rect;
  GdkWindowObject *private = (GdkWindowObject *)window;
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);

  GDK_QUARTZ_ALLOC_POOL;

  frame_rect = [impl->toplevel frame];
  content_rect = [impl->toplevel contentRectForFrameRect:frame_rect];

  _gdk_quartz_window_xy_to_gdk_xy (content_rect.origin.x,
                                   content_rect.origin.y + content_rect.size.height,
                                   &private->x, &private->y);


  GDK_QUARTZ_RELEASE_POOL;
}

void
_gdk_windowing_update_window_sizes (GdkScreen *screen)
{
  GList *windows, *list;
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  GdkWindowObject *private = (GdkWindowObject *)_gdk_root;

  /* The size of the root window is so that it can contain all
   * monitors attached to this machine.  The monitors are laid out
   * within this root window.  We calculate the size of the root window
   * and the positions of the different monitors in gdkscreen-quartz.c.
   *
   * This data is updated when the monitor configuration is changed.
   */
  private->x = 0;
  private->y = 0;
  private->abs_x = 0;
  private->abs_y = 0;
  private->width = gdk_screen_get_width (screen);
  private->height = gdk_screen_get_height (screen);
1091
1092
1093
1094
1095
1096
1097

  windows = gdk_screen_get_toplevel_windows (screen);

  for (list = windows; list; list = list->next)
    _gdk_quartz_window_update_position (list->data);

  g_list_free (windows);
1098
1099
}

Anders Carlsson's avatar
Anders Carlsson committed
1100
1101
1102
1103
void
_gdk_windowing_window_init (void)
{
  GdkWindowObject *private;
Richard Hult's avatar
Richard Hult committed
1104
  GdkWindowImplQuartz *impl;
1105
  GdkDrawableImplQuartz *drawable_impl;
Anders Carlsson's avatar
Anders Carlsson committed
1106
1107
1108
1109

  g_assert (_gdk_root == NULL);

  _gdk_root = g_object_new (GDK_TYPE_WINDOW, NULL);
Anders Carlsson's avatar
Anders Carlsson committed
1110

1111
1112
  private = (GdkWindowObject *)_gdk_root;
  private->impl = g_object_new (_gdk_window_impl_get_type (), NULL);
1113
  private->impl_window = private;
1114

Richard Hult's avatar
Richard Hult committed
1115
  impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (_gdk_root)->impl);
1116

1117
  _gdk_windowing_update_window_sizes (_gdk_screen);
Richard Hult's avatar
Richard Hult committed
1118

Anders Carlsson's avatar
Anders Carlsson committed
1119
  private->state = 0; /* We don't want GDK_WINDOW_STATE_WITHDRAWN here */
Anders Carlsson's avatar
Anders Carlsson committed
1120
1121
  private->window_type = GDK_WINDOW_ROOT;
  private->depth = 24;
1122
  private->viewable = TRUE;
1123
1124
1125
1126
1127
1128

  drawable_impl = GDK_DRAWABLE_IMPL_QUARTZ (private->impl);
  
  drawable_impl->wrapper = GDK_DRAWABLE (private);
  drawable_impl->colormap = gdk_screen_get_system_colormap (_gdk_screen);
  g_object_ref (drawable_impl->colormap);
Anders Carlsson's avatar
Anders Carlsson committed
1129
1130
}

1131
1132
1133
1134
static void
_gdk_quartz_window_destroy (GdkWindow *window,
                            gboolean   recursing,
                            gboolean   foreign_destroy)
Anders Carlsson's avatar
Anders Carlsson committed
1135
{
1136
1137
1138
1139
1140
1141
1142
  GdkWindowObject *private;
  GdkWindowImplQuartz *impl;
  GdkWindowObject *parent;

  private = GDK_WINDOW_OBJECT (window);
  impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);

1143
  main_window_stack = g_slist_remove (main_window_stack, window);
1144

1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
  g_list_free (impl->sorted_children);
  impl->sorted_children = NULL;

  parent = private->parent;
  if (parent)
    {
      GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);

      parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window);
    }

1156
  _gdk_quartz_drawable_finish (GDK_DRAWABLE (impl));
Anders Carlsson's avatar
Anders Carlsson committed
1157

1158
1159
  if (!recursing && !foreign_destroy)
    {
1160
1161
      GDK_QUARTZ_ALLOC_POOL;

Anders Carlsson's avatar
Anders Carlsson committed
1162
1163
1164
      if (impl->toplevel)
	[impl->toplevel close];
      else if (impl->view)
1165
	[impl->view removeFromSuperview];
1166
1167

      GDK_QUARTZ_RELEASE_POOL;
Anders Carlsson's avatar
Anders Carlsson committed
1168
1169
1170
1171
1172
1173
    }
}

void
_gdk_windowing_window_destroy_foreign (GdkWindow *window)
{
1174
  /* Foreign windows aren't supported in OSX. */