gdkwindow-quartz.c 84.3 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
 *
 * 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
Javier Jardón's avatar
Javier Jardón committed
17
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Anders Carlsson's avatar
Anders Carlsson committed
18 19
 */

20
#include "config.h"
Anders Carlsson's avatar
Anders Carlsson committed
21

22 23 24 25
#include <gdk/gdk.h>
#include <gdk/gdkdeviceprivate.h>
#include <gdk/gdkdisplayprivate.h>

26
#include "gdkwindowimpl.h"
Anders Carlsson's avatar
Anders Carlsson committed
27
#include "gdkprivate-quartz.h"
28
#include "gdkglcontext-quartz.h"
29 30 31 32
#include "gdkquartzscreen.h"
#include "gdkquartzcursor.h"

#include <Carbon/Carbon.h>
33
#include <AvailabilityMacros.h>
Anders Carlsson's avatar
Anders Carlsson committed
34

35 36 37
#include <sys/time.h>
#include <cairo-quartz.h>

Anders Carlsson's avatar
Anders Carlsson committed
38
static gpointer parent_class;
39
static gpointer root_window_parent_class;
Anders Carlsson's avatar
Anders Carlsson committed
40

41 42
static GSList   *update_nswindows;
static gboolean  in_process_all_updates = FALSE;
43 44

static GSList *main_window_stack;
45

46 47
void _gdk_quartz_window_flush (GdkWindowImplQuartz *window_impl);

48 49 50 51 52 53 54 55
typedef struct
{
  gint            x, y;
  gint            width, height;
  GdkWMDecoration decor;
} FullscreenSavedGeometry;


56 57 58 59 60 61
#ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
static FullscreenSavedGeometry *get_fullscreen_geometry (GdkWindow *window);
#endif

#define FULLSCREEN_DATA "fullscreen-data"

62
static void update_toplevel_order (void);
63 64
static void clear_toplevel_order  (void);

65 66 67 68
#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)
69

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
/*
 * GdkQuartzWindow
 */

struct _GdkQuartzWindow
{
  GdkWindow parent;
};

struct _GdkQuartzWindowClass
{
  GdkWindowClass parent_class;
};

G_DEFINE_TYPE (GdkQuartzWindow, gdk_quartz_window, GDK_TYPE_WINDOW);

static void
gdk_quartz_window_class_init (GdkQuartzWindowClass *quartz_window_class)
{
}

static void
gdk_quartz_window_init (GdkQuartzWindow *quartz_window)
{
}


/*
 * GdkQuartzWindowImpl
 */

101 102 103
NSView *
gdk_quartz_window_get_nsview (GdkWindow *window)
{
104 105 106
  if (GDK_WINDOW_DESTROYED (window))
    return NULL;

107
  return ((GdkWindowImplQuartz *)window->impl)->view;
108 109
}

110 111 112 113 114 115
NSWindow *
gdk_quartz_window_get_nswindow (GdkWindow *window)
{
  if (GDK_WINDOW_DESTROYED (window))
    return NULL;

116
  return ((GdkWindowImplQuartz *)window->impl)->toplevel;
117 118
}

119
static CGContextRef
120 121
gdk_window_impl_quartz_get_context (GdkWindowImplQuartz *window_impl,
				    gboolean             antialias)
122 123
{
  CGContextRef cg_context;
124
  CGSize scale;
125

126
  if (GDK_WINDOW_DESTROYED (window_impl->wrapper))
127 128 129 130 131 132
    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
133
   * buttons in spinbuttons or the position marker in rulers.
134 135 136 137 138 139 140 141 142 143 144
   */
  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);

145 146 147 148 149 150
  /* Undo the default scaling transform, since we apply our own
   * in gdk_quartz_ref_cairo_surface () */
  scale = CGContextConvertSizeToDeviceSpace (cg_context,
                                             CGSizeMake (1.0, 1.0));
  CGContextScaleCTM (cg_context, 1.0 / scale.width, 1.0 / scale.height);

151 152 153
  return cg_context;
}

154
static void
155 156
gdk_window_impl_quartz_release_context (GdkWindowImplQuartz *window_impl,
                                        CGContextRef         cg_context)
157 158 159 160
{
  CGContextRestoreGState (cg_context);
  CGContextSetAllowsAntialiasing (cg_context, TRUE);

161
  /* See comment in gdk_quartz_window_get_context(). */
162 163
  if (window_impl->in_paint_rect_count == 0)
    {
164
      _gdk_quartz_window_flush (window_impl);
165 166 167 168
      [window_impl->view unlockFocus];
    }
}

169 170 171
static void
check_grab_unmap (GdkWindow *window)
{
172
  GList *list, *l;
173
  GdkDisplay *display = gdk_window_get_display (window);
174
  GdkDeviceManager *device_manager;
175

176 177 178 179
  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)
180
    {
181
      _gdk_display_end_device_grab (display, l->data, 0, window, TRUE);
182
    }
183 184

  g_list_free (list);
185 186 187 188 189
}

static void
check_grab_destroy (GdkWindow *window)
{
190
  GList *list, *l;
191
  GdkDisplay *display = gdk_window_get_display (window);
192
  GdkDeviceManager *device_manager;
193 194

  /* Make sure there is no lasting grab in this native window */
195 196 197 198 199
  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)
200
    {
201 202 203 204 205 206 207 208 209
      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;
        }
210 211
    }

212
  g_list_free (list);
213 214
}

Anders Carlsson's avatar
Anders Carlsson committed
215 216 217 218 219
static void
gdk_window_impl_quartz_finalize (GObject *object)
{
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (object);

220
  check_grab_destroy (GDK_WINDOW_IMPL_QUARTZ (object)->wrapper);
221

222 223 224
  if (impl->transient_for)
    g_object_unref (impl->transient_for);

Anders Carlsson's avatar
Anders Carlsson committed
225 226 227
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

228 229 230 231 232
/* Help preventing "beam sync penalty" where CG makes all graphics code
 * block until the next vsync if we try to flush (including call display on
 * a view) too often. We do this by limiting the manual flushing done
 * outside of expose calls to less than some frequency when measured over
 * the last 4 flushes. This is a bit arbitray, but seems to make it possible
233
 * for some quick manual flushes (such as gtkruler or gimp’s marching ants)
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
 * without hitting the max flush frequency.
 *
 * If drawable NULL, no flushing is done, only registering that a flush was
 * done externally.
 */
void
_gdk_quartz_window_flush (GdkWindowImplQuartz *window_impl)
{
  static struct timeval prev_tv;
  static gint intervals[4];
  static gint index;
  struct timeval tv;
  gint ms;

  gettimeofday (&tv, NULL);
  ms = (tv.tv_sec - prev_tv.tv_sec) * 1000 + (tv.tv_usec - prev_tv.tv_usec) / 1000;
  intervals[index++ % 4] = ms;

  if (window_impl)
    {
      ms = intervals[0] + intervals[1] + intervals[2] + intervals[3];

      /* ~25Hz on average. */
      if (ms > 4*40)
        {
          if (window_impl)
            [window_impl->toplevel flushWindow];

          prev_tv = tv;
        }
    }
  else
    prev_tv = tv;
}

static cairo_user_data_key_t gdk_quartz_cairo_key;

typedef struct {
  GdkWindowImplQuartz  *window_impl;
  CGContextRef  cg_context;
} GdkQuartzCairoSurfaceData;

Anders Carlsson's avatar
Anders Carlsson committed
276
static void
277
gdk_quartz_cairo_surface_destroy (void *data)
Anders Carlsson's avatar
Anders Carlsson committed
278
{
279
  GdkQuartzCairoSurfaceData *surface_data = data;
Anders Carlsson's avatar
Anders Carlsson committed
280

281
  surface_data->window_impl->cairo_surface = NULL;
Anders Carlsson's avatar
Anders Carlsson committed
282

283 284
  gdk_quartz_window_release_context (surface_data->window_impl,
                                     surface_data->cg_context);
285

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
  g_free (surface_data);
}

static cairo_surface_t *
gdk_quartz_create_cairo_surface (GdkWindowImplQuartz *impl,
				 int                  width,
				 int                  height)
{
  CGContextRef cg_context;
  GdkQuartzCairoSurfaceData *surface_data;
  cairo_surface_t *surface;

  cg_context = gdk_quartz_window_get_context (impl, TRUE);

  if (!cg_context)
    return NULL;

  surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
  surface_data->window_impl = impl;
  surface_data->cg_context = cg_context;

  surface = cairo_quartz_surface_create_for_cg_context (cg_context,
                                                        width, height);

  cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
                               surface_data,
                               gdk_quartz_cairo_surface_destroy);

  return surface;
}

static cairo_surface_t *
gdk_quartz_ref_cairo_surface (GdkWindow *window)
{
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);

  if (GDK_WINDOW_DESTROYED (window))
    return NULL;

  if (!impl->cairo_surface)
    {
327 328
      gint scale = gdk_window_get_scale_factor (impl->wrapper);

329 330
      impl->cairo_surface = 
          gdk_quartz_create_cairo_surface (impl,
331 332 333 334
                                           gdk_window_get_width (impl->wrapper) * scale,
                                           gdk_window_get_height (impl->wrapper) * scale);

      cairo_surface_set_device_scale (impl->cairo_surface, scale, scale);
335 336 337 338 339
    }
  else
    cairo_surface_reference (impl->cairo_surface);

  return impl->cairo_surface;
Anders Carlsson's avatar
Anders Carlsson committed
340 341 342 343 344
}

static void
gdk_window_impl_quartz_init (GdkWindowImplQuartz *impl)
{
345
  impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
Anders Carlsson's avatar
Anders Carlsson committed
346 347
}

348
static gboolean
349
gdk_window_impl_quartz_begin_paint (GdkWindow *window)
350
{
351
  return FALSE;
352 353
}

354 355 356
static void
gdk_quartz_window_set_needs_display_in_region (GdkWindow    *window,
                                               cairo_region_t    *region)
357 358
{
  GdkWindowImplQuartz *impl;
359
  int i, n_rects;
360

361
  impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
362 363

  if (!impl->needs_display_region)
364
    impl->needs_display_region = cairo_region_create ();
365

366
  cairo_region_union (impl->needs_display_region, region);
367

368 369 370 371 372 373 374 375
  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)];
    }
376 377
}

378
void
379 380
_gdk_quartz_window_process_updates_recurse (GdkWindow *window,
                                            cairo_region_t *region)
381
{
382 383 384 385
  /* Make sure to only flush each toplevel at most once if we're called
   * from process_all_updates.
   */
  if (in_process_all_updates)
386
    {
387 388
      GdkWindow *toplevel;

389 390
      toplevel = gdk_window_get_effective_toplevel (window);
      if (toplevel && WINDOW_IS_TOPLEVEL (toplevel))
391
        {
392
          GdkWindowImplQuartz *toplevel_impl;
393 394
          NSWindow *nswindow;

395
          toplevel_impl = (GdkWindowImplQuartz *)toplevel->impl;
396
          nswindow = toplevel_impl->toplevel;
397

398 399 400
          /* In theory, we could skip the flush disabling, since we only
           * have one NSView.
           */
401 402
          if (nswindow && ![nswindow isFlushWindowDisabled]) 
            {
403
              [nswindow retain];
404
              [nswindow disableFlushWindow];
405
              update_nswindows = g_slist_prepend (update_nswindows, nswindow);
406
            }
407
        }
408 409
    }

410
  if (WINDOW_IS_TOPLEVEL (window))
411
    gdk_quartz_window_set_needs_display_in_region (window, region);
412 413
  else
    _gdk_window_process_updates_recurse (window, region);
414

415 416 417 418
  /* 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.
   */
419 420
}

421
void
422
_gdk_quartz_display_before_process_all_updates (GdkDisplay *display)
423
{
424
  in_process_all_updates = TRUE;
425

426 427 428 429 430 431 432 433
  if (gdk_quartz_osx_version () >= GDK_OSX_EL_CAPITAN)
    {
      [NSAnimationContext endGrouping];
    }
  else
    {
      NSDisableScreenUpdates ();
    }
434 435
}

436
void
437
_gdk_quartz_display_after_process_all_updates (GdkDisplay *display)
438
{
439 440
  GSList *old_update_nswindows = update_nswindows;
  GSList *tmp_list = update_nswindows;
441

442
  update_nswindows = NULL;
443

444
  while (tmp_list)
445
    {
446 447
      NSWindow *nswindow = tmp_list->data;

448 449
      [[nswindow contentView] displayIfNeeded];

450
      _gdk_quartz_window_flush (NULL);
451

452 453 454
      [nswindow enableFlushWindow];
      [nswindow flushWindow];
      [nswindow release];
455

456
      tmp_list = tmp_list->next;
457
    }
458

459
  g_slist_free (old_update_nswindows);
460

461
  in_process_all_updates = FALSE;
462

463 464 465 466 467 468 469 470
  if (gdk_quartz_osx_version() >= GDK_OSX_EL_CAPITAN)
    {
      [NSAnimationContext beginGrouping];
    }
  else
    {
      NSEnableScreenUpdates ();
    }
471 472
}

Anders Carlsson's avatar
Anders Carlsson committed
473 474 475 476 477 478 479 480 481 482 483 484
static const gchar *
get_default_title (void)
{
  const char *title;

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

  return title;
}

485 486 487 488 489 490 491 492
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)
{
493
  while (child_window != ancestor_window)
494
    {
495 496
      child_x += child_window->x;
      child_y += child_window->y;
497

498
      child_window = child_window->parent;
499 500 501 502 503 504 505
    }

  *ancestor_x = child_x;
  *ancestor_y = child_y;
}

void
506
_gdk_quartz_window_debug_highlight (GdkWindow *window, gint number)
507 508
{
  gint x, y;
509
  gint gx, gy;
510 511
  GdkWindow *toplevel;
  gint tx, ty;
512 513
  static NSWindow *debug_window[10];
  static NSRect old_rect[10];
514
  NSRect rect;
515 516 517
  NSColor *color;

  g_return_if_fail (number >= 0 && number <= 9);
518 519 520 521 522

  if (window == _gdk_root)
    return;

  if (window == NULL)
523 524 525 526 527 528 529
    {
      if (debug_window[number])
        [debug_window[number] close];
      debug_window[number] = NULL;

      return;
    }
530 531 532 533 534 535 536 537

  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;

538
  _gdk_quartz_window_gdk_xy_to_xy (x, y + window->height,
539 540
                                   &gx, &gy);

541
  rect = NSMakeRect (gx, gy, window->width, window->height);
542

543 544 545 546
  if (debug_window[number] && NSEqualRects (rect, old_rect[number]))
    return;

  old_rect[number] = rect;
547

548 549
  if (debug_window[number])
    [debug_window[number] close];
550

551 552 553 554
  debug_window[number] = [[NSWindow alloc] initWithContentRect:rect
                                                     styleMask:NSBorderlessWindowMask
			                               backing:NSBackingStoreBuffered
			                                 defer:NO];
555

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
  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;
    }
580

581 582 583 584 585 586
  [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];
587

588
  [debug_window[number] orderFront:nil];
589 590
}

591 592 593 594 595 596 597 598 599 600 601 602
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)));
}

603

604
/* See notes on top of gdkscreen-quartz.c */
605 606 607 608 609 610
void
_gdk_quartz_window_gdk_xy_to_xy (gint  gdk_x,
                                 gint  gdk_y,
                                 gint *ns_x,
                                 gint *ns_y)
{
611
  GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
612 613 614 615 616 617 618 619 620 621 622 623 624

  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
625
{
626
  GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
Anders Carlsson's avatar
Anders Carlsson committed
627

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

631 632 633
  if (gdk_x)
    *gdk_x = ns_x - screen_quartz->min_x;
}
634

635 636 637 638 639 640 641
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
642 643
}

644 645 646 647 648
static GdkWindow *
find_child_window_helper (GdkWindow *window,
			  gint       x,
			  gint       y,
			  gint       x_offset,
649 650
			  gint       y_offset,
                          gboolean   get_toplevel)
651
{
652
  GdkWindowImplQuartz *impl;
653 654
  GList *l;

655
  impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
656 657 658 659 660

  if (window == _gdk_root)
    update_toplevel_order ();

  for (l = impl->sorted_children; l; l = l->next)
661
    {
662 663
      GdkWindow *child = l->data;
      GdkWindowImplQuartz *child_impl = GDK_WINDOW_IMPL_QUARTZ (child->impl);
664 665
      int temp_x, temp_y;

666
      if (!GDK_WINDOW_IS_MAPPED (child))
667 668
	continue;

669 670
      temp_x = x_offset + child->x;
      temp_y = y_offset + child->y;
671 672 673 674 675 676 677 678 679 680 681

      /* 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;
682
          NSUInteger mask;
683 684 685 686 687 688 689 690 691 692 693
          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 &&
694
              x < temp_x + child->width && y < temp_y)
695 696 697 698 699 700 701 702
            {
              /* The root means "unknown" i.e. a window not managed by
               * GDK.
               */
              return (GdkWindow *)_gdk_root;
            }
        }

703 704
      if ((!get_toplevel || (get_toplevel && window == _gdk_root)) &&
          x >= temp_x && y >= temp_y &&
705
	  x < temp_x + child->width && y < temp_y + child->height)
706 707 708 709
	{
	  /* Look for child windows. */
	  return find_child_window_helper (l->data,
					   x, y,
710 711
					   temp_x, temp_y,
                                           get_toplevel);
712 713 714 715 716 717 718
	}
    }
  
  return window;
}

/* Given a GdkWindow and coordinates relative to it, returns the
719 720
 * innermost subwindow that contains the point. If the coordinates are
 * outside the passed in window, NULL is returned.
721 722 723 724
 */
GdkWindow *
_gdk_quartz_window_find_child (GdkWindow *window,
			       gint       x,
725 726
			       gint       y,
                               gboolean   get_toplevel)
727
{
728
  if (x >= 0 && y >= 0 && x < window->width && y < window->height)
729
    return find_child_window_helper (window, x, y, 0, 0, get_toplevel);
730 731 732 733

  return NULL;
}

734

735 736 737 738 739
void
_gdk_quartz_window_did_become_main (GdkWindow *window)
{
  main_window_stack = g_slist_remove (main_window_stack, window);

740
  if (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 747 748 749 750 751 752 753 754 755 756
}

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;

757
      toplevels = gdk_screen_get_toplevel_windows (gdk_screen_get_default ());
758 759 760 761 762 763 764 765
      if (toplevels)
        new_window = toplevels->data;
      g_list_free (toplevels);
    }

  if (new_window &&
      new_window != window &&
      GDK_WINDOW_IS_MAPPED (new_window) &&
766
      WINDOW_IS_TOPLEVEL (new_window))
767
    {
768
      GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (new_window->impl);
769 770 771

      [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
    }
772 773

  clear_toplevel_order ();
774 775
}

776
static NSScreen *
777
get_nsscreen_for_point (gint x, gint y)
778 779 780
{
  int i;
  NSArray *screens;
781
  NSScreen *screen = NULL;
782 783 784 785 786 787 788 789 790

  GDK_QUARTZ_ALLOC_POOL;

  screens = [NSScreen screens];

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

791 792
      if (x >= rect.origin.x && x <= rect.origin.x + rect.size.width &&
          y >= rect.origin.y && y <= rect.origin.y + rect.size.height)
793 794 795 796
        {
          screen = [screens objectAtIndex:i];
          break;
        }
797 798 799 800
    }

  GDK_QUARTZ_RELEASE_POOL;

801
  return screen;
802 803
}

804
void
805 806 807 808 809 810 811
_gdk_quartz_display_create_window_impl (GdkDisplay    *display,
                                        GdkWindow     *window,
                                        GdkWindow     *real_parent,
                                        GdkScreen     *screen,
                                        GdkEventMask   event_mask,
                                        GdkWindowAttr *attributes,
                                        gint           attributes_mask)
Anders Carlsson's avatar
Anders Carlsson committed
812 813
{
  GdkWindowImplQuartz *impl;
814
  GdkWindowImplQuartz *parent_impl;
Anders Carlsson's avatar
Anders Carlsson committed
815

816
  GDK_QUARTZ_ALLOC_POOL;
Anders Carlsson's avatar
Anders Carlsson committed
817

818
  impl = g_object_new (GDK_TYPE_WINDOW_IMPL_QUARTZ, NULL);
819 820
  window->impl = GDK_WINDOW_IMPL (impl);
  impl->wrapper = window;
Anders Carlsson's avatar
Anders Carlsson committed
821

822
  parent_impl = GDK_WINDOW_IMPL_QUARTZ (window->parent->impl);
Anders Carlsson's avatar
Anders Carlsson committed
823

824
  switch (window->window_type)
Anders Carlsson's avatar
Anders Carlsson committed
825 826 827
    {
    case GDK_WINDOW_TOPLEVEL:
    case GDK_WINDOW_TEMP:
828
      if (GDK_WINDOW_TYPE (window->parent) != GDK_WINDOW_ROOT)
Anders Carlsson's avatar
Anders Carlsson committed
829
	{
830
	  /* The common code warns for this case */
831
          parent_impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
Anders Carlsson's avatar
Anders Carlsson committed
832 833 834
	}
    }

835
  /* Maintain the z-ordered list of children. */
836
  if (window->parent != _gdk_root)
837 838 839
    parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window);
  else
    clear_toplevel_order ();
Anders Carlsson's avatar
Anders Carlsson committed
840 841 842 843 844

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

845 846
  impl->view = NULL;

847
  switch (window->window_type)
Anders Carlsson's avatar
Anders Carlsson committed
848 849 850 851
    {
    case GDK_WINDOW_TOPLEVEL:
    case GDK_WINDOW_TEMP:
      {
852 853
        NSScreen *screen;
        NSRect screen_rect;
854
        NSRect content_rect;
855
        NSUInteger style_mask;
856
        int nx, ny;
857 858
        const char *title;

859 860 861 862 863
        /* 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.
         */
864
        _gdk_quartz_window_gdk_xy_to_xy (window->x, window->y, &nx, &ny);
865

866
        screen = get_nsscreen_for_point (nx, ny);
867 868 869 870
        screen_rect = [screen frame];
        nx -= screen_rect.origin.x;
        ny -= screen_rect.origin.y;

871 872 873
        content_rect = NSMakeRect (nx, ny - window->height,
                                   window->width,
                                   window->height);
Anders Carlsson's avatar
Anders Carlsson committed
874

875 876 877
        if (window->window_type == GDK_WINDOW_TEMP ||
            ((attributes_mask & GDK_WA_TYPE_HINT) &&
              attributes->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN))
878 879
          {
            style_mask = NSBorderlessWindowMask;
880 881 882
          }
        else
          {
883 884 885 886 887
            style_mask = (NSTitledWindowMask |
                          NSClosableWindowMask |
                          NSMiniaturizableWindowMask |
                          NSResizableWindowMask);
          }
Anders Carlsson's avatar
Anders Carlsson committed
888

889 890 891 892 893
	impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:content_rect 
			                                      styleMask:style_mask
			                                        backing:NSBackingStoreBuffered
			                                          defer:NO
                                                                  screen:screen];
Michael Natterer's avatar
Michael Natterer committed
894

Anders Carlsson's avatar
Anders Carlsson committed
895 896 897 898 899 900
	if (attributes_mask & GDK_WA_TITLE)
	  title = attributes->title;
	else
	  title = get_default_title ();

	gdk_window_set_title (window, title);
901
  
902
	if (gdk_window_get_visual (window) == gdk_screen_get_rgba_visual (_gdk_screen))
Anders Carlsson's avatar
Anders Carlsson committed
903 904 905 906 907
	  {
	    [impl->toplevel setOpaque:NO];
	    [impl->toplevel setBackgroundColor:[NSColor clearColor]];
	  }

908 909 910
        content_rect.origin.x = 0;
        content_rect.origin.y = 0;

Anders Carlsson's avatar
Anders Carlsson committed
911 912 913
	impl->view = [[GdkQuartzView alloc] initWithFrame:content_rect];
	[impl->view setGdkWindow:window];
	[impl->toplevel setContentView:impl->view];
914
	[impl->view release];
Anders Carlsson's avatar
Anders Carlsson committed
915 916
      }
      break;
917

Anders Carlsson's avatar
Anders Carlsson committed
918 919
    case GDK_WINDOW_CHILD:
      {
920
	GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (window->parent->impl);
Anders Carlsson's avatar
Anders Carlsson committed
921

922
	if (!window->input_only)
Anders Carlsson's avatar
Anders Carlsson committed
923
	  {
924 925 926 927
	    NSRect frame_rect = NSMakeRect (window->x + window->parent->abs_x,
                                            window->y + window->parent->abs_y,
                                            window->width,
                                            window->height);
Anders Carlsson's avatar
Anders Carlsson committed
928 929 930 931 932 933 934 935
	
	    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];
936
	    [impl->view release];
Anders Carlsson's avatar
Anders Carlsson committed
937 938 939
	  }
      }
      break;
940

Anders Carlsson's avatar
Anders Carlsson committed
941 942 943 944 945 946
    default:
      g_assert_not_reached ();
    }

  GDK_QUARTZ_RELEASE_POOL;

947 948
  if (attributes_mask & GDK_WA_TYPE_HINT)
    gdk_window_set_type_hint (window, attributes->type_hint);
Anders Carlsson's avatar
Anders Carlsson committed
949 950
}

951
void
952
_gdk_quartz_window_update_position (GdkWindow *window)
953
{
954 955
  NSRect frame_rect;
  NSRect content_rect;
956
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
957 958 959 960 961 962 963 964

  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,
965
                                   &window->x, &window->y);
966 967 968 969 970 971


  GDK_QUARTZ_RELEASE_POOL;
}

void
972 973
_gdk_quartz_window_init_windowing (GdkDisplay *display,
                                   GdkScreen  *screen)
Anders Carlsson's avatar
Anders Carlsson committed
974
{
975
  GdkWindowImplQuartz *impl;
Anders Carlsson's avatar
Anders Carlsson committed
976 977 978

  g_assert (_gdk_root == NULL);

979
  _gdk_root = _gdk_display_create_window (display);
980

981 982
  _gdk_root->impl = g_object_new (_gdk_root_window_impl_quartz_get_type (), NULL);
  _gdk_root->impl_window = _gdk_root;
983
  _gdk_root->visual = gdk_screen_get_system_visual (screen);
984

985
  impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
986

987
  _gdk_quartz_screen_update_window_sizes (screen);
988

989 990 991 992
  _gdk_root->state = 0; /* We don't want GDK_WINDOW_STATE_WITHDRAWN here */
  _gdk_root->window_type = GDK_WINDOW_ROOT;
  _gdk_root->depth = 24;
  _gdk_root->viewable = TRUE;
993

994
  impl->wrapper = _gdk_root;
Anders Carlsson's avatar
Anders Carlsson committed
995 996
}

997
static void
998 999 1000
gdk_quartz_window_destroy (GdkWindow *window,
                           gboolean   recursing,
                           gboolean   foreign_destroy)
Anders Carlsson's avatar
Anders Carlsson committed
1001
{
1002
  GdkWindowImplQuartz *impl;
1003
  GdkWindow *parent;
1004

1005
  impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1006

1007
  main_window_stack = g_slist_remove (main_window_stack, window);
1008

1009 1010 1011
  g_list_free (impl->sorted_children);
  impl->sorted_children = NULL;

1012
  parent = window->parent;
1013 1014 1015 1016 1017 1018 1019
  if (parent)
    {
      GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);

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

1020 1021 1022 1023 1024 1025 1026
  if (impl->cairo_surface)
    {
      cairo_surface_finish (impl->cairo_surface);
      cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
				   NULL, NULL);
      impl->cairo_surface = NULL;
    }
Anders Carlsson's avatar
Anders Carlsson committed
1027

1028 1029
  if (!recursing && !foreign_destroy)
    {
1030 1031
      GDK_QUARTZ_ALLOC_POOL;

Anders Carlsson's avatar
Anders Carlsson committed
1032 1033 1034
      if (impl->toplevel)
	[impl->toplevel close];
      else if (impl->view)
1035
	[impl->view removeFromSuperview];
1036 1037

      GDK_QUARTZ_RELEASE_POOL;
Anders Carlsson's avatar
Anders Carlsson committed
1038 1039 1040
    }
}

1041 1042
static void
gdk_quartz_window_destroy_foreign (GdkWindow *window)
Anders Carlsson's avatar
Anders Carlsson committed
1043
{
1044
  /* Foreign windows aren't supported in OSX. */
Anders Carlsson's avatar
Anders Carlsson committed
1045 1046
}

1047 1048 1049
/* FIXME: This might be possible to simplify with client-side windows. Also
 * note that already_mapped is not used yet, see the x11 backend.
*/
Anders Carlsson's avatar
Anders Carlsson committed
1050
static void
1051
gdk_window_quartz_show (GdkWindow *window, gboolean already_mapped)
Anders Carlsson's avatar
Anders Carlsson committed
1052
{
1053
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1054
  gboolean focus_on_map;
Anders Carlsson's avatar
Anders Carlsson committed
1055 1056 1057

  GDK_QUARTZ_ALLOC_POOL;

1058
  if (!GDK_WINDOW_IS_MAPPED (window))
1059
    focus_on_map = window->focus_on_map;
1060 1061 1062
  else
    focus_on_map = TRUE;

1063
  if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel)
Anders Carlsson's avatar
Anders Carlsson committed
1064
    {
1065 1066
      gboolean make_key;

1067 1068
      make_key = (window->accept_focus && focus_on_map &&
                  window->window_type != GDK_WINDOW_TEMP);
1069

1070
      [(GdkQuartzNSWindow*)impl->toplevel showAndMakeKey:make_key];
1071
      clear_toplevel_order ();
1072

1073
      _gdk_quartz_events_send_map_event (window);
Anders Carlsson's avatar
Anders Carlsson committed
1074 1075 1076 1077 1078 1079
    }
  else
    {
      [impl->view setHidden:NO];
    }

1080 1081
  [impl->view setNeedsDisplay:YES];

Anders Carlsson's avatar
Anders Carlsson committed
1082 1083
  gdk_synthesize_window_state (window, GDK_WINDOW_STATE_WITHDRAWN, 0);

1084
  if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
1085 1086
    gdk_window_maximize (window);

1087
  if (window->state & GDK_WINDOW_STATE_ICONIFIED)
1088 1089
    gdk_window_iconify (window);

1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
  if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
    _gdk_quartz_window_attach_to_parent (window);

  GDK_QUARTZ_RELEASE_POOL;
}

/* Temporarily unsets the parent window, if the window is a
 * transient. 
 */
void
_gdk_quartz_window_detach_from_parent (GdkWindow *window)
{
  GdkWindowImplQuartz *impl;

  g_return_if_fail (GDK_IS_WINDOW (window));

1106
  impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1107 1108 1109
  
  g_return_if_fail (impl->toplevel != NULL);

1110 1111 1112 1113
  if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
    {
      GdkWindowImplQuartz *parent_impl;

1114
      parent_impl = GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
1115
      [parent_impl->toplevel removeChildWindow:impl->toplevel];
1116
      clear_toplevel_order ();
1117
    }
1118
}
1119

1120 1121 1122 1123 1124 1125 1126 1127
/* Re-sets the parent window, if the window is a transient. */
void
_gdk_quartz_window_attach_to_parent (GdkWindow *window)
{
  GdkWindowImplQuartz *impl;

  g_return_if_fail (GDK_IS_WINDOW (window));

1128
  impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
1129 1130 1131 1132 1133 1134 1135
  
  g_return_if_fail (impl->toplevel != NULL);

  if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
    {
      GdkWindowImplQuartz *parent_impl;

1136
      parent_impl = GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
1137
      [parent_impl->toplevel addChildWindow:impl->toplevel ordered:NSWindowAbove];
1138
      clear_toplevel_order ();
1139
    }
Anders Carlsson's avatar
Anders Carlsson committed
1140 1141 1142
}

void
1143
gdk_window_quartz_hide (GdkWindow *window)
Anders Carlsson's avatar
Anders Carlsson committed
1144 1145 1146
{
  GdkWindowImplQuartz *impl;

1147
  /* Make sure we're not stuck in fullscreen mode. */
1148
#ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
1149
  if (get_fullscreen_geometry (window))
1150
    SetSystemUIMode (kUIModeNormal, 0);
1151
#endif
1152

1153 1154
  check_grab_unmap (window);

Anders Carlsson's avatar
Anders Carlsson committed
1155 1156
  _gdk_window_clear_update_area (window);

1157
  impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
Anders Carlsson's avatar
Anders Carlsson committed
1158

1159
  if (WINDOW_IS_TOPLEVEL (window)) 
Anders Carlsson's avatar
Anders Carlsson committed
1160
    {
1161
     /* Update main window. */
1162 1163 1164 1165
      main_window_stack = g_slist_remove (main_window_stack, window);
      if ([NSApp mainWindow] == impl->toplevel)
        _gdk_quartz_window_did_resign_main (window);

1166
      if (impl->transient_for)
1167
        _gdk_quartz_window_detach_from_parent (window);
1168

1169
      [(GdkQuartzNSWindow*)impl->toplevel hide];
Anders Carlsson's avatar
Anders Carlsson committed
1170 1171 1172 1173 1174 1175 1176 1177
    }
  else if (impl->view)
    {
      [impl->view setHidden:YES];
    }
}

void
1178
gdk_window_quartz_withdraw (GdkWindow *window)
Anders Carlsson's avatar
Anders Carlsson committed
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
{
  gdk_window_hide (window);
}

static void
move_resize_window_internal (GdkWindow *window,
			     gint       x,
			     gint       y,
			     gint       width,
			     gint       height)
{
  GdkWindowImplQuartz *impl;
1191 1192 1193
  GdkRectangle old_visible;
  GdkRectangle new_visible;
  GdkRectangle scroll_rect;
1194 1195
  cairo_region_t *old_region;
  cairo_region_t *expose_region;
1196
  NSSize delta;
Anders Carlsson's avatar
Anders Carlsson committed
1197 1198

  if (GDK_WINDOW_DESTROYED (window))
1199
    return;
Anders Carlsson's avatar
Anders Carlsson committed
1200

1201
  impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
Anders Carlsson's avatar
Anders Carlsson committed
1202

1203 1204 1205 1206
  if ((x == -1 || (x == window->x)) &&
      (y == -1 || (y == window->y)) &&
      (width == -1 || (width == window->width)) &&
      (height == -1 || (height == window->height)))
1207 1208 1209 1210
    {
      return;
    }

1211 1212 1213 1214 1215
  if (!impl->toplevel)
    {
      /* The previously visible area of this window in a coordinate
       * system rooted at the origin of this window.
       */
1216 1217
      old_visible.x = -window->x;
      old_visible.y = -window->y;
1218

1219 1220
      old_visible.width = window->width;
      old_visible.height = window->height;
1221 1222
    }

Anders Carlsson's avatar
Anders Carlsson committed
1223
  if (x != -1)
1224
    {
1225 1226
      delta.width = x - window->x;
      window->x = x;
1227 1228 1229 1230 1231
    }
  else
    {
      delta.width = 0;
    }
Anders Carlsson's avatar
Anders Carlsson committed
1232 1233

  if (y != -1)
1234
    {
1235 1236
      delta.height = y - window->y;
      window->y = y;
1237 1238 1239 1240 1241
    }
  else
    {
      delta.height = 0;
    }
Anders Carlsson's avatar
Anders Carlsson committed
1242 1243

  if (width != -1)
1244
    window->width = width;
Anders Carlsson's avatar
Anders Carlsson committed
1245 1246

  if (height != -1)
1247
    window->height = height;
Anders Carlsson's avatar
Anders Carlsson committed
1248

1249 1250
  GDK_QUARTZ_ALLOC_POOL;

Anders Carlsson's avatar
Anders Carlsson committed
1251 1252
  if (impl->toplevel)
    {
1253 1254
      NSRect content_rect;
      NSRect frame_rect;
1255
      gint gx, gy;
1256

1257
      _gdk_quartz_window_gdk_xy_to_xy (window->x, window->y + window->height,
1258 1259
                                       &gx, &gy);

1260
      content_rect = NSMakeRect (gx, gy, window->width, window->height);
1261

1262 1263
      frame_rect = [impl->toplevel frameRectForContentRect:content_rect];
      [impl->toplevel setFrame:frame_rect display:YES];
Anders Carlsson's avatar
Anders Carlsson committed
1264 1265 1266
    }
  else 
    {
1267
      if (!window->input_only)
1268 1269
        {
          NSRect nsrect;
1270

1271
          nsrect = NSMakeRect (window->x, window->y, window->width, window->height);
1272 1273 1274 1275

          /* The newly visible area of this window in a coordinate
           * system rooted at the origin of this window.
           */
1276 1277
          new_visible.x = -window->x;
          new_visible.y = -window->y;
1278 1279 1280
          new_visible.width = old_visible.width;   /* parent has not changed size */
          new_visible.height = old_visible.height; /* parent has not changed size */

1281 1282 1283
          expose_region = cairo_region_create_rectangle (&new_visible);
          old_region = cairo_region_create_rectangle (&old_visible);
          cairo_region_subtract (expose_region, old_region);
1284 1285 1286 1287 1288 1289 1290 1291 1292

          /* Determine what (if any) part of the previously visible
           * part of the window can be copied without a redraw
           */
          scroll_rect = old_visible;
          scroll_rect.x -= delta.width;
          scroll_rect.y -= delta.height;
          gdk_rectangle_intersect (&scroll_rect, &old_visible, &scroll_rect);

1293
          if (!cairo_region_is_empty (expose_region))
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
            {
              if (scroll_rect.width != 0 && scroll_rect.height != 0)
                {
                  [impl->view scrollRect:NSMakeRect (scroll_rect.x,
                                                     scroll_rect.y,
                                                     scroll_rect.width,
                                                     scroll_rect.height)
			              by:delta];
                }

              [impl->view setFrame:nsrect];

1306
              gdk_quartz_window_set_needs_display_in_region (window, expose_region);
1307 1308 1309 1310 1311 1312 1313
            }
          else
            {
              [impl->view setFrame:nsrect];
              [impl->view setNeedsDisplay:YES];
            }

1314 1315
          cairo_region_destroy (expose_region);
          cairo_region_destroy (old_region);
1316
        }
Anders Carlsson's avatar
Anders Carlsson committed
1317
    }
1318 1319

  GDK_QUARTZ_RELEASE_POOL;
Anders Carlsson's avatar
Anders Carlsson committed
1320 1321
}

1322 1323 1324 1325
static inline void
window_quartz_move (GdkWindow *window,
                    gint       x,
                    gint       y)
Anders Carlsson's avatar
Anders Carlsson committed
1326 1327 1328
{
  g_return_if_fail (GDK_IS_WINDOW (window));

1329
  if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1330 1331
    return;

Anders Carlsson's avatar
Anders Carlsson committed
1332 1333 1334
  move_resize_window_internal (window, x, y, -1, -1);
}

1335 1336 1337 1338
static inline void
window_quartz_resize (GdkWindow *window,
                      gint       width,
                      gint       height)
Anders Carlsson's avatar
Anders Carlsson committed
1339 1340 1341
{
  g_return_if_fail (GDK_IS_WINDOW (window));

1342
  if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
1343 1344
    return;

Anders Carlsson's avatar
Anders Carlsson committed
1345 1346 1347 1348 1349 1350 1351 1352
  if (width < 1)
    width = 1;
  if (height < 1)
    height = 1;

  move_resize_window_internal (window, -1, -1, width, height);
}

1353 1354 1355 1356 1357 1358
static inline void
window_quartz_move_resize (GdkWindow *window,
                           gint       x,
                           gint       y,
                           gint       width,
                           gint       height)
Anders Carlsson's avatar
Anders Carlsson committed
1359 1360 1361 1362 1363 1364 1365 1366 1367
{
  if (width < 1)
    width = 1;
  if (height < 1)
    height = 1;

  move_resize_window_internal (window, x, y,