#include "pch.h" #include "general_settings.h" #include "auto_start_helper.h" #include "Generated files/resource.h" #include #include "powertoy_module.h" #include #include "trace.h" #include #include #include // TODO: would be nice to get rid of these globals, since they're basically cached json settings static std::wstring settings_theme = L"system"; static bool startup_disabled_manually = false; static bool run_as_elevated = false; static bool download_updates_automatically = true; json::JsonObject GeneralSettings::to_json() { json::JsonObject result; result.SetNamedValue(L"startup", json::value(isStartupEnabled)); if (!startupDisabledReason.empty()) { result.SetNamedValue(L"startup_disabled_reason", json::value(startupDisabledReason)); } json::JsonObject enabled; for (const auto& [name, isEnabled] : isModulesEnabledMap) { enabled.SetNamedValue(name, json::value(isEnabled)); } result.SetNamedValue(L"enabled", std::move(enabled)); result.SetNamedValue(L"is_elevated", json::value(isElevated)); result.SetNamedValue(L"run_elevated", json::value(isRunElevated)); result.SetNamedValue(L"download_updates_automatically", json::value(downloadUpdatesAutomatically)); result.SetNamedValue(L"is_admin", json::value(isAdmin)); result.SetNamedValue(L"theme", json::value(theme)); result.SetNamedValue(L"system_theme", json::value(systemTheme)); result.SetNamedValue(L"powertoys_version", json::value(powerToysVersion)); return result; } json::JsonObject load_general_settings() { auto loaded = PTSettingsHelper::load_general_settings(); settings_theme = loaded.GetNamedString(L"theme", L"system"); if (settings_theme != L"dark" && settings_theme != L"light") { settings_theme = L"system"; } run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false); download_updates_automatically = loaded.GetNamedBoolean(L"download_updates_automatically", true) && check_user_is_admin(); return loaded; } GeneralSettings get_general_settings() { const bool is_user_admin = check_user_is_admin(); GeneralSettings settings{ .isElevated = is_process_elevated(), .isRunElevated = run_as_elevated, .isAdmin = is_user_admin, .downloadUpdatesAutomatically = download_updates_automatically && is_user_admin, .theme = settings_theme, .systemTheme = WindowsColors::is_dark_mode() ? L"dark" : L"light", .powerToysVersion = get_product_version() }; settings.isStartupEnabled = is_auto_start_task_active_for_this_user(); for (auto& [name, powertoy] : modules()) { settings.isModulesEnabledMap[name] = powertoy->is_enabled(); } return settings; } void apply_general_settings(const json::JsonObject& general_configs, bool save) { Logger::info(L"apply_general_settings: {}", std::wstring{ general_configs.ToString() }); run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false); download_updates_automatically = general_configs.GetNamedBoolean(L"download_updates_automatically", true); if (json::has(general_configs, L"startup", json::JsonValueType::Boolean)) { const bool startup = general_configs.GetNamedBoolean(L"startup"); auto settings = get_general_settings(); static std::once_flag once_flag; std::call_once(once_flag, [settings, startup, general_configs] { if (json::has(general_configs, L"startup", json::JsonValueType::Boolean)) { if (startup == true && settings.isStartupEnabled == false) { Logger::info("PowerToys run at startup disabled manually"); startup_disabled_manually = true; } } }); if (startup && !startup_disabled_manually) { if (is_process_elevated()) { delete_auto_start_task_for_this_user(); create_auto_start_task_for_this_user(general_configs.GetNamedBoolean(L"run_elevated", false)); } else { if (!is_auto_start_task_active_for_this_user()) { delete_auto_start_task_for_this_user(); create_auto_start_task_for_this_user(false); run_as_elevated = false; } else if (!general_configs.GetNamedBoolean(L"run_elevated", false)) { delete_auto_start_task_for_this_user(); create_auto_start_task_for_this_user(false); } } } else { delete_auto_start_task_for_this_user(); startup_disabled_manually = false; } } if (json::has(general_configs, L"enabled")) { for (const auto& enabled_element : general_configs.GetNamedObject(L"enabled")) { const auto value = enabled_element.Value(); if (value.ValueType() != json::JsonValueType::Boolean) { continue; } const std::wstring name{ enabled_element.Key().c_str() }; const bool found = modules().find(name) != modules().end(); if (!found) { continue; } PowertoyModule& powertoy = modules().at(name); const bool module_inst_enabled = powertoy->is_enabled(); const bool target_enabled = value.GetBoolean(); if (module_inst_enabled == target_enabled) { continue; } if (target_enabled) { Logger::info(L"apply_general_settings: Enabling powertoy {}", name); powertoy->enable(); } else { Logger::info(L"apply_general_settings: Disabling powertoy {}", name); powertoy->disable(); } // Sync the hotkey state with the module state, so it can be removed for disabled modules. powertoy.UpdateHotkeyEx(); } } if (json::has(general_configs, L"theme", json::JsonValueType::String)) { settings_theme = general_configs.GetNamedString(L"theme"); } if (save) { GeneralSettings save_settings = get_general_settings(); PTSettingsHelper::save_general_settings(save_settings.to_json()); Trace::SettingsChanged(save_settings); } } void start_enabled_powertoys() { std::unordered_set powertoys_to_disable; // Take into account default values supplied by modules themselves for (auto& [name, powertoy] : modules()) { if (!powertoy->is_enabled_by_default()) powertoys_to_disable.emplace(name); } json::JsonObject general_settings; try { general_settings = load_general_settings(); if (general_settings.HasKey(L"enabled")) { json::JsonObject enabled = general_settings.GetNamedObject(L"enabled"); for (const auto& disabled_element : enabled) { std::wstring disable_module_name{ static_cast(disabled_element.Key()) }; // Disable explicitly disabled modules if (!disabled_element.Value().GetBoolean()) { Logger::info(L"start_enabled_powertoys: Powertoy {} explicitly disabled", disable_module_name); powertoys_to_disable.emplace(std::move(disable_module_name)); } // If module was scheduled for disable, but it's enabled in the settings - override default value else if (auto it = powertoys_to_disable.find(disable_module_name); it != end(powertoys_to_disable)) { Logger::info(L"start_enabled_powertoys: Overriding default enabled value for {} powertoy", disable_module_name); powertoys_to_disable.erase(it); } } } } catch (...) { } for (auto& [name, powertoy] : modules()) { if (!powertoys_to_disable.contains(name)) { Logger::info(L"start_enabled_powertoys: Enabling powertoy {}", name); powertoy->enable(); powertoy.UpdateHotkeyEx(); } } }