mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
* fix corners * save corner preference * added fz setting * add option to settings * return original preference despite the setting * removed reset to default corner preference
271 lines
13 KiB
C++
271 lines
13 KiB
C++
#include "pch.h"
|
|
#include "Settings.h"
|
|
|
|
#include <common/logger/call_tracer.h>
|
|
#include <common/logger/logger.h>
|
|
#include <common/SettingsAPI/FileWatcher.h>
|
|
#include <common/utils/resources.h>
|
|
#include <common/utils/string_utils.h>
|
|
|
|
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
|
#include <FancyZonesLib/SettingsObserver.h>
|
|
#include <FancyZonesLib/trace.h>
|
|
|
|
// Non-Localizable strings
|
|
namespace NonLocalizable
|
|
{
|
|
// FancyZones settings descriptions are localized, but underlying toggle (spinner, color picker) names are not.
|
|
const wchar_t ShiftDragID[] = L"fancyzones_shiftDrag";
|
|
const wchar_t MouseSwitchID[] = L"fancyzones_mouseSwitch";
|
|
const wchar_t OverrideSnapHotKeysID[] = L"fancyzones_overrideSnapHotkeys";
|
|
const wchar_t MoveWindowAcrossMonitorsID[] = L"fancyzones_moveWindowAcrossMonitors";
|
|
const wchar_t MoveWindowsBasedOnPositionID[] = L"fancyzones_moveWindowsBasedOnPosition";
|
|
const wchar_t OverlappingZonesAlgorithmID[] = L"fancyzones_overlappingZonesAlgorithm";
|
|
const wchar_t DisplayChangeMoveWindowsID[] = L"fancyzones_displayChange_moveWindows";
|
|
const wchar_t ZoneSetChangeMoveWindowsID[] = L"fancyzones_zoneSetChange_moveWindows";
|
|
const wchar_t AppLastZoneMoveWindowsID[] = L"fancyzones_appLastZone_moveWindows";
|
|
const wchar_t OpenWindowOnActiveMonitorID[] = L"fancyzones_openWindowOnActiveMonitor";
|
|
const wchar_t RestoreSizeID[] = L"fancyzones_restoreSize";
|
|
const wchar_t QuickLayoutSwitch[] = L"fancyzones_quickLayoutSwitch";
|
|
const wchar_t FlashZonesOnQuickSwitch[] = L"fancyzones_flashZonesOnQuickSwitch";
|
|
const wchar_t UseCursorPosEditorStartupScreenID[] = L"use_cursorpos_editor_startupscreen";
|
|
const wchar_t ShowOnAllMonitorsID[] = L"fancyzones_show_on_all_monitors";
|
|
const wchar_t SpanZonesAcrossMonitorsID[] = L"fancyzones_span_zones_across_monitors";
|
|
const wchar_t MakeDraggedWindowTransparentID[] = L"fancyzones_makeDraggedWindowTransparent";
|
|
const wchar_t AllowPopupWindowSnapID[] = L"fancyzones_allowPopupWindowSnap";
|
|
const wchar_t AllowChildWindowSnapID[] = L"fancyzones_allowChildWindowSnap";
|
|
const wchar_t DisableRoundCornersOnSnapping[] = L"fancyzones_disableRoundCornersOnSnap";
|
|
|
|
const wchar_t SystemThemeID[] = L"fancyzones_systemTheme";
|
|
const wchar_t ZoneColorID[] = L"fancyzones_zoneColor";
|
|
const wchar_t ZoneBorderColorID[] = L"fancyzones_zoneBorderColor";
|
|
const wchar_t ZoneHighlightColorID[] = L"fancyzones_zoneHighlightColor";
|
|
const wchar_t ZoneNumberColorID[] = L"fancyzones_zoneNumberColor";
|
|
const wchar_t EditorHotkeyID[] = L"fancyzones_editor_hotkey";
|
|
const wchar_t WindowSwitchingToggleID[] = L"fancyzones_windowSwitching";
|
|
const wchar_t NextTabHotkeyID[] = L"fancyzones_nextTab_hotkey";
|
|
const wchar_t PrevTabHotkeyID[] = L"fancyzones_prevTab_hotkey";
|
|
const wchar_t ExcludedAppsID[] = L"fancyzones_excluded_apps";
|
|
const wchar_t ZoneHighlightOpacityID[] = L"fancyzones_highlight_opacity";
|
|
const wchar_t ShowZoneNumberID[] = L"fancyzones_showZoneNumber";
|
|
}
|
|
|
|
FancyZonesSettings::FancyZonesSettings()
|
|
{
|
|
const std::wstring& settingsFileName = GetSettingsFileName();
|
|
m_settingsFileWatcher = std::make_unique<FileWatcher>(settingsFileName, [&]() {
|
|
PostMessageW(HWND_BROADCAST, WM_PRIV_SETTINGS_CHANGED, NULL, NULL);
|
|
});
|
|
}
|
|
|
|
FancyZonesSettings& FancyZonesSettings::instance()
|
|
{
|
|
static FancyZonesSettings instance;
|
|
return instance;
|
|
}
|
|
|
|
void FancyZonesSettings::AddObserver(SettingsObserver& observer)
|
|
{
|
|
m_observers.insert(&observer);
|
|
}
|
|
|
|
void FancyZonesSettings::RemoveObserver(SettingsObserver& observer)
|
|
{
|
|
auto iter = m_observers.find(&observer);
|
|
if (iter != m_observers.end())
|
|
{
|
|
m_observers.erase(iter);
|
|
}
|
|
}
|
|
|
|
void FancyZonesSettings::SetBoolFlag(const PowerToysSettings::PowerToyValues& values, const wchar_t* id, SettingId notificationId, bool& out)
|
|
{
|
|
if (const auto val = values.get_bool_value(id))
|
|
{
|
|
if (out != *val)
|
|
{
|
|
out = *val;
|
|
NotifyObservers(notificationId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FancyZonesSettings::LoadSettings()
|
|
{
|
|
_TRACER_;
|
|
|
|
try
|
|
{
|
|
auto jsonOpt = json::from_file(GetSettingsFileName());
|
|
if (!jsonOpt)
|
|
{
|
|
Logger::warn(L"Failed to read from settings file");
|
|
return;
|
|
}
|
|
|
|
PowerToysSettings::PowerToyValues values = PowerToysSettings::PowerToyValues::from_json_string(jsonOpt->Stringify(), NonLocalizable::ModuleKey);
|
|
|
|
// flags
|
|
SetBoolFlag(values, NonLocalizable::ShiftDragID, SettingId::ShiftDrag, m_settings.shiftDrag);
|
|
SetBoolFlag(values, NonLocalizable::MouseSwitchID, SettingId::MouseSwitch, m_settings.mouseSwitch);
|
|
SetBoolFlag(values, NonLocalizable::OverrideSnapHotKeysID, SettingId::OverrideSnapHotkeys, m_settings.overrideSnapHotkeys);
|
|
SetBoolFlag(values, NonLocalizable::MoveWindowAcrossMonitorsID, SettingId::MoveWindowAcrossMonitors, m_settings.moveWindowAcrossMonitors);
|
|
SetBoolFlag(values, NonLocalizable::MoveWindowsBasedOnPositionID, SettingId::MoveWindowsBasedOnPosition, m_settings.moveWindowsBasedOnPosition);
|
|
SetBoolFlag(values, NonLocalizable::DisplayChangeMoveWindowsID, SettingId::DisplayChangeMoveWindows, m_settings.displayChange_moveWindows);
|
|
SetBoolFlag(values, NonLocalizable::ZoneSetChangeMoveWindowsID, SettingId::ZoneSetChangeMoveWindows, m_settings.zoneSetChange_moveWindows);
|
|
SetBoolFlag(values, NonLocalizable::AppLastZoneMoveWindowsID, SettingId::AppLastZoneMoveWindows, m_settings.appLastZone_moveWindows);
|
|
SetBoolFlag(values, NonLocalizable::OpenWindowOnActiveMonitorID, SettingId::OpenWindowOnActiveMonitor, m_settings.openWindowOnActiveMonitor);
|
|
SetBoolFlag(values, NonLocalizable::RestoreSizeID, SettingId::RestoreWindowSize, m_settings.restoreSize);
|
|
SetBoolFlag(values, NonLocalizable::QuickLayoutSwitch, SettingId::QuickLayoutSwitch, m_settings.quickLayoutSwitch);
|
|
SetBoolFlag(values, NonLocalizable::FlashZonesOnQuickSwitch, SettingId::FlashZonesOnQuickSwitch, m_settings.flashZonesOnQuickSwitch);
|
|
SetBoolFlag(values, NonLocalizable::UseCursorPosEditorStartupScreenID, SettingId::LaunchEditorOnScreenWhereCursorPlaced, m_settings.use_cursorpos_editor_startupscreen);
|
|
SetBoolFlag(values, NonLocalizable::ShowOnAllMonitorsID, SettingId::ShowOnAllMonitors, m_settings.showZonesOnAllMonitors);
|
|
SetBoolFlag(values, NonLocalizable::SpanZonesAcrossMonitorsID, SettingId::SpanZonesAcrossMonitors, m_settings.spanZonesAcrossMonitors);
|
|
SetBoolFlag(values, NonLocalizable::MakeDraggedWindowTransparentID, SettingId::MakeDraggedWindowsTransparent, m_settings.makeDraggedWindowTransparent);
|
|
SetBoolFlag(values, NonLocalizable::WindowSwitchingToggleID, SettingId::WindowSwitching, m_settings.windowSwitching);
|
|
SetBoolFlag(values, NonLocalizable::SystemThemeID, SettingId::SystemTheme, m_settings.systemTheme);
|
|
SetBoolFlag(values, NonLocalizable::ShowZoneNumberID, SettingId::ShowZoneNumber, m_settings.showZoneNumber);
|
|
SetBoolFlag(values, NonLocalizable::AllowPopupWindowSnapID, SettingId::AllowSnapPopupWindows, m_settings.allowSnapPopupWindows);
|
|
SetBoolFlag(values, NonLocalizable::AllowChildWindowSnapID, SettingId::AllowSnapChildWindows, m_settings.allowSnapChildWindows);
|
|
SetBoolFlag(values, NonLocalizable::DisableRoundCornersOnSnapping, SettingId::DisableRoundCornersOnSnapping, m_settings.disableRoundCorners);
|
|
|
|
// colors
|
|
if (auto val = values.get_string_value(NonLocalizable::ZoneColorID))
|
|
{
|
|
if (m_settings.zoneColor != *val)
|
|
{
|
|
m_settings.zoneColor = std::move(*val);
|
|
NotifyObservers(SettingId::ZoneColor);
|
|
}
|
|
}
|
|
|
|
if (auto val = values.get_string_value(NonLocalizable::ZoneBorderColorID))
|
|
{
|
|
if (m_settings.zoneBorderColor != *val)
|
|
{
|
|
m_settings.zoneBorderColor = std::move(*val);
|
|
NotifyObservers(SettingId::ZoneBorderColor);
|
|
}
|
|
}
|
|
|
|
if (auto val = values.get_string_value(NonLocalizable::ZoneHighlightColorID))
|
|
{
|
|
if (m_settings.zoneHighlightColor != *val)
|
|
{
|
|
m_settings.zoneHighlightColor = std::move(*val);
|
|
NotifyObservers(SettingId::ZoneHighlightColor);
|
|
}
|
|
}
|
|
|
|
if (auto val = values.get_string_value(NonLocalizable::ZoneNumberColorID))
|
|
{
|
|
if (m_settings.zoneNumberColor != *val)
|
|
{
|
|
m_settings.zoneNumberColor = std::move(*val);
|
|
NotifyObservers(SettingId::ZoneNumberColor);
|
|
}
|
|
}
|
|
|
|
if (auto val = values.get_int_value(NonLocalizable::ZoneHighlightOpacityID))
|
|
{
|
|
if (m_settings.zoneHighlightOpacity != *val)
|
|
{
|
|
m_settings.zoneHighlightOpacity = std::move(*val);
|
|
NotifyObservers(SettingId::ZoneHighlightOpacity);
|
|
}
|
|
}
|
|
|
|
// hotkeys
|
|
if (const auto val = values.get_json(NonLocalizable::EditorHotkeyID))
|
|
{
|
|
auto hotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
|
if (m_settings.editorHotkey.get_modifiers() != hotkey.get_modifiers() || m_settings.editorHotkey.get_key() != hotkey.get_key() || m_settings.editorHotkey.get_code() != hotkey.get_code())
|
|
{
|
|
m_settings.editorHotkey = std::move(hotkey);
|
|
NotifyObservers(SettingId::EditorHotkey);
|
|
}
|
|
}
|
|
|
|
if (const auto val = values.get_json(NonLocalizable::NextTabHotkeyID))
|
|
{
|
|
auto hotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
|
if (m_settings.nextTabHotkey.get_modifiers() != hotkey.get_modifiers() || m_settings.nextTabHotkey.get_key() != hotkey.get_key() || m_settings.nextTabHotkey.get_code() != hotkey.get_code())
|
|
{
|
|
m_settings.nextTabHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
|
NotifyObservers(SettingId::NextTabHotkey);
|
|
}
|
|
}
|
|
|
|
if (const auto val = values.get_json(NonLocalizable::PrevTabHotkeyID))
|
|
{
|
|
auto hotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
|
if (m_settings.prevTabHotkey.get_modifiers() != hotkey.get_modifiers() || m_settings.prevTabHotkey.get_key() != hotkey.get_key() || m_settings.prevTabHotkey.get_code() != hotkey.get_code())
|
|
{
|
|
m_settings.prevTabHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
|
NotifyObservers(SettingId::PrevTabHotkey);
|
|
}
|
|
}
|
|
|
|
// excluded apps
|
|
if (auto val = values.get_string_value(NonLocalizable::ExcludedAppsID))
|
|
{
|
|
std::wstring apps = std::move(*val);
|
|
std::vector<std::wstring> excludedApps;
|
|
auto excludedUppercase = apps;
|
|
CharUpperBuffW(excludedUppercase.data(), (DWORD)excludedUppercase.length());
|
|
std::wstring_view view(excludedUppercase);
|
|
view = left_trim<wchar_t>(trim<wchar_t>(view));
|
|
|
|
while (!view.empty())
|
|
{
|
|
auto pos = (std::min)(view.find_first_of(L"\r\n"), view.length());
|
|
excludedApps.emplace_back(view.substr(0, pos));
|
|
view.remove_prefix(pos);
|
|
view = left_trim<wchar_t>(trim<wchar_t>(view));
|
|
}
|
|
|
|
if (m_settings.excludedAppsArray != excludedApps)
|
|
{
|
|
m_settings.excludedApps = apps;
|
|
m_settings.excludedAppsArray = excludedApps;
|
|
NotifyObservers(SettingId::ExcludedApps);
|
|
}
|
|
}
|
|
|
|
// algorithms
|
|
if (auto val = values.get_int_value(NonLocalizable::OverlappingZonesAlgorithmID))
|
|
{
|
|
// Avoid undefined behavior
|
|
if (*val >= 0 || *val < (int)OverlappingZonesAlgorithm::EnumElements)
|
|
{
|
|
auto algorithm = (OverlappingZonesAlgorithm)*val;
|
|
if (m_settings.overlappingZonesAlgorithm != algorithm)
|
|
{
|
|
m_settings.overlappingZonesAlgorithm = algorithm;
|
|
NotifyObservers(SettingId::OverlappingZonesAlgorithm);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (const winrt::hresult_error& e)
|
|
{
|
|
// Failure to load settings does not break FancyZones functionality. Display error message and continue with default settings.
|
|
Logger::error(L"Failed to read settings. {}", e.message());
|
|
MessageBox(NULL,
|
|
GET_RESOURCE_STRING(IDS_FANCYZONES_SETTINGS_LOAD_ERROR).c_str(),
|
|
GET_RESOURCE_STRING(IDS_POWERTOYS_FANCYZONES).c_str(),
|
|
MB_OK);
|
|
}
|
|
}
|
|
|
|
void FancyZonesSettings::NotifyObservers(SettingId id) const
|
|
{
|
|
for (auto observer : m_observers)
|
|
{
|
|
if (observer->WantsToBeNotified(id))
|
|
{
|
|
observer->SettingsUpdate(id);
|
|
}
|
|
}
|
|
}
|