QMacStyle: fix group box for macOS Mojave

This change is based on a patch started by Gabriel. It works around the
apparently noop (on macOS Mojave, light theme)  -drawRect: call on NSBox,
replacing it with  -displayRectIgnoringOpacity:inContext:. Unfortunately,
this turns out to be  extremely slow with dark theme, so we have to resort
to a custom version of NSBox/-drawRect:  which calls its super's -drawRect:
and look more or less correct.

Task-number: QTBUG-69650
Change-Id: I5a614d7cd8002b378c6c3804663b6559e227f628
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
Timur Pocheptsov 2018-10-12 15:45:27 +02:00
parent 0b4ab214db
commit 3c4f94b7cb
2 changed files with 63 additions and 7 deletions

View File

@ -238,6 +238,33 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QVerticalSplitView);
}
@end
// See render code in drawPrimitive(PE_FrameTabWidget)
@interface QT_MANGLE_NAMESPACE(QDarkNSBox) : NSBox
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QDarkNSBox);
@implementation QDarkNSBox
- (instancetype)init
{
if ((self = [super init])) {
self.title = @"";
self.titlePosition = NSNoTitle;
self.boxType = NSBoxCustom;
self.cornerRadius = 3;
self.borderColor = [NSColor.controlColor colorWithAlphaComponent:0.1];
self.fillColor = [NSColor.darkGrayColor colorWithAlphaComponent:0.2];
}
return self;
}
- (void)drawRect:(NSRect)rect
{
[super drawRect:rect];
}
@end
QT_BEGIN_NAMESPACE
// The following constants are used for adjusting the size
@ -1704,18 +1731,28 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
|| widget.size == QStyleHelper::SizeDefault)
return nil;
if (widget.type == Box) {
if (__builtin_available(macOS 10.14, *)) {
if (qt_mac_applicationIsInDarkMode()) {
// See render code in drawPrimitive(PE_FrameTabWidget)
widget.type = Box_Dark;
}
}
}
NSView *bv = cocoaControls.value(widget, nil);
if (!bv) {
switch (widget.type) {
case Box: {
NSBox *bc = [[NSBox alloc] init];
bc.title = @"";
bc.titlePosition = NSNoTitle;
bc.boxType = NSBoxPrimary;
bc.borderType = NSBezelBorder;
bv = bc;
NSBox *box = [[NSBox alloc] init];
bv = box;
box.title = @"";
box.titlePosition = NSNoTitle;
break;
}
case Box_Dark:
bv = [[QDarkNSBox alloc] init];
break;
case Button_CheckBox:
case Button_Disclosure:
case Button_PushButton:
@ -2922,10 +2959,28 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
{
const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
auto *box = static_cast<NSBox *>(d->cocoaControl(cw));
// FIXME Since macOS 10.14, simply calling drawRect: won't display anything anymore.
// The AppKit team is aware of this and has proposed a couple of solutions.
// The first solution was to call displayRectIgnoringOpacity:inContext: instead.
// However, it doesn't seem to work on 10.13. More importantly, dark mode on 10.14
// is extremely slow. Light mode works fine.
// The second solution is to subclass NSBox and reimplement a trivial drawRect: which
// would only call super. This works without any issue on 10.13, but a double border
// shows on 10.14 in both light and dark modes.
// The code below picks what works on each version and mode. On 10.13 and earlier, we
// simply call drawRect: on a regular NSBox. On 10.14, we call displayRectIgnoringOpacity:
// inContext:, but only in light mode. In dark mode, we use a custom NSBox subclass,
// QDarkNSBox, of type NSBoxCustom. Its appearance is close enough to the real thing so
// we can use this for now.
d->drawNSViewInRect(box, opt->rect, p, ^(CGContextRef ctx, const CGRect &rect) {
CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
CGContextScaleCTM(ctx, 1, -1);
[box drawRect:rect];
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave
|| [box isMemberOfClass:QDarkNSBox.class]) {
[box drawRect:rect];
} else {
[box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
}
});
break;
}

View File

@ -187,6 +187,7 @@ public:
enum CocoaControlType {
NoControl, // For when there's no such a control in Cocoa
Box, // QGroupBox
Box_Dark, // FIXME See render code in drawPrimitive(PE_FrameTabWidget)
Button_CheckBox,
Button_Disclosure, // Disclosure triangle, like in QTreeView
Button_PopupButton, // Non-editable QComboBox