[quartz] GdkWindow, GdkNSView frame and cairo surface same size.

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.
This commit is contained in:
John Ralls
2023-01-19 10:37:55 -08:00
parent 6a2fb84446
commit f60359c183
4 changed files with 31 additions and 11 deletions

View File

@@ -229,6 +229,9 @@
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]))
@@ -241,13 +244,18 @@
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 */

View 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);
}

View 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 */

View 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);