Add ability to switch color scheme from system default on Windows

This commit is contained in:
Cacodemon345
2025-08-28 14:34:39 +06:00
parent b582e65a99
commit 4f81c12b81
34 changed files with 410 additions and 64 deletions

View File

@@ -236,6 +236,7 @@ char monitor_edid_path[1024] = { 0 }; /* (C) Path to
double video_gl_input_scale = 1.0; /* (C) OpenGL 3.x input scale */
int video_gl_input_scale_mode = FULLSCR_SCALE_FULL; /* (C) OpenGL 3.x input stretch mode */
int color_scheme = 0; /* (C) Color scheme of UI (Windows-only) */
// Accelerator key array
struct accelKey acc_keys[NUM_ACCELS];

View File

@@ -128,6 +128,7 @@ load_global(void)
confirm_reset = ini_section_get_int(cat, "confirm_reset", 1);
confirm_exit = ini_section_get_int(cat, "confirm_exit", 1);
confirm_save = ini_section_get_int(cat, "confirm_save", 1);
color_scheme = ini_section_get_int(cat, "color_scheme", 0);
inhibit_multimedia_keys = ini_section_get_int(cat, "inhibit_multimedia_keys", 0);
@@ -2222,6 +2223,11 @@ save_global(void)
ini_section_set_string(cat, "language", buffer);
}
if (color_scheme)
ini_section_set_int(cat, "color_scheme", color_scheme);
else
ini_section_delete_var(cat, "color_scheme");
if (open_dir_usr_path)
ini_section_set_int(cat, "open_dir_usr_path", open_dir_usr_path);
else

View File

@@ -206,6 +206,8 @@ extern int portable_mode; /* we are running in portable mode
extern int monitor_edid; /* (C) Which EDID to use. 0=default, 1=custom. */
extern char monitor_edid_path[1024]; /* (C) Path to custom EDID */
extern int color_scheme; /* (C) Color scheme of UI (Windows-only) */
#ifndef USE_NEW_DYNAREC
extern FILE *stdlog; /* file to log output to */
#endif

View File

@@ -2972,3 +2972,15 @@ msgstr ""
msgid "OpenGL input stretch mode"
msgstr ""
msgid "Color scheme"
msgstr ""
msgid "System"
msgstr ""
msgid "Light"
msgstr ""
msgid "Dark"
msgstr ""

View File

@@ -2972,3 +2972,12 @@ msgstr "Vstupní měřítko OpenGL"
msgid "OpenGL input stretch mode"
msgstr "režim roztažení vstupu OpenGL"
msgid "Color scheme"
msgstr "Barevné schéma"
msgid "Light"
msgstr "Světlo"
msgid "Dark"
msgstr "Tmavá"

View File

@@ -2972,3 +2972,12 @@ msgstr "Eingabeskala von OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Eingabestreckungsmodus von OpenGL"
msgid "Color scheme"
msgstr "Farbschema"
msgid "Light"
msgstr "Licht"
msgid "Dark"
msgstr "Dunkel"

View File

@@ -2972,3 +2972,12 @@ msgstr "Escala de entrada de OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Modo de estiramiento de entrada de OpenGL"
msgid "Color scheme"
msgstr "Esquema de colores"
msgid "Light"
msgstr "Luz"
msgid "Dark"
msgstr "Oscuro"

View File

@@ -2972,3 +2972,12 @@ msgstr "OpenGL:n syöttöasteikko"
msgid "OpenGL input stretch mode"
msgstr "OpenGL:n syötteen venytystila"
msgid "Color scheme"
msgstr "Värimaailma"
msgid "Light"
msgstr "Valo"
msgid "Dark"
msgstr "Tumma"

View File

@@ -2972,3 +2972,12 @@ msgstr "Échelle d'entrée d'OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Mode d'étirement des données d'entrée d'OpenGL"
msgid "Color scheme"
msgstr "Palette de couleurs"
msgid "Light"
msgstr "Lumière"
msgid "Dark"
msgstr "Sombre"

View File

@@ -2972,3 +2972,12 @@ msgstr "Ulazna skala OpenGL-a"
msgid "OpenGL input stretch mode"
msgstr "Način rastezanja ulaza u OpenGL-u"
msgid "Color scheme"
msgstr "Shema boja"
msgid "Light"
msgstr "Svjetlo"
msgid "Dark"
msgstr "Tamno"

View File

@@ -2972,3 +2972,12 @@ msgstr "Scala di input di OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Modalità di allungamento dell'input di OpenGL"
msgid "Color scheme"
msgstr "Combinazione di colori"
msgid "Light"
msgstr "Luce"
msgid "Dark"
msgstr "Scuro"

View File

@@ -2972,3 +2972,12 @@ msgstr "OpenGLの入力スケール"
msgid "OpenGL input stretch mode"
msgstr "OpenGLの入力ストレッチモード"
msgid "Color scheme"
msgstr "配色"
msgid "Light"
msgstr "光"
msgid "Dark"
msgstr "暗闇"

View File

@@ -2972,3 +2972,12 @@ msgstr "OpenGL 입력 스케일"
msgid "OpenGL input stretch mode"
msgstr "OpenGL 입력 스트레치 모드"
msgid "Color scheme"
msgstr "색상 구성"
msgid "Light"
msgstr "빛"
msgid "Dark"
msgstr "어둠"

View File

@@ -2972,3 +2972,12 @@ msgstr "Inngangsskala for OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Inngangsstrekkmodus for OpenGL"
msgid "Color scheme"
msgstr "Fargevalg"
msgid "Light"
msgstr "Lys"
msgid "Dark"
msgstr "Mørk"

View File

@@ -2972,3 +2972,12 @@ msgstr "Invoerschaal van OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Input stretch-modus van OpenGL"
msgid "Color scheme"
msgstr "Kleurenschema"
msgid "Light"
msgstr "Licht"
msgid "Dark"
msgstr "Donker"

View File

@@ -2972,3 +2972,12 @@ msgstr "Skala wejściowa OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Tryb rozciągania wejściowego OpenGL"
msgid "Color scheme"
msgstr "Schemat kolorów"
msgid "Light"
msgstr "Światło"
msgid "Dark"
msgstr "Ciemny"

View File

@@ -2972,3 +2972,12 @@ msgstr "Escala de entrada do OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Modo de expansão de entrada do OpenGL"
msgid "Color scheme"
msgstr "Esquema de cores"
msgid "Light"
msgstr "Luz"
msgid "Dark"
msgstr "Escuro"

View File

@@ -2972,3 +2972,12 @@ msgstr "Escala de entrada do OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Modo de expansão de entrada do OpenGL"
msgid "Color scheme"
msgstr "Esquema de cores"
msgid "Light"
msgstr "Luz"
msgid "Dark"
msgstr "Escuro"

View File

@@ -2972,3 +2972,12 @@ msgstr "Масштаб ввода OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Режим растяжения ввода OpenGL"
msgid "Color scheme"
msgstr "Цветовая гамма"
msgid "Light"
msgstr "Свет"
msgid "Dark"
msgstr "Темный"

View File

@@ -2972,3 +2972,12 @@ msgstr "Vstupná stupnica OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Režim rozťahovania vstupu OpenGL"
msgid "Color scheme"
msgstr "Farebná schéma"
msgid "Light"
msgstr "Svetlo"
msgid "Dark"
msgstr "Tmavá"

View File

@@ -2972,3 +2972,12 @@ msgstr "Vhodna lestvica OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Način raztezanja vhoda OpenGL"
msgid "Color scheme"
msgstr "Barvna shema"
msgid "Light"
msgstr "Svetloba"
msgid "Dark"
msgstr "Temno"

View File

@@ -2972,3 +2972,12 @@ msgstr "Inmatningsskala för OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Inmatningssträckningsläge för OpenGL"
msgid "Color scheme"
msgstr "Färgschema"
msgid "Light"
msgstr "Ljus"
msgid "Dark"
msgstr "Mörk"

View File

@@ -2972,3 +2972,12 @@ msgstr "OpenGL'nin giriş ölçeği"
msgid "OpenGL input stretch mode"
msgstr "OpenGL'nin giriş germe modu"
msgid "Color scheme"
msgstr "Renk şeması"
msgid "Light"
msgstr "Işık"
msgid "Dark"
msgstr "Karanlık"

View File

@@ -2972,3 +2972,12 @@ msgstr "Шкала введення OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Режим розтягування вхідних даних OpenGL"
msgid "Color scheme"
msgstr "Колірна гамма"
msgid "Light"
msgstr "Світло"
msgid "Dark"
msgstr "Темний"

View File

@@ -2972,3 +2972,12 @@ msgstr "Độ phân giải đầu vào của OpenGL"
msgid "OpenGL input stretch mode"
msgstr "Chế độ kéo giãn đầu vào của OpenGL"
msgid "Color scheme"
msgstr "Bảng màu"
msgid "Light"
msgstr "Ánh sáng"
msgid "Dark"
msgstr "Tối"

View File

@@ -2972,3 +2972,12 @@ msgstr "OpenGL的输入比例"
msgid "OpenGL input stretch mode"
msgstr "OpenGL的输入拉伸模式"
msgid "Color scheme"
msgstr "配色方案"
msgid "Light"
msgstr "光"
msgid "Dark"
msgstr "黑暗"

View File

@@ -2972,3 +2972,12 @@ msgstr "OpenGL 的輸入比例"
msgid "OpenGL input stretch mode"
msgstr "OpenGL 的輸入拉伸模式"
msgid "Color scheme"
msgstr "配色方案"
msgid "Light"
msgstr "光"
msgid "Dark"
msgstr "黑暗"

View File

@@ -519,6 +519,7 @@ int
main(int argc, char *argv[])
{
#ifdef Q_OS_WINDOWS
bool wasDarkTheme = false;
/* Check if Windows supports UTF-8 */
if (GetACP() == CP_UTF8)
acp_utf8 = 1;
@@ -554,6 +555,7 @@ main(int argc, char *argv[])
f.open(QFile::ReadOnly | QFile::Text);
QTextStream ts(&f);
qApp->setStyleSheet(ts.readAll());
wasDarkTheme = true;
}
QPalette palette(qApp->palette());
palette.setColor(QPalette::Link, Qt::white);
@@ -585,6 +587,16 @@ main(int argc, char *argv[])
return 0;
}
#ifdef Q_OS_WINDOWS
if (util::isWindowsLightTheme() && wasDarkTheme) {
qApp->setStyleSheet("");
QPalette palette(qApp->palette());
palette.setColor(QPalette::Link, Qt::blue);
palette.setColor(QPalette::LinkVisited, Qt::magenta);
qApp->setPalette(palette);
}
#endif
if (!start_vmm)
#ifdef Q_OS_MACOS
qt_set_sequence_auto_mnemonic(false);
@@ -864,6 +876,10 @@ main(int argc, char *argv[])
/* Initialize the rendering window, or fullscreen. */
QTimer::singleShot(0, &app, [] {
#ifdef Q_OS_WINDOWS
extern bool NewDarkMode;
NewDarkMode = util::isWindowsLightTheme();
#endif
pc_reset_hard_init();
/* Set the PAUSE mode depending on the renderer. */

View File

@@ -96,8 +96,13 @@ ProgSettings::ProgSettings(QWidget *parent)
ui->checkBoxConfirmSave->setChecked(confirm_save);
ui->checkBoxConfirmHardReset->setChecked(confirm_reset);
ui->radioButtonSystem->setChecked(color_scheme == 0);
ui->radioButtonLight->setChecked(color_scheme == 1);
ui->radioButtonDark->setChecked(color_scheme == 2);
#ifndef Q_OS_WINDOWS
ui->checkBoxMultimediaKeys->setHidden(true);
ui->groupBox->setHidden(true);
#endif
}
@@ -111,6 +116,13 @@ ProgSettings::accept()
confirm_reset = ui->checkBoxConfirmHardReset->isChecked() ? 1 : 0;
inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked() ? 1 : 0;
color_scheme = (ui->radioButtonSystem->isChecked()) ? 0 : (ui->radioButtonLight->isChecked() ? 1 : 2);
#ifdef Q_OS_WINDOWS
extern void selectDarkMode();
selectDarkMode();
#endif
loadTranslators(QCoreApplication::instance());
reloadStrings();
update_mouse_msg();

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>458</width>
<height>391</height>
<height>508</height>
</rect>
</property>
<property name="minimumSize">
@@ -27,7 +27,7 @@
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
<enum>QLayout::SizeConstraint::SetFixedSize</enum>
</property>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_2">
@@ -36,6 +36,40 @@
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="checkBoxMultimediaKeys">
<property name="text">
<string>Inhibit multimedia keys</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Mouse sensitivity:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Default</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="comboBoxLanguage">
<property name="maxVisibleItems">
@@ -48,30 +82,10 @@
</item>
</widget>
</item>
<item row="2" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButtonLanguage">
<item row="8" column="0">
<widget class="QCheckBox" name="checkBoxConfirmSave">
<property name="text">
<string>Default</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Mouse sensitivity:</string>
<string>Ask for confirmation before saving settings</string>
</property>
</widget>
</item>
@@ -93,27 +107,7 @@
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Default</string>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@@ -127,19 +121,25 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="checkBoxMultimediaKeys">
<item row="2" column="1">
<widget class="QPushButton" name="pushButtonLanguage">
<property name="text">
<string>Inhibit multimedia keys</string>
<string>Default</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="checkBoxConfirmSave">
<property name="text">
<string>Ask for confirmation before saving settings</string>
<item row="5" column="0">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="checkBoxConfirmExit">
@@ -148,6 +148,16 @@
</property>
</widget>
</item>
<item row="14" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="checkBoxConfirmHardReset">
<property name="text">
@@ -155,14 +165,34 @@
</property>
</widget>
</item>
<item row="13" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<item row="13" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Color scheme</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="radioButtonSystem">
<property name="text">
<string>System</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonLight">
<property name="text">
<string>Light</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonDark">
<property name="text">
<string>Dark</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>

View File

@@ -118,5 +118,7 @@ SpecifyDimensions::on_SpecifyDimensions_accepted()
+ main_window->menuBar()->height()
+ (main_window->statusBar()->height() * !hide_status_bar)
+ (main_window->ui->toolBar->height() * !hide_tool_bar));
window_w = ui->spinBoxWidth->value();
window_h = ui->spinBoxHeight->value();
}
}

View File

@@ -66,6 +66,10 @@ screenOfWidget(QWidget *widget)
bool
isWindowsLightTheme(void) {
if (color_scheme != 0) {
return (color_scheme == 1);
}
// 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

View File

@@ -52,7 +52,8 @@ WindowsDarkModeFilter::nativeEventFilter(const QByteArray &eventType, void *mess
if ((msg != nullptr) && (msg->message == WM_SETTINGCHANGE)) {
if ((((void *) msg->lParam) != nullptr) &&
(wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0)) {
(wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0) &&
color_scheme == 0) {
bool OldDarkMode = NewDarkMode;

View File

@@ -74,7 +74,9 @@ extern void win_keyboard_handle(uint32_t scancode, int up, int e0, int e1);
#include "qt_util.hpp"
#include "ui_qt_mainwindow.h"
static bool NewDarkMode = FALSE;
bool NewDarkMode = FALSE;
extern MainWindow* main_window;
struct
{
@@ -307,6 +309,56 @@ device_change(WPARAM wParam, LPARAM lParam)
}
}
void
selectDarkMode()
{
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);
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;
}
if (NewDarkMode != OldDarkMode)
QTimer::singleShot(1000, []() {
BOOL DarkMode = NewDarkMode;
DwmSetWindowAttribute((HWND) main_window->winId(),
DWMWA_USE_IMMERSIVE_DARK_MODE,
(LPCVOID) &DarkMode,
sizeof(DarkMode));
main_window->resizeContents(monitors[0].mon_scrnsz_x,
monitors[0].mon_scrnsz_y);
for (int i = 1; i < MONITORS_NUM; i++) {
auto mon = &(monitors[i]);
if ((main_window->renderers[i] != nullptr) && !main_window->renderers[i]->isHidden())
main_window->resizeContentsMonitor(mon->mon_scrnsz_x,
mon->mon_scrnsz_y, i);
}
});
}
bool
WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *message, result_t *result)
{
@@ -328,7 +380,8 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess
return true;
case WM_SETTINGCHANGE:
if ((((void *) msg->lParam) != nullptr) &&
(wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0)) {
(wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0) &&
color_scheme == 0) {
bool OldDarkMode = NewDarkMode;
#if 0