Draw window to image_surface and apply to CALayer.
This commit is contained in:
parent
2d3eb0c6a7
commit
be60902805
@ -24,6 +24,8 @@
|
||||
#include "gdkprivate-quartz.h"
|
||||
#include "gdkquartz.h"
|
||||
#include "gdkinternal-quartz.h"
|
||||
#include <cairo/cairo-quartz.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@implementation GdkQuartzView
|
||||
|
||||
@ -185,7 +187,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));
|
||||
}
|
||||
@ -307,43 +309,32 @@
|
||||
[super viewWillDraw];
|
||||
}
|
||||
|
||||
-(void)drawRect: (NSRect)rect
|
||||
-(BOOL)wantsUpdateLayer
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
static void
|
||||
provider_release_cb (void* info, const void* data, size_t size)
|
||||
{
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
-(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;
|
||||
CALayer *ca_layer = [self layer];
|
||||
CGRect layer_bounds = [ca_layer bounds];
|
||||
CGRect backing_bounds = [self convertRectToBacking: layer_bounds];
|
||||
cairo_rectangle_int_t surface_extents = { layer_bounds.origin.x,
|
||||
layer_bounds.origin.y,
|
||||
backing_bounds.size.width,
|
||||
backing_bounds.size.height };
|
||||
cairo_surface_t *image_surface = NULL;
|
||||
|
||||
if (GDK_WINDOW_DESTROYED (gdk_window))
|
||||
return;
|
||||
|
||||
if (! (gdk_window->event_mask & GDK_EXPOSURE_MASK))
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (impl->needs_display_region)
|
||||
{
|
||||
_gdk_window_process_updates_recurse (gdk_window, impl->needs_display_region);
|
||||
@ -352,31 +343,66 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
[self getRectsBeingDrawn: &drawn_rects count: &count];
|
||||
cairo_region_t* region = cairo_region_create ();
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
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_region_union_rectangle (region, &gdk_rect);
|
||||
}
|
||||
|
||||
impl->in_paint_rect_count++;
|
||||
cairo_region_t *region = cairo_region_create_rectangle (&surface_extents);
|
||||
++impl->in_paint_rect_count;
|
||||
_gdk_window_process_updates_recurse (gdk_window, region);
|
||||
impl->in_paint_rect_count--;
|
||||
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
|
||||
if (!impl || !impl->cairo_surface)
|
||||
return;
|
||||
|
||||
if (needsInvalidateShadow)
|
||||
image_surface = cairo_surface_map_to_image (impl->cairo_surface,
|
||||
&surface_extents);
|
||||
if (!cairo_surface_status (image_surface))
|
||||
{
|
||||
[[self window] invalidateShadow];
|
||||
needsInvalidateShadow = NO;
|
||||
cairo_format_t image_format = cairo_image_surface_get_format (image_surface);
|
||||
if (image_format == CAIRO_FORMAT_ARGB32)
|
||||
{
|
||||
int image_width = cairo_image_surface_get_width (image_surface);
|
||||
int image_height = cairo_image_surface_get_height (image_surface);
|
||||
int image_stride = cairo_image_surface_get_stride (image_surface);
|
||||
void* image_data = g_malloc (image_height * image_stride);
|
||||
int color_bits = 8;
|
||||
int pixel_bits = 32;
|
||||
CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB ();
|
||||
CGBitmapInfo bitinfo =
|
||||
kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst;
|
||||
CGDataProviderRef provider =
|
||||
CGDataProviderCreateWithData (image_data, image_data,
|
||||
image_height * image_stride,
|
||||
provider_release_cb);
|
||||
const CGFloat *decode = NULL;
|
||||
bool interpolate = YES;
|
||||
CGSize image_size = {image_height, image_width};
|
||||
NSImage* ns_image = NULL;
|
||||
|
||||
if (ca_layer.contents)
|
||||
[(NSImage*)ca_layer.contents release];
|
||||
|
||||
memcpy (image_data, cairo_image_surface_get_data (image_surface),
|
||||
image_height * image_stride);
|
||||
|
||||
ns_image = [[NSImage alloc]
|
||||
initWithCGImage:CGImageCreate (image_width,
|
||||
image_height,
|
||||
color_bits,
|
||||
pixel_bits,
|
||||
image_stride,
|
||||
color_space,
|
||||
bitinfo,
|
||||
provider,
|
||||
decode,
|
||||
interpolate,
|
||||
kCGRenderingIntentDefault)
|
||||
size:image_size];
|
||||
ca_layer.contents = ns_image;
|
||||
}
|
||||
}
|
||||
cairo_surface_unmap_image (impl->cairo_surface, image_surface);
|
||||
cairo_surface_destroy (impl->cairo_surface);
|
||||
--impl->in_paint_rect_count;
|
||||
|
||||
}
|
||||
|
||||
-(void)setNeedsInvalidateShadow: (BOOL)invalidate
|
||||
|
@ -148,7 +148,7 @@ gdk_window_impl_quartz_get_context (GdkWindowImplQuartz *window_impl,
|
||||
gboolean antialias)
|
||||
{
|
||||
CGContextRef cg_context = NULL;
|
||||
CGSize scale;
|
||||
// CGSize scale;
|
||||
|
||||
if (GDK_WINDOW_DESTROYED (window_impl->wrapper))
|
||||
return NULL;
|
||||
@ -186,9 +186,8 @@ gdk_window_impl_quartz_get_context (GdkWindowImplQuartz *window_impl,
|
||||
|
||||
/* 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));
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -247,10 +246,6 @@ gdk_quartz_cairo_surface_destroy (void *data)
|
||||
|
||||
surface_data->window_impl->cairo_surface = NULL;
|
||||
|
||||
if (surface_data->cg_context)
|
||||
gdk_quartz_window_release_context (surface_data->window_impl,
|
||||
surface_data->cg_context);
|
||||
|
||||
g_free (surface_data);
|
||||
}
|
||||
|
||||
@ -259,21 +254,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;
|
||||
surface_data->cg_context = NULL;
|
||||
|
||||
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 = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||
|
||||
cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
|
||||
surface_data,
|
||||
@ -286,19 +275,17 @@ static cairo_surface_t *
|
||||
gdk_quartz_ref_cairo_surface (GdkWindow *window)
|
||||
{
|
||||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||||
gint scale = gdk_window_get_scale_factor (impl->wrapper);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
@ -316,6 +303,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;
|
||||
}
|
||||
|
||||
@ -3204,37 +3192,15 @@ gdk_quartz_window_release_context (GdkWindowImplQuartz *window,
|
||||
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)
|
||||
@ -3250,6 +3216,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
|
||||
@ -3279,3 +3261,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);
|
||||
}
|
||||
|
@ -103,6 +103,8 @@ typedef struct _GdkRootWindowImplQuartzClass GdkRootWindowImplQuartzClass;
|
||||
struct _GdkRootWindowImplQuartz
|
||||
{
|
||||
GdkWindowImplQuartz parent_instance;
|
||||
CGContextRef cg_context;
|
||||
GList* cg_layers;
|
||||
};
|
||||
|
||||
struct _GdkRootWindowImplQuartzClass
|
||||
|
Loading…
Reference in New Issue
Block a user