summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <[email protected]>2025-04-15 23:46:13 +0200
committerTor Arne Vestbø <[email protected]>2025-05-22 18:21:37 +0200
commitee78c173e9cb2a3ec6eac9b67b760bdd1904ff26 (patch)
tree5d38d59e5ac0067cd582aefe4b59f6f4a556893b
parent82015992c853b50dac167da26b8b858ac4794c66 (diff)
macOS: Port from deprecated NSAppearance.currentAppearance
When the system appearance changes, it will be reflected through NSApp.effectiveAppearance, but NSAppearance.currentAppearance and NSAppearance.currentDrawingAppearance will remain as is for some reason (perhaps as a compatibility for apps that were not ready to handle dark mode). The original way to deal with this was to explicitly set the NSAppearance.currentAppearance to the new effective appearance, which would take effect for the thread from that point on. But this API has been deprecated, most likely because overriding it globally could mess up views or logic that was not prepared for dark mode). The replacement API, NSAppearance performAsCurrentDrawingAppearance is given a block, and will only override NSAppearance.currentAppearance during the block, which isolates it from other fragile components. We generally use NSApp.effectiveAppearance in our own code when resolving dark mode, so we only need to wrap AppKit APIs we use with performAsCurrentDrawingAppearance, including NSColor for our palette, and NSView/NSControl drawing in our styles. For the latter case we introduce a helper that we can also use in the Qt Quick Mac style. This helper can also be the basis of shared style functionality between Widgets and Quick going forward. Fixes: QTBUG-135789 Done-with: Volker Hilsheimer <[email protected]> Change-Id: I4d006b8b1fbbd7ff888da8b903066c183adad188 Reviewed-by: Doris Verria <[email protected]>
-rw-r--r--src/gui/CMakeLists.txt1
-rw-r--r--src/gui/platform/macos/qmacstyle_p.h81
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm19
-rw-r--r--src/plugins/styles/mac/main.mm2
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm44
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac_p.h5
6 files changed, 108 insertions, 44 deletions
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index ba77cb1cccc..024bcfab426 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -395,6 +395,7 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_opengl
qt_internal_extend_target(Gui CONDITION MACOS
SOURCES
platform/macos/qcocoanativeinterface.mm
+ platform/macos/qmacstyle_p.h
LIBRARIES
${FWAppKit}
${FWCarbon}
diff --git a/src/gui/platform/macos/qmacstyle_p.h b/src/gui/platform/macos/qmacstyle_p.h
new file mode 100644
index 00000000000..bbfbc1a06e3
--- /dev/null
+++ b/src/gui/platform/macos/qmacstyle_p.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QMACSTYLE_P_H
+#define QMACSTYLE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qtguiglobal.h>
+
+#if defined(QT_WIDGETS_LIB) && defined(QT_QUICK_LIB)
+# error "Cannot use QtGui Mac style with both Widgets and Quick"
+#endif
+
+#if defined(QT_WIDGETS_LIB)
+# define OPTIONAL_WIDGET_ARGUMENT , const QWidget *w = nullptr
+# define FORWARD_OPTIONAL_WIDGET_ARGUMENT , w
+# else
+# define OPTIONAL_WIDGET_ARGUMENT
+# define FORWARD_OPTIONAL_WIDGET_ARGUMENT
+#endif
+
+#include <AppKit/NSApplication.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Helper class to ensure that the Mac style in Widgets and Quick
+ draw their NSViews and NSCells with the correct appearance,
+ as the native controls use NSAppearance.currentDrawingAppearance
+ instead of NSApp.effectiveAppearance when drawing.
+
+ Due to the duplicated class hierarchies between Widgets and Quick
+ for the styles, with the Quick styles missing the QWidget pointer
+ in the function parameters, we have to opt for an awkward macro
+ to solve this.
+*/
+template <typename Style>
+class QMacApperanceStyle : public Style
+{
+public:
+ void drawPrimitive(typename Style::PrimitiveElement pe, const QStyleOption *opt, QPainter *p
+ OPTIONAL_WIDGET_ARGUMENT) const override
+ {
+ [NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{
+ Style::drawPrimitive(pe, opt, p
+ FORWARD_OPTIONAL_WIDGET_ARGUMENT);
+ }];
+ }
+
+ void drawControl(typename Style::ControlElement element, const QStyleOption *opt, QPainter *p
+ OPTIONAL_WIDGET_ARGUMENT) const override
+ {
+ [NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{
+ Style::drawControl(element, opt, p
+ FORWARD_OPTIONAL_WIDGET_ARGUMENT);
+ }];
+ }
+
+ void drawComplexControl(typename Style::ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p
+ OPTIONAL_WIDGET_ARGUMENT) const override
+ {
+ [NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{
+ Style::drawComplexControl(cc, opt, p
+ FORWARD_OPTIONAL_WIDGET_ARGUMENT);
+ }];
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QMACSTYLE_P_H
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index 3e7e01d8048..e3ff518b4e1 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -214,7 +214,6 @@ QCocoaTheme::QCocoaTheme()
: m_systemPalette(nullptr)
{
m_appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] {
- NSAppearance.currentAppearance = NSApp.effectiveAppearance;
handleSystemThemeChange();
});
@@ -291,13 +290,23 @@ QPlatformSystemTrayIcon *QCocoaTheme::createPlatformSystemTrayIcon() const
const QPalette *QCocoaTheme::palette(Palette type) const
{
+ // Note: NSColor resolves its RGB values based on the current
+ // drawing appearance, so we need to propagate the effective
+ // appearance when (re)creating the palettes.
+
if (type == SystemPalette) {
- if (!m_systemPalette)
- m_systemPalette = qt_mac_createSystemPalette();
+ if (!m_systemPalette) {
+ [NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{
+ m_systemPalette = qt_mac_createSystemPalette();
+ }];
+ }
return m_systemPalette;
} else {
- if (m_palettes.isEmpty())
- m_palettes = qt_mac_createRolePalettes();
+ if (m_palettes.isEmpty()) {
+ [NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{
+ m_palettes = qt_mac_createRolePalettes();
+ }];
+ }
return m_palettes.value(type, nullptr);
}
return nullptr;
diff --git a/src/plugins/styles/mac/main.mm b/src/plugins/styles/mac/main.mm
index 5f4fbd9eb8e..ef6ca46045d 100644
--- a/src/plugins/styles/mac/main.mm
+++ b/src/plugins/styles/mac/main.mm
@@ -20,7 +20,7 @@ QStyle *QMacStylePlugin::create(const QString &key)
{
QMacAutoReleasePool pool;
if (key.compare(QLatin1String("macos"), Qt::CaseInsensitive) == 0)
- return new QMacStyle();
+ return QMacStyle::create();
return 0;
}
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index bc411eb72d8..83b2d284e86 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -41,6 +41,8 @@
#include <QtWidgets/qwizard.h>
#endif
+#include <QtGui/private/qmacstyle_p.h>
+
#include <cmath>
QT_USE_NAMESPACE
@@ -338,40 +340,6 @@ static const int toolButtonArrowMargin = 2;
static const qreal focusRingWidth = 3.5;
-// An application can force 'Aqua' theme while the system theme is one of
-// the 'Dark' variants. Since in Qt we sometimes use NSControls and even
-// NSCells directly without attaching them to any view hierarchy, we have
-// to set NSAppearance.currentAppearance to 'Aqua' manually, to make sure
-// the correct rendering path is triggered. Apple recommends us to un-set
-// the current appearance back after we finished with drawing. This is what
-// AppearanceSync is for.
-
-class AppearanceSync {
-public:
- AppearanceSync()
- {
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
- && !isDarkMode()) {
- auto requiredAppearanceName = NSApplication.sharedApplication.effectiveAppearance.name;
- if (![NSAppearance.currentAppearance.name isEqualToString:requiredAppearanceName]) {
- previous = NSAppearance.currentAppearance;
- NSAppearance.currentAppearance = [NSAppearance appearanceNamed:requiredAppearanceName];
- }
- }
- }
-
- ~AppearanceSync()
- {
- if (previous)
- NSAppearance.currentAppearance = previous;
- }
-
-private:
- NSAppearance *previous = nil;
-
- Q_DISABLE_COPY(AppearanceSync)
-};
-
static bool setupScroller(NSScroller *scroller, const QStyleOptionSlider *sb)
{
const qreal length = sb->maximum - sb->minimum + sb->pageStep;
@@ -1995,6 +1963,11 @@ void QMacStylePrivate::resolveCurrentNSView(QWindow *window) const
backingStoreNSView = window ? (NSView *)window->winId() : nil;
}
+QMacStyle *QMacStyle::create()
+{
+ return new QMacApperanceStyle<QMacStyle>;
+}
+
QMacStyle::QMacStyle()
: QCommonStyle(*new QMacStylePrivate)
{
@@ -2886,7 +2859,6 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
const QWidget *w) const
{
Q_D(const QMacStyle);
- const AppearanceSync appSync;
QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() : nullptr;
d->resolveCurrentNSView(window);
@@ -3414,7 +3386,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
const QWidget *w) const
{
Q_D(const QMacStyle);
- const AppearanceSync sync;
const QMacAutoReleasePool pool;
QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() : nullptr;
@@ -5086,7 +5057,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const QWidget *widget) const
{
Q_D(const QMacStyle);
- const AppearanceSync sync;
QMacCGContext cg(p);
QWindow *window = widget && widget->window() ? widget->window()->windowHandle() : nullptr;
d->resolveCurrentNSView(window);
diff --git a/src/plugins/styles/mac/qmacstyle_mac_p.h b/src/plugins/styles/mac/qmacstyle_mac_p.h
index 99c8d1fec42..15ced48e21d 100644
--- a/src/plugins/styles/mac/qmacstyle_mac_p.h
+++ b/src/plugins/styles/mac/qmacstyle_mac_p.h
@@ -28,10 +28,13 @@ class QMacStylePrivate;
class QMacStyle : public QCommonStyle
{
Q_OBJECT
-public:
+protected:
QMacStyle();
+public:
virtual ~QMacStyle();
+ static QMacStyle *create();
+
void polish(QWidget *w);
void unpolish(QWidget *w);