[quartz] GdkWindow, GdkNSView frame and cairo surface same size.
authorJohn Ralls <jralls@ceridwen.us>
Thu, 19 Jan 2023 18:37:55 +0000 (10:37 -0800)
committerJohn Ralls <jralls@ceridwen.us>
Thu, 19 Jan 2023 18:37:55 +0000 (10:37 -0800)
The cairo surface must be padded to 4 pixels in order to
transfer correctly to the GPU. The GdkWindow and GdkNSView's
content frame must be the same width, otherwise there's a mismatch
that causes either the GdkWindow to draw wider than the frame or the
frame to be clipped narrower than the title bar.

Fixes #5535.

gdk/quartz/GdkQuartzNSWindow.c
gdk/quartz/GdkQuartzView.c
gdk/quartz/gdkprivate-quartz.h
gdk/quartz/gdkwindow-quartz.c

index f0e57434f40468b3d701493f5aa72fb6cb9356dd..5a546891aa48608ce6b410b97f050c814712e70b 100644 (file)
   GdkWindow *window = [[self contentView] gdkWindow];
   GdkEvent *event;
   gboolean maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
+  /* Alignment to 4 pixels is on scaled pixels and these are unscaled pixels so divide by scale to compensate. */
+  const gint scale = gdk_window_get_scale_factor (window);
+  const guint align = GDK_WINDOW_QUARTZ_ALIGNMENT / scale;
 
   /* see same in windowDidMove */
   if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
   window->width = content_rect.size.width;
   window->height = content_rect.size.height;
 
+  if(window->width % align)
+    content_rect.size.width += align - window->width % align;
+
+  content_rect.origin.x = 0;
+  content_rect.origin.y = 0;
+
+  [[self contentView] setFrame:content_rect];
+
   /* Certain resize operations (e.g. going fullscreen), also move the
    * origin of the window.
    */
   _gdk_quartz_window_update_position (window);
-
-  [[self contentView] setFrame:NSMakeRect (0, 0, window->width, window->height)];
-
   _gdk_window_update_size (window);
 
   /* Synthesize a configure event */
index bd34365a1eda46a6d648ff83b303db733598d501..81c2d320078e18cbe74ee0141e5899f740670c8b 100644 (file)
@@ -424,8 +424,7 @@ copy_rectangle_argb32 (cairo_surface_t *dest, cairo_surface_t *source,
     return;
 
   ++impl->in_paint_rect_count;
-  cairo_rect_from_nsrect (&bounds_rect, &backing_bounds);
-  bounds_region = cairo_region_create_rectangle (&bounds_rect);
+
   if (impl->needs_display_region)
     {
       cairo_region_t *region = impl->needs_display_region;
@@ -439,7 +438,7 @@ copy_rectangle_argb32 (cairo_surface_t *dest, cairo_surface_t *source,
       cairo_region_t *region;
 
       cairo_rect_from_nsrect (&bounds, &layer_bounds);
-      region = cairo_region_create_rectangle (&bounds);
+      region = cairo_region_create_rectangle(&bounds);
       _gdk_window_process_updates_recurse (gdk_window, region);
       cairo_region_destroy (region);
     }
@@ -447,8 +446,6 @@ copy_rectangle_argb32 (cairo_surface_t *dest, cairo_surface_t *source,
   if (!impl || !impl->cairo_surface)
     return;
 
-  impl_rect.width = cairo_image_surface_get_width (impl->cairo_surface);
-  impl_rect.height = cairo_image_surface_get_height (impl->cairo_surface);
   CVPixelBufferLockBaseAddress (pixels, 0);
   cvpb_surface =
     cairo_image_surface_create_for_data (CVPixelBufferGetBaseAddress (pixels),
@@ -458,6 +455,12 @@ copy_rectangle_argb32 (cairo_surface_t *dest, cairo_surface_t *source,
                                          (int)CVPixelBufferGetBytesPerRow (pixels));
 
 
+  cairo_rect_from_nsrect (&bounds_rect, &backing_bounds);
+  bounds_region = cairo_region_create_rectangle (&bounds_rect);
+
+  impl_rect.width = cairo_image_surface_get_width (impl->cairo_surface);
+  impl_rect.height = cairo_image_surface_get_height (impl->cairo_surface);
+
   cairo_region_intersect_rectangle (bounds_region, &impl_rect);
   copy_rectangle_argb32 (cvpb_surface, impl->cairo_surface, bounds_region);
 
@@ -465,7 +468,9 @@ copy_rectangle_argb32 (cairo_surface_t *dest, cairo_surface_t *source,
   cairo_region_destroy (bounds_region);
   _gdk_quartz_unref_cairo_surface (gdk_window); // reffed in gdk_window_impl_quartz_begin_paint
   CVPixelBufferUnlockBaseAddress (pixels, 0);
+
   --impl->in_paint_rect_count;
+
   self.layer.contents = NULL;
   self.layer.contents = (id)CVPixelBufferGetIOSurface (pixels);
 }
index a6e644b870d97c3157f0e428240b3eaadf9d7812..6b7986cedd267e084ed9a149df6a9f9a0ec7eab3 100644 (file)
@@ -27,7 +27,8 @@
 #include "config.h"
 
 #define GDK_WINDOW_IS_QUARTZ(win)        (GDK_IS_WINDOW_IMPL_QUARTZ (((GdkWindow *)win)->impl))
-
+/* Cairo surface widths must be 4-pixel byte aligned so that the image will transfer to the CPU. */
+#define GDK_WINDOW_QUARTZ_ALIGNMENT 16
 
 /* Display */
 
index 9f8534e5c159157b4e9da41d5cc9b641b5c9a73f..429f2bc0cfe63ef6758aa08fb15d0bcc0e66dee3 100644 (file)
@@ -306,9 +306,10 @@ gdk_quartz_ref_cairo_surface (GdkWindow *window)
       gint height = gdk_window_get_height (impl->wrapper);
       gint scale = gdk_window_get_scale_factor (impl->wrapper);
       gint scaled_width = width * scale;
+      const gint align = GDK_WINDOW_QUARTZ_ALIGNMENT;
 
-      if (scaled_width % 16)
-          scaled_width += 16 - scaled_width % 16; // Surface widths must be 4-pixel aligned
+      if (scaled_width % align)
+          scaled_width += align - scaled_width % align; // Surface widths must be 4-pixel aligned
 
       impl->cairo_surface = gdk_quartz_create_cairo_surface (impl,
                                                              scaled_width,
@@ -929,6 +930,8 @@ _gdk_quartz_display_create_window_impl (GdkDisplay    *display,
         NSUInteger style_mask;
         int nx, ny;
         const char *title;
+        const gint scale = gdk_window_get_scale_factor (window);
+        const guint align = GDK_WINDOW_QUARTZ_ALIGNMENT / scale;
 
         /* initWithContentRect will place on the mainScreen by default.
          * We want to select the screen to place on ourselves.  We need
@@ -942,6 +945,9 @@ _gdk_quartz_display_create_window_impl (GdkDisplay    *display,
         nx -= screen_rect.origin.x;
         ny -= screen_rect.origin.y;
 
+        if (window->width % align)
+          window->width += align - window->width % align;
+
         content_rect = NSMakeRect (nx, ny - window->height,
                                    window->width,
                                    window->height);