[gtk/gtk-3-24: 7/10] Draw window to image_surface and apply to CALayer.




commit be60902805d577e2bfdfab4fc6d31ee655b0ec44
Author: John Ralls <jralls ceridwen us>
Date:   Thu Oct 28 15:15:20 2021 -0700

    Draw window to image_surface and apply to CALayer.

 gdk/quartz/GdkQuartzView.c    | 128 +++++++++++++++++++++++++-----------------
 gdk/quartz/gdkwindow-quartz.c | 115 ++++++++++++++++++++-----------------
 gdk/quartz/gdkwindow-quartz.h |   2 +
 3 files changed, 141 insertions(+), 104 deletions(-)
---
diff --git a/gdk/quartz/GdkQuartzView.c b/gdk/quartz/GdkQuartzView.c
index 557451606c..3e85d35880 100644
--- a/gdk/quartz/GdkQuartzView.c
+++ b/gdk/quartz/GdkQuartzView.c
@@ -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
 {
-  GdkRectangle gdk_rect;
-  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (gdk_window->impl);
-  const NSRect *drawn_rects;
-  NSInteger count;
-  int i;
-  cairo_region_t *region;
+     return YES;
+}
 
-  if (GDK_WINDOW_DESTROYED (gdk_window))
-    return;
+static void
+provider_release_cb (void* info, const void* data, size_t size)
+{
+  g_free (info);
+}
 
-  if (! (gdk_window->event_mask & GDK_EXPOSURE_MASK))
-    return;
+-(void)updateLayer
+{
+  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (gdk_window->impl);
+  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 (NSEqualRects (rect, NSZeroRect))
+  if (GDK_WINDOW_DESTROYED (gdk_window))
     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
diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c
index ce740d426b..d9d449bb19 100644
--- a/gdk/quartz/gdkwindow-quartz.c
+++ b/gdk/quartz/gdkwindow-quartz.c
@@ -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);
+}
diff --git a/gdk/quartz/gdkwindow-quartz.h b/gdk/quartz/gdkwindow-quartz.h
index e93c5abfed..de9a5ebccf 100644
--- a/gdk/quartz/gdkwindow-quartz.h
+++ b/gdk/quartz/gdkwindow-quartz.h
@@ -103,6 +103,8 @@ typedef struct _GdkRootWindowImplQuartzClass GdkRootWindowImplQuartzClass;
 struct _GdkRootWindowImplQuartz
 {
   GdkWindowImplQuartz parent_instance;
+  CGContextRef cg_context;
+  GList* cg_layers;
 };
  
 struct _GdkRootWindowImplQuartzClass 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]