Cocoa: Update palette after accent color or appearance changes

This updates the UI after the accent color or NSApp's effective
appearance have changed. For the accent color, we listen to
NSSystemColorsDidChangeNotification. For the effective appearance
changes, we do KVO on NSApp.effectiveAppearance.

Both changes will trigger rebuilding the system palettes followed
by a ThemeChangeEvent in the window system interface layer.

Task-number: QTBUG-68891
Change-Id: Iab1ec874e05f1f6d54cd60217c273e0f8ffbf49e
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Gabriel de Dietrich 2018-06-15 23:18:49 +02:00 committed by Tor Arne Vestbø
parent a09c8b0ee6
commit da62e76eac
2 changed files with 59 additions and 22 deletions

View File

@ -43,7 +43,7 @@
#include <QtCore/QHash>
#include <qpa/qplatformtheme.h>
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver));
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver));
QT_BEGIN_NAMESPACE
@ -78,11 +78,13 @@ public:
static const char *name;
void handleSystemThemeChange();
private:
mutable QPalette *m_systemPalette;
mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes;
mutable QHash<QPlatformTheme::Font, QFont*> m_fonts;
mutable QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) *m_notificationReceiver;
QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) *m_appearanceObserver;
};
QT_END_NAMESPACE

View File

@ -42,6 +42,7 @@
#include "qcocoatheme.h"
#include "messages.h"
#include <QtCore/QOperatingSystemVersion>
#include <QtCore/QVariant>
#include "qcocoasystemsettings.h"
@ -77,26 +78,48 @@
#include <CoreServices/CoreServices.h>
@interface QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) : NSObject
#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
@interface NSApplication (MojaveForwardDeclarations)
@property (readonly, strong) NSAppearance *effectiveAppearance NS_AVAILABLE_MAC(10_14);
@end
#endif
@interface QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) : NSObject
@property (readonly, nonatomic) QCocoaTheme *theme;
- (instancetype)initWithTheme:(QCocoaTheme *)theme;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeNotificationReceiver);
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeAppAppearanceObserver);
@implementation QCocoaThemeNotificationReceiver {
QCocoaTheme *mPrivate;
}
- (instancetype)initWithPrivate:(QCocoaTheme *)priv
@implementation QCocoaThemeAppAppearanceObserver
- (instancetype)initWithTheme:(QCocoaTheme *)theme
{
if ((self = [self init]))
mPrivate = priv;
if ((self = [super init])) {
_theme = theme;
[NSApp addObserver:self forKeyPath:@"effectiveAppearance" options:NSKeyValueObservingOptionNew context:nullptr];
}
return self;
}
- (void)systemColorsDidChange:(NSNotification *)__unused notification
- (void)dealloc
{
mPrivate->reset();
QWindowSystemInterface::handleThemeChange(nullptr);
[NSApp removeObserver:self forKeyPath:@"effectiveAppearance"];
[super dealloc];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
{
Q_UNUSED(change);
Q_UNUSED(context);
Q_ASSERT(object == NSApp);
Q_ASSERT([keyPath isEqualToString:@"effectiveAppearance"]);
if (__builtin_available(macOS 10.14, *))
NSAppearance.currentAppearance = NSApp.effectiveAppearance;
self.theme->handleSystemThemeChange();
}
@end
@ -105,19 +128,22 @@ QT_BEGIN_NAMESPACE
const char *QCocoaTheme::name = "cocoa";
QCocoaTheme::QCocoaTheme()
: m_systemPalette(nullptr)
: m_systemPalette(nullptr), m_appearanceObserver(nil)
{
m_notificationReceiver = [[QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) alloc] initWithPrivate:this];
[[NSNotificationCenter defaultCenter] addObserver:m_notificationReceiver
selector:@selector(systemColorsDidChange:)
name:NSSystemColorsDidChangeNotification
object:nil];
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
m_appearanceObserver = [[QCocoaThemeAppAppearanceObserver alloc] initWithTheme:this];
[[NSNotificationCenter defaultCenter] addObserverForName:NSSystemColorsDidChangeNotification
object:nil queue:nil usingBlock:^(NSNotification *) {
handleSystemThemeChange();
}];
}
QCocoaTheme::~QCocoaTheme()
{
[[NSNotificationCenter defaultCenter] removeObserver:m_notificationReceiver];
[m_notificationReceiver release];
if (m_appearanceObserver)
[m_appearanceObserver release];
reset();
qDeleteAll(m_fonts);
}
@ -130,6 +156,15 @@ void QCocoaTheme::reset()
m_palettes.clear();
}
void QCocoaTheme::handleSystemThemeChange()
{
reset();
m_systemPalette = qt_mac_createSystemPalette();
m_palettes = qt_mac_createRolePalettes();
QWindowSystemInterface::handleThemeChange(nullptr);
}
bool QCocoaTheme::usePlatformNativeDialog(DialogType dialogType) const
{
if (dialogType == QPlatformTheme::FileDialog)