Manager: Fix style not reacting to Windows light/dark mode change
Add a native event filter for dark mode update, move the function that queries the current theme to qt_util.cpp and make widgets with custom stylesheets update their style on update
This commit is contained in:
@@ -374,6 +374,8 @@ if (WIN32)
|
||||
target_sources(ui PRIVATE
|
||||
qt_winrawinputfilter.hpp
|
||||
qt_winrawinputfilter.cpp
|
||||
qt_vmmanager_windarkmodefilter.hpp
|
||||
qt_vmmanager_windarkmodefilter.cpp
|
||||
qt_winmanagerfilter.hpp
|
||||
qt_winmanagerfilter.cpp
|
||||
)
|
||||
|
||||
@@ -66,6 +66,7 @@ extern "C" {
|
||||
# include "qt_rendererstack.hpp"
|
||||
# include "qt_winrawinputfilter.hpp"
|
||||
# include "qt_winmanagerfilter.hpp"
|
||||
# include "qt_vmmanager_windarkmodefilter.hpp"
|
||||
# include <86box/win.h>
|
||||
# include <shobjidl.h>
|
||||
# include <windows.h>
|
||||
@@ -514,10 +515,6 @@ main_thread_fn()
|
||||
|
||||
static std::thread *main_thread;
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
extern bool windows_is_light_theme();
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@@ -548,7 +545,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
QApplication::setAttribute(Qt::AA_NativeWindows);
|
||||
|
||||
if (!windows_is_light_theme()) {
|
||||
if (!util::isWindowsLightTheme()) {
|
||||
QFile f(":qdarkstyle/dark/darkstyle.qss");
|
||||
|
||||
if (!f.exists()) {
|
||||
@@ -558,6 +555,10 @@ main(int argc, char *argv[])
|
||||
QTextStream ts(&f);
|
||||
qApp->setStyleSheet(ts.readAll());
|
||||
}
|
||||
QPalette palette(qApp->palette());
|
||||
palette.setColor(QPalette::Link, Qt::white);
|
||||
palette.setColor(QPalette::LinkVisited, Qt::lightGray);
|
||||
qApp->setPalette(palette);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -632,8 +633,19 @@ main(int argc, char *argv[])
|
||||
// QApplication::setApplicationDisplayName("86Box VM Manager");
|
||||
// vmm.show();
|
||||
// vmm.exec();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
auto darkModeFilter = std::unique_ptr<WindowsDarkModeFilter>(new WindowsDarkModeFilter());
|
||||
if (darkModeFilter) {
|
||||
qApp->installNativeEventFilter(darkModeFilter.get());
|
||||
}
|
||||
QTimer::singleShot(0, [&darkModeFilter] {
|
||||
#else
|
||||
QTimer::singleShot(0, [] {
|
||||
#endif
|
||||
const auto vmm_main_window = new VMManagerMainWindow();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
darkModeFilter.get()->setWindow(vmm_main_window);
|
||||
#endif
|
||||
vmm_main_window->show();
|
||||
});
|
||||
QApplication::exec();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* Copyright 2022 Teemu Korhonen
|
||||
*/
|
||||
#include "qt_styleoverride.hpp"
|
||||
#include "qt_util.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QAbstractItemView>
|
||||
@@ -64,8 +65,7 @@ StyleOverride::polish(QWidget *widget)
|
||||
}
|
||||
widget->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
extern bool windows_is_light_theme();
|
||||
BOOL DarkMode = !windows_is_light_theme();
|
||||
BOOL DarkMode = !util::isWindowsLightTheme();
|
||||
DwmSetWindowAttribute((HWND)widget->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "qt_util.hpp"
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
# include <windows.h>
|
||||
# include <dwmapi.h>
|
||||
# ifndef DWMWA_WINDOW_CORNER_PREFERENCE
|
||||
# define DWMWA_WINDOW_CORNER_PREFERENCE 33
|
||||
@@ -62,6 +63,36 @@ screenOfWidget(QWidget *widget)
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
|
||||
bool
|
||||
isWindowsLightTheme(void) {
|
||||
// based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application
|
||||
|
||||
// The value is expected to be a REG_DWORD, which is a signed 32-bit little-endian
|
||||
auto buffer = std::vector<char>(4);
|
||||
auto cbData = static_cast<DWORD>(buffer.size() * sizeof(char));
|
||||
auto res = RegGetValueW(
|
||||
HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
L"AppsUseLightTheme",
|
||||
RRF_RT_REG_DWORD, // expected value type
|
||||
nullptr,
|
||||
buffer.data(),
|
||||
&cbData);
|
||||
|
||||
if (res != ERROR_SUCCESS) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// convert bytes written to our buffer to an int, assuming little-endian
|
||||
auto i = int(buffer[3] << 24 |
|
||||
buffer[2] << 16 |
|
||||
buffer[1] << 8 |
|
||||
buffer[0]);
|
||||
|
||||
return i == 1;
|
||||
}
|
||||
|
||||
void
|
||||
setWin11RoundedCorners(WId hwnd, bool enable)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@ QString DlgFilter(QStringList extensions, bool last = false);
|
||||
/* Returns screen the widget is on */
|
||||
QScreen *screenOfWidget(QWidget *widget);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
bool isWindowsLightTheme(void);
|
||||
void setWin11RoundedCorners(WId hwnd, bool enable);
|
||||
#endif
|
||||
QString currentUuid();
|
||||
|
||||
@@ -19,12 +19,19 @@
|
||||
#include <QDebug>
|
||||
#include <QStyle>
|
||||
|
||||
#include "qt_util.hpp"
|
||||
#include "qt_vmmanager_details.hpp"
|
||||
#include "ui_qt_vmmanager_details.h"
|
||||
|
||||
#define TOOLBUTTON_STYLESHEET_LIGHT "QToolButton {background: transparent; border: none; padding: 5px} QToolButton:hover {background: palette(midlight)} QToolButton:pressed {background: palette(mid)}"
|
||||
#ifdef Q_OS_WINDOWS
|
||||
extern bool windows_is_light_theme();
|
||||
# define TOOLBUTTON_STYLESHEET_DARK "QToolButton {padding: 5px}"
|
||||
# define SCREENSHOTBORDER_STYLESHEET_DARK "QLabel { border: 1px solid gray }"
|
||||
#else
|
||||
# define TOOLBUTTON_STYLESHEET_DARK "QToolButton {background: transparent; border: none; padding: 5px} QToolButton:hover {background: palette(dark)} QToolButton:pressed {background: palette(mid)}"
|
||||
#endif
|
||||
#define SCROLLAREA_STYLESHEET_LIGHT "QWidget {background-color: palette(light)} QScrollBar{ background-color: none }"
|
||||
#define SYSTEMLABEL_STYLESHEET_LIGHT "background-color: palette(midlight);"
|
||||
|
||||
using namespace VMManager;
|
||||
|
||||
@@ -100,18 +107,14 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) :
|
||||
QString toolButtonStyleSheet;
|
||||
// Simple method to try and determine if light mode is enabled
|
||||
#ifdef Q_OS_WINDOWS
|
||||
const bool lightMode = windows_is_light_theme();
|
||||
const bool lightMode = util::isWindowsLightTheme();
|
||||
#else
|
||||
const bool lightMode = QApplication::palette().window().color().value() > QApplication::palette().windowText().color().value();
|
||||
#endif
|
||||
if (lightMode) {
|
||||
toolButtonStyleSheet = "QToolButton {background: transparent; border: none; padding: 5px} QToolButton:hover {background: palette(midlight)} QToolButton:pressed {background: palette(mid)}";
|
||||
toolButtonStyleSheet = TOOLBUTTON_STYLESHEET_LIGHT;
|
||||
} else {
|
||||
#ifndef Q_OS_WINDOWS
|
||||
toolButtonStyleSheet = "QToolButton {background: transparent; border: none; padding: 5px} QToolButton:hover {background: palette(dark)} QToolButton:pressed {background: palette(mid)}";
|
||||
#else
|
||||
toolButtonStyleSheet = "QToolButton {padding: 5px}";
|
||||
#endif
|
||||
toolButtonStyleSheet = TOOLBUTTON_STYLESHEET_DARK;
|
||||
}
|
||||
ui->ssNavTBHolder->setStyleSheet(toolButtonStyleSheet);
|
||||
|
||||
@@ -150,6 +153,17 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) :
|
||||
|
||||
ui->notesTextEdit->setEnabled(false);
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
connect(this, &VMManagerDetails::styleUpdated, systemSection, &VMManagerDetailSection::updateStyle);
|
||||
connect(this, &VMManagerDetails::styleUpdated, videoSection, &VMManagerDetailSection::updateStyle);
|
||||
connect(this, &VMManagerDetails::styleUpdated, storageSection, &VMManagerDetailSection::updateStyle);
|
||||
connect(this, &VMManagerDetails::styleUpdated, audioSection, &VMManagerDetailSection::updateStyle);
|
||||
connect(this, &VMManagerDetails::styleUpdated, networkSection, &VMManagerDetailSection::updateStyle);
|
||||
connect(this, &VMManagerDetails::styleUpdated, inputSection, &VMManagerDetailSection::updateStyle);
|
||||
connect(this, &VMManagerDetails::styleUpdated, portsSection, &VMManagerDetailSection::updateStyle);
|
||||
connect(this, &VMManagerDetails::styleUpdated, otherSection, &VMManagerDetailSection::updateStyle);
|
||||
#endif
|
||||
|
||||
sysconfig = new VMManagerSystem();
|
||||
}
|
||||
|
||||
@@ -163,12 +177,11 @@ VMManagerDetails::updateData(VMManagerSystem *passed_sysconfig) {
|
||||
// Set the scrollarea background but also set the scroll bar to none. Otherwise it will also
|
||||
// set the scrollbar background to the same.
|
||||
#ifdef Q_OS_WINDOWS
|
||||
extern bool windows_is_light_theme();
|
||||
if (windows_is_light_theme())
|
||||
if (util::isWindowsLightTheme())
|
||||
#endif
|
||||
{
|
||||
ui->scrollArea->setStyleSheet("QWidget {background-color: palette(light)} QScrollBar{ background-color: none }");
|
||||
ui->systemLabel->setStyleSheet("background-color: palette(midlight);");
|
||||
ui->scrollArea->setStyleSheet(SCROLLAREA_STYLESHEET_LIGHT);
|
||||
ui->systemLabel->setStyleSheet(SYSTEMLABEL_STYLESHEET_LIGHT);
|
||||
}
|
||||
// Margins are a little different on macos
|
||||
#ifdef Q_OS_MACOS
|
||||
@@ -331,8 +344,8 @@ VMManagerDetails::updateScreenshots(VMManagerSystem *passed_sysconfig) {
|
||||
ui->screenshot->setEnabled(false);
|
||||
ui->screenshot->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (!windows_is_light_theme()) {
|
||||
ui->screenshot->setStyleSheet("QLabel { border: 1px solid gray }");
|
||||
if (!util::isWindowsLightTheme()) {
|
||||
ui->screenshot->setStyleSheet(SCREENSHOTBORDER_STYLESHEET_DARK);
|
||||
} else {
|
||||
ui->screenshot->setStyleSheet("");
|
||||
}
|
||||
@@ -390,6 +403,32 @@ VMManagerDetails::updateWindowStatus()
|
||||
updateProcessStatus();
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
void
|
||||
VMManagerDetails::updateStyle()
|
||||
{
|
||||
QString toolButtonStyleSheet;
|
||||
const bool lightMode = util::isWindowsLightTheme();
|
||||
if (lightMode) {
|
||||
toolButtonStyleSheet = TOOLBUTTON_STYLESHEET_LIGHT;
|
||||
ui->scrollArea->setStyleSheet(SCROLLAREA_STYLESHEET_LIGHT);
|
||||
ui->systemLabel->setStyleSheet(SYSTEMLABEL_STYLESHEET_LIGHT);
|
||||
if (!ui->screenshot->isEnabled())
|
||||
ui->screenshot->setStyleSheet("");
|
||||
} else {
|
||||
toolButtonStyleSheet = TOOLBUTTON_STYLESHEET_DARK;
|
||||
ui->scrollArea->setStyleSheet("");
|
||||
ui->systemLabel->setStyleSheet("");
|
||||
if (!ui->screenshot->isEnabled())
|
||||
ui->screenshot->setStyleSheet(SCREENSHOTBORDER_STYLESHEET_DARK);
|
||||
}
|
||||
ui->ssNavTBHolder->setStyleSheet(toolButtonStyleSheet);
|
||||
ui->toolButtonHolder->setStyleSheet(toolButtonStyleSheet);
|
||||
|
||||
emit styleUpdated();
|
||||
}
|
||||
#endif
|
||||
|
||||
QWidget *
|
||||
VMManagerDetails::createHorizontalLine(const int leftSpacing, const int rightSpacing)
|
||||
{
|
||||
|
||||
@@ -42,8 +42,18 @@ public:
|
||||
void updateProcessStatus();
|
||||
|
||||
void updateWindowStatus();
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
void updateStyle();
|
||||
#endif
|
||||
|
||||
// CollapseButton *systemCollapseButton;
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
signals:
|
||||
void styleUpdated();
|
||||
#endif
|
||||
|
||||
private:
|
||||
Ui::VMManagerDetails *ui;
|
||||
VMManagerSystem *sysconfig;
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
#include "ui_qt_vmmanager_detailsection.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include "qt_util.hpp"
|
||||
|
||||
#define HEADER_STYLESHEET_LIGHT "background-color: palette(midlight);"
|
||||
#ifdef Q_OS_WINDOWS
|
||||
# define HEADER_STYLESHEET_DARK "background-color: #616161;"
|
||||
# define BACKGROUND_STYLESHEET_DARK "background-color: #272727;"
|
||||
#else
|
||||
# define HEADER_STYLESHEET_DARK "background-color: palette(mid);"
|
||||
#endif
|
||||
|
||||
const QString VMManagerDetailSection::sectionSeparator = ";";
|
||||
using namespace VMManager;
|
||||
@@ -40,21 +49,18 @@ VMManagerDetailSection(const QString §ionName)
|
||||
|
||||
// Simple method to try and determine if light mode is enabled on the host
|
||||
#ifdef Q_OS_WINDOWS
|
||||
extern bool windows_is_light_theme();
|
||||
const bool lightMode = windows_is_light_theme();
|
||||
const bool lightMode = util::isWindowsLightTheme();
|
||||
#else
|
||||
const bool lightMode = QApplication::palette().window().color().value() > QApplication::palette().windowText().color().value();
|
||||
#endif
|
||||
// Alternate layout
|
||||
if (lightMode) {
|
||||
ui->collapseButtonHolder->setStyleSheet("background-color: palette(midlight);");
|
||||
ui->collapseButtonHolder->setStyleSheet(HEADER_STYLESHEET_LIGHT);
|
||||
} else {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
ui->outerFrame->setStyleSheet("background-color: #272727;");
|
||||
ui->collapseButtonHolder->setStyleSheet("background-color: #616161;");
|
||||
#else
|
||||
ui->collapseButtonHolder->setStyleSheet("background-color: palette(mid);");
|
||||
ui->outerFrame->setStyleSheet(BACKGROUND_STYLESHEET_DARK);
|
||||
#endif
|
||||
ui->collapseButtonHolder->setStyleSheet(HEADER_STYLESHEET_DARK);
|
||||
}
|
||||
const auto sectionLabel = new QLabel(sectionName);
|
||||
sectionLabel->setStyleSheet(sectionLabel->styleSheet().append("font-weight: bold;"));
|
||||
@@ -214,6 +220,21 @@ VMManagerDetailSection::clear()
|
||||
ui->detailFrame->setLayout(frameGridLayout);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
void
|
||||
VMManagerDetailSection::updateStyle()
|
||||
{
|
||||
const bool lightMode = util::isWindowsLightTheme();
|
||||
if (lightMode) {
|
||||
ui->outerFrame->setStyleSheet("");
|
||||
ui->collapseButtonHolder->setStyleSheet(HEADER_STYLESHEET_LIGHT);
|
||||
} else {
|
||||
ui->outerFrame->setStyleSheet(BACKGROUND_STYLESHEET_DARK);
|
||||
ui->collapseButtonHolder->setStyleSheet(HEADER_STYLESHEET_DARK);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// QT for Linux and Windows doesn't have the same default margins as QT on MacOS.
|
||||
// For consistency in appearance we'll have to return the margins on a per-OS basis
|
||||
QMargins
|
||||
|
||||
@@ -74,6 +74,10 @@ public:
|
||||
|
||||
static const QString sectionSeparator;
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
public slots:
|
||||
void updateStyle();
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum class MarginSection {
|
||||
|
||||
@@ -18,13 +18,10 @@
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "qt_util.hpp"
|
||||
#include "qt_vmmanager_listviewdelegate.hpp"
|
||||
#include "qt_vmmanager_model.hpp"
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
extern bool windows_is_light_theme();
|
||||
#endif
|
||||
|
||||
|
||||
// Thanks to scopchanov https://github.com/scopchanov/SO-MessageLog
|
||||
// from https://stackoverflow.com/questions/53105343/is-it-possible-to-add-a-custom-widget-into-a-qlistview
|
||||
@@ -52,7 +49,7 @@ void VMManagerListViewDelegate::paint(QPainter *painter, const QStyleOptionViewI
|
||||
const QModelIndex &index) const {
|
||||
bool windows_light_mode = true;
|
||||
#ifdef Q_OS_WINDOWS
|
||||
windows_light_mode = windows_is_light_theme();
|
||||
windows_light_mode = util::isWindowsLightTheme();
|
||||
#endif
|
||||
QStyleOptionViewItem opt(option);
|
||||
initStyleOption(&opt, index);
|
||||
|
||||
@@ -349,7 +349,7 @@ illegal_chars:
|
||||
});
|
||||
|
||||
// Initial default details view
|
||||
vm_details = new VMManagerDetails();
|
||||
vm_details = new VMManagerDetails(ui->detailsArea);
|
||||
ui->detailsArea->layout()->addWidget(vm_details);
|
||||
const QItemSelectionModel *selection_model = ui->listView->selectionModel();
|
||||
|
||||
@@ -785,6 +785,14 @@ VMManagerMain::onLanguageUpdated()
|
||||
vm_details->updateData(selected_sysconfig);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
void
|
||||
VMManagerMain::onDarkModeUpdated()
|
||||
{
|
||||
vm_details->updateStyle();
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
VMManagerMain::getActiveMachineCount()
|
||||
{
|
||||
|
||||
@@ -80,6 +80,9 @@ public slots:
|
||||
void modelDataChange();
|
||||
void onPreferencesUpdated();
|
||||
void onLanguageUpdated();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
void onDarkModeUpdated();
|
||||
#endif
|
||||
void onConfigUpdated(const QString &uuid);
|
||||
int getActiveMachineCount();
|
||||
|
||||
|
||||
@@ -116,6 +116,9 @@ VMManagerMainWindow(QWidget *parent)
|
||||
// Inform the main view when preferences are updated
|
||||
connect(this, &VMManagerMainWindow::preferencesUpdated, vmm, &VMManagerMain::onPreferencesUpdated);
|
||||
connect(this, &VMManagerMainWindow::languageUpdated, vmm, &VMManagerMain::onLanguageUpdated);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
connect(this, &VMManagerMainWindow::darkModeUpdated, vmm, &VMManagerMain::onDarkModeUpdated);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -178,6 +181,15 @@ VMManagerMainWindow::updateLanguage()
|
||||
emit languageUpdated();
|
||||
}
|
||||
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
void
|
||||
VMManagerMainWindow::updateDarkMode()
|
||||
{
|
||||
emit darkModeUpdated();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
VMManagerMainWindow::changeEvent(QEvent *event)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,9 @@ public:
|
||||
signals:
|
||||
void preferencesUpdated();
|
||||
void languageUpdated();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
void darkModeUpdated();
|
||||
#endif
|
||||
|
||||
private:
|
||||
Ui::VMManagerMainWindow *ui;
|
||||
@@ -48,6 +51,9 @@ public slots:
|
||||
void setStatusLeft(const QString &text) const;
|
||||
void setStatusRight(const QString &text) const;
|
||||
void updateLanguage();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
void updateDarkMode();
|
||||
#endif
|
||||
|
||||
private slots:
|
||||
void vmmSelectionChanged(const QModelIndex ¤tSelection, QProcess::ProcessState processState) const;
|
||||
|
||||
99
src/qt/qt_vmmanager_windarkmodefilter.cpp
Normal file
99
src/qt/qt_vmmanager_windarkmodefilter.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Generic Windows native event filter for dark mode handling
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Teemu Korhonen
|
||||
* Cacodemon345
|
||||
*
|
||||
* Copyright 2021 Teemu Korhonen
|
||||
* Copyright 2024-2025 Cacodemon345.
|
||||
*/
|
||||
|
||||
#include "qt_vmmanager_windarkmodefilter.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTextStream>
|
||||
#include <QFile>
|
||||
#include <QApplication>
|
||||
#include <QTimer>
|
||||
|
||||
#include <windows.h>
|
||||
#include <dwmapi.h>
|
||||
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
|
||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
|
||||
#endif
|
||||
|
||||
#include <86box/86box.h>
|
||||
#include <86box/plat.h>
|
||||
|
||||
#include "qt_util.hpp"
|
||||
|
||||
static bool NewDarkMode = FALSE;
|
||||
|
||||
void
|
||||
WindowsDarkModeFilter::setWindow(VMManagerMainWindow *window)
|
||||
{
|
||||
this->window = window;
|
||||
}
|
||||
|
||||
bool
|
||||
WindowsDarkModeFilter::nativeEventFilter(const QByteArray &eventType, void *message, result_t *result)
|
||||
{
|
||||
if ((window != nullptr) && (eventType == "windows_generic_MSG")) {
|
||||
MSG *msg = static_cast<MSG *>(message);
|
||||
|
||||
if ((msg != nullptr) && (msg->message == WM_SETTINGCHANGE)) {
|
||||
if ((((void *) msg->lParam) != nullptr) &&
|
||||
(wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0)) {
|
||||
|
||||
bool OldDarkMode = NewDarkMode;
|
||||
|
||||
if (!util::isWindowsLightTheme()) {
|
||||
QFile f(":qdarkstyle/dark/darkstyle.qss");
|
||||
|
||||
if (!f.exists())
|
||||
printf("Unable to set stylesheet, file not found\n");
|
||||
else {
|
||||
f.open(QFile::ReadOnly | QFile::Text);
|
||||
QTextStream ts(&f);
|
||||
qApp->setStyleSheet(ts.readAll());
|
||||
}
|
||||
QPalette palette(qApp->palette());
|
||||
palette.setColor(QPalette::Link, Qt::white);
|
||||
palette.setColor(QPalette::LinkVisited, Qt::lightGray);
|
||||
qApp->setPalette(palette);
|
||||
window->resize(window->size());
|
||||
|
||||
NewDarkMode = TRUE;
|
||||
} else {
|
||||
qApp->setStyleSheet("");
|
||||
QPalette palette(qApp->palette());
|
||||
palette.setColor(QPalette::Link, Qt::blue);
|
||||
palette.setColor(QPalette::LinkVisited, Qt::magenta);
|
||||
qApp->setPalette(palette);
|
||||
window->resize(window->size());
|
||||
NewDarkMode = FALSE;
|
||||
}
|
||||
window->updateDarkMode();
|
||||
|
||||
if (NewDarkMode != OldDarkMode) QTimer::singleShot(1000, [this] () {
|
||||
BOOL DarkMode = NewDarkMode;
|
||||
DwmSetWindowAttribute((HWND) window->winId(),
|
||||
DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||
(LPCVOID) &DarkMode,
|
||||
sizeof(DarkMode));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
47
src/qt/qt_vmmanager_windarkmodefilter.hpp
Normal file
47
src/qt/qt_vmmanager_windarkmodefilter.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Header file for Windows dark mode native messages filter
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Teemu Korhonen
|
||||
*
|
||||
* Copyright 2022 Teemu Korhonen
|
||||
*/
|
||||
|
||||
#ifndef QT_WINDOWSDARKMODEEVENTFILTER_HPP
|
||||
#define QT_WINDOWSDARKMODEEVENTFILTER_HPP
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QByteArray>
|
||||
#include <QEvent>
|
||||
#include <QWindow>
|
||||
|
||||
#include "qt_vmmanager_mainwindow.hpp"
|
||||
|
||||
#if QT_VERSION_MAJOR >= 6
|
||||
# define result_t qintptr
|
||||
#else
|
||||
# define result_t long
|
||||
#endif
|
||||
|
||||
class WindowsDarkModeFilter : public QObject, public QAbstractNativeEventFilter {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowsDarkModeFilter() = default;
|
||||
void setWindow(VMManagerMainWindow *window);
|
||||
bool nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) override;
|
||||
|
||||
private:
|
||||
VMManagerMainWindow *window;
|
||||
};
|
||||
|
||||
#endif // QT_WINDOWSDARKMODEEVENTFILTER_HPP
|
||||
@@ -71,38 +71,11 @@ extern void win_keyboard_handle(uint32_t scancode, int up, int e0, int e1);
|
||||
#include <memory>
|
||||
|
||||
#include "qt_rendererstack.hpp"
|
||||
#include "qt_util.hpp"
|
||||
#include "ui_qt_mainwindow.h"
|
||||
|
||||
static bool NewDarkMode = FALSE;
|
||||
|
||||
bool windows_is_light_theme() {
|
||||
// based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application
|
||||
|
||||
// The value is expected to be a REG_DWORD, which is a signed 32-bit little-endian
|
||||
auto buffer = std::vector<char>(4);
|
||||
auto cbData = static_cast<DWORD>(buffer.size() * sizeof(char));
|
||||
auto res = RegGetValueW(
|
||||
HKEY_CURRENT_USER,
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
L"AppsUseLightTheme",
|
||||
RRF_RT_REG_DWORD, // expected value type
|
||||
nullptr,
|
||||
buffer.data(),
|
||||
&cbData);
|
||||
|
||||
if (res != ERROR_SUCCESS) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// convert bytes written to our buffer to an int, assuming little-endian
|
||||
auto i = int(buffer[3] << 24 |
|
||||
buffer[2] << 16 |
|
||||
buffer[1] << 8 |
|
||||
buffer[0]);
|
||||
|
||||
return i == 1;
|
||||
}
|
||||
|
||||
struct
|
||||
{
|
||||
HANDLE done_event = 0, ready_event = 0;
|
||||
@@ -365,7 +338,7 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!windows_is_light_theme()) {
|
||||
if (!util::isWindowsLightTheme()) {
|
||||
QFile f(":qdarkstyle/dark/darkstyle.qss");
|
||||
|
||||
if (!f.exists())
|
||||
@@ -375,9 +348,17 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess
|
||||
QTextStream ts(&f);
|
||||
qApp->setStyleSheet(ts.readAll());
|
||||
}
|
||||
QPalette palette(qApp->palette());
|
||||
palette.setColor(QPalette::Link, Qt::white);
|
||||
palette.setColor(QPalette::LinkVisited, Qt::lightGray);
|
||||
qApp->setPalette(palette);
|
||||
NewDarkMode = TRUE;
|
||||
} else {
|
||||
qApp->setStyleSheet("");
|
||||
QPalette palette(qApp->palette());
|
||||
palette.setColor(QPalette::Link, Qt::blue);
|
||||
palette.setColor(QPalette::LinkVisited, Qt::magenta);
|
||||
qApp->setPalette(palette);
|
||||
NewDarkMode = FALSE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user