Currently on macOS when display mode emulation is enabled, the space (letterboxes/pillarboxes) around the scaled full-screen content is usually white. We want it to be black instead, like it would be in the case of a real display mode change.
To do this: in `WindowPosChanged` when `fullscreen == TRUE`, cover the window with black borders so that only the `window` rect is visible. A `CAShapeLayer` is used, and added as a sublayer to the window's `contentView.layer`.
From: Brendan Shanks bshanks@codeweavers.com
--- dlls/winemac.drv/cocoa_window.m | 62 +++++++++++++++++++++++++++++++++ dlls/winemac.drv/macdrv.h | 1 + dlls/winemac.drv/macdrv_cocoa.h | 1 + dlls/winemac.drv/window.c | 11 ++++-- 4 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 4dac9a3bfd2..6e69ddb1fc1 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -2776,6 +2776,53 @@ - (void) setRetinaMode:(int)mode ignore_windowResize = FALSE; }
+ - (void) setMask:(CGRect)rect + { + /* Draw black bars to cover every part of the window except for 'rect'. + * Intended for use on a window covering the full screen. + */ + if (CGRectIsEmpty(rect)) + { + [[[self.contentView.layer sublayers] firstObject] removeFromSuperlayer]; + return; + } + + CAShapeLayer *shapeLayer = [CAShapeLayer layer]; + shapeLayer.bounds = self.contentView.layer.bounds; + shapeLayer.position = self.contentView.layer.position; + shapeLayer.geometryFlipped = self.contentView.layer.geometryFlipped; + shapeLayer.anchorPoint = self.contentView.layer.anchorPoint; + shapeLayer.fillColor = CGColorGetConstantColor(kCGColorBlack); + + CGMutablePathRef path = CGPathCreateMutable(); + /* left/right */ + if (rect.origin.x > 0.0) + CGPathAddRect(path, NULL, CGRectMake(0, 0, rect.origin.x, shapeLayer.bounds.size.height)); + if (rect.origin.x + rect.size.width < shapeLayer.bounds.size.width) + CGPathAddRect(path, NULL, CGRectMake(rect.origin.x + rect.size.width, + 0, + shapeLayer.bounds.size.width - (rect.origin.x + rect.size.width), + shapeLayer.bounds.size.height)); + + /* top/bottom */ + if (rect.origin.y > 0.0) + CGPathAddRect(path, NULL, CGRectMake(0, 0, shapeLayer.bounds.size.width, rect.origin.y)); + if (rect.origin.y + rect.size.height < shapeLayer.bounds.size.height) + CGPathAddRect(path, NULL, CGRectMake(0, + rect.origin.y + rect.size.height, + shapeLayer.bounds.size.width, + shapeLayer.bounds.size.height - (rect.origin.y + rect.size.height))); + + shapeLayer.path = path; + CGPathRelease(path); + + if ([[self.contentView.layer sublayers] firstObject]) + [self.contentView.layer replaceSublayer:[[self.contentView.layer sublayers] firstObject] + with:shapeLayer]; + else + [self.contentView.layer addSublayer:shapeLayer]; + } +
/* * ---------- NSResponder method overrides ---------- @@ -3632,6 +3679,21 @@ void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha) } }
+/*********************************************************************** + * macdrv_set_window_mask + */ +void macdrv_set_window_mask(macdrv_window w, CGRect rect) +{ +@autoreleasepool +{ + WineWindow* window = (WineWindow*)w; + + OnMainThread(^{ + [window setMask:rect]; + }); +} +} + /*********************************************************************** * macdrv_give_cocoa_window_focus * diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 9b545cbf29c..22e96fa1129 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -188,6 +188,7 @@ extern BOOL macdrv_SystemParametersInfo(UINT action, UINT int_param, void *ptr_p unsigned int ulw_layered : 1; /* has UpdateLayeredWindow() been called for window? */ unsigned int per_pixel_alpha : 1; /* is window using per-pixel alpha? */ unsigned int minimized : 1; /* is window minimized? */ + unsigned int fullscreen : 1; /* is the window visible rect fullscreen? (unrelated to native AppKit/Cocoa fullscreen) */ };
struct macdrv_client_surface diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 82a577fed37..1ab20ec2724 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -508,6 +508,7 @@ extern void macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev, extern void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count); extern void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha); extern void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha); +extern void macdrv_set_window_mask(macdrv_window w, CGRect rect); extern void macdrv_give_cocoa_window_focus(macdrv_window w, int activate); extern void macdrv_set_window_min_max_sizes(macdrv_window w, CGSize min_size, CGSize max_size); extern macdrv_view macdrv_create_view(CGRect rect); diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 5fa90223004..10e719068ac 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1604,8 +1604,8 @@ void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT old_rects = data->rects; data->rects = *new_rects;
- TRACE("win %p/%p new_rects %s style %08x flags %08x surface %p\n", hwnd, data->cocoa_window, - debugstr_window_rects(new_rects), new_style, swp_flags, surface); + TRACE("win %p/%p new_rects %s style %08x flags %08x fullscreen %u surface %p\n", hwnd, data->cocoa_window, + debugstr_window_rects(new_rects), new_style, swp_flags, fullscreen, surface);
if (!data->cocoa_window) goto done;
@@ -1640,6 +1640,13 @@ void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT } }
+ if (fullscreen || fullscreen != data->fullscreen) + { + CGRect rect = (fullscreen && !EqualRect(&data->rects.window, &data->rects.visible)) ? cgrect_from_rect(data->rects.window) : CGRectZero; + macdrv_set_window_mask(data->cocoa_window, rect); + data->fullscreen = fullscreen; + } + done: release_win_data(data); }