forked from AuroraMiddleware/gtk
36315cbe2b
In macOS-12.sdk CGContextConverSizeToDeviceSpace returns a negative height and passing that to CGContextScaleCTM in turn causes the cairo surface to draw outside the window where it can't be seen. Passing the absolute values of the scale factors fixes the display on macOS 12 without affecting earlier macOS versions.
3275 lines
89 KiB
C
3275 lines
89 KiB
C
/* gdkwindow-quartz.c
|
||
*
|
||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||
* Copyright (C) 2005-2007 Imendio AB
|
||
*
|
||
* 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, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include "config.h"
|
||
|
||
#include <gdk/gdk.h>
|
||
#include <gdk/gdkdeviceprivate.h>
|
||
#include <gdk/gdkdisplayprivate.h>
|
||
|
||
#include "gdkwindowimpl.h"
|
||
#include "gdkwindow-quartz.h"
|
||
#include "gdkprivate-quartz.h"
|
||
#include "gdkglcontext-quartz.h"
|
||
#include "gdkquartzglcontext.h"
|
||
#include "gdkquartzscreen.h"
|
||
#include "gdkquartzcursor.h"
|
||
#include "gdkquartz-cocoa-access.h"
|
||
#include "gdkinternal-quartz.h"
|
||
|
||
#include <Carbon/Carbon.h>
|
||
#include <AvailabilityMacros.h>
|
||
|
||
#include <sys/time.h>
|
||
#include <cairo-quartz.h>
|
||
|
||
static gpointer parent_class;
|
||
static gpointer root_window_parent_class;
|
||
|
||
static GSList *update_nswindows;
|
||
static gboolean in_process_all_updates = FALSE;
|
||
|
||
static GSList *main_window_stack;
|
||
|
||
void _gdk_quartz_window_flush (GdkWindowImplQuartz *window_impl);
|
||
|
||
typedef struct
|
||
{
|
||
gint x, y;
|
||
gint width, height;
|
||
GdkWMDecoration decor;
|
||
} FullscreenSavedGeometry;
|
||
|
||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
|
||
typedef enum
|
||
{
|
||
GDK_QUARTZ_BORDERLESS_WINDOW = NSBorderlessWindowMask,
|
||
GDK_QUARTZ_CLOSABLE_WINDOW = NSClosableWindowMask,
|
||
#if MAC_OS_X_VERSION_MIN_REQUIRED > 1060
|
||
/* Added in 10.7. Apple's docs are wrong to say it's from earlier. */
|
||
GDK_QUARTZ_FULLSCREEN_WINDOW = NSFullScreenWindowMask,
|
||
#endif
|
||
GDK_QUARTZ_MINIATURIZABLE_WINDOW = NSMiniaturizableWindowMask,
|
||
GDK_QUARTZ_RESIZABLE_WINDOW = NSResizableWindowMask,
|
||
GDK_QUARTZ_TITLED_WINDOW = NSTitledWindowMask,
|
||
} GdkQuartzWindowMask;
|
||
#else
|
||
typedef enum
|
||
{
|
||
GDK_QUARTZ_BORDERLESS_WINDOW = NSWindowStyleMaskBorderless,
|
||
GDK_QUARTZ_CLOSABLE_WINDOW = NSWindowStyleMaskClosable,
|
||
GDK_QUARTZ_FULLSCREEN_WINDOW = NSWindowStyleMaskFullScreen,
|
||
GDK_QUARTZ_MINIATURIZABLE_WINDOW = NSWindowStyleMaskMiniaturizable,
|
||
GDK_QUARTZ_RESIZABLE_WINDOW = NSWindowStyleMaskResizable,
|
||
GDK_QUARTZ_TITLED_WINDOW = NSWindowStyleMaskTitled,
|
||
} GdkQuartzWindowMask;
|
||
#endif
|
||
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
static FullscreenSavedGeometry *get_fullscreen_geometry (GdkWindow *window);
|
||
#endif
|
||
|
||
#define FULLSCREEN_DATA "fullscreen-data"
|
||
|
||
static void update_toplevel_order (void);
|
||
static void clear_toplevel_order (void);
|
||
|
||
#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)
|
||
|
||
/*
|
||
* 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
|
||
*/
|
||
|
||
NSView *
|
||
gdk_quartz_window_get_nsview (GdkWindow *window)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return NULL;
|
||
|
||
return ((GdkWindowImplQuartz *)window->impl)->view;
|
||
}
|
||
|
||
NSWindow *
|
||
gdk_quartz_window_get_nswindow (GdkWindow *window)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return NULL;
|
||
|
||
return ((GdkWindowImplQuartz *)window->impl)->toplevel;
|
||
}
|
||
|
||
static CGContextRef
|
||
gdk_window_impl_quartz_get_context (GdkWindowImplQuartz *window_impl,
|
||
gboolean antialias)
|
||
{
|
||
CGContextRef cg_context = NULL;
|
||
CGSize scale;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window_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
|
||
* buttons in spinbuttons or the position marker in rulers.
|
||
*/
|
||
if (window_impl->in_paint_rect_count == 0)
|
||
{
|
||
if (![window_impl->view lockFocusIfCanDraw])
|
||
return NULL;
|
||
}
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101000
|
||
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
|
||
#else
|
||
if (gdk_quartz_osx_version () < GDK_OSX_YOSEMITE)
|
||
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
|
||
else
|
||
cg_context = [[NSGraphicsContext currentContext] CGContext];
|
||
#endif
|
||
|
||
if (!cg_context)
|
||
return NULL;
|
||
CGContextSaveGState (cg_context);
|
||
CGContextSetAllowsAntialiasing (cg_context, antialias);
|
||
|
||
/* 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 / fabs(scale.width), 1.0 / fabs(scale.height));
|
||
return cg_context;
|
||
}
|
||
|
||
static void
|
||
gdk_window_impl_quartz_release_context (GdkWindowImplQuartz *window_impl,
|
||
CGContextRef cg_context)
|
||
{
|
||
if (cg_context)
|
||
{
|
||
CGContextRestoreGState (cg_context);
|
||
CGContextSetAllowsAntialiasing (cg_context, TRUE);
|
||
}
|
||
|
||
/* See comment in gdk_quartz_window_get_context(). */
|
||
if (window_impl->in_paint_rect_count == 0)
|
||
{
|
||
_gdk_quartz_window_flush (window_impl);
|
||
[window_impl->view unlockFocus];
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_window_impl_quartz_finalize (GObject *object)
|
||
{
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (object);
|
||
GdkDisplay *display = gdk_window_get_display (impl->wrapper);
|
||
GdkSeat *seat = gdk_display_get_default_seat (display);
|
||
|
||
gdk_seat_ungrab (seat);
|
||
|
||
if (impl->transient_for)
|
||
g_object_unref (impl->transient_for);
|
||
|
||
if (impl->view)
|
||
[[NSNotificationCenter defaultCenter] removeObserver: impl->toplevel
|
||
name: @"NSViewFrameDidChangeNotification"
|
||
object: impl->view];
|
||
|
||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||
}
|
||
|
||
/* 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
|
||
* for some quick manual flushes (such as gtkruler or gimp’s marching ants)
|
||
* without hitting the max flush frequency.
|
||
*
|
||
* If drawable NULL, no flushing is done, only registering that a flush was
|
||
* done externally.
|
||
*
|
||
* Note: As of MacOS 10.14 NSWindow flushWindow is deprecated because
|
||
* Quartz has the ability to handle deferred drawing on its own.
|
||
*/
|
||
void
|
||
_gdk_quartz_window_flush (GdkWindowImplQuartz *window_impl)
|
||
{
|
||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
|
||
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;
|
||
#endif
|
||
}
|
||
|
||
static cairo_user_data_key_t gdk_quartz_cairo_key;
|
||
|
||
typedef struct {
|
||
GdkWindowImplQuartz *window_impl;
|
||
CGContextRef cg_context;
|
||
} GdkQuartzCairoSurfaceData;
|
||
|
||
static void
|
||
gdk_quartz_cairo_surface_destroy (void *data)
|
||
{
|
||
GdkQuartzCairoSurfaceData *surface_data = data;
|
||
|
||
surface_data->window_impl->cairo_surface = NULL;
|
||
|
||
gdk_quartz_window_release_context (surface_data->window_impl,
|
||
surface_data->cg_context);
|
||
|
||
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);
|
||
|
||
surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
|
||
surface_data->window_impl = impl;
|
||
surface_data->cg_context = cg_context;
|
||
|
||
if (cg_context)
|
||
surface = cairo_quartz_surface_create_for_cg_context (cg_context,
|
||
width, height);
|
||
else
|
||
surface = cairo_quartz_surface_create(CAIRO_FORMAT_ARGB32, 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)
|
||
{
|
||
gint scale = gdk_window_get_scale_factor (impl->wrapper);
|
||
|
||
impl->cairo_surface =
|
||
gdk_quartz_create_cairo_surface (impl,
|
||
gdk_window_get_width (impl->wrapper) * scale,
|
||
gdk_window_get_height (impl->wrapper) * scale);
|
||
|
||
cairo_surface_set_device_scale (impl->cairo_surface, scale, scale);
|
||
}
|
||
else
|
||
cairo_surface_reference (impl->cairo_surface);
|
||
|
||
return impl->cairo_surface;
|
||
}
|
||
|
||
static void
|
||
gdk_window_impl_quartz_init (GdkWindowImplQuartz *impl)
|
||
{
|
||
impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
|
||
}
|
||
|
||
static gboolean
|
||
gdk_window_impl_quartz_begin_paint (GdkWindow *window)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_needs_display_in_region (GdkWindow *window,
|
||
cairo_region_t *region)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
int i, n_rects;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (!impl->needs_display_region)
|
||
impl->needs_display_region = cairo_region_create ();
|
||
|
||
cairo_region_union (impl->needs_display_region, region);
|
||
|
||
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)];
|
||
}
|
||
}
|
||
|
||
void
|
||
_gdk_quartz_window_process_updates_recurse (GdkWindow *window,
|
||
cairo_region_t *region)
|
||
{
|
||
/* Make sure to only flush each toplevel at most once if we're called
|
||
* from process_all_updates.
|
||
*/
|
||
if (in_process_all_updates)
|
||
{
|
||
GdkWindow *toplevel;
|
||
|
||
toplevel = gdk_window_get_effective_toplevel (window);
|
||
if (toplevel && WINDOW_IS_TOPLEVEL (toplevel))
|
||
{
|
||
GdkWindowImplQuartz *toplevel_impl;
|
||
NSWindow *nswindow;
|
||
|
||
toplevel_impl = (GdkWindowImplQuartz *)toplevel->impl;
|
||
nswindow = toplevel_impl->toplevel;
|
||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
|
||
/* In theory, we could skip the flush disabling, since we only
|
||
* have one NSView.
|
||
*/
|
||
if (nswindow && ![nswindow isFlushWindowDisabled])
|
||
{
|
||
[nswindow retain];
|
||
[nswindow disableFlushWindow];
|
||
update_nswindows = g_slist_prepend (update_nswindows, nswindow);
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
if (WINDOW_IS_TOPLEVEL (window))
|
||
gdk_quartz_window_set_needs_display_in_region (window, region);
|
||
else
|
||
_gdk_window_process_updates_recurse (window, region);
|
||
|
||
/* 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.
|
||
*/
|
||
}
|
||
|
||
void
|
||
_gdk_quartz_display_before_process_all_updates (GdkDisplay *display)
|
||
{
|
||
in_process_all_updates = TRUE;
|
||
|
||
if (gdk_quartz_osx_version () >= GDK_OSX_EL_CAPITAN)
|
||
{
|
||
[NSAnimationContext endGrouping];
|
||
}
|
||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
|
||
else
|
||
{
|
||
NSDisableScreenUpdates ();
|
||
}
|
||
#endif
|
||
}
|
||
|
||
void
|
||
_gdk_quartz_display_after_process_all_updates (GdkDisplay *display)
|
||
{
|
||
GSList *tmp_list = update_nswindows;
|
||
|
||
update_nswindows = NULL;
|
||
|
||
while (tmp_list)
|
||
{
|
||
NSWindow *nswindow = tmp_list->data;
|
||
|
||
[[nswindow contentView] displayIfNeeded];
|
||
|
||
_gdk_quartz_window_flush (NULL);
|
||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
|
||
[nswindow enableFlushWindow];
|
||
[nswindow flushWindow];
|
||
#endif
|
||
[nswindow release];
|
||
|
||
tmp_list = g_slist_remove_link (tmp_list, tmp_list);
|
||
}
|
||
|
||
in_process_all_updates = FALSE;
|
||
|
||
if (gdk_quartz_osx_version() >= GDK_OSX_EL_CAPITAN)
|
||
{
|
||
[NSAnimationContext beginGrouping];
|
||
}
|
||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
|
||
else
|
||
{
|
||
NSEnableScreenUpdates ();
|
||
}
|
||
#endif
|
||
}
|
||
|
||
static const gchar *
|
||
get_default_title (void)
|
||
{
|
||
const char *title;
|
||
|
||
title = g_get_application_name ();
|
||
if (!title)
|
||
title = g_get_prgname ();
|
||
|
||
return title;
|
||
}
|
||
|
||
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)
|
||
{
|
||
while (child_window != ancestor_window)
|
||
{
|
||
child_x += child_window->x;
|
||
child_y += child_window->y;
|
||
|
||
child_window = child_window->parent;
|
||
}
|
||
|
||
*ancestor_x = child_x;
|
||
*ancestor_y = child_y;
|
||
}
|
||
|
||
void
|
||
_gdk_quartz_window_debug_highlight (GdkWindow *window, gint number)
|
||
{
|
||
gint x, y;
|
||
gint gx, gy;
|
||
GdkWindow *toplevel;
|
||
gint tx, ty;
|
||
static NSWindow *debug_window[10];
|
||
static NSRect old_rect[10];
|
||
NSRect rect;
|
||
NSColor *color;
|
||
|
||
g_return_if_fail (number >= 0 && number <= 9);
|
||
|
||
if (window == _gdk_root)
|
||
return;
|
||
|
||
if (window == NULL)
|
||
{
|
||
if (debug_window[number])
|
||
[debug_window[number] close];
|
||
debug_window[number] = NULL;
|
||
|
||
return;
|
||
}
|
||
|
||
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;
|
||
|
||
_gdk_quartz_window_gdk_xy_to_xy (x, y + window->height,
|
||
&gx, &gy);
|
||
|
||
rect = NSMakeRect (gx, gy, window->width, window->height);
|
||
|
||
if (debug_window[number] && NSEqualRects (rect, old_rect[number]))
|
||
return;
|
||
|
||
old_rect[number] = rect;
|
||
|
||
if (debug_window[number])
|
||
[debug_window[number] close];
|
||
|
||
debug_window[number] = [[NSWindow alloc] initWithContentRect:rect
|
||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
|
||
styleMask:(NSUInteger)GDK_QUARTZ_BORDERLESS_WINDOW
|
||
#else
|
||
styleMask:(NSWindowStyleMask)GDK_QUARTZ_BORDERLESS_WINDOW
|
||
#endif
|
||
backing:NSBackingStoreBuffered
|
||
defer:NO];
|
||
|
||
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;
|
||
}
|
||
|
||
[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];
|
||
|
||
[debug_window[number] orderFront:nil];
|
||
}
|
||
|
||
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)));
|
||
}
|
||
|
||
|
||
/* See notes on top of gdkscreen-quartz.c */
|
||
void
|
||
_gdk_quartz_window_gdk_xy_to_xy (gint gdk_x,
|
||
gint gdk_y,
|
||
gint *ns_x,
|
||
gint *ns_y)
|
||
{
|
||
GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
|
||
|
||
if (ns_y)
|
||
*ns_y = screen_quartz->orig_y - gdk_y;
|
||
|
||
if (ns_x)
|
||
*ns_x = gdk_x + screen_quartz->orig_x;
|
||
}
|
||
|
||
void
|
||
_gdk_quartz_window_xy_to_gdk_xy (gint ns_x,
|
||
gint ns_y,
|
||
gint *gdk_x,
|
||
gint *gdk_y)
|
||
{
|
||
GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
|
||
|
||
if (gdk_y)
|
||
*gdk_y = screen_quartz->orig_y - ns_y;
|
||
|
||
if (gdk_x)
|
||
*gdk_x = ns_x - screen_quartz->orig_x;
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
static GdkWindow *
|
||
find_child_window_helper (GdkWindow *window,
|
||
gint x,
|
||
gint y,
|
||
gint x_offset,
|
||
gint y_offset,
|
||
gboolean get_toplevel)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
GList *l;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (window == _gdk_root)
|
||
update_toplevel_order ();
|
||
|
||
for (l = impl->sorted_children; l; l = l->next)
|
||
{
|
||
GdkWindow *child = l->data;
|
||
GdkWindowImplQuartz *child_impl = GDK_WINDOW_IMPL_QUARTZ (child->impl);
|
||
int temp_x, temp_y;
|
||
|
||
if (!GDK_WINDOW_IS_MAPPED (child))
|
||
continue;
|
||
|
||
temp_x = x_offset + child->x;
|
||
temp_y = y_offset + child->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;
|
||
NSUInteger mask;
|
||
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 &&
|
||
x < temp_x + child->width && y < temp_y)
|
||
{
|
||
/* The root means "unknown" i.e. a window not managed by
|
||
* GDK.
|
||
*/
|
||
return (GdkWindow *)_gdk_root;
|
||
}
|
||
}
|
||
|
||
if ((!get_toplevel || (get_toplevel && window == _gdk_root)) &&
|
||
x >= temp_x && y >= temp_y &&
|
||
x < temp_x + child->width && y < temp_y + child->height)
|
||
{
|
||
/* Look for child windows. */
|
||
return find_child_window_helper (l->data,
|
||
x, y,
|
||
temp_x, temp_y,
|
||
get_toplevel);
|
||
}
|
||
}
|
||
|
||
return window;
|
||
}
|
||
|
||
/* Given a GdkWindow and coordinates relative to it, returns the
|
||
* innermost subwindow that contains the point. If the coordinates are
|
||
* outside the passed in window, NULL is returned.
|
||
*/
|
||
GdkWindow *
|
||
_gdk_quartz_window_find_child (GdkWindow *window,
|
||
gint x,
|
||
gint y,
|
||
gboolean get_toplevel)
|
||
{
|
||
if (x >= 0 && y >= 0 && x < window->width && y < window->height)
|
||
return find_child_window_helper (window, x, y, 0, 0, get_toplevel);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
/* Raises a transient window.
|
||
*/
|
||
static void
|
||
raise_transient (GdkWindowImplQuartz *impl)
|
||
{
|
||
/* In quartz the transient-for behavior is implemented by
|
||
* attaching the transient-for GdkNSWindows to the parent's
|
||
* GdkNSWindow. Stacking is managed by Quartz and the order
|
||
* is that of the parent's childWindows array. The only way
|
||
* to change that order is to remove the child from the
|
||
* parent and then add it back in.
|
||
*/
|
||
GdkWindowImplQuartz *parent_impl =
|
||
GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
|
||
[parent_impl->toplevel removeChildWindow:impl->toplevel];
|
||
[parent_impl->toplevel addChildWindow:impl->toplevel
|
||
ordered:NSWindowAbove];
|
||
}
|
||
|
||
void
|
||
_gdk_quartz_window_did_become_main (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
main_window_stack = g_slist_remove (main_window_stack, window);
|
||
|
||
if (window->window_type != GDK_WINDOW_TEMP)
|
||
main_window_stack = g_slist_prepend (main_window_stack, window);
|
||
|
||
if (impl->transient_for)
|
||
raise_transient (impl);
|
||
|
||
clear_toplevel_order ();
|
||
}
|
||
|
||
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;
|
||
|
||
toplevels = gdk_screen_get_toplevel_windows (gdk_screen_get_default ());
|
||
if (toplevels)
|
||
new_window = toplevels->data;
|
||
g_list_free (toplevels);
|
||
}
|
||
|
||
if (new_window &&
|
||
new_window != window &&
|
||
GDK_WINDOW_IS_MAPPED (new_window) &&
|
||
WINDOW_IS_TOPLEVEL (new_window))
|
||
{
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (new_window->impl);
|
||
|
||
[impl->toplevel makeKeyAndOrderFront:impl->toplevel];
|
||
}
|
||
|
||
clear_toplevel_order ();
|
||
}
|
||
|
||
static NSScreen *
|
||
get_nsscreen_for_point (gint x, gint y)
|
||
{
|
||
int i;
|
||
NSArray *screens;
|
||
NSScreen *screen = NULL;
|
||
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
screens = [NSScreen screens];
|
||
|
||
for (i = 0; i < [screens count]; i++)
|
||
{
|
||
NSRect rect = [[screens objectAtIndex:i] frame];
|
||
|
||
if (x >= rect.origin.x && x <= rect.origin.x + rect.size.width &&
|
||
y >= rect.origin.y && y <= rect.origin.y + rect.size.height)
|
||
{
|
||
screen = [screens objectAtIndex:i];
|
||
break;
|
||
}
|
||
}
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
|
||
return screen;
|
||
}
|
||
|
||
void
|
||
_gdk_quartz_display_create_window_impl (GdkDisplay *display,
|
||
GdkWindow *window,
|
||
GdkWindow *real_parent,
|
||
GdkScreen *screen,
|
||
GdkEventMask event_mask,
|
||
GdkWindowAttr *attributes,
|
||
gint attributes_mask)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
GdkWindowImplQuartz *parent_impl;
|
||
GdkWindowTypeHint type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
|
||
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
impl = g_object_new (GDK_TYPE_WINDOW_IMPL_QUARTZ, NULL);
|
||
window->impl = GDK_WINDOW_IMPL (impl);
|
||
impl->wrapper = window;
|
||
|
||
parent_impl = GDK_WINDOW_IMPL_QUARTZ (window->parent->impl);
|
||
|
||
switch (window->window_type)
|
||
{
|
||
case GDK_WINDOW_TOPLEVEL:
|
||
case GDK_WINDOW_TEMP:
|
||
if (GDK_WINDOW_TYPE (window->parent) != GDK_WINDOW_ROOT)
|
||
{
|
||
/* The common code warns for this case */
|
||
parent_impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
|
||
}
|
||
}
|
||
|
||
/* Maintain the z-ordered list of children. */
|
||
if (window->parent != _gdk_root)
|
||
parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window);
|
||
else
|
||
clear_toplevel_order ();
|
||
|
||
gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
|
||
(attributes->cursor) :
|
||
NULL));
|
||
|
||
impl->view = NULL;
|
||
|
||
if (attributes_mask & GDK_WA_TYPE_HINT)
|
||
{
|
||
type_hint = attributes->type_hint;
|
||
gdk_window_set_type_hint (window, type_hint);
|
||
}
|
||
|
||
switch (window->window_type)
|
||
{
|
||
case GDK_WINDOW_TOPLEVEL:
|
||
case GDK_WINDOW_TEMP:
|
||
{
|
||
NSScreen *screen;
|
||
NSRect screen_rect;
|
||
NSRect content_rect;
|
||
NSUInteger style_mask;
|
||
int nx, ny;
|
||
const char *title;
|
||
|
||
/* 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 (window->x, window->y, &nx, &ny);
|
||
|
||
screen = get_nsscreen_for_point (nx, ny);
|
||
screen_rect = [screen frame];
|
||
nx -= screen_rect.origin.x;
|
||
ny -= screen_rect.origin.y;
|
||
|
||
content_rect = NSMakeRect (nx, ny - window->height,
|
||
window->width,
|
||
window->height);
|
||
|
||
if (window->window_type == GDK_WINDOW_TEMP ||
|
||
type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN)
|
||
{
|
||
style_mask = GDK_QUARTZ_BORDERLESS_WINDOW;
|
||
}
|
||
else
|
||
{
|
||
style_mask = (GDK_QUARTZ_TITLED_WINDOW |
|
||
GDK_QUARTZ_CLOSABLE_WINDOW |
|
||
GDK_QUARTZ_MINIATURIZABLE_WINDOW |
|
||
GDK_QUARTZ_RESIZABLE_WINDOW);
|
||
}
|
||
|
||
impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:content_rect
|
||
styleMask:style_mask
|
||
backing:NSBackingStoreBuffered
|
||
defer:NO
|
||
screen:screen];
|
||
|
||
if (type_hint != GDK_WINDOW_TYPE_HINT_NORMAL)
|
||
impl->toplevel.excludedFromWindowsMenu = true;
|
||
|
||
if (attributes_mask & GDK_WA_TITLE)
|
||
title = attributes->title;
|
||
else
|
||
title = get_default_title ();
|
||
|
||
gdk_window_set_title (window, title);
|
||
|
||
if (gdk_window_get_visual (window) == gdk_screen_get_rgba_visual (_gdk_screen))
|
||
{
|
||
[impl->toplevel setOpaque:NO];
|
||
[impl->toplevel setBackgroundColor:[NSColor clearColor]];
|
||
}
|
||
|
||
content_rect.origin.x = 0;
|
||
content_rect.origin.y = 0;
|
||
|
||
impl->view = [[GdkQuartzView alloc] initWithFrame:content_rect];
|
||
[impl->view setGdkWindow:window];
|
||
[impl->toplevel setContentView:impl->view];
|
||
[[NSNotificationCenter defaultCenter] addObserver: impl->toplevel
|
||
selector: @selector (windowDidResize:)
|
||
name: @"NSViewFrameDidChangeNotification"
|
||
object: impl->view];
|
||
[impl->view release];
|
||
}
|
||
break;
|
||
|
||
case GDK_WINDOW_CHILD:
|
||
{
|
||
GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (window->parent->impl);
|
||
|
||
if (!window->input_only)
|
||
{
|
||
NSRect frame_rect = NSMakeRect (window->x + window->parent->abs_x,
|
||
window->y + window->parent->abs_y,
|
||
window->width,
|
||
window->height);
|
||
|
||
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];
|
||
[impl->view release];
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
g_assert_not_reached ();
|
||
}
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
|
||
void
|
||
_gdk_quartz_window_update_position (GdkWindow *window)
|
||
{
|
||
NSRect frame_rect;
|
||
NSRect content_rect;
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->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,
|
||
&window->x, &window->y);
|
||
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
|
||
void
|
||
_gdk_quartz_window_init_windowing (GdkDisplay *display,
|
||
GdkScreen *screen)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
g_assert (_gdk_root == NULL);
|
||
|
||
_gdk_root = _gdk_display_create_window (display);
|
||
|
||
_gdk_root->impl = g_object_new (_gdk_root_window_impl_quartz_get_type (), NULL);
|
||
_gdk_root->impl_window = _gdk_root;
|
||
_gdk_root->visual = gdk_screen_get_system_visual (screen);
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
|
||
|
||
_gdk_quartz_screen_update_window_sizes (screen);
|
||
|
||
_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;
|
||
|
||
impl->wrapper = _gdk_root;
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_destroy (GdkWindow *window,
|
||
gboolean recursing,
|
||
gboolean foreign_destroy)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
GdkWindow *parent;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
main_window_stack = g_slist_remove (main_window_stack, window);
|
||
|
||
g_list_free (impl->sorted_children);
|
||
impl->sorted_children = NULL;
|
||
|
||
parent = window->parent;
|
||
if (parent)
|
||
{
|
||
GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
|
||
|
||
parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window);
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
if (!recursing && !foreign_destroy)
|
||
{
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
if (impl->toplevel)
|
||
[impl->toplevel close];
|
||
else if (impl->view)
|
||
[impl->view removeFromSuperview];
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_destroy_foreign (GdkWindow *window)
|
||
{
|
||
/* Foreign windows aren't supported in OSX. */
|
||
}
|
||
|
||
/* FIXME: This might be possible to simplify with client-side windows. Also
|
||
* note that already_mapped is not used yet, see the x11 backend.
|
||
*/
|
||
static void
|
||
gdk_window_quartz_show (GdkWindow *window, gboolean already_mapped)
|
||
{
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
gboolean focus_on_map;
|
||
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
if (!GDK_WINDOW_IS_MAPPED (window))
|
||
focus_on_map = window->focus_on_map;
|
||
else
|
||
focus_on_map = TRUE;
|
||
|
||
if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel)
|
||
{
|
||
gboolean make_key;
|
||
|
||
make_key = (window->accept_focus && focus_on_map &&
|
||
window->window_type != GDK_WINDOW_TEMP);
|
||
|
||
[(GdkQuartzNSWindow*)impl->toplevel showAndMakeKey:make_key];
|
||
clear_toplevel_order ();
|
||
|
||
_gdk_quartz_events_send_map_event (window);
|
||
}
|
||
else
|
||
{
|
||
[impl->view setHidden:NO];
|
||
}
|
||
|
||
[impl->view setNeedsDisplay:YES];
|
||
|
||
gdk_synthesize_window_state (window, GDK_WINDOW_STATE_WITHDRAWN, 0);
|
||
|
||
if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
|
||
gdk_window_maximize (window);
|
||
|
||
if (window->state & GDK_WINDOW_STATE_ICONIFIED)
|
||
gdk_window_iconify (window);
|
||
|
||
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));
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
g_return_if_fail (impl->toplevel != NULL);
|
||
|
||
if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
|
||
{
|
||
GdkWindowImplQuartz *parent_impl;
|
||
|
||
parent_impl = GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
|
||
[parent_impl->toplevel removeChildWindow:impl->toplevel];
|
||
clear_toplevel_order ();
|
||
}
|
||
}
|
||
|
||
/* 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));
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
g_return_if_fail (impl->toplevel != NULL);
|
||
|
||
if (impl->transient_for && !GDK_WINDOW_DESTROYED (impl->transient_for))
|
||
{
|
||
GdkWindowImplQuartz *parent_impl;
|
||
|
||
parent_impl = GDK_WINDOW_IMPL_QUARTZ (impl->transient_for->impl);
|
||
[parent_impl->toplevel addChildWindow:impl->toplevel ordered:NSWindowAbove];
|
||
clear_toplevel_order ();
|
||
}
|
||
}
|
||
|
||
void
|
||
gdk_window_quartz_hide (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
GdkDisplay *display = gdk_window_get_display (window);
|
||
GdkSeat *seat = gdk_display_get_default_seat (display);
|
||
gdk_seat_ungrab (seat);
|
||
|
||
/* Make sure we're not stuck in fullscreen mode. */
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
if (get_fullscreen_geometry (window))
|
||
SetSystemUIMode (kUIModeNormal, 0);
|
||
#endif
|
||
|
||
_gdk_window_clear_update_area (window);
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (WINDOW_IS_TOPLEVEL (window))
|
||
{
|
||
/* Update main window. */
|
||
main_window_stack = g_slist_remove (main_window_stack, window);
|
||
if ([NSApp mainWindow] == impl->toplevel)
|
||
_gdk_quartz_window_did_resign_main (window);
|
||
|
||
if (impl->transient_for)
|
||
_gdk_quartz_window_detach_from_parent (window);
|
||
|
||
[(GdkQuartzNSWindow*)impl->toplevel hide];
|
||
}
|
||
else if (impl->view)
|
||
{
|
||
[impl->view setHidden:YES];
|
||
}
|
||
}
|
||
|
||
void
|
||
gdk_window_quartz_withdraw (GdkWindow *window)
|
||
{
|
||
gdk_window_hide (window);
|
||
}
|
||
|
||
static void
|
||
move_resize_window_internal (GdkWindow *window,
|
||
gint x,
|
||
gint y,
|
||
gint width,
|
||
gint height)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
GdkRectangle old_visible;
|
||
GdkRectangle new_visible;
|
||
GdkRectangle scroll_rect;
|
||
cairo_region_t *old_region;
|
||
cairo_region_t *expose_region;
|
||
NSSize delta;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if ((x == -1 || (x == window->x)) &&
|
||
(y == -1 || (y == window->y)) &&
|
||
(width == -1 || (width == window->width)) &&
|
||
(height == -1 || (height == window->height)))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (!impl->toplevel)
|
||
{
|
||
/* The previously visible area of this window in a coordinate
|
||
* system rooted at the origin of this window.
|
||
*/
|
||
old_visible.x = -window->x;
|
||
old_visible.y = -window->y;
|
||
|
||
old_visible.width = window->width;
|
||
old_visible.height = window->height;
|
||
}
|
||
|
||
if (x != -1)
|
||
{
|
||
delta.width = x - window->x;
|
||
window->x = x;
|
||
}
|
||
else
|
||
{
|
||
delta.width = 0;
|
||
}
|
||
|
||
if (y != -1)
|
||
{
|
||
delta.height = y - window->y;
|
||
window->y = y;
|
||
}
|
||
else
|
||
{
|
||
delta.height = 0;
|
||
}
|
||
|
||
if (width != -1)
|
||
window->width = width;
|
||
|
||
if (height != -1)
|
||
window->height = height;
|
||
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
if (impl->toplevel)
|
||
{
|
||
NSRect content_rect;
|
||
NSRect frame_rect;
|
||
gint gx, gy;
|
||
|
||
_gdk_quartz_window_gdk_xy_to_xy (window->x, window->y + window->height,
|
||
&gx, &gy);
|
||
|
||
content_rect = NSMakeRect (gx, gy, window->width, window->height);
|
||
|
||
frame_rect = [impl->toplevel frameRectForContentRect:content_rect];
|
||
[impl->toplevel setFrame:frame_rect display:YES];
|
||
}
|
||
else
|
||
{
|
||
if (!window->input_only)
|
||
{
|
||
NSRect nsrect;
|
||
|
||
nsrect = NSMakeRect (window->x, window->y, window->width, window->height);
|
||
|
||
/* The newly visible area of this window in a coordinate
|
||
* system rooted at the origin of this window.
|
||
*/
|
||
new_visible.x = -window->x;
|
||
new_visible.y = -window->y;
|
||
new_visible.width = old_visible.width; /* parent has not changed size */
|
||
new_visible.height = old_visible.height; /* parent has not changed size */
|
||
|
||
expose_region = cairo_region_create_rectangle (&new_visible);
|
||
old_region = cairo_region_create_rectangle (&old_visible);
|
||
cairo_region_subtract (expose_region, old_region);
|
||
|
||
/* 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);
|
||
|
||
if (!cairo_region_is_empty (expose_region))
|
||
{
|
||
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];
|
||
|
||
gdk_quartz_window_set_needs_display_in_region (window, expose_region);
|
||
}
|
||
else
|
||
{
|
||
[impl->view setFrame:nsrect];
|
||
[impl->view setNeedsDisplay:YES];
|
||
}
|
||
|
||
cairo_region_destroy (expose_region);
|
||
cairo_region_destroy (old_region);
|
||
}
|
||
}
|
||
|
||
if (window->gl_paint_context != NULL)
|
||
[GDK_QUARTZ_GL_CONTEXT (window->gl_paint_context)->gl_context update];
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
|
||
static inline void
|
||
window_quartz_move (GdkWindow *window,
|
||
gint x,
|
||
gint y)
|
||
{
|
||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||
|
||
if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
|
||
return;
|
||
|
||
move_resize_window_internal (window, x, y, -1, -1);
|
||
}
|
||
|
||
static inline void
|
||
window_quartz_resize (GdkWindow *window,
|
||
gint width,
|
||
gint height)
|
||
{
|
||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||
|
||
if (window->state & GDK_WINDOW_STATE_FULLSCREEN)
|
||
return;
|
||
|
||
if (width < 1)
|
||
width = 1;
|
||
if (height < 1)
|
||
height = 1;
|
||
|
||
move_resize_window_internal (window, -1, -1, width, height);
|
||
}
|
||
|
||
static inline void
|
||
window_quartz_move_resize (GdkWindow *window,
|
||
gint x,
|
||
gint y,
|
||
gint width,
|
||
gint height)
|
||
{
|
||
if (width < 1)
|
||
width = 1;
|
||
if (height < 1)
|
||
height = 1;
|
||
|
||
move_resize_window_internal (window, x, y, width, height);
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_move_resize (GdkWindow *window,
|
||
gboolean with_move,
|
||
gint x,
|
||
gint y,
|
||
gint width,
|
||
gint height)
|
||
{
|
||
if (with_move && (width < 0 && height < 0))
|
||
window_quartz_move (window, x, y);
|
||
else
|
||
{
|
||
if (with_move)
|
||
window_quartz_move_resize (window, x, y, width, height);
|
||
else
|
||
window_quartz_resize (window, width, height);
|
||
}
|
||
}
|
||
|
||
/* FIXME: This might need fixing (reparenting didn't work before client-side
|
||
* windows either).
|
||
*/
|
||
static gboolean
|
||
gdk_window_quartz_reparent (GdkWindow *window,
|
||
GdkWindow *new_parent,
|
||
gint x,
|
||
gint y)
|
||
{
|
||
GdkWindow *old_parent;
|
||
GdkWindowImplQuartz *impl, *old_parent_impl, *new_parent_impl;
|
||
NSView *view, *new_parent_view;
|
||
|
||
if (new_parent == _gdk_root)
|
||
{
|
||
/* Could be added, just needs implementing. */
|
||
g_warning ("Reparenting to root window is not supported yet in the Mac OS X backend");
|
||
return FALSE;
|
||
}
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
view = impl->view;
|
||
|
||
new_parent_impl = GDK_WINDOW_IMPL_QUARTZ (new_parent->impl);
|
||
new_parent_view = new_parent_impl->view;
|
||
|
||
old_parent = window->parent;
|
||
old_parent_impl = GDK_WINDOW_IMPL_QUARTZ (old_parent->impl);
|
||
|
||
[view retain];
|
||
|
||
[view removeFromSuperview];
|
||
[new_parent_view addSubview:view];
|
||
|
||
[view release];
|
||
|
||
window->parent = new_parent;
|
||
|
||
if (old_parent)
|
||
{
|
||
old_parent_impl->sorted_children = g_list_remove (old_parent_impl->sorted_children, window);
|
||
}
|
||
|
||
new_parent_impl->sorted_children = g_list_prepend (new_parent_impl->sorted_children, window);
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
/* Get the toplevel ordering from NSApp and update our own list. We do
|
||
* this on demand since the NSApp’s list is not up to date directly
|
||
* after we get windowDidBecomeMain.
|
||
*/
|
||
static void
|
||
update_toplevel_order (void)
|
||
{
|
||
GdkWindowImplQuartz *root_impl;
|
||
NSEnumerator *enumerator;
|
||
id nswindow;
|
||
GList *toplevels = NULL;
|
||
|
||
root_impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
|
||
|
||
if (root_impl->sorted_children)
|
||
return;
|
||
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
enumerator = [[NSApp orderedWindows] objectEnumerator];
|
||
while ((nswindow = [enumerator nextObject]))
|
||
{
|
||
GdkWindow *window;
|
||
|
||
if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
|
||
continue;
|
||
|
||
window = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
|
||
toplevels = g_list_prepend (toplevels, window);
|
||
}
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
|
||
root_impl->sorted_children = g_list_reverse (toplevels);
|
||
}
|
||
|
||
static void
|
||
clear_toplevel_order (void)
|
||
{
|
||
GdkWindowImplQuartz *root_impl;
|
||
|
||
root_impl = GDK_WINDOW_IMPL_QUARTZ (_gdk_root->impl);
|
||
|
||
g_list_free (root_impl->sorted_children);
|
||
root_impl->sorted_children = NULL;
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_raise (GdkWindow *window)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return;
|
||
|
||
if (WINDOW_IS_TOPLEVEL (window))
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (impl->transient_for)
|
||
raise_transient (impl);
|
||
else
|
||
[impl->toplevel orderFront:impl->toplevel];
|
||
|
||
clear_toplevel_order ();
|
||
}
|
||
else
|
||
{
|
||
GdkWindow *parent = window->parent;
|
||
|
||
if (parent)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
impl = (GdkWindowImplQuartz *)parent->impl;
|
||
|
||
impl->sorted_children = g_list_remove (impl->sorted_children, window);
|
||
impl->sorted_children = g_list_prepend (impl->sorted_children, window);
|
||
}
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_lower (GdkWindow *window)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return;
|
||
|
||
if (WINDOW_IS_TOPLEVEL (window))
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
[impl->toplevel orderBack:impl->toplevel];
|
||
|
||
clear_toplevel_order ();
|
||
}
|
||
else
|
||
{
|
||
GdkWindow *parent = window->parent;
|
||
|
||
if (parent)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
impl = (GdkWindowImplQuartz *)parent->impl;
|
||
|
||
impl->sorted_children = g_list_remove (impl->sorted_children, window);
|
||
impl->sorted_children = g_list_append (impl->sorted_children, window);
|
||
}
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_restack_toplevel (GdkWindow *window,
|
||
GdkWindow *sibling,
|
||
gboolean above)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
gint sibling_num;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (sibling->impl);
|
||
sibling_num = [impl->toplevel windowNumber];
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (above)
|
||
[impl->toplevel orderWindow:NSWindowAbove relativeTo:sibling_num];
|
||
else
|
||
[impl->toplevel orderWindow:NSWindowBelow relativeTo:sibling_num];
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_set_background (GdkWindow *window,
|
||
cairo_pattern_t *pattern)
|
||
{
|
||
/* FIXME: We could theoretically set the background color for toplevels
|
||
* here. (Currently we draw the background before emitting expose events)
|
||
*/
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_set_device_cursor (GdkWindow *window,
|
||
GdkDevice *device,
|
||
GdkCursor *cursor)
|
||
{
|
||
NSCursor *nscursor;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return;
|
||
|
||
nscursor = _gdk_quartz_cursor_get_ns_cursor (cursor);
|
||
|
||
[nscursor set];
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_get_geometry (GdkWindow *window,
|
||
gint *x,
|
||
gint *y,
|
||
gint *width,
|
||
gint *height)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
NSRect ns_rect;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
if (window == _gdk_root)
|
||
{
|
||
if (x)
|
||
*x = 0;
|
||
if (y)
|
||
*y = 0;
|
||
|
||
if (width)
|
||
*width = window->width;
|
||
if (height)
|
||
*height = window->height;
|
||
}
|
||
else if (WINDOW_IS_TOPLEVEL (window))
|
||
{
|
||
ns_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
|
||
|
||
/* This doesn't work exactly as in X. There doesn't seem to be a
|
||
* way to get the coords relative to the parent window (usually
|
||
* the window frame), but that seems useless except for
|
||
* borderless windows where it's relative to the root window. So
|
||
* we return (0, 0) (should be something like (0, 22)) for
|
||
* windows with borders and the root relative coordinates
|
||
* otherwise.
|
||
*/
|
||
if ([impl->toplevel styleMask] == GDK_QUARTZ_BORDERLESS_WINDOW)
|
||
{
|
||
_gdk_quartz_window_xy_to_gdk_xy (ns_rect.origin.x,
|
||
ns_rect.origin.y + ns_rect.size.height,
|
||
x, y);
|
||
}
|
||
else
|
||
{
|
||
if (x)
|
||
*x = 0;
|
||
if (y)
|
||
*y = 0;
|
||
}
|
||
|
||
if (width)
|
||
*width = ns_rect.size.width;
|
||
if (height)
|
||
*height = ns_rect.size.height;
|
||
}
|
||
else
|
||
{
|
||
ns_rect = [impl->view frame];
|
||
|
||
if (x)
|
||
*x = ns_rect.origin.x;
|
||
if (y)
|
||
*y = ns_rect.origin.y;
|
||
if (width)
|
||
*width = ns_rect.size.width;
|
||
if (height)
|
||
*height = ns_rect.size.height;
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_get_root_coords (GdkWindow *window,
|
||
gint x,
|
||
gint y,
|
||
gint *root_x,
|
||
gint *root_y)
|
||
{
|
||
int tmp_x = 0, tmp_y = 0;
|
||
GdkWindow *toplevel;
|
||
NSRect content_rect;
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
{
|
||
if (root_x)
|
||
*root_x = 0;
|
||
if (root_y)
|
||
*root_y = 0;
|
||
|
||
return;
|
||
}
|
||
|
||
if (window == _gdk_root)
|
||
{
|
||
if (root_x)
|
||
*root_x = x;
|
||
if (root_y)
|
||
*root_y = y;
|
||
|
||
return;
|
||
}
|
||
|
||
toplevel = gdk_window_get_toplevel (window);
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
|
||
|
||
content_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
|
||
|
||
_gdk_quartz_window_xy_to_gdk_xy (content_rect.origin.x,
|
||
content_rect.origin.y + content_rect.size.height,
|
||
&tmp_x, &tmp_y);
|
||
|
||
tmp_x += x;
|
||
tmp_y += y;
|
||
|
||
while (window != toplevel)
|
||
{
|
||
if (_gdk_window_has_impl ((GdkWindow *)window))
|
||
{
|
||
tmp_x += window->x;
|
||
tmp_y += window->y;
|
||
}
|
||
|
||
window = window->parent;
|
||
}
|
||
|
||
if (root_x)
|
||
*root_x = tmp_x;
|
||
if (root_y)
|
||
*root_y = tmp_y;
|
||
}
|
||
|
||
/* Returns coordinates relative to the passed in window. */
|
||
static GdkWindow *
|
||
gdk_window_quartz_get_device_state_helper (GdkWindow *window,
|
||
GdkDevice *device,
|
||
gdouble *x,
|
||
gdouble *y,
|
||
GdkModifierType *mask)
|
||
{
|
||
NSPoint point;
|
||
gint x_tmp, y_tmp;
|
||
GdkWindow *toplevel;
|
||
GdkWindow *found_window;
|
||
|
||
g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
|
||
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
{
|
||
*x = 0;
|
||
*y = 0;
|
||
*mask = 0;
|
||
return NULL;
|
||
}
|
||
|
||
toplevel = gdk_window_get_toplevel (window);
|
||
|
||
*mask = _gdk_quartz_events_get_current_keyboard_modifiers () |
|
||
_gdk_quartz_events_get_current_mouse_modifiers ();
|
||
|
||
/* Get the y coordinate, needs to be flipped. */
|
||
if (window == _gdk_root)
|
||
{
|
||
point = [NSEvent mouseLocation];
|
||
_gdk_quartz_window_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
|
||
}
|
||
else
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
NSWindow *nswindow;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
|
||
nswindow = impl->toplevel;
|
||
|
||
point = [nswindow mouseLocationOutsideOfEventStream];
|
||
|
||
x_tmp = point.x;
|
||
y_tmp = toplevel->height - point.y;
|
||
|
||
window = (GdkWindow *)toplevel;
|
||
}
|
||
|
||
found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp,
|
||
FALSE);
|
||
|
||
/* We never return the root window. */
|
||
if (found_window == _gdk_root)
|
||
found_window = NULL;
|
||
|
||
*x = x_tmp;
|
||
*y = y_tmp;
|
||
|
||
return found_window;
|
||
}
|
||
|
||
static gboolean
|
||
gdk_window_quartz_get_device_state (GdkWindow *window,
|
||
GdkDevice *device,
|
||
gdouble *x,
|
||
gdouble *y,
|
||
GdkModifierType *mask)
|
||
{
|
||
return gdk_window_quartz_get_device_state_helper (window,
|
||
device,
|
||
x, y, mask) != NULL;
|
||
}
|
||
|
||
static GdkEventMask
|
||
gdk_window_quartz_get_events (GdkWindow *window)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return 0;
|
||
else
|
||
return window->event_mask;
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_set_events (GdkWindow *window,
|
||
GdkEventMask event_mask)
|
||
{
|
||
/* The mask is set in the common code. */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_urgency_hint (GdkWindow *window,
|
||
gboolean urgent)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_geometry_hints (GdkWindow *window,
|
||
const GdkGeometry *geometry,
|
||
GdkWindowHints geom_mask)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
g_return_if_fail (geometry != NULL);
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
if (!impl->toplevel)
|
||
return;
|
||
|
||
if (geom_mask & GDK_HINT_POS)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
if (geom_mask & GDK_HINT_USER_POS)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
if (geom_mask & GDK_HINT_USER_SIZE)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
if (geom_mask & GDK_HINT_MIN_SIZE)
|
||
{
|
||
NSSize size;
|
||
|
||
size.width = geometry->min_width;
|
||
size.height = geometry->min_height;
|
||
|
||
[impl->toplevel setContentMinSize:size];
|
||
}
|
||
|
||
if (geom_mask & GDK_HINT_MAX_SIZE)
|
||
{
|
||
NSSize size;
|
||
|
||
size.width = geometry->max_width;
|
||
size.height = geometry->max_height;
|
||
|
||
[impl->toplevel setContentMaxSize:size];
|
||
}
|
||
|
||
if (geom_mask & GDK_HINT_BASE_SIZE)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
if (geom_mask & GDK_HINT_RESIZE_INC)
|
||
{
|
||
NSSize size;
|
||
|
||
size.width = geometry->width_inc;
|
||
size.height = geometry->height_inc;
|
||
|
||
[impl->toplevel setContentResizeIncrements:size];
|
||
}
|
||
|
||
if (geom_mask & GDK_HINT_ASPECT)
|
||
{
|
||
NSSize size;
|
||
|
||
if (geometry->min_aspect != geometry->max_aspect)
|
||
{
|
||
g_warning ("Only equal minimum and maximum aspect ratios are supported on Mac OS. Using minimum aspect ratio...");
|
||
}
|
||
|
||
size.width = geometry->min_aspect;
|
||
size.height = 1.0;
|
||
|
||
[impl->toplevel setContentAspectRatio:size];
|
||
}
|
||
|
||
if (geom_mask & GDK_HINT_WIN_GRAVITY)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_title (GdkWindow *window,
|
||
const gchar *title)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
g_return_if_fail (title != NULL);
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (impl->toplevel)
|
||
{
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
[impl->toplevel setTitle:[NSString stringWithUTF8String:title]];
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_role (GdkWindow *window,
|
||
const gchar *role)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_startup_id (GdkWindow *window,
|
||
const gchar *startup_id)
|
||
{
|
||
/* FIXME: Implement? */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_transient_for (GdkWindow *window,
|
||
GdkWindow *parent)
|
||
{
|
||
GdkWindowImplQuartz *window_impl;
|
||
GdkWindowImplQuartz *parent_impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) || GDK_WINDOW_DESTROYED (parent) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
window_impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
if (!window_impl->toplevel)
|
||
return;
|
||
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
if (window_impl->transient_for)
|
||
{
|
||
_gdk_quartz_window_detach_from_parent (window);
|
||
|
||
g_object_unref (window_impl->transient_for);
|
||
window_impl->transient_for = NULL;
|
||
}
|
||
|
||
parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
|
||
if (parent_impl->toplevel)
|
||
{
|
||
/* We save the parent because it needs to be unset/reset when
|
||
* hiding and showing the window.
|
||
*/
|
||
|
||
/* We don't set transients for tooltips, they are already
|
||
* handled by the window level being the top one. If we do, then
|
||
* the parent window will be brought to the top just because the
|
||
* tooltip is, which is not what we want.
|
||
*/
|
||
if (gdk_window_get_type_hint (window) != GDK_WINDOW_TYPE_HINT_TOOLTIP)
|
||
{
|
||
window_impl->transient_for = g_object_ref (parent);
|
||
|
||
/* We only add the window if it is shown, otherwise it will
|
||
* be shown unconditionally here. If it is not shown, the
|
||
* window will be added in show() instead.
|
||
*/
|
||
if (!(window->state & GDK_WINDOW_STATE_WITHDRAWN))
|
||
_gdk_quartz_window_attach_to_parent (window);
|
||
}
|
||
}
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_shape_combine_region (GdkWindow *window,
|
||
const cairo_region_t *shape,
|
||
gint x,
|
||
gint y)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_window_quartz_input_shape_combine_region (GdkWindow *window,
|
||
const cairo_region_t *shape_region,
|
||
gint offset_x,
|
||
gint offset_y)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_override_redirect (GdkWindow *window,
|
||
gboolean override_redirect)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_accept_focus (GdkWindow *window,
|
||
gboolean accept_focus)
|
||
{
|
||
window->accept_focus = accept_focus != FALSE;
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_focus_on_map (GdkWindow *window,
|
||
gboolean focus_on_map)
|
||
{
|
||
window->focus_on_map = focus_on_map != FALSE;
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_icon_name (GdkWindow *window,
|
||
const gchar *name)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_focus (GdkWindow *window,
|
||
guint32 timestamp)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
if (window->accept_focus && window->window_type != GDK_WINDOW_TEMP)
|
||
{
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
[impl->toplevel makeKeyAndOrderFront:impl->toplevel];
|
||
clear_toplevel_order ();
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
}
|
||
|
||
static gint
|
||
window_type_hint_to_level (GdkWindowTypeHint hint)
|
||
{
|
||
/* the order in this switch statement corresponds to the actual
|
||
* stacking order: the first group is top, the last group is bottom
|
||
*/
|
||
switch (hint)
|
||
{
|
||
case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
|
||
case GDK_WINDOW_TYPE_HINT_COMBO:
|
||
case GDK_WINDOW_TYPE_HINT_DND:
|
||
case GDK_WINDOW_TYPE_HINT_TOOLTIP:
|
||
return NSPopUpMenuWindowLevel;
|
||
|
||
case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
|
||
case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
|
||
return NSStatusWindowLevel;
|
||
|
||
case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
|
||
case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
|
||
return NSTornOffMenuWindowLevel;
|
||
|
||
case GDK_WINDOW_TYPE_HINT_DOCK:
|
||
return NSFloatingWindowLevel; /* NSDockWindowLevel is deprecated, and not replaced */
|
||
|
||
case GDK_WINDOW_TYPE_HINT_UTILITY:
|
||
case GDK_WINDOW_TYPE_HINT_DIALOG: /* Dialog window */
|
||
case GDK_WINDOW_TYPE_HINT_NORMAL: /* Normal toplevel window */
|
||
case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
|
||
return NSNormalWindowLevel;
|
||
|
||
case GDK_WINDOW_TYPE_HINT_DESKTOP:
|
||
return kCGDesktopWindowLevelKey; /* doesn't map to any real Cocoa model */
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return NSNormalWindowLevel;
|
||
}
|
||
|
||
static gboolean
|
||
window_type_hint_to_shadow (GdkWindowTypeHint hint)
|
||
{
|
||
switch (hint)
|
||
{
|
||
case GDK_WINDOW_TYPE_HINT_NORMAL: /* Normal toplevel window */
|
||
case GDK_WINDOW_TYPE_HINT_DIALOG: /* Dialog window */
|
||
case GDK_WINDOW_TYPE_HINT_DOCK:
|
||
case GDK_WINDOW_TYPE_HINT_UTILITY:
|
||
case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
|
||
case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
|
||
case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
|
||
case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
|
||
case GDK_WINDOW_TYPE_HINT_COMBO:
|
||
case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
|
||
case GDK_WINDOW_TYPE_HINT_TOOLTIP:
|
||
return TRUE;
|
||
|
||
case GDK_WINDOW_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
|
||
case GDK_WINDOW_TYPE_HINT_DESKTOP: /* N/A */
|
||
case GDK_WINDOW_TYPE_HINT_DND:
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static gboolean
|
||
window_type_hint_to_hides_on_deactivate (GdkWindowTypeHint hint)
|
||
{
|
||
switch (hint)
|
||
{
|
||
case GDK_WINDOW_TYPE_HINT_UTILITY:
|
||
case GDK_WINDOW_TYPE_HINT_MENU: /* Torn-off menu */
|
||
case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
|
||
case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
|
||
case GDK_WINDOW_TYPE_HINT_TOOLTIP:
|
||
return TRUE;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static void
|
||
_gdk_quartz_window_update_has_shadow (GdkWindowImplQuartz *impl)
|
||
{
|
||
gboolean has_shadow;
|
||
|
||
/* In case there is any shadow set we have to turn off the
|
||
* NSWindow setHasShadow as the system drawn ones wont match our
|
||
* window boundary anymore */
|
||
has_shadow = (window_type_hint_to_shadow (impl->type_hint) && !impl->shadow_max);
|
||
|
||
[impl->toplevel setHasShadow: has_shadow];
|
||
}
|
||
|
||
static void
|
||
_gdk_quartz_window_set_collection_behavior (NSWindow *nswindow,
|
||
GdkWindowTypeHint hint)
|
||
{
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
|
||
#define GDK_QUARTZ_ALLOWS_TILING NSWindowCollectionBehaviorFullScreenAllowsTiling
|
||
#define GDK_QUARTZ_DISALLOWS_TILING NSWindowCollectionBehaviorFullScreenDisallowsTiling
|
||
#else
|
||
#define GDK_QUARTZ_ALLOWS_TILING 1 << 11
|
||
#define GDK_QUARTZ_DISALLOWS_TILING 1 << 12
|
||
#endif
|
||
if (gdk_quartz_osx_version() >= GDK_OSX_LION)
|
||
{
|
||
/* Fullscreen Collection Behavior */
|
||
NSWindowCollectionBehavior behavior = [nswindow collectionBehavior];
|
||
switch (hint)
|
||
{
|
||
case GDK_WINDOW_TYPE_HINT_NORMAL:
|
||
case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
|
||
behavior &= ~(NSWindowCollectionBehaviorFullScreenAuxiliary &
|
||
GDK_QUARTZ_DISALLOWS_TILING);
|
||
behavior |= (NSWindowCollectionBehaviorFullScreenPrimary |
|
||
GDK_QUARTZ_ALLOWS_TILING);
|
||
|
||
break;
|
||
default:
|
||
behavior &= ~(NSWindowCollectionBehaviorFullScreenPrimary &
|
||
GDK_QUARTZ_ALLOWS_TILING);
|
||
behavior |= (NSWindowCollectionBehaviorFullScreenAuxiliary |
|
||
GDK_QUARTZ_DISALLOWS_TILING);
|
||
break;
|
||
}
|
||
[nswindow setCollectionBehavior:behavior];
|
||
}
|
||
#undef GDK_QUARTZ_ALLOWS_TILING
|
||
#undef GDK_QUARTZ_DISALLOWS_TILING
|
||
#endif
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_type_hint (GdkWindow *window,
|
||
GdkWindowTypeHint hint)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
impl->type_hint = hint;
|
||
|
||
/* Match the documentation, only do something if we're not mapped yet. */
|
||
if (GDK_WINDOW_IS_MAPPED (window))
|
||
return;
|
||
|
||
_gdk_quartz_window_update_has_shadow (impl);
|
||
if (impl->toplevel)
|
||
_gdk_quartz_window_set_collection_behavior (impl->toplevel, hint);
|
||
[impl->toplevel setLevel: window_type_hint_to_level (hint)];
|
||
[impl->toplevel setHidesOnDeactivate: window_type_hint_to_hides_on_deactivate (hint)];
|
||
}
|
||
|
||
static GdkWindowTypeHint
|
||
gdk_quartz_window_get_type_hint (GdkWindow *window)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return GDK_WINDOW_TYPE_HINT_NORMAL;
|
||
|
||
return GDK_WINDOW_IMPL_QUARTZ (window->impl)->type_hint;
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_modal_hint (GdkWindow *window,
|
||
gboolean modal)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_skip_taskbar_hint (GdkWindow *window,
|
||
gboolean skips_taskbar)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_skip_pager_hint (GdkWindow *window,
|
||
gboolean skips_pager)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_begin_resize_drag (GdkWindow *window,
|
||
GdkWindowEdge edge,
|
||
GdkDevice *device,
|
||
gint button,
|
||
gint root_x,
|
||
gint root_y,
|
||
guint32 timestamp)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (!impl->toplevel)
|
||
{
|
||
g_warning ("Can't call gdk_window_begin_resize_drag on non-toplevel window");
|
||
return;
|
||
}
|
||
|
||
[(GdkQuartzNSWindow *)impl->toplevel beginManualResize:edge];
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_begin_move_drag (GdkWindow *window,
|
||
GdkDevice *device,
|
||
gint button,
|
||
gint root_x,
|
||
gint root_y,
|
||
guint32 timestamp)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (!impl->toplevel)
|
||
{
|
||
g_warning ("Can't call gdk_window_begin_move_drag on non-toplevel window");
|
||
return;
|
||
}
|
||
|
||
[(GdkQuartzNSWindow *)impl->toplevel beginManualMove];
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_icon_list (GdkWindow *window,
|
||
GList *pixbufs)
|
||
{
|
||
/* FIXME: Implement */
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_get_frame_extents (GdkWindow *window,
|
||
GdkRectangle *rect)
|
||
{
|
||
GdkWindow *toplevel;
|
||
GdkWindowImplQuartz *impl;
|
||
NSRect ns_rect;
|
||
|
||
g_return_if_fail (rect != NULL);
|
||
|
||
|
||
rect->x = 0;
|
||
rect->y = 0;
|
||
rect->width = 1;
|
||
rect->height = 1;
|
||
|
||
toplevel = gdk_window_get_effective_toplevel (window);
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (toplevel->impl);
|
||
|
||
ns_rect = [impl->toplevel frame];
|
||
|
||
_gdk_quartz_window_xy_to_gdk_xy (ns_rect.origin.x,
|
||
ns_rect.origin.y + ns_rect.size.height,
|
||
&rect->x, &rect->y);
|
||
|
||
rect->width = ns_rect.size.width;
|
||
rect->height = ns_rect.size.height;
|
||
}
|
||
|
||
/* Fake protocol to make gcc think that it's OK to call setStyleMask
|
||
even if it isn't. We check to make sure before actually calling
|
||
it. */
|
||
|
||
@protocol CanSetStyleMask
|
||
- (void)setStyleMask:(int)mask;
|
||
@end
|
||
|
||
static void
|
||
gdk_quartz_window_set_decorations (GdkWindow *window,
|
||
GdkWMDecoration decorations)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
NSUInteger old_mask, new_mask;
|
||
NSView *old_view;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP ||
|
||
impl->type_hint == GDK_WINDOW_TYPE_HINT_SPLASHSCREEN )
|
||
{
|
||
new_mask = GDK_QUARTZ_BORDERLESS_WINDOW;
|
||
}
|
||
else if (decorations == 0) {
|
||
new_mask = GDK_QUARTZ_BORDERLESS_WINDOW | GDK_QUARTZ_MINIATURIZABLE_WINDOW;
|
||
}
|
||
else
|
||
{
|
||
/* FIXME: Honor other GDK_DECOR_* flags. */
|
||
new_mask = (GDK_QUARTZ_TITLED_WINDOW | GDK_QUARTZ_CLOSABLE_WINDOW |
|
||
GDK_QUARTZ_MINIATURIZABLE_WINDOW |
|
||
GDK_QUARTZ_RESIZABLE_WINDOW);
|
||
}
|
||
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
old_mask = [impl->toplevel styleMask];
|
||
|
||
if (old_mask != new_mask)
|
||
{
|
||
NSRect rect;
|
||
|
||
old_view = [[impl->toplevel contentView] retain];
|
||
|
||
rect = [impl->toplevel frame];
|
||
|
||
/* Properly update the size of the window when the titlebar is
|
||
* added or removed.
|
||
*/
|
||
if (old_mask == GDK_QUARTZ_BORDERLESS_WINDOW &&
|
||
new_mask != GDK_QUARTZ_BORDERLESS_WINDOW)
|
||
{
|
||
rect = [NSWindow frameRectForContentRect:rect styleMask:new_mask];
|
||
|
||
}
|
||
else if (old_mask != GDK_QUARTZ_BORDERLESS_WINDOW &&
|
||
new_mask == GDK_QUARTZ_BORDERLESS_WINDOW)
|
||
{
|
||
rect = [NSWindow contentRectForFrameRect:rect styleMask:old_mask];
|
||
}
|
||
|
||
/* Note, before OS 10.6 there doesn't seem to be a way to change this
|
||
* without recreating the toplevel. From 10.6 onward, a simple call to
|
||
* setStyleMask takes care of most of this, except for ensuring that the
|
||
* title is set.
|
||
*/
|
||
if ([impl->toplevel respondsToSelector:@selector(setStyleMask:)])
|
||
{
|
||
NSString *title = [impl->toplevel title];
|
||
|
||
[(id<CanSetStyleMask>)impl->toplevel setStyleMask:new_mask];
|
||
|
||
/* It appears that unsetting and then resetting
|
||
* GDK_QUARTZ_TITLED_WINDOW does not reset the title in the
|
||
* title bar as might be expected.
|
||
*
|
||
* In theory we only need to set this if new_mask includes
|
||
* GDK_QUARTZ_TITLED_WINDOW. This behaved extremely oddly when
|
||
* conditionalized upon that and since it has no side effects (i.e.
|
||
* if GDK_QUARTZ_TITLED_WINDOW is not requested, the title will not be
|
||
* displayed) just do it unconditionally. We also must null check
|
||
* 'title' before setting it to avoid crashing.
|
||
*/
|
||
if (title)
|
||
[impl->toplevel setTitle:title];
|
||
}
|
||
else
|
||
{
|
||
NSString *title = [impl->toplevel title];
|
||
NSColor *bg = [impl->toplevel backgroundColor];
|
||
NSScreen *screen = [impl->toplevel screen];
|
||
|
||
/* Make sure the old window is closed, recall that releasedWhenClosed
|
||
* is set on GdkQuartzWindows.
|
||
*/
|
||
[impl->toplevel close];
|
||
|
||
impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:rect
|
||
styleMask:new_mask
|
||
backing:NSBackingStoreBuffered
|
||
defer:NO
|
||
screen:screen];
|
||
_gdk_quartz_window_update_has_shadow (impl);
|
||
|
||
[impl->toplevel setLevel: window_type_hint_to_level (impl->type_hint)];
|
||
if (title)
|
||
[impl->toplevel setTitle:title];
|
||
[impl->toplevel setBackgroundColor:bg];
|
||
[impl->toplevel setHidesOnDeactivate: window_type_hint_to_hides_on_deactivate (impl->type_hint)];
|
||
[impl->toplevel setContentView:old_view];
|
||
}
|
||
|
||
if (new_mask == GDK_QUARTZ_BORDERLESS_WINDOW)
|
||
{
|
||
[impl->toplevel setContentSize:rect.size];
|
||
}
|
||
else
|
||
[impl->toplevel setFrame:rect display:YES];
|
||
|
||
/* Invalidate the window shadow for non-opaque views that have shadow
|
||
* enabled, to get the shadow shape updated.
|
||
*/
|
||
if (![old_view isOpaque] && [impl->toplevel hasShadow])
|
||
[(GdkQuartzView*)old_view setNeedsInvalidateShadow:YES];
|
||
|
||
[old_view release];
|
||
}
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
|
||
static gboolean
|
||
gdk_quartz_window_get_decorations (GdkWindow *window,
|
||
GdkWMDecoration *decorations)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return FALSE;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (decorations)
|
||
{
|
||
/* Borderless is 0, so we can't check it as a bit being set. */
|
||
if ([impl->toplevel styleMask] == GDK_QUARTZ_BORDERLESS_WINDOW)
|
||
{
|
||
*decorations = 0;
|
||
}
|
||
else
|
||
{
|
||
/* FIXME: Honor the other GDK_DECOR_* flags. */
|
||
*decorations = GDK_DECOR_ALL;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_functions (GdkWindow *window,
|
||
GdkWMFunction functions)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
gboolean min, max, close;
|
||
|
||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (functions & GDK_FUNC_ALL)
|
||
{
|
||
min = !(functions & GDK_FUNC_MINIMIZE);
|
||
max = !(functions & GDK_FUNC_MAXIMIZE);
|
||
close = !(functions & GDK_FUNC_CLOSE);
|
||
}
|
||
else
|
||
{
|
||
min = (functions & GDK_FUNC_MINIMIZE);
|
||
max = (functions & GDK_FUNC_MAXIMIZE);
|
||
close = (functions & GDK_FUNC_CLOSE);
|
||
}
|
||
|
||
if (impl->toplevel)
|
||
{
|
||
NSUInteger mask = [impl->toplevel styleMask];
|
||
|
||
if (min)
|
||
mask = mask | GDK_QUARTZ_MINIATURIZABLE_WINDOW;
|
||
else
|
||
mask = mask & ~GDK_QUARTZ_MINIATURIZABLE_WINDOW;
|
||
|
||
if (max)
|
||
mask = mask | GDK_QUARTZ_RESIZABLE_WINDOW;
|
||
else
|
||
mask = mask & ~GDK_QUARTZ_RESIZABLE_WINDOW;
|
||
|
||
if (close)
|
||
mask = mask | GDK_QUARTZ_CLOSABLE_WINDOW;
|
||
else
|
||
mask = mask & ~GDK_QUARTZ_CLOSABLE_WINDOW;
|
||
|
||
[impl->toplevel setStyleMask:mask];
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_stick (GdkWindow *window)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_unstick (GdkWindow *window)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_maximize (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
gboolean maximized;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
|
||
|
||
if (GDK_WINDOW_IS_MAPPED (window))
|
||
{
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
if (impl->toplevel && !maximized)
|
||
[impl->toplevel zoom:nil];
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_unmaximize (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
gboolean maximized;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
|
||
|
||
if (GDK_WINDOW_IS_MAPPED (window))
|
||
{
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
if (impl->toplevel && maximized)
|
||
[impl->toplevel zoom:nil];
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_iconify (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (GDK_WINDOW_IS_MAPPED (window))
|
||
{
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
if (impl->toplevel)
|
||
[impl->toplevel miniaturize:nil];
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
else
|
||
{
|
||
gdk_synthesize_window_state (window,
|
||
0,
|
||
GDK_WINDOW_STATE_ICONIFIED);
|
||
}
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_deiconify (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (GDK_WINDOW_IS_MAPPED (window))
|
||
{
|
||
GDK_QUARTZ_ALLOC_POOL;
|
||
|
||
if (impl->toplevel)
|
||
[impl->toplevel deminiaturize:nil];
|
||
|
||
GDK_QUARTZ_RELEASE_POOL;
|
||
}
|
||
else
|
||
{
|
||
gdk_synthesize_window_state (window,
|
||
GDK_WINDOW_STATE_ICONIFIED,
|
||
0);
|
||
}
|
||
}
|
||
|
||
static gboolean
|
||
window_is_fullscreen (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
if (gdk_quartz_osx_version() >= GDK_OSX_LION)
|
||
return ([impl->toplevel styleMask] & GDK_QUARTZ_FULLSCREEN_WINDOW) != 0;
|
||
else
|
||
#endif
|
||
return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA) != NULL;
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_fullscreen (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
if (gdk_quartz_osx_version() >= GDK_OSX_LION)
|
||
{
|
||
if (!window_is_fullscreen (window))
|
||
[impl->toplevel toggleFullScreen:nil];
|
||
}
|
||
else
|
||
{
|
||
#endif
|
||
FullscreenSavedGeometry *geometry;
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
NSRect frame;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
geometry = get_fullscreen_geometry (window);
|
||
if (!geometry)
|
||
{
|
||
geometry = g_new (FullscreenSavedGeometry, 1);
|
||
|
||
geometry->x = window->x;
|
||
geometry->y = window->y;
|
||
geometry->width = window->width;
|
||
geometry->height = window->height;
|
||
|
||
if (!gdk_window_get_decorations (window, &geometry->decor))
|
||
geometry->decor = GDK_DECOR_ALL;
|
||
|
||
g_object_set_data_full (G_OBJECT (window),
|
||
FULLSCREEN_DATA, geometry,
|
||
g_free);
|
||
|
||
gdk_window_set_decorations (window, 0);
|
||
|
||
frame = [[impl->toplevel screen] frame];
|
||
move_resize_window_internal (window,
|
||
0, 0,
|
||
frame.size.width, frame.size.height);
|
||
[impl->toplevel setContentSize:frame.size];
|
||
[impl->toplevel makeKeyAndOrderFront:impl->toplevel];
|
||
|
||
clear_toplevel_order ();
|
||
}
|
||
|
||
SetSystemUIMode (kUIModeAllHidden, kUIOptionAutoShowMenuBar);
|
||
|
||
gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
}
|
||
#endif
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_unfullscreen (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
if (gdk_quartz_osx_version() >= GDK_OSX_LION)
|
||
{
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (window_is_fullscreen (window))
|
||
[impl->toplevel toggleFullScreen:nil];
|
||
}
|
||
else
|
||
{
|
||
#endif
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
FullscreenSavedGeometry *geometry;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
geometry = get_fullscreen_geometry (window);
|
||
if (geometry)
|
||
{
|
||
SetSystemUIMode (kUIModeNormal, 0);
|
||
|
||
move_resize_window_internal (window,
|
||
geometry->x,
|
||
geometry->y,
|
||
geometry->width,
|
||
geometry->height);
|
||
|
||
gdk_window_set_decorations (window, geometry->decor);
|
||
|
||
g_object_set_data (G_OBJECT (window), FULLSCREEN_DATA, NULL);
|
||
|
||
[impl->toplevel makeKeyAndOrderFront:impl->toplevel];
|
||
clear_toplevel_order ();
|
||
|
||
gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
|
||
}
|
||
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
}
|
||
#endif
|
||
}
|
||
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
static FullscreenSavedGeometry *
|
||
get_fullscreen_geometry (GdkWindow *window)
|
||
{
|
||
return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA);
|
||
}
|
||
#endif
|
||
|
||
void
|
||
_gdk_quartz_window_update_fullscreen_state (GdkWindow *window)
|
||
{
|
||
if (GDK_WINDOW_DESTROYED (window) || !WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||
if (gdk_quartz_osx_version() >= GDK_OSX_LION)
|
||
{
|
||
gboolean is_fullscreen = window_is_fullscreen (window);
|
||
gboolean was_fullscreen = (gdk_window_get_state (window) &
|
||
GDK_WINDOW_STATE_FULLSCREEN) != 0;
|
||
|
||
if (is_fullscreen != was_fullscreen)
|
||
{
|
||
if (is_fullscreen)
|
||
gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FULLSCREEN);
|
||
else
|
||
gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FULLSCREEN, 0);
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_keep_above (GdkWindow *window,
|
||
gboolean setting)
|
||
{
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
gint level;
|
||
|
||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
level = window_type_hint_to_level (gdk_window_get_type_hint (window));
|
||
|
||
/* Adjust normal window level by one if necessary. */
|
||
[impl->toplevel setLevel: level + (setting ? 1 : 0)];
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_keep_below (GdkWindow *window,
|
||
gboolean setting)
|
||
{
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
gint level;
|
||
|
||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
level = window_type_hint_to_level (gdk_window_get_type_hint (window));
|
||
|
||
/* Adjust normal window level by one if necessary. */
|
||
[impl->toplevel setLevel: level - (setting ? 1 : 0)];
|
||
}
|
||
|
||
/* X11 "feature" not useful in other backends. */
|
||
static GdkWindow *
|
||
gdk_quartz_window_get_group (GdkWindow *window)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
/* X11 "feature" not useful in other backends. */
|
||
static void
|
||
gdk_quartz_window_set_group (GdkWindow *window,
|
||
GdkWindow *leader)
|
||
{
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_destroy_notify (GdkWindow *window)
|
||
{
|
||
GdkDisplay *display = gdk_window_get_display (window);
|
||
GdkSeat *seat = gdk_display_get_default_seat (display);
|
||
gdk_seat_ungrab (seat);
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_opacity (GdkWindow *window,
|
||
gdouble opacity)
|
||
{
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||
g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
if (opacity < 0)
|
||
opacity = 0;
|
||
else if (opacity > 1)
|
||
opacity = 1;
|
||
|
||
[impl->toplevel setAlphaValue: opacity];
|
||
}
|
||
|
||
static void
|
||
gdk_quartz_window_set_shadow_width (GdkWindow *window,
|
||
gint left,
|
||
gint right,
|
||
gint top,
|
||
gint bottom)
|
||
{
|
||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||
g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
|
||
|
||
if (GDK_WINDOW_DESTROYED (window) ||
|
||
!WINDOW_IS_TOPLEVEL (window))
|
||
return;
|
||
|
||
impl->shadow_top = top;
|
||
impl->shadow_max = MAX (MAX (left, right), MAX (top, bottom));
|
||
_gdk_quartz_window_update_has_shadow (impl);
|
||
}
|
||
|
||
static cairo_region_t *
|
||
gdk_quartz_window_get_shape (GdkWindow *window)
|
||
{
|
||
/* FIXME: implement */
|
||
return NULL;
|
||
}
|
||
|
||
static cairo_region_t *
|
||
gdk_quartz_window_get_input_shape (GdkWindow *window)
|
||
{
|
||
/* FIXME: implement */
|
||
return NULL;
|
||
}
|
||
|
||
/* Protocol to build cleanly for OSX < 10.7 */
|
||
@protocol ScaleFactor
|
||
- (CGFloat) backingScaleFactor;
|
||
@end
|
||
|
||
static gint
|
||
gdk_quartz_window_get_scale_factor (GdkWindow *window)
|
||
{
|
||
GdkWindowImplQuartz *impl;
|
||
|
||
if (GDK_WINDOW_DESTROYED (window))
|
||
return 1;
|
||
|
||
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||
|
||
if (impl->toplevel != NULL && gdk_quartz_osx_version() >= GDK_OSX_LION)
|
||
return [(id <ScaleFactor>) impl->toplevel backingScaleFactor];
|
||
|
||
return 1;
|
||
}
|
||
|
||
static void
|
||
gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass)
|
||
{
|
||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
|
||
GdkWindowImplQuartzClass *impl_quartz_class = GDK_WINDOW_IMPL_QUARTZ_CLASS (klass);
|
||
|
||
parent_class = g_type_class_peek_parent (klass);
|
||
|
||
object_class->finalize = gdk_window_impl_quartz_finalize;
|
||
|
||
impl_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
|
||
impl_class->show = gdk_window_quartz_show;
|
||
impl_class->hide = gdk_window_quartz_hide;
|
||
impl_class->withdraw = gdk_window_quartz_withdraw;
|
||
impl_class->set_events = gdk_window_quartz_set_events;
|
||
impl_class->get_events = gdk_window_quartz_get_events;
|
||
impl_class->raise = gdk_window_quartz_raise;
|
||
impl_class->lower = gdk_window_quartz_lower;
|
||
impl_class->restack_toplevel = gdk_window_quartz_restack_toplevel;
|
||
impl_class->move_resize = gdk_window_quartz_move_resize;
|
||
impl_class->set_background = gdk_window_quartz_set_background;
|
||
impl_class->reparent = gdk_window_quartz_reparent;
|
||
impl_class->set_device_cursor = gdk_window_quartz_set_device_cursor;
|
||
impl_class->get_geometry = gdk_window_quartz_get_geometry;
|
||
impl_class->get_root_coords = gdk_window_quartz_get_root_coords;
|
||
impl_class->get_device_state = gdk_window_quartz_get_device_state;
|
||
impl_class->shape_combine_region = gdk_window_quartz_shape_combine_region;
|
||
impl_class->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
|
||
impl_class->destroy = gdk_quartz_window_destroy;
|
||
impl_class->destroy_foreign = gdk_quartz_window_destroy_foreign;
|
||
impl_class->get_shape = gdk_quartz_window_get_shape;
|
||
impl_class->get_input_shape = gdk_quartz_window_get_input_shape;
|
||
impl_class->begin_paint = gdk_window_impl_quartz_begin_paint;
|
||
impl_class->get_scale_factor = gdk_quartz_window_get_scale_factor;
|
||
|
||
impl_class->focus = gdk_quartz_window_focus;
|
||
impl_class->set_type_hint = gdk_quartz_window_set_type_hint;
|
||
impl_class->get_type_hint = gdk_quartz_window_get_type_hint;
|
||
impl_class->set_modal_hint = gdk_quartz_window_set_modal_hint;
|
||
impl_class->set_skip_taskbar_hint = gdk_quartz_window_set_skip_taskbar_hint;
|
||
impl_class->set_skip_pager_hint = gdk_quartz_window_set_skip_pager_hint;
|
||
impl_class->set_urgency_hint = gdk_quartz_window_set_urgency_hint;
|
||
impl_class->set_geometry_hints = gdk_quartz_window_set_geometry_hints;
|
||
impl_class->set_title = gdk_quartz_window_set_title;
|
||
impl_class->set_role = gdk_quartz_window_set_role;
|
||
impl_class->set_startup_id = gdk_quartz_window_set_startup_id;
|
||
impl_class->set_transient_for = gdk_quartz_window_set_transient_for;
|
||
impl_class->get_frame_extents = gdk_quartz_window_get_frame_extents;
|
||
impl_class->set_override_redirect = gdk_quartz_window_set_override_redirect;
|
||
impl_class->set_accept_focus = gdk_quartz_window_set_accept_focus;
|
||
impl_class->set_focus_on_map = gdk_quartz_window_set_focus_on_map;
|
||
impl_class->set_icon_list = gdk_quartz_window_set_icon_list;
|
||
impl_class->set_icon_name = gdk_quartz_window_set_icon_name;
|
||
impl_class->iconify = gdk_quartz_window_iconify;
|
||
impl_class->deiconify = gdk_quartz_window_deiconify;
|
||
impl_class->stick = gdk_quartz_window_stick;
|
||
impl_class->unstick = gdk_quartz_window_unstick;
|
||
impl_class->maximize = gdk_quartz_window_maximize;
|
||
impl_class->unmaximize = gdk_quartz_window_unmaximize;
|
||
impl_class->fullscreen = gdk_quartz_window_fullscreen;
|
||
impl_class->unfullscreen = gdk_quartz_window_unfullscreen;
|
||
impl_class->set_keep_above = gdk_quartz_window_set_keep_above;
|
||
impl_class->set_keep_below = gdk_quartz_window_set_keep_below;
|
||
impl_class->get_group = gdk_quartz_window_get_group;
|
||
impl_class->set_group = gdk_quartz_window_set_group;
|
||
impl_class->set_decorations = gdk_quartz_window_set_decorations;
|
||
impl_class->get_decorations = gdk_quartz_window_get_decorations;
|
||
impl_class->set_functions = gdk_quartz_window_set_functions;
|
||
impl_class->begin_resize_drag = gdk_quartz_window_begin_resize_drag;
|
||
impl_class->begin_move_drag = gdk_quartz_window_begin_move_drag;
|
||
impl_class->set_opacity = gdk_quartz_window_set_opacity;
|
||
impl_class->set_shadow_width = gdk_quartz_window_set_shadow_width;
|
||
impl_class->destroy_notify = gdk_quartz_window_destroy_notify;
|
||
impl_class->register_dnd = _gdk_quartz_window_register_dnd;
|
||
impl_class->drag_begin = _gdk_quartz_window_drag_begin;
|
||
impl_class->process_updates_recurse = _gdk_quartz_window_process_updates_recurse;
|
||
impl_class->sync_rendering = _gdk_quartz_window_sync_rendering;
|
||
impl_class->simulate_key = _gdk_quartz_window_simulate_key;
|
||
impl_class->simulate_button = _gdk_quartz_window_simulate_button;
|
||
impl_class->get_property = _gdk_quartz_window_get_property;
|
||
impl_class->change_property = _gdk_quartz_window_change_property;
|
||
impl_class->delete_property = _gdk_quartz_window_delete_property;
|
||
|
||
impl_class->create_gl_context = gdk_quartz_window_create_gl_context;
|
||
impl_class->invalidate_for_new_frame = gdk_quartz_window_invalidate_for_new_frame;
|
||
|
||
impl_quartz_class->get_context = gdk_window_impl_quartz_get_context;
|
||
impl_quartz_class->release_context = gdk_window_impl_quartz_release_context;
|
||
}
|
||
|
||
GType
|
||
_gdk_window_impl_quartz_get_type (void)
|
||
{
|
||
static GType object_type = 0;
|
||
|
||
if (!object_type)
|
||
{
|
||
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,
|
||
};
|
||
|
||
object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL,
|
||
"GdkWindowImplQuartz",
|
||
&object_info, 0);
|
||
}
|
||
|
||
return object_type;
|
||
}
|
||
|
||
CGContextRef
|
||
gdk_quartz_window_get_context (GdkWindowImplQuartz *window,
|
||
gboolean antialias)
|
||
{
|
||
if (!GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->get_context)
|
||
{
|
||
g_warning ("%s doesn't implement GdkWindowImplQuartzClass::get_context()",
|
||
G_OBJECT_TYPE_NAME (window));
|
||
return NULL;
|
||
}
|
||
|
||
return GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->get_context (window, antialias);
|
||
}
|
||
|
||
void
|
||
gdk_quartz_window_release_context (GdkWindowImplQuartz *window,
|
||
CGContextRef cg_context)
|
||
{
|
||
if (!GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->release_context)
|
||
{
|
||
g_warning ("%s doesn't implement GdkWindowImplQuartzClass::release_context()",
|
||
G_OBJECT_TYPE_NAME (window));
|
||
return;
|
||
}
|
||
|
||
GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->release_context (window, cg_context);
|
||
}
|
||
|
||
|
||
|
||
static CGContextRef
|
||
gdk_root_window_impl_quartz_get_context (GdkWindowImplQuartz *window,
|
||
gboolean antialias)
|
||
{
|
||
CGColorSpaceRef colorspace;
|
||
CGContextRef cg_context;
|
||
GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (window);
|
||
|
||
if (GDK_WINDOW_DESTROYED (window_impl->wrapper))
|
||
return NULL;
|
||
|
||
/* We do not have the notion of a root window on OS X. We fake this
|
||
* by creating a 1x1 bitmap and return a context to that.
|
||
*/
|
||
colorspace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
|
||
cg_context = CGBitmapContextCreate (NULL,
|
||
1, 1, 8, 4, colorspace,
|
||
(CGBitmapInfo)kCGImageAlphaPremultipliedLast);
|
||
CGColorSpaceRelease (colorspace);
|
||
|
||
return cg_context;
|
||
}
|
||
|
||
static void
|
||
gdk_root_window_impl_quartz_release_context (GdkWindowImplQuartz *window,
|
||
CGContextRef cg_context)
|
||
{
|
||
CGContextRelease (cg_context);
|
||
}
|
||
|
||
static void
|
||
gdk_root_window_impl_quartz_class_init (GdkRootWindowImplQuartzClass *klass)
|
||
{
|
||
GdkWindowImplQuartzClass *window_quartz_class = GDK_WINDOW_IMPL_QUARTZ_CLASS (klass);
|
||
|
||
root_window_parent_class = g_type_class_peek_parent (klass);
|
||
|
||
window_quartz_class->get_context = gdk_root_window_impl_quartz_get_context;
|
||
window_quartz_class->release_context = gdk_root_window_impl_quartz_release_context;
|
||
}
|
||
|
||
static void
|
||
gdk_root_window_impl_quartz_init (GdkRootWindowImplQuartz *impl)
|
||
{
|
||
}
|
||
|
||
GType
|
||
_gdk_root_window_impl_quartz_get_type (void)
|
||
{
|
||
static GType object_type = 0;
|
||
|
||
if (!object_type)
|
||
{
|
||
const GTypeInfo object_info =
|
||
{
|
||
sizeof (GdkRootWindowImplQuartzClass),
|
||
(GBaseInitFunc) NULL,
|
||
(GBaseFinalizeFunc) NULL,
|
||
(GClassInitFunc) gdk_root_window_impl_quartz_class_init,
|
||
NULL, /* class_finalize */
|
||
NULL, /* class_data */
|
||
sizeof (GdkRootWindowImplQuartz),
|
||
0, /* n_preallocs */
|
||
(GInstanceInitFunc) gdk_root_window_impl_quartz_init,
|
||
};
|
||
|
||
object_type = g_type_register_static (GDK_TYPE_WINDOW_IMPL_QUARTZ,
|
||
"GdkRootWindowQuartz",
|
||
&object_info, 0);
|
||
}
|
||
|
||
return object_type;
|
||
}
|