Merge branch 'quartz-redraw-pixbuf' into 'gtk-3-24'
quartz: Use CALayer to back GdkQuartzView See merge request GNOME/gtk!4728
This commit is contained in:
@@ -24,16 +24,34 @@
|
||||
#include "gdkprivate-quartz.h"
|
||||
#include "gdkquartz.h"
|
||||
#include "gdkinternal-quartz.h"
|
||||
#include <cairo/cairo-quartz.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <IOSurface/IOSurface.h>
|
||||
|
||||
@implementation GdkQuartzView
|
||||
|
||||
|
||||
|
||||
-(id)initWithFrame: (NSRect)frameRect
|
||||
{
|
||||
if ((self = [super initWithFrame: frameRect]))
|
||||
{
|
||||
CVReturn rv;
|
||||
pb_props = @{
|
||||
(id)kCVPixelBufferIOSurfaceCoreAnimationCompatibilityKey: @1,
|
||||
(id)kCVPixelBufferBytesPerRowAlignmentKey: @64,
|
||||
};
|
||||
[pb_props retain];
|
||||
cfpb_props = (__bridge CFDictionaryRef)pb_props;
|
||||
|
||||
markedRange = NSMakeRange (NSNotFound, 0);
|
||||
selectedRange = NSMakeRange (0, 0);
|
||||
rv = CVPixelBufferCreate (NULL, frameRect.size.width,
|
||||
frameRect.size.height,
|
||||
kCVPixelFormatType_32ARGB,
|
||||
cfpb_props, &pixels);
|
||||
}
|
||||
|
||||
[self setValue: @(YES) forKey: @"postsFrameChangedNotifications"];
|
||||
|
||||
return self;
|
||||
@@ -185,7 +203,7 @@
|
||||
|
||||
-(void)doCommandBySelector: (SEL)aSelector
|
||||
{
|
||||
GDK_NOTE (EVENTS, g_message ("doCommandBySelector %s", aSelector));
|
||||
GDK_NOTE (EVENTS, g_message ("doCommandBySelector %s", [NSStringFromSelector (aSelector) UTF8String]));
|
||||
g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
|
||||
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
|
||||
}
|
||||
@@ -256,6 +274,12 @@
|
||||
trackingRect = 0;
|
||||
}
|
||||
|
||||
if (pixels)
|
||||
{
|
||||
CVPixelBufferRelease (pixels);
|
||||
}
|
||||
|
||||
[pb_props release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -276,7 +300,7 @@
|
||||
|
||||
-(BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(BOOL)isOpaque
|
||||
@@ -298,7 +322,7 @@
|
||||
*/
|
||||
if(gdk_quartz_osx_version() >= GDK_OSX_BIGSUR)
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
|
||||
CALayer* layer = self.layer;
|
||||
layer.contentsFormat = kCAContentsFormatRGBA8Uint;
|
||||
#endif
|
||||
@@ -307,74 +331,128 @@
|
||||
[super viewWillDraw];
|
||||
}
|
||||
|
||||
-(void)drawRect: (NSRect)rect
|
||||
-(BOOL)wantsUpdateLayer
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
static void
|
||||
nsrect_from_cairo_rect (NSRect *nsrect, cairo_rectangle_int_t *rect)
|
||||
{
|
||||
nsrect->origin.x = (CGFloat)rect->x;
|
||||
nsrect->origin.y = (CGFloat)rect->y;
|
||||
nsrect->size.width = (CGFloat)rect->width;
|
||||
nsrect->size.height = (CGFloat)rect->height;
|
||||
}
|
||||
|
||||
static void
|
||||
cairo_rect_from_nsrect (cairo_rectangle_int_t *rect, NSRect *nsrect)
|
||||
{
|
||||
rect->x = (int)nsrect->origin.x;
|
||||
rect->y = (int)nsrect->origin.y;
|
||||
rect->width = (int)nsrect->size.width;
|
||||
rect->height = (int)nsrect->size.height;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
copy_rectangle_argb32 (cairo_surface_t *dest, cairo_surface_t *source,
|
||||
cairo_rectangle_int_t *rect)
|
||||
{
|
||||
cairo_surface_t *source_img, *dest_img;
|
||||
cairo_status_t status;
|
||||
cairo_format_t format;
|
||||
int height, width, stride;
|
||||
|
||||
source_img = cairo_surface_map_to_image (source, rect);
|
||||
status = cairo_surface_status (source_img);
|
||||
|
||||
if (status)
|
||||
{
|
||||
g_warning ("Failed to map source image surface, %d %d %d %d on %d %d: %s\n",
|
||||
rect->x, rect->y, rect->width, rect->height,
|
||||
cairo_image_surface_get_width (source),
|
||||
cairo_image_surface_get_height (source),
|
||||
cairo_status_to_string (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
format = cairo_image_surface_get_format (source_img);
|
||||
dest_img = cairo_surface_map_to_image (dest, rect);
|
||||
status = cairo_surface_status (dest_img);
|
||||
|
||||
if (status)
|
||||
{
|
||||
g_warning ("Failed to map destination image surface, %d %d %d %d on %d %d: %s\n",
|
||||
rect->x, rect->y, rect->width, rect->height,
|
||||
cairo_image_surface_get_width (source),
|
||||
cairo_image_surface_get_height (source),
|
||||
cairo_status_to_string (status));
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
width = cairo_image_surface_get_width (source_img);
|
||||
stride = cairo_format_stride_for_width (format, width);
|
||||
height = cairo_image_surface_get_height (source_img);
|
||||
memcpy (cairo_image_surface_get_data (dest_img),
|
||||
cairo_image_surface_get_data (source_img),
|
||||
stride * height);
|
||||
cairo_surface_unmap_image (dest, dest_img);
|
||||
|
||||
CLEANUP:
|
||||
cairo_surface_unmap_image (source, source_img);
|
||||
return status;
|
||||
}
|
||||
|
||||
-(void)updateLayer
|
||||
{
|
||||
GdkRectangle gdk_rect;
|
||||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (gdk_window->impl);
|
||||
const NSRect *drawn_rects;
|
||||
NSInteger count;
|
||||
int i;
|
||||
cairo_region_t *region;
|
||||
CGRect layer_bounds = [self.layer bounds];
|
||||
CGRect backing_bounds = [self convertRectToBacking: layer_bounds];
|
||||
cairo_rectangle_int_t extents;
|
||||
cairo_surface_t *cvpb_surface;
|
||||
|
||||
if (GDK_WINDOW_DESTROYED (gdk_window))
|
||||
return;
|
||||
|
||||
if (! (gdk_window->event_mask & GDK_EXPOSURE_MASK))
|
||||
return;
|
||||
++impl->in_paint_rect_count;
|
||||
CVPixelBufferLockBaseAddress (pixels, 0);
|
||||
cvpb_surface =
|
||||
cairo_image_surface_create_for_data (CVPixelBufferGetBaseAddress (pixels),
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
(int)CVPixelBufferGetWidth (pixels),
|
||||
(int)CVPixelBufferGetHeight (pixels),
|
||||
(int)CVPixelBufferGetBytesPerRow (pixels));
|
||||
|
||||
if (NSEqualRects (rect, NSZeroRect))
|
||||
return;
|
||||
|
||||
if (!GDK_WINDOW_IS_MAPPED (gdk_window))
|
||||
{
|
||||
/* If the window is not yet mapped, clip_region_with_children
|
||||
* will be empty causing the usual code below to draw nothing.
|
||||
* To not see garbage on the screen, we draw an aesthetic color
|
||||
* here. The garbage would be visible if any widget enabled
|
||||
* the NSView's CALayer in order to add sublayers for custom
|
||||
* native rendering.
|
||||
*/
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
|
||||
[[NSColor windowBackgroundColor] setFill];
|
||||
[NSBezierPath fillRect: rect];
|
||||
|
||||
[NSGraphicsContext restoreGraphicsState];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear our own bookkeeping of regions that need display */
|
||||
cairo_rect_from_nsrect (&extents, &backing_bounds);
|
||||
if (impl->needs_display_region)
|
||||
{
|
||||
cairo_region_destroy (impl->needs_display_region);
|
||||
cairo_region_t *region = impl->needs_display_region;
|
||||
_gdk_window_process_updates_recurse (gdk_window, region);
|
||||
cairo_region_destroy (region);
|
||||
impl->needs_display_region = NULL;
|
||||
}
|
||||
|
||||
[self getRectsBeingDrawn: &drawn_rects count: &count];
|
||||
region = cairo_region_create ();
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
else
|
||||
{
|
||||
gdk_rect.x = drawn_rects[i].origin.x;
|
||||
gdk_rect.y = drawn_rects[i].origin.y;
|
||||
gdk_rect.width = drawn_rects[i].size.width;
|
||||
gdk_rect.height = drawn_rects[i].size.height;
|
||||
cairo_rectangle_int_t bounds;
|
||||
cairo_region_t *region;
|
||||
|
||||
cairo_region_union_rectangle (region, &gdk_rect);
|
||||
cairo_rect_from_nsrect (&bounds, &layer_bounds);
|
||||
region = cairo_region_create_rectangle (&bounds);
|
||||
_gdk_window_process_updates_recurse (gdk_window, region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
|
||||
if (!impl || !impl->cairo_surface)
|
||||
return;
|
||||
|
||||
impl->in_paint_rect_count++;
|
||||
_gdk_window_process_updates_recurse (gdk_window, region);
|
||||
impl->in_paint_rect_count--;
|
||||
copy_rectangle_argb32 (cvpb_surface, impl->cairo_surface, &extents);
|
||||
|
||||
cairo_region_destroy (region);
|
||||
|
||||
if (needsInvalidateShadow)
|
||||
{
|
||||
[[self window] invalidateShadow];
|
||||
needsInvalidateShadow = NO;
|
||||
}
|
||||
cairo_surface_destroy (cvpb_surface);
|
||||
_gdk_quartz_unref_cairo_surface (gdk_window);
|
||||
CVPixelBufferUnlockBaseAddress (pixels, 0);
|
||||
--impl->in_paint_rect_count;
|
||||
self.layer.contents = NULL;
|
||||
self.layer.contents = (id)CVPixelBufferGetIOSurface (pixels);
|
||||
}
|
||||
|
||||
-(void)setNeedsInvalidateShadow: (BOOL)invalidate
|
||||
@@ -432,9 +510,21 @@
|
||||
|
||||
-(void)setFrame: (NSRect)frame
|
||||
{
|
||||
CVReturn rv;
|
||||
NSRect rect = self.layer ? self.layer.bounds : frame;
|
||||
NSRect backing_rect = [self convertRectToBacking: rect];
|
||||
|
||||
if (GDK_WINDOW_DESTROYED (gdk_window))
|
||||
return;
|
||||
|
||||
CVPixelBufferRelease (pixels);
|
||||
rv = CVPixelBufferCreate (NULL, backing_rect.size.width,
|
||||
backing_rect.size.height,
|
||||
kCVPixelFormatType_32BGRA,
|
||||
cfpb_props, &pixels);
|
||||
|
||||
//Force a new cairo_surface for drawing
|
||||
_gdk_quartz_unref_cairo_surface (gdk_window);
|
||||
[super setFrame: frame];
|
||||
|
||||
if ([self window])
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
#include "gdk/gdk.h"
|
||||
|
||||
/* Text Input Client */
|
||||
@@ -40,6 +41,9 @@
|
||||
BOOL needsInvalidateShadow;
|
||||
NSRange markedRange;
|
||||
NSRange selectedRange;
|
||||
CVPixelBufferRef pixels;
|
||||
NSDictionary *pb_props;
|
||||
CFDictionaryRef cfpb_props;
|
||||
}
|
||||
|
||||
- (void)setGdkWindow: (GdkWindow *)window;
|
||||
|
||||
@@ -30,6 +30,8 @@ libgdk_quartz_la_SOURCES = \
|
||||
gdkdevicemanager-core-quartz.h \
|
||||
gdkdisplay-quartz.c \
|
||||
gdkdisplay-quartz.h \
|
||||
gdkdisplaylinksource.c \
|
||||
gdkdisplaylinksource.h \
|
||||
gdkdisplaymanager-quartz.c \
|
||||
gdkdnd-quartz.c \
|
||||
gdkdnd-quartz.h \
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gdk/gdkmonitorprivate.h>
|
||||
#include <gdk/gdkframeclockprivate.h>
|
||||
|
||||
#include "gdkprivate-quartz.h"
|
||||
#include "gdkquartzscreen.h"
|
||||
@@ -29,6 +30,7 @@
|
||||
#include "gdkquartzdevicemanager-core.h"
|
||||
#include "gdkscreen.h"
|
||||
#include "gdkmonitorprivate.h"
|
||||
#include "gdkdisplaylinksource.h"
|
||||
#include "gdkdisplay-quartz.h"
|
||||
#include "gdkmonitor-quartz.h"
|
||||
#include "gdkglcontext-quartz.h"
|
||||
@@ -84,6 +86,112 @@ _gdk_device_manager_new (GdkDisplay *display)
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_quartz_display_add_frame_callback (GdkDisplay *display,
|
||||
GdkWindow *window)
|
||||
{
|
||||
GdkQuartzDisplay *display_quartz;
|
||||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -102,6 +210,8 @@ _gdk_quartz_display_open (const gchar *display_name)
|
||||
|
||||
/* Initialize application */
|
||||
[NSApplication sharedApplication];
|
||||
gdk_quartz_display_init_display_link (_gdk_display);
|
||||
|
||||
#if 0
|
||||
/* FIXME: Remove the #if 0 when we have these functions */
|
||||
_gdk_quartz_dnd_init ();
|
||||
|
||||
@@ -37,6 +37,10 @@ struct _GdkQuartzDisplay
|
||||
NSRect geometry; /* In AppKit coordinates. */
|
||||
NSSize size; /* Aggregate size of displays in millimeters. */
|
||||
GPtrArray *monitors;
|
||||
/* This structure is not allocated. It points to an embedded
|
||||
* GList in the GdkWindow. */
|
||||
GList *windows_awaiting_frame;
|
||||
GSource *frame_source;
|
||||
};
|
||||
|
||||
struct _GdkQuartzDisplayClass
|
||||
|
||||
251
gdk/quartz/gdkdisplaylinksource.c
Normal file
251
gdk/quartz/gdkdisplaylinksource.c
Normal 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 "gdkinternal-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: NSEventTypeApplicationDefined
|
||||
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;
|
||||
}
|
||||
48
gdk/quartz/gdkdisplaylinksource.h
Normal file
48
gdk/quartz/gdkdisplaylinksource.h
Normal 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 */
|
||||
@@ -396,7 +396,7 @@ get_window_point_from_screen_point (GdkWindow *window,
|
||||
static gboolean
|
||||
is_mouse_button_press_event (NSEventType type)
|
||||
{
|
||||
switch (type)
|
||||
switch ((int)type)
|
||||
{
|
||||
case GDK_QUARTZ_LEFT_MOUSE_DOWN:
|
||||
case GDK_QUARTZ_RIGHT_MOUSE_DOWN:
|
||||
@@ -1029,7 +1029,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 GDK_QUARTZ_LEFT_MOUSE_DOWN:
|
||||
case GDK_QUARTZ_RIGHT_MOUSE_DOWN:
|
||||
|
||||
@@ -284,5 +284,10 @@ void _gdk_quartz_window_change_property (GdkWindow *window,
|
||||
void _gdk_quartz_window_delete_property (GdkWindow *window,
|
||||
GdkAtom property);
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif /* __GDK_INTERNAL_QUARTZ_H__ */
|
||||
|
||||
@@ -33,5 +33,7 @@
|
||||
|
||||
GdkDisplay * _gdk_quartz_display_open (const gchar *name);
|
||||
|
||||
/* Window Impl */
|
||||
void _gdk_quartz_unref_cairo_surface (GdkWindow *window);
|
||||
|
||||
#endif /* __GDK_PRIVATE_QUARTZ_H__ */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkdeviceprivate.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gdk/gdkframeclockprivate.h>
|
||||
|
||||
#include "gdkwindowimpl.h"
|
||||
#include "gdkwindow-quartz.h"
|
||||
@@ -47,8 +48,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;
|
||||
@@ -149,7 +148,6 @@ 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;
|
||||
@@ -160,38 +158,31 @@ gdk_window_impl_quartz_get_context (GdkWindowImplQuartz *window_impl,
|
||||
* 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 MAC_OS_X_VERSION_MAX_ALLOWED < 101400
|
||||
if (gdk_quartz_osx_version() < GDK_OSX_MOJAVE &&
|
||||
window_impl->in_paint_rect_count == 0)
|
||||
{
|
||||
/* The NSView focus-locking API set was deprecated in MacOS 10.14 and
|
||||
* has a significant cost in MacOS 11 - every lock/unlock seems to
|
||||
* has a significant cost in MacOS 11 - every lock/unlock seems to
|
||||
* trigger a drawRect: call for the entire window. To return the
|
||||
* lost performance, do not use the locking API in MacOS 11+
|
||||
*/
|
||||
if(gdk_quartz_osx_version() < GDK_OSX_BIGSUR)
|
||||
{
|
||||
if (![window_impl->view lockFocusIfCanDraw])
|
||||
if (![window_impl->view lockFocusIfCanDraw])
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101000
|
||||
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
#else
|
||||
#endif
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
|
||||
if (gdk_quartz_osx_version () < GDK_OSX_YOSEMITE)
|
||||
cg_context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
else
|
||||
cg_context = [[NSGraphicsContext currentContext] CGContext];
|
||||
#endif
|
||||
cg_context = [[NSGraphicsContext currentContext] CGContext];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -206,19 +197,14 @@ 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)
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
|
||||
if (gdk_quartz_osx_version() < GDK_OSX_MOJAVE &&
|
||||
window_impl->in_paint_rect_count == 0)
|
||||
{
|
||||
_gdk_quartz_window_flush (window_impl);
|
||||
|
||||
/* As per gdk_window_impl_quartz_get_context(), the NSView
|
||||
* focus-locking API set was deprecated in MacOS 10.14 and has
|
||||
* a significant cost in MacOS 11 - every lock/unlock seems to
|
||||
* trigger a drawRect: call for the entire window. To return the
|
||||
* lost performance, do not use the locking API in MacOS 11+
|
||||
*/
|
||||
if(gdk_quartz_osx_version() < GDK_OSX_BIGSUR)
|
||||
[window_impl->view unlockFocus];
|
||||
[window_impl->toplevel flushWindow];
|
||||
[window_impl->view unlockFocus];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -241,52 +227,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 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 {
|
||||
@@ -298,12 +238,11 @@ static void
|
||||
gdk_quartz_cairo_surface_destroy (void *data)
|
||||
{
|
||||
GdkQuartzCairoSurfaceData *surface_data = data;
|
||||
cairo_surface_t *surface = surface_data->window_impl->cairo_surface;
|
||||
|
||||
if (!cairo_surface_get_reference_count (surface))
|
||||
surface_data->window_impl->cairo_surface = NULL;
|
||||
|
||||
gdk_quartz_window_release_context (surface_data->window_impl,
|
||||
surface_data->cg_context);
|
||||
|
||||
g_free (surface_data);
|
||||
}
|
||||
|
||||
@@ -312,22 +251,15 @@ 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);
|
||||
surface_data->cg_context = NULL;
|
||||
|
||||
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||
cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
|
||||
surface_data,
|
||||
gdk_quartz_cairo_surface_destroy);
|
||||
@@ -345,21 +277,44 @@ gdk_quartz_ref_cairo_surface (GdkWindow *window)
|
||||
|
||||
if (!impl->cairo_surface)
|
||||
{
|
||||
gint width = gdk_window_get_width (impl->wrapper);
|
||||
gint height = gdk_window_get_height (impl->wrapper);
|
||||
gint scale = gdk_window_get_scale_factor (impl->wrapper);
|
||||
gint scaled_width = width * scale;
|
||||
|
||||
impl->cairo_surface =
|
||||
gdk_quartz_create_cairo_surface (impl,
|
||||
gdk_window_get_width (impl->wrapper) * scale,
|
||||
gdk_window_get_height (impl->wrapper) * scale);
|
||||
if (scaled_width % 16)
|
||||
scaled_width += 16 - scaled_width % 16; // Surface widths must be 4-pixel aligned
|
||||
|
||||
impl->cairo_surface = gdk_quartz_create_cairo_surface (impl,
|
||||
scaled_width,
|
||||
height * scale);
|
||||
cairo_surface_set_device_scale (impl->cairo_surface, scale, scale);
|
||||
cairo_surface_reference (impl->cairo_surface); // The caller will destroy the returned one.
|
||||
}
|
||||
else
|
||||
cairo_surface_reference (impl->cairo_surface);
|
||||
{
|
||||
cairo_surface_reference (impl->cairo_surface);
|
||||
}
|
||||
|
||||
return impl->cairo_surface;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_quartz_unref_cairo_surface (GdkWindow *window)
|
||||
{
|
||||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||||
if (GDK_WINDOW_DESTROYED (window))
|
||||
return;
|
||||
|
||||
if (impl->cairo_surface)
|
||||
{
|
||||
cairo_surface_destroy (impl->cairo_surface);
|
||||
if (impl->cairo_surface &&
|
||||
!cairo_surface_get_reference_count (impl->cairo_surface))
|
||||
impl->cairo_surface = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_window_impl_quartz_init (GdkWindowImplQuartz *impl)
|
||||
{
|
||||
@@ -369,6 +324,7 @@ gdk_window_impl_quartz_init (GdkWindowImplQuartz *impl)
|
||||
static gboolean
|
||||
gdk_window_impl_quartz_begin_paint (GdkWindow *window)
|
||||
{
|
||||
gdk_quartz_ref_cairo_surface (window);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -419,13 +375,14 @@ _gdk_quartz_window_process_updates_recurse (GdkWindow *window,
|
||||
/* In theory, we could skip the flush disabling, since we only
|
||||
* have one NSView.
|
||||
*/
|
||||
if (nswindow && ![nswindow isFlushWindowDisabled])
|
||||
if (gdk_quartz_osx_version() < GDK_OSX_MOJAVE &&
|
||||
nswindow && ![nswindow isFlushWindowDisabled])
|
||||
{
|
||||
[nswindow retain];
|
||||
[nswindow disableFlushWindow];
|
||||
update_nswindows = g_slist_prepend (update_nswindows, nswindow);
|
||||
}
|
||||
#endif
|
||||
update_nswindows = g_slist_prepend (update_nswindows, nswindow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,10 +427,12 @@ _gdk_quartz_display_after_process_all_updates (GdkDisplay *display)
|
||||
|
||||
[[nswindow contentView] displayIfNeeded];
|
||||
|
||||
_gdk_quartz_window_flush (NULL);
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400
|
||||
[nswindow enableFlushWindow];
|
||||
[nswindow flushWindow];
|
||||
if(gdk_quartz_osx_version() < GDK_OSX_BIGSUR)
|
||||
{
|
||||
[nswindow enableFlushWindow];
|
||||
[nswindow flushWindow];
|
||||
}
|
||||
#endif
|
||||
[nswindow release];
|
||||
|
||||
@@ -852,6 +811,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,
|
||||
@@ -864,6 +846,7 @@ _gdk_quartz_display_create_window_impl (GdkDisplay *display,
|
||||
GdkWindowImplQuartz *impl;
|
||||
GdkWindowImplQuartz *parent_impl;
|
||||
GdkWindowTypeHint type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
|
||||
GdkFrameClock *frame_clock;
|
||||
|
||||
GDK_QUARTZ_ALLOC_POOL;
|
||||
|
||||
@@ -1008,6 +991,16 @@ _gdk_quartz_display_create_window_impl (GdkDisplay *display,
|
||||
}
|
||||
|
||||
GDK_QUARTZ_RELEASE_POOL;
|
||||
|
||||
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
|
||||
@@ -1063,9 +1056,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);
|
||||
@@ -1257,6 +1255,7 @@ move_resize_window_internal (GdkWindow *window,
|
||||
cairo_region_t *old_region;
|
||||
cairo_region_t *expose_region;
|
||||
NSSize delta;
|
||||
gboolean resized = FALSE;
|
||||
|
||||
if (GDK_WINDOW_DESTROYED (window))
|
||||
return;
|
||||
@@ -1304,10 +1303,18 @@ move_resize_window_internal (GdkWindow *window,
|
||||
}
|
||||
|
||||
if (width != -1)
|
||||
window->width = width;
|
||||
{
|
||||
if (window->width != width)
|
||||
resized = TRUE;
|
||||
window->width = width;
|
||||
}
|
||||
|
||||
if (height != -1)
|
||||
window->height = height;
|
||||
{
|
||||
if (window->height != height)
|
||||
resized = TRUE;
|
||||
window->height = height;
|
||||
}
|
||||
|
||||
GDK_QUARTZ_ALLOC_POOL;
|
||||
|
||||
@@ -1324,6 +1331,7 @@ move_resize_window_internal (GdkWindow *window,
|
||||
|
||||
frame_rect = [impl->toplevel frameRectForContentRect:content_rect];
|
||||
[impl->toplevel setFrame:frame_rect display:YES];
|
||||
impl->cairo_surface = gdk_quartz_ref_cairo_surface (window);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3211,40 +3219,19 @@ gdk_quartz_window_release_context (GdkWindowImplQuartz *window,
|
||||
return;
|
||||
}
|
||||
|
||||
g_return_if_fail (cg_context);
|
||||
GDK_WINDOW_IMPL_QUARTZ_GET_CLASS (window)->release_context (window, cg_context);
|
||||
}
|
||||
|
||||
/* macOS doesn't define a root window, but Gdk needs one for two
|
||||
* purposes: To be a parent reference for some toplevels and to be a
|
||||
* fallback window when gdk_window_create_image_surface is called with
|
||||
* a NULL GdkWindow.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
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 CGContextRef gdk_root_window_impl_quartz_get_context (GdkWindowImplQuartz *window, gboolean antialias);
|
||||
static void gdk_root_window_impl_quartz_release_context (GdkWindowImplQuartz *window, CGContextRef cg_context);
|
||||
|
||||
static void
|
||||
gdk_root_window_impl_quartz_class_init (GdkRootWindowImplQuartzClass *klass)
|
||||
@@ -3260,6 +3247,22 @@ gdk_root_window_impl_quartz_class_init (GdkRootWindowImplQuartzClass *klass)
|
||||
static void
|
||||
gdk_root_window_impl_quartz_init (GdkRootWindowImplQuartz *impl)
|
||||
{
|
||||
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB ();
|
||||
/* Alpha channel Info: Cairo, CGImage, and CVPixelBuffer all use
|
||||
* kCGImageAlphaPremultipliedFirst, CALayer.contents wants
|
||||
* kCGImageAlphaPremultipliedLast.
|
||||
*/
|
||||
CGBitmapInfo info = (CGBitmapInfo)kCGImageAlphaPremultipliedLast;
|
||||
impl->cg_context = CGBitmapContextCreate (NULL, 1, 1, 8, 4,
|
||||
colorspace, info);
|
||||
CGColorSpaceRelease (colorspace);
|
||||
impl->cg_layers = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_root_window_impl_quartz_dispose (GdkRootWindowImplQuartz *impl)
|
||||
{
|
||||
g_list_free_full (impl->cg_layers, (GDestroyNotify)CGLayerRelease);
|
||||
}
|
||||
|
||||
GType
|
||||
@@ -3289,3 +3292,30 @@ _gdk_root_window_impl_quartz_get_type (void)
|
||||
|
||||
return object_type;
|
||||
}
|
||||
|
||||
|
||||
static CGContextRef
|
||||
gdk_root_window_impl_quartz_get_context (GdkWindowImplQuartz *window,
|
||||
gboolean antialias)
|
||||
{
|
||||
GdkWindowImplQuartz *window_impl = GDK_WINDOW_IMPL_QUARTZ (window);
|
||||
GdkRootWindowImplQuartz *impl = GDK_ROOT_WINDOW_IMPL_QUARTZ (window);
|
||||
CGSize size;
|
||||
CGLayerRef layer;
|
||||
|
||||
if (GDK_WINDOW_DESTROYED (window_impl->wrapper))
|
||||
return NULL;
|
||||
|
||||
size.width = gdk_window_get_width (window_impl->wrapper);
|
||||
size.height = gdk_window_get_height (window_impl->wrapper);
|
||||
layer = CGLayerCreateWithContext(impl->cg_context, size, NULL);
|
||||
impl->cg_layers = g_list_prepend(impl->cg_layers, CGLayerRetain (layer));
|
||||
return CGContextRetain (CGLayerGetContext (layer));
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_root_window_impl_quartz_release_context (GdkWindowImplQuartz *window,
|
||||
CGContextRef cg_context)
|
||||
{
|
||||
CGContextRelease (cg_context);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@ struct _GdkWindowImplQuartz
|
||||
gint shadow_top;
|
||||
|
||||
gint shadow_max;
|
||||
|
||||
gboolean use_cg_context;
|
||||
GList frame_link;
|
||||
gint pending_frame_counter;
|
||||
};
|
||||
|
||||
struct _GdkWindowImplQuartzClass
|
||||
@@ -99,6 +103,8 @@ typedef struct _GdkRootWindowImplQuartzClass GdkRootWindowImplQuartzClass;
|
||||
struct _GdkRootWindowImplQuartz
|
||||
{
|
||||
GdkWindowImplQuartz parent_instance;
|
||||
CGContextRef cg_context;
|
||||
GList* cg_layers;
|
||||
};
|
||||
|
||||
struct _GdkRootWindowImplQuartzClass
|
||||
|
||||
@@ -8,6 +8,7 @@ gdk_quartz_sources = files(
|
||||
'gdkdevice-core-quartz.c',
|
||||
'gdkdevicemanager-core-quartz.c',
|
||||
'gdkdisplay-quartz.c',
|
||||
'gdkdisplaylinksource.c',
|
||||
'gdkdisplaymanager-quartz.c',
|
||||
'gdkdnd-quartz.c',
|
||||
'gdkevents-quartz.c',
|
||||
@@ -49,8 +50,9 @@ appkit_dep = dependency('appleframeworks', modules : 'AppKit', required : true)
|
||||
cocoa_dep = dependency('appleframeworks', modules : 'Cocoa', required : true)
|
||||
carbon_dep = dependency('appleframeworks', modules : 'Carbon', required : true)
|
||||
quartzcore_dep = dependency('appleframeworks', modules : 'QuartzCore', required : true)
|
||||
iosurface_dep = dependency('appleframeworks', modules: 'IOSurface', required: true)
|
||||
|
||||
gdk_quartz_deps = [ core_graphics_dep, appkit_dep, cocoa_dep, carbon_dep, quartzcore_dep ]
|
||||
gdk_quartz_deps = [ core_graphics_dep, appkit_dep, cocoa_dep, carbon_dep, quartzcore_dep, iosurface_dep ]
|
||||
|
||||
libgdk_quartz = static_library('gdk-quartz',
|
||||
gdk_quartz_sources, gdkconfig, gdkenum_h,
|
||||
|
||||
Reference in New Issue
Block a user