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
|
target_sources(ui PRIVATE
|
||||||
qt_winrawinputfilter.hpp
|
qt_winrawinputfilter.hpp
|
||||||
qt_winrawinputfilter.cpp
|
qt_winrawinputfilter.cpp
|
||||||
|
qt_vmmanager_windarkmodefilter.hpp
|
||||||
|
qt_vmmanager_windarkmodefilter.cpp
|
||||||
qt_winmanagerfilter.hpp
|
qt_winmanagerfilter.hpp
|
||||||
qt_winmanagerfilter.cpp
|
qt_winmanagerfilter.cpp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ extern "C" {
|
|||||||
# include "qt_rendererstack.hpp"
|
# include "qt_rendererstack.hpp"
|
||||||
# include "qt_winrawinputfilter.hpp"
|
# include "qt_winrawinputfilter.hpp"
|
||||||
# include "qt_winmanagerfilter.hpp"
|
# include "qt_winmanagerfilter.hpp"
|
||||||
|
# include "qt_vmmanager_windarkmodefilter.hpp"
|
||||||
# include <86box/win.h>
|
# include <86box/win.h>
|
||||||
# include <shobjidl.h>
|
# include <shobjidl.h>
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
@@ -514,10 +515,6 @@ main_thread_fn()
|
|||||||
|
|
||||||
static std::thread *main_thread;
|
static std::thread *main_thread;
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
|
||||||
extern bool windows_is_light_theme();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@@ -548,7 +545,7 @@ main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
QApplication::setAttribute(Qt::AA_NativeWindows);
|
QApplication::setAttribute(Qt::AA_NativeWindows);
|
||||||
|
|
||||||
if (!windows_is_light_theme()) {
|
if (!util::isWindowsLightTheme()) {
|
||||||
QFile f(":qdarkstyle/dark/darkstyle.qss");
|
QFile f(":qdarkstyle/dark/darkstyle.qss");
|
||||||
|
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
@@ -558,6 +555,10 @@ main(int argc, char *argv[])
|
|||||||
QTextStream ts(&f);
|
QTextStream ts(&f);
|
||||||
qApp->setStyleSheet(ts.readAll());
|
qApp->setStyleSheet(ts.readAll());
|
||||||
}
|
}
|
||||||
|
QPalette palette(qApp->palette());
|
||||||
|
palette.setColor(QPalette::Link, Qt::white);
|
||||||
|
palette.setColor(QPalette::LinkVisited, Qt::lightGray);
|
||||||
|
qApp->setPalette(palette);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -632,8 +633,19 @@ main(int argc, char *argv[])
|
|||||||
// QApplication::setApplicationDisplayName("86Box VM Manager");
|
// QApplication::setApplicationDisplayName("86Box VM Manager");
|
||||||
// vmm.show();
|
// vmm.show();
|
||||||
// vmm.exec();
|
// 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, [] {
|
QTimer::singleShot(0, [] {
|
||||||
|
#endif
|
||||||
const auto vmm_main_window = new VMManagerMainWindow();
|
const auto vmm_main_window = new VMManagerMainWindow();
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
darkModeFilter.get()->setWindow(vmm_main_window);
|
||||||
|
#endif
|
||||||
vmm_main_window->show();
|
vmm_main_window->show();
|
||||||
});
|
});
|
||||||
QApplication::exec();
|
QApplication::exec();
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
* Copyright 2022 Teemu Korhonen
|
* Copyright 2022 Teemu Korhonen
|
||||||
*/
|
*/
|
||||||
#include "qt_styleoverride.hpp"
|
#include "qt_styleoverride.hpp"
|
||||||
|
#include "qt_util.hpp"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QAbstractItemView>
|
#include <QAbstractItemView>
|
||||||
@@ -64,8 +65,7 @@ StyleOverride::polish(QWidget *widget)
|
|||||||
}
|
}
|
||||||
widget->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
widget->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
extern bool windows_is_light_theme();
|
BOOL DarkMode = !util::isWindowsLightTheme();
|
||||||
BOOL DarkMode = !windows_is_light_theme();
|
|
||||||
DwmSetWindowAttribute((HWND)widget->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode));
|
DwmSetWindowAttribute((HWND)widget->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "qt_util.hpp"
|
#include "qt_util.hpp"
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
|
# include <windows.h>
|
||||||
# include <dwmapi.h>
|
# include <dwmapi.h>
|
||||||
# ifndef DWMWA_WINDOW_CORNER_PREFERENCE
|
# ifndef DWMWA_WINDOW_CORNER_PREFERENCE
|
||||||
# define DWMWA_WINDOW_CORNER_PREFERENCE 33
|
# define DWMWA_WINDOW_CORNER_PREFERENCE 33
|
||||||
@@ -62,6 +63,36 @@ screenOfWidget(QWidget *widget)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
#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
|
void
|
||||||
setWin11RoundedCorners(WId hwnd, bool enable)
|
setWin11RoundedCorners(WId hwnd, bool enable)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ QString DlgFilter(QStringList extensions, bool last = false);
|
|||||||
/* Returns screen the widget is on */
|
/* Returns screen the widget is on */
|
||||||
QScreen *screenOfWidget(QWidget *widget);
|
QScreen *screenOfWidget(QWidget *widget);
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
|
bool isWindowsLightTheme(void);
|
||||||
void setWin11RoundedCorners(WId hwnd, bool enable);
|
void setWin11RoundedCorners(WId hwnd, bool enable);
|
||||||
#endif
|
#endif
|
||||||
QString currentUuid();
|
QString currentUuid();
|
||||||
|
|||||||
@@ -19,12 +19,19 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
|
|
||||||
|
#include "qt_util.hpp"
|
||||||
#include "qt_vmmanager_details.hpp"
|
#include "qt_vmmanager_details.hpp"
|
||||||
#include "ui_qt_vmmanager_details.h"
|
#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
|
#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
|
#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;
|
using namespace VMManager;
|
||||||
|
|
||||||
@@ -100,18 +107,14 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) :
|
|||||||
QString toolButtonStyleSheet;
|
QString toolButtonStyleSheet;
|
||||||
// Simple method to try and determine if light mode is enabled
|
// Simple method to try and determine if light mode is enabled
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
const bool lightMode = windows_is_light_theme();
|
const bool lightMode = util::isWindowsLightTheme();
|
||||||
#else
|
#else
|
||||||
const bool lightMode = QApplication::palette().window().color().value() > QApplication::palette().windowText().color().value();
|
const bool lightMode = QApplication::palette().window().color().value() > QApplication::palette().windowText().color().value();
|
||||||
#endif
|
#endif
|
||||||
if (lightMode) {
|
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 {
|
} else {
|
||||||
#ifndef Q_OS_WINDOWS
|
toolButtonStyleSheet = TOOLBUTTON_STYLESHEET_DARK;
|
||||||
toolButtonStyleSheet = "QToolButton {background: transparent; border: none; padding: 5px} QToolButton:hover {background: palette(dark)} QToolButton:pressed {background: palette(mid)}";
|
|
||||||
#else
|
|
||||||
toolButtonStyleSheet = "QToolButton {padding: 5px}";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
ui->ssNavTBHolder->setStyleSheet(toolButtonStyleSheet);
|
ui->ssNavTBHolder->setStyleSheet(toolButtonStyleSheet);
|
||||||
|
|
||||||
@@ -150,6 +153,17 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) :
|
|||||||
|
|
||||||
ui->notesTextEdit->setEnabled(false);
|
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();
|
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 scrollarea background but also set the scroll bar to none. Otherwise it will also
|
||||||
// set the scrollbar background to the same.
|
// set the scrollbar background to the same.
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
extern bool windows_is_light_theme();
|
if (util::isWindowsLightTheme())
|
||||||
if (windows_is_light_theme())
|
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
ui->scrollArea->setStyleSheet("QWidget {background-color: palette(light)} QScrollBar{ background-color: none }");
|
ui->scrollArea->setStyleSheet(SCROLLAREA_STYLESHEET_LIGHT);
|
||||||
ui->systemLabel->setStyleSheet("background-color: palette(midlight);");
|
ui->systemLabel->setStyleSheet(SYSTEMLABEL_STYLESHEET_LIGHT);
|
||||||
}
|
}
|
||||||
// Margins are a little different on macos
|
// Margins are a little different on macos
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
@@ -331,8 +344,8 @@ VMManagerDetails::updateScreenshots(VMManagerSystem *passed_sysconfig) {
|
|||||||
ui->screenshot->setEnabled(false);
|
ui->screenshot->setEnabled(false);
|
||||||
ui->screenshot->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
ui->screenshot->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
if (!windows_is_light_theme()) {
|
if (!util::isWindowsLightTheme()) {
|
||||||
ui->screenshot->setStyleSheet("QLabel { border: 1px solid gray }");
|
ui->screenshot->setStyleSheet(SCREENSHOTBORDER_STYLESHEET_DARK);
|
||||||
} else {
|
} else {
|
||||||
ui->screenshot->setStyleSheet("");
|
ui->screenshot->setStyleSheet("");
|
||||||
}
|
}
|
||||||
@@ -390,6 +403,32 @@ VMManagerDetails::updateWindowStatus()
|
|||||||
updateProcessStatus();
|
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 *
|
QWidget *
|
||||||
VMManagerDetails::createHorizontalLine(const int leftSpacing, const int rightSpacing)
|
VMManagerDetails::createHorizontalLine(const int leftSpacing, const int rightSpacing)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,8 +42,18 @@ public:
|
|||||||
void updateProcessStatus();
|
void updateProcessStatus();
|
||||||
|
|
||||||
void updateWindowStatus();
|
void updateWindowStatus();
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
void updateStyle();
|
||||||
|
#endif
|
||||||
|
|
||||||
// CollapseButton *systemCollapseButton;
|
// CollapseButton *systemCollapseButton;
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
signals:
|
||||||
|
void styleUpdated();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::VMManagerDetails *ui;
|
Ui::VMManagerDetails *ui;
|
||||||
VMManagerSystem *sysconfig;
|
VMManagerSystem *sysconfig;
|
||||||
|
|||||||
@@ -19,6 +19,15 @@
|
|||||||
#include "ui_qt_vmmanager_detailsection.h"
|
#include "ui_qt_vmmanager_detailsection.h"
|
||||||
|
|
||||||
#include <QPushButton>
|
#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 = ";";
|
const QString VMManagerDetailSection::sectionSeparator = ";";
|
||||||
using namespace VMManager;
|
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
|
// Simple method to try and determine if light mode is enabled on the host
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
extern bool windows_is_light_theme();
|
const bool lightMode = util::isWindowsLightTheme();
|
||||||
const bool lightMode = windows_is_light_theme();
|
|
||||||
#else
|
#else
|
||||||
const bool lightMode = QApplication::palette().window().color().value() > QApplication::palette().windowText().color().value();
|
const bool lightMode = QApplication::palette().window().color().value() > QApplication::palette().windowText().color().value();
|
||||||
#endif
|
#endif
|
||||||
// Alternate layout
|
// Alternate layout
|
||||||
if ( lightMode) {
|
if (lightMode) {
|
||||||
ui->collapseButtonHolder->setStyleSheet("background-color: palette(midlight);");
|
ui->collapseButtonHolder->setStyleSheet(HEADER_STYLESHEET_LIGHT);
|
||||||
} else {
|
} else {
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
ui->outerFrame->setStyleSheet("background-color: #272727;");
|
ui->outerFrame->setStyleSheet(BACKGROUND_STYLESHEET_DARK);
|
||||||
ui->collapseButtonHolder->setStyleSheet("background-color: #616161;");
|
|
||||||
#else
|
|
||||||
ui->collapseButtonHolder->setStyleSheet("background-color: palette(mid);");
|
|
||||||
#endif
|
#endif
|
||||||
|
ui->collapseButtonHolder->setStyleSheet(HEADER_STYLESHEET_DARK);
|
||||||
}
|
}
|
||||||
const auto sectionLabel = new QLabel(sectionName);
|
const auto sectionLabel = new QLabel(sectionName);
|
||||||
sectionLabel->setStyleSheet(sectionLabel->styleSheet().append("font-weight: bold;"));
|
sectionLabel->setStyleSheet(sectionLabel->styleSheet().append("font-weight: bold;"));
|
||||||
@@ -214,6 +220,21 @@ VMManagerDetailSection::clear()
|
|||||||
ui->detailFrame->setLayout(frameGridLayout);
|
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.
|
// 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
|
// For consistency in appearance we'll have to return the margins on a per-OS basis
|
||||||
QMargins
|
QMargins
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ public:
|
|||||||
|
|
||||||
static const QString sectionSeparator;
|
static const QString sectionSeparator;
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
public slots:
|
||||||
|
void updateStyle();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class MarginSection {
|
enum class MarginSection {
|
||||||
|
|||||||
@@ -18,13 +18,10 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include "qt_util.hpp"
|
||||||
#include "qt_vmmanager_listviewdelegate.hpp"
|
#include "qt_vmmanager_listviewdelegate.hpp"
|
||||||
#include "qt_vmmanager_model.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
|
// 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
|
// 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 {
|
const QModelIndex &index) const {
|
||||||
bool windows_light_mode = true;
|
bool windows_light_mode = true;
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
windows_light_mode = windows_is_light_theme();
|
windows_light_mode = util::isWindowsLightTheme();
|
||||||
#endif
|
#endif
|
||||||
QStyleOptionViewItem opt(option);
|
QStyleOptionViewItem opt(option);
|
||||||
initStyleOption(&opt, index);
|
initStyleOption(&opt, index);
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ illegal_chars:
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Initial default details view
|
// Initial default details view
|
||||||
vm_details = new VMManagerDetails();
|
vm_details = new VMManagerDetails(ui->detailsArea);
|
||||||
ui->detailsArea->layout()->addWidget(vm_details);
|
ui->detailsArea->layout()->addWidget(vm_details);
|
||||||
const QItemSelectionModel *selection_model = ui->listView->selectionModel();
|
const QItemSelectionModel *selection_model = ui->listView->selectionModel();
|
||||||
|
|
||||||
@@ -785,6 +785,14 @@ VMManagerMain::onLanguageUpdated()
|
|||||||
vm_details->updateData(selected_sysconfig);
|
vm_details->updateData(selected_sysconfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
void
|
||||||
|
VMManagerMain::onDarkModeUpdated()
|
||||||
|
{
|
||||||
|
vm_details->updateStyle();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
VMManagerMain::getActiveMachineCount()
|
VMManagerMain::getActiveMachineCount()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ public slots:
|
|||||||
void modelDataChange();
|
void modelDataChange();
|
||||||
void onPreferencesUpdated();
|
void onPreferencesUpdated();
|
||||||
void onLanguageUpdated();
|
void onLanguageUpdated();
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
void onDarkModeUpdated();
|
||||||
|
#endif
|
||||||
void onConfigUpdated(const QString &uuid);
|
void onConfigUpdated(const QString &uuid);
|
||||||
int getActiveMachineCount();
|
int getActiveMachineCount();
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,9 @@ VMManagerMainWindow(QWidget *parent)
|
|||||||
// Inform the main view when preferences are updated
|
// Inform the main view when preferences are updated
|
||||||
connect(this, &VMManagerMainWindow::preferencesUpdated, vmm, &VMManagerMain::onPreferencesUpdated);
|
connect(this, &VMManagerMainWindow::preferencesUpdated, vmm, &VMManagerMain::onPreferencesUpdated);
|
||||||
connect(this, &VMManagerMainWindow::languageUpdated, vmm, &VMManagerMain::onLanguageUpdated);
|
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();
|
emit languageUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
void
|
||||||
|
VMManagerMainWindow::updateDarkMode()
|
||||||
|
{
|
||||||
|
emit darkModeUpdated();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
VMManagerMainWindow::changeEvent(QEvent *event)
|
VMManagerMainWindow::changeEvent(QEvent *event)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void preferencesUpdated();
|
void preferencesUpdated();
|
||||||
void languageUpdated();
|
void languageUpdated();
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
void darkModeUpdated();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::VMManagerMainWindow *ui;
|
Ui::VMManagerMainWindow *ui;
|
||||||
@@ -48,6 +51,9 @@ public slots:
|
|||||||
void setStatusLeft(const QString &text) const;
|
void setStatusLeft(const QString &text) const;
|
||||||
void setStatusRight(const QString &text) const;
|
void setStatusRight(const QString &text) const;
|
||||||
void updateLanguage();
|
void updateLanguage();
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
void updateDarkMode();
|
||||||
|
#endif
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void vmmSelectionChanged(const QModelIndex ¤tSelection, QProcess::ProcessState processState) const;
|
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 <memory>
|
||||||
|
|
||||||
#include "qt_rendererstack.hpp"
|
#include "qt_rendererstack.hpp"
|
||||||
|
#include "qt_util.hpp"
|
||||||
#include "ui_qt_mainwindow.h"
|
#include "ui_qt_mainwindow.h"
|
||||||
|
|
||||||
static bool NewDarkMode = FALSE;
|
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
|
struct
|
||||||
{
|
{
|
||||||
HANDLE done_event = 0, ready_event = 0;
|
HANDLE done_event = 0, ready_event = 0;
|
||||||
@@ -365,7 +338,7 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!windows_is_light_theme()) {
|
if (!util::isWindowsLightTheme()) {
|
||||||
QFile f(":qdarkstyle/dark/darkstyle.qss");
|
QFile f(":qdarkstyle/dark/darkstyle.qss");
|
||||||
|
|
||||||
if (!f.exists())
|
if (!f.exists())
|
||||||
@@ -375,9 +348,17 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess
|
|||||||
QTextStream ts(&f);
|
QTextStream ts(&f);
|
||||||
qApp->setStyleSheet(ts.readAll());
|
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;
|
NewDarkMode = TRUE;
|
||||||
} else {
|
} else {
|
||||||
qApp->setStyleSheet("");
|
qApp->setStyleSheet("");
|
||||||
|
QPalette palette(qApp->palette());
|
||||||
|
palette.setColor(QPalette::Link, Qt::blue);
|
||||||
|
palette.setColor(QPalette::LinkVisited, Qt::magenta);
|
||||||
|
qApp->setPalette(palette);
|
||||||
NewDarkMode = FALSE;
|
NewDarkMode = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user