Compare commits

...

8 Commits

Author SHA1 Message Date
Christian Hergert
67aef5f542 wip: pixelcache: ensure we use CGLayer on quartz
This is a special case for quartz where we want to ensure that a
CGLayer is used for the pixel cache. create_similar_surface() is not
enough since only a few CGLayer backed surfaces seem possible
before we can’t create them anymore.

This requires cairo-quartz patches for
cairo_quartz_surface_create_cg_layer()
2015-09-30 18:39:00 -07:00
Christian Hergert
b1be2a70fd wip: quartz: use colorspace from primary display
Using the default RGB colorspace seems to go through colorspace
conversion on tested macbook retina devices. Instead, default to the
colorspace of the main display so that it does not incur the conversion
cost on every frame.

This probably requires the equivalent patch to cairo, I have not tested
without it yet.
2015-09-30 18:37:16 -07:00
Christian Hergert
abe99e4611 quartz: release linked list as we process it
Rather than performing the list iteration and the list free as separate
steps, free the list link while iterating.
2015-09-30 18:34:16 -07:00
Christian Hergert
f7b7c33cc9 quartz: drop beam sync penalty code
Now that we have a frame clock in place, we should be able to drop
the beam-sync penalty prevention code as we should be aligning our
draws with CVDisplayLink.
2015-09-30 18:33:08 -07:00
Christian Hergert
519e5a94d2 quartz: squash warning with explicit cast 2015-09-30 18:30:02 -07:00
Christian Hergert
7e1db6cf64 quartz: fix unused variable warnings 2015-09-30 18:26:28 -07:00
Christian Hergert
f9395b52f7 quartz: squash compiler warning about enums
We don’t care about the other enums, fine to squash the warning.
2015-09-30 18:25:07 -07:00
Christian Hergert
01e633a763 quartz: add CVDisplayLink based frame clock
This uses CVDisplayLink to drive the GdkFrameClock. A GdkWindow
can register a frame callback to thaw their frame clock as necessary
based on the next notification from CVDisplayLink.

CVDisplayLink notifies us on a high-priority thread. We use the same
NSEventas gdkeventloop-quartz.c to wakeup the main loop. This is done
so that we don’t pathologically wake up the select thread to then
continue notifying the main loop.

We use an embedded GList node in the GdkWindowImplQuartz so that we
can avoid allocating any lists or arrays for pending frame callbacks.
Compare this to the same design in GdkWindow for children.
2015-09-30 18:24:26 -07:00
12 changed files with 497 additions and 66 deletions

View File

@@ -178,7 +178,6 @@
GdkWindow *window = [[self contentView] gdkWindow];
GdkEvent *event;
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
gboolean maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
/* In case the window is changed when maximized remove the maximized state */
@@ -209,7 +208,6 @@
NSRect content_rect = [self contentRectForFrameRect:[self frame]];
GdkWindow *window = [[self contentView] gdkWindow];
GdkEvent *event;
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
gboolean maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
/* see same in windowDidMove */
@@ -254,7 +252,7 @@
screen:screen];
[self setAcceptsMouseMovedEvents:YES];
[self setDelegate:self];
[self setDelegate:(id)self];
[self setReleasedWhenClosed:YES];
return self;
@@ -781,7 +779,6 @@ update_context_from_dragging_info (id <NSDraggingInfo> sender)
{
NSRect screenFrame = [[self screen] visibleFrame];
GdkWindow *window = [[self contentView] gdkWindow];
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
gboolean maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
if (!maximized)
@@ -795,7 +792,6 @@ update_context_from_dragging_info (id <NSDraggingInfo> sender)
{
GdkWindow *window = [[self contentView] gdkWindow];
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
gboolean maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
if (maximized)

View File

@@ -122,7 +122,6 @@
-(void)unmarkText
{
GDK_NOTE (EVENTS, g_print ("unmarkText\n"));
gchar *prev_str;
markedRange = selectedRange = NSMakeRange (NSNotFound, 0);
g_object_set_data_full (G_OBJECT (gdk_window), TIC_MARKED_TEXT, NULL, g_free);
@@ -132,7 +131,6 @@
{
GDK_NOTE (EVENTS, g_print ("setMarkedText\n"));
const char *str;
gchar *prev_str;
if (replacementRange.location == NSNotFound)
{
@@ -182,7 +180,6 @@
GDK_NOTE (EVENTS, g_print ("insertText\n"));
const char *str;
NSString *string;
gchar *prev_str;
if ([self hasMarkedText])
[self unmarkText];

View File

@@ -28,6 +28,8 @@ libgdk_quartz_la_SOURCES = \
gdkdevicemanager-core-quartz.c \
gdkdevicemanager-core-quartz.h \
gdkdisplay-quartz.c \
gdkdisplaylinksource.c \
gdkdisplaylinksource.h \
gdkdisplaymanager-quartz.c \
gdkdnd-quartz.c \
gdkdnd-quartz.h \

View File

@@ -20,12 +20,14 @@
#include <gdk/gdk.h>
#include <gdk/gdkdisplayprivate.h>
#include <gdk/gdkframeclockprivate.h>
#include "gdkprivate-quartz.h"
#include "gdkquartzscreen.h"
#include "gdkquartzwindow.h"
#include "gdkquartzdisplay.h"
#include "gdkquartzdevicemanager-core.h"
#include "gdkdisplaylinksource.h"
struct _GdkQuartzDisplay
@@ -33,6 +35,11 @@ struct _GdkQuartzDisplay
GdkDisplay display;
GList *input_devices;
/* This structure is not allocated. It points to an embedded
* GList in the GdkWindow. */
GList *windows_awaiting_frame;
GSource *frame_source;
};
struct _GdkQuartzDisplayClass
@@ -108,6 +115,112 @@ gdk_quartz_display_init_input (GdkDisplay *display)
g_list_free (list);
}
void
_gdk_quartz_display_add_frame_callback (GdkDisplay *display,
GdkWindow *window)
{
GdkQuartzDisplay *display_quartz;
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window);
display_quartz = GDK_QUARTZ_DISPLAY (display);
impl->frame_link.data = window;
impl->frame_link.prev = NULL;
impl->frame_link.next = display_quartz->windows_awaiting_frame;
display_quartz->windows_awaiting_frame = &impl->frame_link;
if (impl->frame_link.next == NULL)
gdk_display_link_source_unpause ((GdkDisplayLinkSource *)display_quartz->frame_source);
}
void
_gdk_quartz_display_remove_frame_callback (GdkDisplay *display,
GdkWindow *window)
{
GdkQuartzDisplay *display_quartz = GDK_QUARTZ_DISPLAY (display);
GList *link;
link = g_list_find (display_quartz->windows_awaiting_frame, window);
if (link != NULL)
{
display_quartz->windows_awaiting_frame =
g_list_remove_link (display_quartz->windows_awaiting_frame, link);
}
if (display_quartz->windows_awaiting_frame == NULL)
gdk_display_link_source_pause ((GdkDisplayLinkSource *)display_quartz->frame_source);
}
static gboolean
gdk_quartz_display_frame_cb (gpointer data)
{
GdkDisplayLinkSource *source;
GdkQuartzDisplay *display_quartz = data;
GList *iter;
gint64 presentation_time;
gint64 now;
source = (GdkDisplayLinkSource *)display_quartz->frame_source;
iter = display_quartz->windows_awaiting_frame;
display_quartz->windows_awaiting_frame = NULL;
if (iter == NULL)
{
gdk_display_link_source_pause (source);
return G_SOURCE_CONTINUE;
}
presentation_time = source->presentation_time;
now = g_source_get_time (display_quartz->frame_source);
for (; iter != NULL; iter = iter->next)
{
GdkWindow *window = iter->data;
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
GdkFrameClock *frame_clock = gdk_window_get_frame_clock (window);
GdkFrameTimings *timings;
if (frame_clock == NULL)
continue;
_gdk_frame_clock_thaw (frame_clock);
if (impl->pending_frame_counter)
{
timings = gdk_frame_clock_get_timings (frame_clock, impl->pending_frame_counter);
if (timings != NULL)
timings->presentation_time = presentation_time - source->refresh_interval;
impl->pending_frame_counter = 0;
}
timings = gdk_frame_clock_get_current_timings (frame_clock);
if (timings != NULL)
{
timings->refresh_interval = source->refresh_interval;
timings->predicted_presentation_time = source->presentation_time;
}
}
return G_SOURCE_CONTINUE;
}
static void
gdk_quartz_display_init_display_link (GdkDisplay *display)
{
GdkQuartzDisplay *display_quartz = GDK_QUARTZ_DISPLAY (display);
display_quartz->frame_source = gdk_display_link_source_new ();
g_source_set_callback (display_quartz->frame_source,
gdk_quartz_display_frame_cb,
display,
NULL);
g_source_attach (display_quartz->frame_source, NULL);
}
GdkDisplay *
_gdk_quartz_display_open (const gchar *display_name)
{
@@ -129,6 +242,8 @@ _gdk_quartz_display_open (const gchar *display_name)
gdk_quartz_display_init_input (_gdk_display);
gdk_quartz_display_init_display_link (_gdk_display);
#if 0
/* FIXME: Remove the #if 0 when we have these functions */
_gdk_quartz_dnd_init ();
@@ -284,6 +399,9 @@ gdk_quartz_display_finalize (GObject *object)
g_list_free_full (display_quartz->input_devices, g_object_unref);
g_source_unref (display_quartz->frame_source);
display_quartz->windows_awaiting_frame = NULL;
G_OBJECT_CLASS (gdk_quartz_display_parent_class)->finalize (object);
}

View File

@@ -0,0 +1,251 @@
/* gdkdisplaylinksource.c
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* 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/>.
*
* Authors:
* Christian Hergert <christian@hergert.me>
*/
#include "config.h"
#include <mach/mach_time.h>
#include "gdkprivate-quartz.h"
#include "gdkdisplaylinksource.h"
static gint64 host_to_frame_clock_time (gint64 host_time);
static gboolean
gdk_display_link_source_prepare (GSource *source,
gint *timeout_)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
gint64 now;
now = g_source_get_time (source);
if (now < impl->presentation_time)
*timeout_ = (impl->presentation_time - now) / 1000L;
else
*timeout_ = -1;
return impl->needs_dispatch;
}
static gboolean
gdk_display_link_source_check (GSource *source)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
return impl->needs_dispatch;
}
static gboolean
gdk_display_link_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
gboolean ret = G_SOURCE_CONTINUE;
impl->needs_dispatch = FALSE;
if (callback != NULL)
ret = callback (user_data);
return ret;
}
static void
gdk_display_link_source_finalize (GSource *source)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
CVDisplayLinkStop (impl->display_link);
CVDisplayLinkRelease (impl->display_link);
}
static GSourceFuncs gdk_display_link_source_funcs = {
gdk_display_link_source_prepare,
gdk_display_link_source_check,
gdk_display_link_source_dispatch,
gdk_display_link_source_finalize
};
void
gdk_display_link_source_pause (GdkDisplayLinkSource *source)
{
CVDisplayLinkStop (source->display_link);
}
void
gdk_display_link_source_unpause (GdkDisplayLinkSource *source)
{
CVDisplayLinkStart (source->display_link);
}
static CVReturn
gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link,
const CVTimeStamp *inNow,
const CVTimeStamp *inOutputTime,
CVOptionFlags flagsIn,
CVOptionFlags *flagsOut,
void *user_data)
{
GdkDisplayLinkSource *impl = user_data;
gint64 presentation_time;
gboolean needs_wakeup;
needs_wakeup = !g_atomic_int_get (&impl->needs_dispatch);
presentation_time = host_to_frame_clock_time (inOutputTime->hostTime);
impl->presentation_time = presentation_time;
impl->needs_dispatch = TRUE;
if (needs_wakeup)
{
NSEvent *event;
/* Post a message so we'll break out of the message loop.
*
* We don't use g_main_context_wakeup() here because that
* would result in sending a message to the pipe(2) fd in
* the select thread which would then send this message as
* well. Lots of extra work.
*/
event = [NSEvent otherEventWithType: NSApplicationDefined
location: NSZeroPoint
modifierFlags: 0
timestamp: 0
windowNumber: 0
context: nil
subtype: GDK_QUARTZ_EVENT_SUBTYPE_EVENTLOOP
data1: 0
data2: 0];
[NSApp postEvent:event atStart:YES];
}
return kCVReturnSuccess;
}
/**
* gdk_display_link_source_new:
*
* Creates a new #GSource that will activate the dispatch function upon
* notification from a CVDisplayLink that a new frame should be drawn.
*
* Effort is made to keep the transition from the high-priority
* CVDisplayLink thread into this GSource lightweight. However, this is
* somewhat non-ideal since the best case would be to do the drawing
* from the high-priority thread.
*
* Returns: (transfer full): A newly created #GSource.
*/
GSource *
gdk_display_link_source_new (void)
{
GdkDisplayLinkSource *impl;
GSource *source;
CVReturn ret;
double period;
source = g_source_new (&gdk_display_link_source_funcs, sizeof *impl);
impl = (GdkDisplayLinkSource *)source;
/*
* Create our link based on currently connected displays.
* If there are multiple displays, this will be something that tries
* to work for all of them. In the future, we may want to explore multiple
* links based on the connected displays.
*/
ret = CVDisplayLinkCreateWithActiveCGDisplays (&impl->display_link);
if (ret != kCVReturnSuccess)
{
g_warning ("Failed to initialize CVDisplayLink!");
return source;
}
/*
* Determine our nominal period between frames.
*/
period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link);
if (period == 0.0)
period = 1.0 / 60.0;
impl->refresh_interval = period * 1000000L;
/*
* Wire up our callback to be executed within the high-priority thread.
*/
CVDisplayLinkSetOutputCallback (impl->display_link,
gdk_display_link_source_frame_cb,
source);
g_source_set_name (source, "[gdk] quartz frame clock");
return source;
}
static gint64
host_to_frame_clock_time (gint64 host_time)
{
static mach_timebase_info_data_t timebase_info;
/*
* NOTE:
*
* This code is taken from GLib to match g_get_monotonic_time().
*/
if (G_UNLIKELY (timebase_info.denom == 0))
{
/* This is a fraction that we must use to scale
* mach_absolute_time() by in order to reach nanoseconds.
*
* We've only ever observed this to be 1/1, but maybe it could be
* 1000/1 if mach time is microseconds already, or 1/1000 if
* picoseconds. Try to deal nicely with that.
*/
mach_timebase_info (&timebase_info);
/* We actually want microseconds... */
if (timebase_info.numer % 1000 == 0)
timebase_info.numer /= 1000;
else
timebase_info.denom *= 1000;
/* We want to make the numer 1 to avoid having to multiply... */
if (timebase_info.denom % timebase_info.numer == 0)
{
timebase_info.denom /= timebase_info.numer;
timebase_info.numer = 1;
}
else
{
/* We could just multiply by timebase_info.numer below, but why
* bother for a case that may never actually exist...
*
* Plus -- performing the multiplication would risk integer
* overflow. If we ever actually end up in this situation, we
* should more carefully evaluate the correct course of action.
*/
mach_timebase_info (&timebase_info); /* Get a fresh copy for a better message */
g_error ("Got weird mach timebase info of %d/%d. Please file a bug against GLib.",
timebase_info.numer, timebase_info.denom);
}
}
return host_time / timebase_info.denom;
}

View File

@@ -0,0 +1,48 @@
/* gdkdisplaylinksource.h
*
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
*
* 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/>.
*
* Authors:
* Christian Hergert <christian@hergert.me>
*/
#ifndef GDK_DISPLAY_LINK_SOURCE_H
#define GDK_DISPLAY_LINK_SOURCE_H
#include <glib.h>
#include <QuartzCore/QuartzCore.h>
G_BEGIN_DECLS
typedef struct
{
GSource source;
CVDisplayLinkRef display_link;
gint64 refresh_interval;
volatile gint64 presentation_time;
volatile guint needs_dispatch;
} GdkDisplayLinkSource;
GSource *gdk_display_link_source_new (void);
void gdk_display_link_source_pause (GdkDisplayLinkSource *source);
void gdk_display_link_source_unpause (GdkDisplayLinkSource *source);
G_END_DECLS
#endif /* GDK_DISPLAY_LINK_SOURCE_H */

View File

@@ -55,7 +55,6 @@ static void
gdk_quartz_display_manager_class_init (GdkQuartzDisplayManagerClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GdkDisplayManagerClass *manager_class = GDK_DISPLAY_MANAGER_CLASS (class);
object_class->finalize = gdk_quartz_display_manager_finalize;
}

View File

@@ -404,7 +404,7 @@ get_window_point_from_screen_point (GdkWindow *window,
static gboolean
is_mouse_button_press_event (NSEventType type)
{
switch (type)
switch ((int)type)
{
case NSLeftMouseDown:
case NSRightMouseDown:
@@ -895,7 +895,7 @@ fill_button_event (GdkWindow *window,
state = get_keyboard_modifiers_from_ns_event (nsevent) |
_gdk_quartz_events_get_current_mouse_modifiers ();
switch ([nsevent type])
switch ((int)[nsevent type])
{
case NSLeftMouseDown:
case NSRightMouseDown:

View File

@@ -125,6 +125,12 @@ void _gdk_quartz_display_create_window_impl (GdkDisplay *display,
GdkWindowAttr *attributes,
gint attributes_mask);
/* Display methods - frame clock */
void _gdk_quartz_display_add_frame_callback (GdkDisplay *display,
GdkWindow *window);
void _gdk_quartz_display_remove_frame_callback (GdkDisplay *display,
GdkWindow *window);
/* Display methods - keymap */
GdkKeymap * _gdk_quartz_display_get_keymap (GdkDisplay *display);

View File

@@ -22,6 +22,7 @@
#include <gdk/gdk.h>
#include <gdk/gdkdeviceprivate.h>
#include <gdk/gdkdisplayprivate.h>
#include <gdk/gdkframeclockprivate.h>
#include "gdkwindowimpl.h"
#include "gdkprivate-quartz.h"
@@ -43,8 +44,6 @@ 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;
@@ -154,7 +153,7 @@ gdk_window_impl_quartz_release_context (GdkWindowImplQuartz *window_impl,
/* See comment in gdk_quartz_window_get_context(). */
if (window_impl->in_paint_rect_count == 0)
{
_gdk_quartz_window_flush (window_impl);
[window_impl->toplevel flushWindow];
[window_impl->view unlockFocus];
}
}
@@ -218,47 +217,6 @@ gdk_window_impl_quartz_finalize (GObject *object)
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 gimps marching ants)
* 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 {
@@ -418,7 +376,6 @@ _gdk_quartz_display_before_process_all_updates (GdkDisplay *display)
void
_gdk_quartz_display_after_process_all_updates (GdkDisplay *display)
{
GSList *old_update_nswindows = update_nswindows;
GSList *tmp_list = update_nswindows;
update_nswindows = NULL;
@@ -429,17 +386,13 @@ _gdk_quartz_display_after_process_all_updates (GdkDisplay *display)
[[nswindow contentView] displayIfNeeded];
_gdk_quartz_window_flush (NULL);
[nswindow enableFlushWindow];
[nswindow flushWindow];
[nswindow release];
tmp_list = tmp_list->next;
tmp_list = g_slist_remove_link (tmp_list, tmp_list);
}
g_slist_free (old_update_nswindows);
in_process_all_updates = FALSE;
NSEnableScreenUpdates ();
@@ -776,6 +729,29 @@ get_nsscreen_for_point (gint x, gint y)
return screen;
}
static void
on_frame_clock_before_paint (GdkFrameClock *frame_clock,
GdkWindow *window)
{
}
static void
on_frame_clock_after_paint (GdkFrameClock *frame_clock,
GdkWindow *window)
{
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
GdkDisplay *display = gdk_window_get_display (window);
GdkFrameTimings *timings;
timings = gdk_frame_clock_get_current_timings (frame_clock);
if (timings != NULL)
impl->pending_frame_counter = timings->frame_counter;
_gdk_quartz_display_add_frame_callback (display, window);
_gdk_frame_clock_freeze (frame_clock);
}
void
_gdk_quartz_display_create_window_impl (GdkDisplay *display,
GdkWindow *window,
@@ -787,6 +763,7 @@ _gdk_quartz_display_create_window_impl (GdkDisplay *display,
{
GdkWindowImplQuartz *impl;
GdkWindowImplQuartz *parent_impl;
GdkFrameClock *frame_clock;
GDK_QUARTZ_ALLOC_POOL;
@@ -921,6 +898,13 @@ _gdk_quartz_display_create_window_impl (GdkDisplay *display,
if (attributes_mask & GDK_WA_TYPE_HINT)
gdk_window_set_type_hint (window, attributes->type_hint);
frame_clock = gdk_window_get_frame_clock (window);
g_signal_connect (frame_clock, "before-paint",
G_CALLBACK (on_frame_clock_before_paint), window);
g_signal_connect (frame_clock, "after-paint",
G_CALLBACK (on_frame_clock_after_paint), window);
}
void
@@ -976,9 +960,14 @@ gdk_quartz_window_destroy (GdkWindow *window,
{
GdkWindowImplQuartz *impl;
GdkWindow *parent;
GdkDisplay *display;
impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
display = gdk_window_get_display (window);
_gdk_quartz_display_remove_frame_callback (display, window);
main_window_stack = g_slist_remove (main_window_stack, window);
g_list_free (impl->sorted_children);
@@ -3025,21 +3014,25 @@ static CGContextRef
gdk_root_window_impl_quartz_get_context (GdkWindowImplQuartz *window,
gboolean antialias)
{
CGColorSpaceRef colorspace;
CGColorSpaceRef colorSpace;
CGContextRef cg_context;
GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (window);
if (GDK_WINDOW_DESTROYED (window_impl->wrapper))
return NULL;
colorSpace = CGDisplayCopyColorSpace (CGMainDisplayID ());
if (!colorSpace)
colorSpace = CGColorSpaceCreateDeviceRGB ();
/* 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,
kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease (colorspace);
1, 1, 8, 4, colorSpace,
kCGBitmapByteOrder32Host|kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease (colorSpace);
return cg_context;
}

View File

@@ -64,6 +64,9 @@ struct _GdkWindowImplQuartz
gint shadow_top;
gint shadow_max;
GList frame_link;
gint pending_frame_counter;
};
struct _GdkWindowImplQuartzClass

View File

@@ -18,9 +18,15 @@
#include "config.h"
#include "gtkdebug.h"
#include "gtkstylecontextprivate.h"
#include "gtkpixelcacheprivate.h"
#include "gtkstylecontextprivate.h"
#ifdef GDK_WINDOWING_QUARTZ
# include <cairo/cairo-quartz.h>
# include <gdk/quartz/gdkquartz.h>
#endif
#define BLOW_CACHE_TIMEOUT_SEC 20
/* The extra size of the offscreen surface we allocate
@@ -243,6 +249,18 @@ _gtk_pixel_cache_create_surface_if_needed (GtkPixelCache *cache,
cache->surface =
gdk_window_create_similar_surface (window, content,
surface_w, surface_h);
#ifdef GDK_WINDOWING_QUARTZ
if (GDK_IS_QUARTZ_WINDOW (window))
{
cairo_surface_t *base;
base = cache->surface;
cache->surface = cairo_quartz_surface_create_cg_layer (base, content, surface_w, surface_h);
cairo_surface_destroy (base);
}
#endif
rect.x = 0;
rect.y = 0;
rect.width = surface_w;