diff --git a/src/app/application.cpp b/src/app/application.cpp index 13ae9c77d..46a520900 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -330,6 +330,22 @@ void Application::initServices() { m_themeService.apply(); m_configService.addReloadCallback([this]() { m_themeService.onConfigReload(); }); + // Watch the dconf user database so Auto mode reacts immediately to system + // color-scheme changes (org.gnome.desktop.interface color-scheme). + { + const char* xdg = std::getenv("XDG_CONFIG_HOME"); + const char* home = std::getenv("HOME"); + std::filesystem::path dconfDb; + if (xdg != nullptr && xdg[0] != '\0') { + dconfDb = std::filesystem::path(xdg) / "dconf" / "user"; + } else if (home != nullptr && home[0] != '\0') { + dconfDb = std::filesystem::path(home) / ".config" / "dconf" / "user"; + } + if (!dconfDb.empty()) { + m_fileWatcher.watch(dconfDb, [this]() { m_themeService.onAutoSchemeChanged(); }); + } + } + if (!m_wayland.connect()) { throw std::runtime_error("failed to connect to Wayland display"); } diff --git a/src/theme/theme_service.cpp b/src/theme/theme_service.cpp index 1ddcf9583..1f293b255 100644 --- a/src/theme/theme_service.cpp +++ b/src/theme/theme_service.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,37 @@ namespace noctalia::theme { std::string mode; }; - std::string resolvedModeName(const ThemeConfig& cfg) { return cfg.mode == ThemeMode::Light ? "light" : "dark"; } + // Returns "light" or "dark" from org.gnome.desktop.interface color-scheme. + std::string_view readSystemColorScheme() { + static GSettings* settings = []() -> GSettings* { + GSettingsSchemaSource* source = g_settings_schema_source_get_default(); + if (source == nullptr) + return nullptr; + GSettingsSchema* schema = g_settings_schema_source_lookup(source, "org.gnome.desktop.interface", TRUE); + if (schema == nullptr) + return nullptr; + const bool hasKey = g_settings_schema_has_key(schema, "color-scheme") != FALSE; + g_settings_schema_unref(schema); + if (!hasKey) + return nullptr; + return g_settings_new("org.gnome.desktop.interface"); + }(); + + if (settings == nullptr) + return "dark"; + gchar* raw = g_settings_get_string(settings, "color-scheme"); + if (raw == nullptr) + return "dark"; + const bool isLight = (std::string_view(raw) == "prefer-light"); + g_free(raw); + return isLight ? "light" : "dark"; + } + + std::string resolvedModeName(const ThemeConfig& cfg) { + if (cfg.mode == ThemeMode::Auto) + return std::string(readSystemColorScheme()); + return cfg.mode == ThemeMode::Light ? "light" : "dark"; + } ResolvedTheme resolveBuiltin(const ThemeConfig& cfg) { const auto* palette = findBuiltinPalette(cfg.builtinPalette); @@ -240,6 +271,12 @@ namespace noctalia::theme { } } + void ThemeService::onAutoSchemeChanged() { + if (m_config.config().theme.mode == ThemeMode::Auto) { + resolveAndSet(/*animate=*/true); + } + } + void ThemeService::toggleLightDark() { const auto next = m_isLightMode ? ThemeMode::Dark : ThemeMode::Light; // Persist via ConfigService → StateService. The resulting overrides-change diff --git a/src/theme/theme_service.h b/src/theme/theme_service.h index 515034ec4..5953bc2ed 100644 --- a/src/theme/theme_service.h +++ b/src/theme/theme_service.h @@ -31,6 +31,7 @@ namespace noctalia::theme { // Resolves the target theme and cross-fades to it. void onConfigReload(); void onWallpaperChange(); + void onAutoSchemeChanged(); void toggleLightDark(); void cycleMode(); [[nodiscard]] ThemeMode configuredMode() const noexcept;