aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaufeat <sahyno1996@gmail.com>2025-08-10 22:14:12 +0200
committercrueter <crueter@eden-emu.dev>2025-08-10 22:14:12 +0200
commit3f02d7713f1bfb36245486019bc014ecc49a1b19 (patch)
treeb98ccf0920f17e2eedf66b866ed1138407f91c40
parentbdf5674d7e3cb6e142079339d72dbc05a20ed6e1 (diff)
[qt] Fix title bar for windows being forced to light theme (#236)
Fixed the title bar being forced to light theme and properly handle it the qt6.5 way See: https://stackoverflow.com/a/78854851 Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/236 Reviewed-by: crueter <crueter@eden-emu.dev> Co-authored-by: Maufeat <sahyno1996@gmail.com> Co-committed-by: Maufeat <sahyno1996@gmail.com>
-rw-r--r--CMakeModules/CopyYuzuQt6Deps.cmake2
-rw-r--r--src/yuzu/main.cpp118
-rw-r--r--src/yuzu/main.h2
3 files changed, 102 insertions, 20 deletions
diff --git a/CMakeModules/CopyYuzuQt6Deps.cmake b/CMakeModules/CopyYuzuQt6Deps.cmake
index 39f88cbc19..5ea8f74233 100644
--- a/CMakeModules/CopyYuzuQt6Deps.cmake
+++ b/CMakeModules/CopyYuzuQt6Deps.cmake
@@ -63,6 +63,4 @@ function(copy_yuzu_Qt6_deps target_dir)
else()
# Update for non-MSVC platforms if needed
endif()
- # Fixes dark mode being forced automatically even when light theme is set in app settings.
- file(WRITE "${CMAKE_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}/qt.conf" "[Platforms]\nWindowsArguments = darkmode=0")
endfunction(copy_yuzu_Qt6_deps)
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 9cf2f9b76c..38c0e4b3ce 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -96,6 +96,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include <QStandardPaths>
#include <QStatusBar>
#include <QString>
+#include <QStyleHints>
#include <QSysInfo>
#include <QUrl>
#include <QtConcurrent/QtConcurrent>
@@ -172,6 +173,91 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/util/clickable_label.h"
#include "yuzu/vk_device_info.h"
+#ifdef _WIN32
+#include <QPlatformSurfaceEvent>
+#include <dwmapi.h>
+#include <windows.h>
+#pragma comment(lib, "Dwmapi.lib")
+
+static inline void ApplyWindowsTitleBarDarkMode(HWND hwnd, bool enabled) {
+ if (!hwnd)
+ return;
+ BOOL val = enabled ? TRUE : FALSE;
+ // 20 = Win11/21H2+
+ if (SUCCEEDED(DwmSetWindowAttribute(hwnd, 20, &val, sizeof(val))))
+ return;
+ // 19 = pre-21H2
+ DwmSetWindowAttribute(hwnd, 19, &val, sizeof(val));
+}
+
+static inline void ApplyDarkToTopLevel(QWidget* w, bool on) {
+ if (!w || !w->isWindow())
+ return;
+ ApplyWindowsTitleBarDarkMode(reinterpret_cast<HWND>(w->winId()), on);
+}
+
+namespace {
+struct TitlebarFilter final : QObject {
+ bool dark;
+ explicit TitlebarFilter(bool is_dark) : QObject(qApp), dark(is_dark) {}
+
+ void setDark(bool is_dark) {
+ dark = is_dark;
+ }
+
+ void onFocusChanged(QWidget*, QWidget* now) {
+ if (now)
+ ApplyDarkToTopLevel(now->window(), dark);
+ }
+
+ bool eventFilter(QObject* obj, QEvent* ev) override {
+ if (auto* w = qobject_cast<QWidget*>(obj)) {
+ switch (ev->type()) {
+ case QEvent::WinIdChange:
+ case QEvent::Show:
+ case QEvent::ShowToParent:
+ case QEvent::Polish:
+ case QEvent::WindowStateChange:
+ case QEvent::ZOrderChange:
+ ApplyDarkToTopLevel(w, dark);
+ break;
+ default:
+ break;
+ }
+ }
+ return QObject::eventFilter(obj, ev);
+ }
+};
+
+static TitlebarFilter* g_filter = nullptr;
+static QMetaObject::Connection g_focusConn;
+
+} // namespace
+
+static void ApplyGlobalDarkTitlebar(bool is_dark) {
+ if (!g_filter) {
+ g_filter = new TitlebarFilter(is_dark);
+ qApp->installEventFilter(g_filter);
+ g_focusConn = QObject::connect(qApp, &QApplication::focusChanged, g_filter,
+ &TitlebarFilter::onFocusChanged);
+ } else {
+ g_filter->setDark(is_dark);
+ }
+ for (QWidget* w : QApplication::topLevelWidgets())
+ ApplyDarkToTopLevel(w, is_dark);
+}
+
+static void RemoveTitlebarFilter() {
+ if (!g_filter)
+ return;
+ qApp->removeEventFilter(g_filter);
+ QObject::disconnect(g_focusConn);
+ g_filter->deleteLater();
+ g_filter = nullptr;
+}
+
+#endif
+
#ifdef YUZU_CRASH_DUMPS
#include "yuzu/breakpad.h"
#endif
@@ -299,16 +385,16 @@ static void OverrideWindowsFont() {
}
#endif
-bool GMainWindow::CheckDarkMode() {
-#ifdef __unix__
- const QPalette test_palette(qApp->palette());
- const QColor text_color = test_palette.color(QPalette::Active, QPalette::Text);
- const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window);
- return (text_color.value() > window_color.value());
+inline static bool isDarkMode() {
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+ const auto scheme = QGuiApplication::styleHints()->colorScheme();
+ return scheme == Qt::ColorScheme::Dark;
#else
- // TODO: Windows
- return false;
-#endif // __unix__
+ const QPalette defaultPalette;
+ const auto text = defaultPalette.color(QPalette::WindowText);
+ const auto window = defaultPalette.color(QPalette::Window);
+ return text.lightness() > window.lightness();
+#endif // QT_VERSION
}
GMainWindow::GMainWindow(bool has_broken_vulkan)
@@ -358,7 +444,6 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
statusBar()->hide();
// Check dark mode before a theme is loaded
- os_dark_mode = CheckDarkMode();
startup_icon_theme = QIcon::themeName();
// fallback can only be set once, colorful theme icons are okay on both light/dark
QIcon::setFallbackThemeName(QStringLiteral("colorful"));
@@ -5383,15 +5468,11 @@ void GMainWindow::UpdateUITheme() {
current_theme = default_theme;
}
-#ifdef _WIN32
- QIcon::setThemeName(current_theme);
- AdjustLinkColor();
-#else
if (current_theme == QStringLiteral("default") || current_theme == QStringLiteral("colorful")) {
QIcon::setThemeName(current_theme == QStringLiteral("colorful") ? current_theme
: startup_icon_theme);
QIcon::setThemeSearchPaths(QStringList(default_theme_paths));
- if (CheckDarkMode()) {
+ if (isDarkMode()) {
current_theme = QStringLiteral("default_dark");
}
} else {
@@ -5399,7 +5480,7 @@ void GMainWindow::UpdateUITheme() {
QIcon::setThemeSearchPaths(QStringList(QStringLiteral(":/icons")));
AdjustLinkColor();
}
-#endif
+
if (current_theme != default_theme) {
QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)};
QFile f(theme_uri);
@@ -5422,6 +5503,11 @@ void GMainWindow::UpdateUITheme() {
qApp->setStyleSheet({});
setStyleSheet({});
}
+
+#ifdef _WIN32
+ RemoveTitlebarFilter();
+ ApplyGlobalDarkTitlebar(UISettings::IsDarkTheme());
+#endif
}
void GMainWindow::LoadTranslation() {
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index e82a9ed335..5e0405ee7f 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -466,7 +466,6 @@ private:
void OpenURL(const QUrl& url);
void LoadTranslation();
void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
- bool CheckDarkMode();
bool CheckFirmwarePresence();
void SetFirmwareVersion();
void ConfigureFilesystemProvider(const std::string& filepath);
@@ -557,7 +556,6 @@ private:
QTimer update_input_timer;
QString startup_icon_theme;
- bool os_dark_mode = false;
// FS
std::shared_ptr<FileSys::VfsFilesystem> vfs;