Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions common/CocoaTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ namespace CocoaTools
void DestroyMetalLayer(WindowInfo* wi);
std::optional<float> GetViewRefreshRate(const WindowInfo& wi);

/// Add a handler to be run when macOS changes between dark and light themes
void AddThemeChangeHandler(void* ctx, void(handler)(void* ctx));
/// Remove a handler previously added using AddThemeChangeHandler with the given context
void RemoveThemeChangeHandler(void* ctx);
/// Mark an NSMenu as the help menu
void MarkHelpMenu(void* menu);
/// Returns the bundle path.
Expand All @@ -44,6 +40,6 @@ namespace CocoaTools
void RunCocoaEventLoop(bool wait_forever = false);
/// Posts an event to the main telling `RunCocoaEventLoop(true)` to exit
void StopMainThreadEventLoop();
}
} // namespace CocoaTools

#endif // __APPLE__
58 changes: 1 addition & 57 deletions common/CocoaTools.mm
Original file line number Diff line number Diff line change
Expand Up @@ -85,63 +85,7 @@
return ret;
}

// MARK: - Theme Change Handlers

@interface PCSX2KVOHelper : NSObject

- (void)addCallback:(void*)ctx run:(void(*)(void*))callback;
- (void)removeCallback:(void*)ctx;

@end

@implementation PCSX2KVOHelper
{
std::vector<std::pair<void*, void(*)(void*)>> _callbacks;
}

- (void)addCallback:(void*)ctx run:(void(*)(void*))callback
{
_callbacks.push_back(std::make_pair(ctx, callback));
}

- (void)removeCallback:(void*)ctx
{
auto new_end = std::remove_if(_callbacks.begin(), _callbacks.end(), [ctx](const auto& entry){
return ctx == entry.first;
});
_callbacks.erase(new_end, _callbacks.end());
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
for (const auto& callback : _callbacks)
callback.second(callback.first);
}

@end

static PCSX2KVOHelper* s_themeChangeHandler;

void CocoaTools::AddThemeChangeHandler(void* ctx, void(handler)(void* ctx))
{
assert([NSThread isMainThread]);
if (!s_themeChangeHandler)
{
s_themeChangeHandler = [[PCSX2KVOHelper alloc] init];
NSApplication* app = [NSApplication sharedApplication];
[app addObserver:s_themeChangeHandler
forKeyPath:@"effectiveAppearance"
options:0
context:nil];
}
[s_themeChangeHandler addCallback:ctx run:handler];
}

void CocoaTools::RemoveThemeChangeHandler(void* ctx)
{
assert([NSThread isMainThread]);
[s_themeChangeHandler removeCallback:ctx];
}
// MARK: - Help menu

void CocoaTools::MarkHelpMenu(void* menu)
{
Expand Down
2 changes: 1 addition & 1 deletion pcsx2-qt/Debugger/DisassemblyView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,7 @@ inline QString DisassemblyView::DisassemblyStringFromAddress(u32 address, QFont
QColor DisassemblyView::GetAddressFunctionColor(u32 address)
{
std::array<QColor, 6> colors;
if (QtUtils::IsLightTheme(palette()))
if (!QtHost::IsDarkApplicationTheme())
{
colors = {
QColor::fromRgba(0xFFFA3434),
Expand Down
5 changes: 3 additions & 2 deletions pcsx2-qt/Debugger/Docking/DropIndicators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "DropIndicators.h"

#include "QtHost.h"
#include "QtUtils.h"
#include "Debugger/Docking/DockViews.h"

Expand All @@ -21,7 +22,7 @@ static std::pair<QColor, QColor> pickNiceColours(const QPalette& palette, bool h
QColor fill = palette.highlight().color();
QColor outline = palette.highlight().color();

if (QtUtils::IsLightTheme(palette))
if (!QtHost::IsDarkApplicationTheme())
{
fill = fill.darker(200);
outline = outline.darker(200);
Expand Down Expand Up @@ -197,7 +198,7 @@ static const constexpr int INDICATOR_MARGIN = 10;
static bool isWayland()
{
return KDDockWidgets::Core::Platform::instance()->displayType() ==
KDDockWidgets::Core::Platform::DisplayType::Wayland;
KDDockWidgets::Core::Platform::DisplayType::Wayland;
}

static QWidget* parentForIndicatorWindow(KDDockWidgets::Core::ClassicDropIndicatorOverlay* classic_indicators)
Expand Down
10 changes: 0 additions & 10 deletions pcsx2-qt/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,21 +138,11 @@ MainWindow::~MainWindow()
#ifdef _WIN32
unregisterForDeviceNotifications();
#endif
#ifdef __APPLE__
CocoaTools::RemoveThemeChangeHandler(this);
#endif
}

void MainWindow::initialize()
{
#ifdef __APPLE__
CocoaTools::AddThemeChangeHandler(this, [](void* ctx) {
// This handler is called *before* the style change has propagated far enough for Qt to see it
// Use RunOnUIThread to delay until it has
QtHost::RunOnUIThread([ctx = static_cast<MainWindow*>(ctx)] {
ctx->updateTheme(); // Qt won't notice the style change without us touching the palette in some way
});
});
// The cocoa backing isn't initialized yet, delay this until stuff is set up with a `RunOnUIThread` call
QtHost::RunOnUIThread([this] {
CocoaTools::MarkHelpMenu(m_ui.menuHelp->toNSMenu());
Expand Down
9 changes: 3 additions & 6 deletions pcsx2-qt/QtUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ namespace QtUtils

const int min_column_width = header->minimumSectionSize();
const int scrollbar_width = ((view->verticalScrollBar() && view->verticalScrollBar()->isVisible()) ||
view->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) ? view->verticalScrollBar()->width() : 0;
view->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) ?
view->verticalScrollBar()->width() :
0;
int num_flex_items = 0;
int total_width = 0;
int column_index = 0;
Expand Down Expand Up @@ -346,11 +348,6 @@ namespace QtUtils
return csv;
}

bool IsLightTheme(const QPalette& palette)
{
return palette.text().color().lightnessF() < 0.5;
}

bool IsCompositorManagerRunning()
{
if (qEnvironmentVariableIsSet("PCSX2_NO_COMPOSITING"))
Expand Down
4 changes: 1 addition & 3 deletions pcsx2-qt/QtUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,7 @@ namespace QtUtils
/// Converts an abstract item model to a CSV string.
QString AbstractItemModelToCSV(QAbstractItemModel* model, int role = Qt::DisplayRole, bool useQuotes = false);

// Heuristic to check if the current theme is a light or dark theme.
bool IsLightTheme(const QPalette& palette);

/// Checks if we can use transparency effects e.g. for dock drop indicators.
bool IsCompositorManagerRunning();

/// Sets the scalable icon to a given label (svg icons, or icons with multiple size pixmaps)
Expand Down
48 changes: 47 additions & 1 deletion pcsx2-qt/Themes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,27 @@
#include <QtCore/QFile>
#include <QtGui/QPalette>
#include <QtGui/QPixmapCache>
#include <QtGui/QStyleHints>
#include <QtWidgets/QApplication>
#include <QtWidgets/QStyle>
#include <QtWidgets/QStyleFactory>

namespace QtHost
{
static void SetStyleFromSettings();
static void SetColorScheme(Qt::ColorScheme color_scheme);
} // namespace QtHost

static QString s_unthemed_style_name;
static QPalette s_unthemed_palette;
static bool s_unthemed_style_name_set;

// This is different than the result of qApp->styleHints()->colorScheme() since
// if we set that to Qt::ColorScheme::Unknown it would return what the Qt
// platform code thinks is the correct color scheme instead (it can still return
// Qt::ColorScheme::Unknown if it doesn't know).
static Qt::ColorScheme s_color_scheme = Qt::ColorScheme::Unknown;

const char* QtHost::GetDefaultThemeName()
{
#ifdef __APPLE__
Expand Down Expand Up @@ -54,8 +62,18 @@ void QtHost::UpdateApplicationTheme()

bool QtHost::IsDarkApplicationTheme()
{
// If the current theme uses a fixed color scheme just return that.
if (s_color_scheme != Qt::ColorScheme::Unknown)
return s_color_scheme == Qt::ColorScheme::Dark;

// Otherwise, fallback to using the palette heuristic. We don't bother
// asking the Qt platform code because it sometimes returns the wrong
// result. In particular, if the Windows Classic (windowsvista) theme is
// applied, and dark mode is enabled in the OS, it will return
// Qt::ColorScheme::Dark even though it's a light theme. We also can't treat
// it as a fixed color theme because of high contrast mode.
QPalette palette = qApp->palette();
return (palette.windowText().color().value() > palette.window().color().value());
return palette.windowText().color().value() > palette.window().color().value();
}

void QtHost::SetIconThemeFromStyle()
Expand All @@ -73,13 +91,18 @@ void QtHost::SetStyleFromSettings()
qApp->setStyle(QStyleFactory::create("Fusion"));
qApp->setPalette(s_unthemed_palette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Unknown);
}
#ifdef _WIN32
else if (theme == "windowsvista")
{
qApp->setStyle(QStyleFactory::create("windowsvista"));
qApp->setPalette(s_unthemed_palette);
qApp->setStyleSheet(QString());

// We can't set this to Qt::ColorScheme::Light because that breaks high
// contrast themes on Windows.
SetColorScheme(Qt::ColorScheme::Unknown);
}
#endif
else if (theme == "darkfusion")
Expand Down Expand Up @@ -116,6 +139,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(darkPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "darkfusionblue")
{
Expand Down Expand Up @@ -151,6 +175,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(darkBluePalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "GreyMatter")
{
Expand Down Expand Up @@ -187,6 +212,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(greyMatterPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "UntouchedLagoon")
{
Expand Down Expand Up @@ -222,6 +248,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(untouchedLagoonPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Light);
}
else if (theme == "BabyPastel")
{
Expand Down Expand Up @@ -259,6 +286,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(babyPastelPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Light);
}
else if (theme == "PizzaBrown")
{
Expand Down Expand Up @@ -296,6 +324,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(pizzaPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Light);
}
else if (theme == "PCSX2Blue")
{
Expand Down Expand Up @@ -331,6 +360,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(pcsx2BluePalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Light);
}
else if (theme == "ScarletDevilRed")
{
Expand Down Expand Up @@ -364,6 +394,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(scarletDevilPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "VioletAngelPurple")
{
Expand Down Expand Up @@ -397,6 +428,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(violetAngelPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "CobaltSky")
{
Expand Down Expand Up @@ -434,6 +466,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(cobaltSkyPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "AMOLED")
{
Expand Down Expand Up @@ -470,6 +503,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(AMOLEDPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "Ruby")
{
Expand Down Expand Up @@ -503,6 +537,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(rubyPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "Sapphire")
{
Expand Down Expand Up @@ -536,6 +571,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(sapphirePalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "Emerald")
{
Expand Down Expand Up @@ -569,6 +605,7 @@ void QtHost::SetStyleFromSettings()

qApp->setPalette(emeraldPalette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Dark);
}
else if (theme == "Custom")
{
Expand All @@ -587,11 +624,20 @@ void QtHost::SetStyleFromSettings()
{
qApp->setStyle(QStyleFactory::create("Fusion"));
}

SetColorScheme(Qt::ColorScheme::Unknown);
}
else
{
qApp->setStyle(s_unthemed_style_name);
qApp->setPalette(s_unthemed_palette);
qApp->setStyleSheet(QString());
SetColorScheme(Qt::ColorScheme::Unknown);
}
}

static void QtHost::SetColorScheme(Qt::ColorScheme color_scheme)
{
s_color_scheme = color_scheme;
qApp->styleHints()->setColorScheme(color_scheme);
}