From bf493c576361ea9b8a2fe63b5939b4b50cb97fac Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 16 Sep 2021 22:23:51 +0200 Subject: [PATCH] ui: Add follow system theme option --- .../source/content/settings_entries.cpp | 1 + plugins/builtin/source/lang/de_DE.cpp | 1 + plugins/builtin/source/lang/en_US.cpp | 1 + plugins/builtin/source/lang/it_IT.cpp | 1 + plugins/libimhex/include/hex/api/event.hpp | 2 + .../libimhex/include/hex/helpers/utils.hpp | 1 + source/views/view_data_processor.cpp | 34 ++++---- source/views/view_pattern_editor.cpp | 30 +++---- source/window/linux_window.cpp | 24 ++++++ source/window/macos_window.cpp | 11 +++ source/window/win_window.cpp | 31 ++++++++ source/window/window.cpp | 79 ++++++++++--------- 12 files changed, 141 insertions(+), 75 deletions(-) diff --git a/plugins/builtin/source/content/settings_entries.cpp b/plugins/builtin/source/content/settings_entries.cpp index 78da8675f..ac3ad0ee0 100644 --- a/plugins/builtin/source/content/settings_entries.cpp +++ b/plugins/builtin/source/content/settings_entries.cpp @@ -31,6 +31,7 @@ namespace hex::plugin::builtin { static int selection = static_cast(setting); const char* themes[] = { + "hex.builtin.setting.interface.color.system"_lang, "hex.builtin.setting.interface.color.dark"_lang, "hex.builtin.setting.interface.color.light"_lang, "hex.builtin.setting.interface.color.classic"_lang diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index ab35c92b4..fd91c69c3 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -583,6 +583,7 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.general.show_tips", "Tipps beim start anzeigen" }, { "hex.builtin.setting.interface", "Aussehen" }, { "hex.builtin.setting.interface.color", "Farbthema" }, + { "hex.builtin.setting.interface.color.system", "System" }, { "hex.builtin.setting.interface.color.dark", "Dunkel" }, { "hex.builtin.setting.interface.color.light", "Hell" }, { "hex.builtin.setting.interface.color.classic", "Klassisch" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index 9b9b7bfa7..095bacf1d 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -584,6 +584,7 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.general.show_tips", "Show tips on startup" }, { "hex.builtin.setting.interface", "Interface" }, { "hex.builtin.setting.interface.color", "Color theme" }, + { "hex.builtin.setting.interface.color.system", "System" }, { "hex.builtin.setting.interface.color.dark", "Dark" }, { "hex.builtin.setting.interface.color.light", "Light" }, { "hex.builtin.setting.interface.color.classic", "Classic" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 5066cb808..b21a425c4 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -582,6 +582,7 @@ namespace hex::plugin::builtin { { "hex.builtin.setting.general.show_tips", "Mostra consigli all'avvio" }, { "hex.builtin.setting.interface", "Interfaccia" }, { "hex.builtin.setting.interface.color", "Colore del Tema" }, + { "hex.builtin.setting.interface.color.system", "Sistema" }, { "hex.builtin.setting.interface.color.dark", "Scuro" }, { "hex.builtin.setting.interface.color.light", "Chiaro" }, { "hex.builtin.setting.interface.color.classic", "Classico" }, diff --git a/plugins/libimhex/include/hex/api/event.hpp b/plugins/libimhex/include/hex/api/event.hpp index 15a9bc170..9fa59569c 100644 --- a/plugins/libimhex/include/hex/api/event.hpp +++ b/plugins/libimhex/include/hex/api/event.hpp @@ -106,6 +106,7 @@ namespace hex { EVENT_DEF(EventProjectFileLoad); EVENT_DEF(EventSettingsChanged); EVENT_DEF(EventAbnormalTermination, int); + EVENT_DEF(EventOSThemeChanged); EVENT_DEF(RequestOpenWindow, std::string); EVENT_DEF(RequestSelectionChange, Region); @@ -114,6 +115,7 @@ namespace hex { EVENT_DEF(RequestChangeWindowTitle, std::string); EVENT_DEF(RequestCloseImHex, bool); EVENT_DEF(RequestOpenFile, std::string); + EVENT_DEF(RequestChangeTheme, u32); EVENT_DEF(QuerySelection, Region&); diff --git a/plugins/libimhex/include/hex/helpers/utils.hpp b/plugins/libimhex/include/hex/helpers/utils.hpp index ba2ca8974..430170f48 100644 --- a/plugins/libimhex/include/hex/helpers/utils.hpp +++ b/plugins/libimhex/include/hex/helpers/utils.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/source/views/view_data_processor.cpp b/source/views/view_data_processor.cpp index 20640cdae..a4b43da42 100644 --- a/source/views/view_data_processor.cpp +++ b/source/views/view_data_processor.cpp @@ -9,25 +9,21 @@ namespace hex { ViewDataProcessor::ViewDataProcessor() : View("hex.view.data_processor.name") { - EventManager::subscribe(this, [] { - auto theme = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color"); - - if (theme.is_number()) { - switch (static_cast(theme)) { - default: - case 0: /* Dark theme */ - ImNodes::StyleColorsDark(); - break; - case 1: /* Light theme */ - ImNodes::StyleColorsLight(); - break; - case 2: /* Classic theme */ - ImNodes::StyleColorsClassic(); - break; - } - - ImNodes::GetStyle().Flags = ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines; + EventManager::subscribe(this, [](u32 theme) { + switch (theme) { + default: + case 1: /* Dark theme */ + ImNodes::StyleColorsDark(); + break; + case 2: /* Light theme */ + ImNodes::StyleColorsLight(); + break; + case 3: /* Classic theme */ + ImNodes::StyleColorsClassic(); + break; } + + ImNodes::GetStyle().Flags = ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines; }); EventManager::subscribe(this, [this] { @@ -50,7 +46,7 @@ namespace hex { for (auto &node : this->m_nodes) delete node; - EventManager::unsubscribe(this); + EventManager::unsubscribe(this); EventManager::unsubscribe(this); EventManager::unsubscribe(this); EventManager::unsubscribe(this); diff --git a/source/views/view_pattern_editor.cpp b/source/views/view_pattern_editor.cpp index 87ffe6393..7291c1955 100644 --- a/source/views/view_pattern_editor.cpp +++ b/source/views/view_pattern_editor.cpp @@ -152,22 +152,18 @@ namespace hex { /* Settings */ { - EventManager::subscribe(this, [this]() { - auto theme = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color"); - - if (theme.is_number()) { - switch (static_cast(theme)) { - default: - case 0: /* Dark theme */ - this->m_textEditor.SetPalette(TextEditor::GetDarkPalette()); - break; - case 1: /* Light theme */ - this->m_textEditor.SetPalette(TextEditor::GetLightPalette()); - break; - case 2: /* Classic theme */ - this->m_textEditor.SetPalette(TextEditor::GetRetroBluePalette()); - break; - } + EventManager::subscribe(this, [this](u32 theme) { + switch (theme) { + default: + case 1: /* Dark theme */ + this->m_textEditor.SetPalette(TextEditor::GetDarkPalette()); + break; + case 2: /* Light theme */ + this->m_textEditor.SetPalette(TextEditor::GetLightPalette()); + break; + case 3: /* Classic theme */ + this->m_textEditor.SetPalette(TextEditor::GetRetroBluePalette()); + break; } }); @@ -181,7 +177,7 @@ namespace hex { EventManager::unsubscribe(this); EventManager::unsubscribe(this); EventManager::unsubscribe(this); - EventManager::unsubscribe(this); + EventManager::unsubscribe(this); } void ViewPatternEditor::drawMenu() { diff --git a/source/window/linux_window.cpp b/source/window/linux_window.cpp index ec6ae8d69..b31ed51db 100644 --- a/source/window/linux_window.cpp +++ b/source/window/linux_window.cpp @@ -2,6 +2,9 @@ #if defined(OS_LINUX) + #include + #include + namespace hex { void Window::initNative() { @@ -9,7 +12,28 @@ } void Window::setupNativeWindow() { + bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0; + EventManager::subscribe(this, [themeFollowSystem]{ + if (!themeFollowSystem) return; + std::array buffer = { 0 }; + std::string result; + + // TODO: In the future maybe support more DEs instead of just GNOME + FILE* pipe = popen("gsettings get org.gnome.desktop.interface gtk-theme 2>&1", "r"); + if (pipe == nullptr) return; + + while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) + result += buffer.data(); + + auto exitCode = WEXITSTATUS(pclose(pipe)); + if (exitCode != 0) return; + + EventManager::post(hex::containsIgnoreCase(result, "dark") ? 1 : 2); + }); + + if (themeFollowSystem) + EventManager::post(); } void Window::updateNativeWindow() { diff --git a/source/window/macos_window.cpp b/source/window/macos_window.cpp index 0415176d7..be396b1be 100644 --- a/source/window/macos_window.cpp +++ b/source/window/macos_window.cpp @@ -2,6 +2,8 @@ #if defined(OS_MACOS) + #include + namespace hex { void Window::initNative() { @@ -9,7 +11,16 @@ } void Window::setupNativeWindow() { + bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0; + EventManager::subscribe(this, [themeFollowSystem]{ + if (!themeFollowSystem) return; + // TODO: Implement this when MacOS build is working again + EventManager::post(1); + }); + + if (themeFollowSystem) + EventManager::post(); } void Window::updateNativeWindow() { diff --git a/source/window/win_window.cpp b/source/window/win_window.cpp index c98773af2..8ddfea13e 100644 --- a/source/window/win_window.cpp +++ b/source/window/win_window.cpp @@ -4,11 +4,14 @@ #if defined(OS_WINDOWS) #include + #include #include #include #include + #include + #include #define GLFW_EXPOSE_NATIVE_WIN32 #include @@ -140,6 +143,15 @@ return HTCAPTION; else break; } + break; + } + case WM_SETTINGCHANGE: + { + if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) { + EventManager::post(); + } + + break; } default: break; } @@ -172,6 +184,25 @@ ::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS | SWP_NOSIZE | SWP_NOMOVE); ::SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_POPUP | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | WS_SYSMENU); + + bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0; + EventManager::subscribe(this, [themeFollowSystem]{ + if (!themeFollowSystem) return; + + HKEY hkey; + if (RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", &hkey) == ERROR_SUCCESS) { + DWORD value = 0; + DWORD size = sizeof(DWORD); + + auto error = RegQueryValueEx(hkey, "AppsUseLightTheme", nullptr, nullptr, reinterpret_cast(&value), &size); + if (error == ERROR_SUCCESS) { + EventManager::post(value == 0 ? 1 : 2); + } + } + }); + + if (themeFollowSystem) + EventManager::post(); } void Window::updateNativeWindow() { diff --git a/source/window/window.cpp b/source/window/window.cpp index f57fcd3eb..7036eddaa 100644 --- a/source/window/window.cpp +++ b/source/window/window.cpp @@ -85,47 +85,12 @@ namespace hex { this->initGLFW(); this->initImGui(); + this->setupNativeWindow(); EventManager::subscribe(this, [this]() { { auto theme = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color"); - - if (this->m_bannerTexture.valid()) - ImGui::UnloadImage(this->m_bannerTexture); - - if (theme.is_number()) { - switch (static_cast(theme)) { - default: - case 0: /* Dark theme */ - ImGui::StyleColorsDark(); - ImGui::StyleCustomColorsDark(); - ImPlot::StyleColorsDark(); - this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size); - break; - case 1: /* Light theme */ - ImGui::StyleColorsLight(); - ImGui::StyleCustomColorsLight(); - ImPlot::StyleColorsLight(); - this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_light, banner_light_size); - break; - case 2: /* Classic theme */ - ImGui::StyleColorsClassic(); - ImGui::StyleCustomColorsClassic(); - ImPlot::StyleColorsClassic(); - this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size); - break; - } - - ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg]; - ImGui::GetStyle().Colors[ImGuiCol_TitleBg] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg]; - ImGui::GetStyle().Colors[ImGuiCol_TitleBgActive] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg]; - ImGui::GetStyle().Colors[ImGuiCol_TitleBgCollapsed] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg]; - - if (!this->m_bannerTexture.valid()) { - log::fatal("Failed to load banner texture!"); - exit(EXIT_FAILURE); - } - } + EventManager::post(theme.get()); } { @@ -154,6 +119,43 @@ namespace hex { } }); + EventManager::subscribe(this, [this](u32 theme) { + if (this->m_bannerTexture.valid()) + ImGui::UnloadImage(this->m_bannerTexture); + + switch (theme) { + default: + case 1: /* Dark theme */ + ImGui::StyleColorsDark(); + ImGui::StyleCustomColorsDark(); + ImPlot::StyleColorsDark(); + this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size); + break; + case 2: /* Light theme */ + ImGui::StyleColorsLight(); + ImGui::StyleCustomColorsLight(); + ImPlot::StyleColorsLight(); + this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_light, banner_light_size); + break; + case 3: /* Classic theme */ + ImGui::StyleColorsClassic(); + ImGui::StyleCustomColorsClassic(); + ImPlot::StyleColorsClassic(); + this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size); + break; + } + + ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg]; + ImGui::GetStyle().Colors[ImGuiCol_TitleBg] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg]; + ImGui::GetStyle().Colors[ImGuiCol_TitleBgActive] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg]; + ImGui::GetStyle().Colors[ImGuiCol_TitleBgCollapsed] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg]; + + if (!this->m_bannerTexture.valid()) { + log::fatal("Failed to load banner texture!"); + std::abort(); + } + }); + EventManager::subscribe(this, [](const std::string &path){ SharedData::recentFilePaths.push_front(path); @@ -262,6 +264,7 @@ namespace hex { EventManager::unsubscribe(this); EventManager::unsubscribe(this); EventManager::unsubscribe(this); + EventManager::unsubscribe(this); ImGui::UnloadImage(this->m_bannerTexture); ImGui::UnloadImage(this->m_logoTexture); @@ -691,8 +694,6 @@ namespace hex { this->m_windowTitle = "ImHex"; this->m_window = glfwCreateWindow(1280 * SharedData::globalScale, 720 * SharedData::globalScale, this->m_windowTitle.c_str(), nullptr, nullptr); - this->setupNativeWindow(); - glfwSetWindowUserPointer(this->m_window, this); if (this->m_window == nullptr)