mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 01:08:18 +08:00
[FancyZones] Child windows support (#16507)
This commit is contained in:
parent
d9c98bbc29
commit
8edfb8fe80
1
.github/actions/spell-check/expect.txt
vendored
1
.github/actions/spell-check/expect.txt
vendored
@ -2020,6 +2020,7 @@ SYSLIB
|
||||
syslog
|
||||
SYSMENU
|
||||
systemd
|
||||
SYSTEMAPPS
|
||||
SYSTEMTIME
|
||||
systemverilog
|
||||
Tadele
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <string>
|
||||
|
||||
// Checks if a process path is included in a list of strings.
|
||||
bool find_app_name_in_path(const std::wstring& where, const std::vector<std::wstring>& what)
|
||||
inline bool find_app_name_in_path(const std::wstring& where, const std::vector<std::wstring>& what)
|
||||
{
|
||||
for (const auto& row : what)
|
||||
{
|
||||
@ -17,3 +17,16 @@ bool find_app_name_in_path(const std::wstring& where, const std::vector<std::wst
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool find_folder_in_path(const std::wstring& where, const std::vector<std::wstring>& what)
|
||||
{
|
||||
for (const auto& row : what)
|
||||
{
|
||||
const auto pos = where.rfind(row);
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -16,11 +16,9 @@
|
||||
FancyZonesApp::FancyZonesApp(const std::wstring& appName, const std::wstring& appKey)
|
||||
{
|
||||
DPIAware::EnableDPIAwarenessForThisProcess();
|
||||
|
||||
m_settings = MakeFancyZonesSettings(reinterpret_cast<HINSTANCE>(&__ImageBase), appName.c_str(), appKey.c_str());
|
||||
|
||||
|
||||
InitializeWinhookEventIds();
|
||||
m_app = MakeFancyZones(reinterpret_cast<HINSTANCE>(&__ImageBase), m_settings, std::bind(&FancyZonesApp::DisableModule, this));
|
||||
m_app = MakeFancyZones(reinterpret_cast<HINSTANCE>(&__ImageBase), std::bind(&FancyZonesApp::DisableModule, this));
|
||||
|
||||
InitHooks();
|
||||
|
||||
|
@ -19,7 +19,6 @@ private:
|
||||
winrt::com_ptr<IFancyZones> m_app;
|
||||
HWINEVENTHOOK m_objectLocationWinEventHook = nullptr;
|
||||
std::vector<HWINEVENTHOOK> m_staticWinEventHooks;
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings;
|
||||
|
||||
void DisableModule() noexcept;
|
||||
|
||||
|
59
src/modules/fancyzones/FancyZonesLib/Colors.cpp
Normal file
59
src/modules/fancyzones/FancyZonesLib/Colors.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "pch.h"
|
||||
#include "Colors.h"
|
||||
|
||||
#include <winrt/Windows.UI.ViewManagement.h>
|
||||
|
||||
#include <FancyZonesLib/Settings.h>
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
namespace Colors
|
||||
{
|
||||
COLORREF currentAccentColor;
|
||||
COLORREF currentBackgroundColor;
|
||||
|
||||
bool GetSystemTheme() noexcept
|
||||
{
|
||||
winrt::Windows::UI::ViewManagement::UISettings settings;
|
||||
auto accentValue = settings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Accent);
|
||||
auto accentColor = RGB(accentValue.R, accentValue.G, accentValue.B);
|
||||
|
||||
auto backgroundValue = settings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Background);
|
||||
auto backgroundColor = RGB(backgroundValue.R, backgroundValue.G, backgroundValue.B);
|
||||
|
||||
if (currentAccentColor != accentColor || currentBackgroundColor != backgroundColor)
|
||||
{
|
||||
currentAccentColor = accentColor;
|
||||
currentBackgroundColor = backgroundColor;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ZoneColors GetZoneColors() noexcept
|
||||
{
|
||||
if (FancyZonesSettings::settings().systemTheme)
|
||||
{
|
||||
GetSystemTheme();
|
||||
auto numberColor = currentBackgroundColor == RGB(0, 0, 0) ? RGB(255, 255, 255) : RGB(0, 0, 0);
|
||||
|
||||
return ZoneColors{
|
||||
.primaryColor = currentBackgroundColor,
|
||||
.borderColor = currentAccentColor,
|
||||
.highlightColor = currentAccentColor,
|
||||
.numberColor = numberColor,
|
||||
.highlightOpacity = FancyZonesSettings::settings().zoneHighlightOpacity
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return ZoneColors{
|
||||
.primaryColor = FancyZonesUtils::HexToRGB(FancyZonesSettings::settings().zoneColor),
|
||||
.borderColor = FancyZonesUtils::HexToRGB(FancyZonesSettings::settings().zoneBorderColor),
|
||||
.highlightColor = FancyZonesUtils::HexToRGB(FancyZonesSettings::settings().zoneHighlightColor),
|
||||
.numberColor = FancyZonesUtils::HexToRGB(FancyZonesSettings::settings().zoneNumberColor),
|
||||
.highlightOpacity = FancyZonesSettings::settings().zoneHighlightOpacity
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
17
src/modules/fancyzones/FancyZonesLib/Colors.h
Normal file
17
src/modules/fancyzones/FancyZonesLib/Colors.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <windef.h>
|
||||
|
||||
namespace Colors
|
||||
{
|
||||
struct ZoneColors
|
||||
{
|
||||
COLORREF primaryColor;
|
||||
COLORREF borderColor;
|
||||
COLORREF highlightColor;
|
||||
COLORREF numberColor;
|
||||
int highlightOpacity;
|
||||
};
|
||||
|
||||
ZoneColors GetZoneColors() noexcept;
|
||||
}
|
@ -21,9 +21,11 @@
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
#include <FancyZonesLib/MonitorUtils.h>
|
||||
#include <FancyZonesLib/Settings.h>
|
||||
#include <FancyZonesLib/SettingsObserver.h>
|
||||
#include <FancyZonesLib/ZoneSet.h>
|
||||
#include <FancyZonesLib/WorkArea.h>
|
||||
#include <FancyZonesLib/WindowMoveHandler.h>
|
||||
#include <FancyZonesLib/WindowUtils.h>
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
#include "on_thread_executor.h"
|
||||
@ -33,7 +35,6 @@
|
||||
#include "util.h"
|
||||
|
||||
#include <FancyZonesLib/SecondaryMouseButtonsHook.h>
|
||||
#include <winrt/Windows.UI.ViewManagement.h>
|
||||
|
||||
enum class DisplayChangeType
|
||||
{
|
||||
@ -50,18 +51,15 @@ namespace NonLocalizable
|
||||
const wchar_t FZEditorExecutablePath[] = L"modules\\FancyZones\\PowerToys.FancyZonesEditor.exe";
|
||||
}
|
||||
|
||||
struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZonesCallback>
|
||||
struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZonesCallback>, public SettingsObserver
|
||||
{
|
||||
public:
|
||||
FancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings, std::function<void()> disableModuleCallback) noexcept :
|
||||
FancyZones(HINSTANCE hinstance, std::function<void()> disableModuleCallback) noexcept :
|
||||
SettingsObserver({ SettingId::EditorHotkey, SettingId::PrevTabHotkey, SettingId::NextTabHotkey, SettingId::SpanZonesAcrossMonitors }),
|
||||
m_hinstance(hinstance),
|
||||
m_settings(settings),
|
||||
m_windowMoveHandler(settings, [this]() {
|
||||
m_windowMoveHandler([this]() {
|
||||
PostMessageW(m_window, WM_PRIV_LOCATIONCHANGE, NULL, NULL);
|
||||
}),
|
||||
m_settingsFileWatcher(FancyZonesDataInstance().GetSettingsFileName(), [this]() {
|
||||
PostMessageW(m_window, WM_PRIV_SETTINGS_CHANGED, NULL, NULL);
|
||||
}),
|
||||
m_virtualDesktop([this]() {
|
||||
PostMessage(m_window, WM_PRIV_VD_INIT, 0, 0);
|
||||
},
|
||||
@ -71,6 +69,8 @@ public:
|
||||
{
|
||||
this->disableModuleCallback = std::move(disableModuleCallback);
|
||||
|
||||
FancyZonesSettings::instance().LoadSettings();
|
||||
|
||||
FancyZonesDataInstance().ReplaceZoneSettingsFileFromOlderVersions();
|
||||
LayoutTemplates::instance().LoadData();
|
||||
CustomLayouts::instance().LoadData();
|
||||
@ -87,23 +87,17 @@ public:
|
||||
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
|
||||
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
||||
{
|
||||
monitor = NULL;
|
||||
}
|
||||
|
||||
// If accent color or theme is changed need to update colors for zones
|
||||
if (m_settings->GetSettings()->systemTheme && GetSystemTheme())
|
||||
{
|
||||
m_workAreaHandler.UpdateZoneColors(GetZoneColors());
|
||||
}
|
||||
|
||||
m_windowMoveHandler.MoveSizeStart(window, monitor, ptScreen, m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId));
|
||||
}
|
||||
|
||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
|
||||
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
||||
{
|
||||
monitor = NULL;
|
||||
}
|
||||
@ -174,8 +168,7 @@ private:
|
||||
void RegisterVirtualDesktopUpdates() noexcept;
|
||||
|
||||
void UpdateHotkey(int hotkeyId, const PowerToysSettings::HotkeyObject& hotkeyObject, bool enable) noexcept;
|
||||
void OnSettingsChanged() noexcept;
|
||||
|
||||
|
||||
std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& workAreaMap) noexcept;
|
||||
void MoveWindowIntoZone(HWND window, winrt::com_ptr<IWorkArea> workArea, const ZoneIndexSet& zoneIndexSet) noexcept;
|
||||
bool MoveToAppLastZone(HWND window, HMONITOR active, HMONITOR primary) noexcept;
|
||||
@ -190,8 +183,7 @@ private:
|
||||
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
|
||||
HMONITOR WorkAreaKeyFromWindow(HWND window) noexcept;
|
||||
|
||||
bool GetSystemTheme() const noexcept;
|
||||
ZoneColors GetZoneColors() const noexcept;
|
||||
virtual void SettingsUpdate(SettingId type) override;
|
||||
|
||||
const HINSTANCE m_hinstance{};
|
||||
|
||||
@ -200,9 +192,6 @@ private:
|
||||
MonitorWorkAreaHandler m_workAreaHandler;
|
||||
VirtualDesktop m_virtualDesktop;
|
||||
|
||||
FileWatcher m_settingsFileWatcher;
|
||||
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings{};
|
||||
GUID m_previousDesktopId{}; // UUID of previously active virtual desktop.
|
||||
GUID m_currentDesktopId{}; // UUID of the current virtual desktop.
|
||||
wil::unique_handle m_terminateEditorEvent; // Handle of FancyZonesEditor.exe we launch and wait on
|
||||
@ -231,8 +220,6 @@ private:
|
||||
};
|
||||
|
||||
std::function<void()> FancyZones::disableModuleCallback = {};
|
||||
COLORREF currentAccentColor;
|
||||
COLORREF currentBackgroundColor;
|
||||
|
||||
// IFancyZones
|
||||
IFACEMETHODIMP_(void)
|
||||
@ -253,11 +240,22 @@ FancyZones::Run() noexcept
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterHotKey(m_window, static_cast<int>(HotkeyId::Editor), m_settings->GetSettings()->editorHotkey.get_modifiers(), m_settings->GetSettings()->editorHotkey.get_code());
|
||||
if (m_settings->GetSettings()->windowSwitching)
|
||||
if (!RegisterHotKey(m_window, static_cast<int>(HotkeyId::Editor), FancyZonesSettings::settings().editorHotkey.get_modifiers(), FancyZonesSettings::settings().editorHotkey.get_code()))
|
||||
{
|
||||
RegisterHotKey(m_window, static_cast<int>(HotkeyId::NextTab), m_settings->GetSettings()->nextTabHotkey.get_modifiers(), m_settings->GetSettings()->nextTabHotkey.get_code());
|
||||
RegisterHotKey(m_window, static_cast<int>(HotkeyId::PrevTab), m_settings->GetSettings()->prevTabHotkey.get_modifiers(), m_settings->GetSettings()->prevTabHotkey.get_code());
|
||||
Logger::error(L"Failed to register hotkey: {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
if (FancyZonesSettings::settings().windowSwitching)
|
||||
{
|
||||
if (!RegisterHotKey(m_window, static_cast<int>(HotkeyId::NextTab), FancyZonesSettings::settings().nextTabHotkey.get_modifiers(), FancyZonesSettings::settings().nextTabHotkey.get_code()))
|
||||
{
|
||||
Logger::error(L"Failed to register hotkey: {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
if (!RegisterHotKey(m_window, static_cast<int>(HotkeyId::PrevTab), FancyZonesSettings::settings().prevTabHotkey.get_modifiers(), FancyZonesSettings::settings().prevTabHotkey.get_code()))
|
||||
{
|
||||
Logger::error(L"Failed to register hotkey: {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
m_virtualDesktop.Init();
|
||||
@ -389,8 +387,8 @@ bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR active, HMONITOR primar
|
||||
|
||||
void FancyZones::WindowCreated(HWND window) noexcept
|
||||
{
|
||||
const bool moveToAppLastZone = m_settings->GetSettings()->appLastZone_moveWindows;
|
||||
const bool openOnActiveMonitor = m_settings->GetSettings()->openWindowOnActiveMonitor;
|
||||
const bool moveToAppLastZone = FancyZonesSettings::settings().appLastZone_moveWindows;
|
||||
const bool openOnActiveMonitor = FancyZonesSettings::settings().openWindowOnActiveMonitor;
|
||||
if (!moveToAppLastZone && !openOnActiveMonitor)
|
||||
{
|
||||
// Nothing to do here then.
|
||||
@ -407,7 +405,7 @@ void FancyZones::WindowCreated(HWND window) noexcept
|
||||
|
||||
// Avoid processing splash screens, already stamped (zoned) windows, or those windows
|
||||
// that belong to excluded applications list.
|
||||
const bool isSplashScreen = FancyZonesUtils::IsSplashScreen(window);
|
||||
const bool isSplashScreen = FancyZonesWindowUtils::IsSplashScreen(window);
|
||||
if (isSplashScreen)
|
||||
{
|
||||
return;
|
||||
@ -425,7 +423,7 @@ void FancyZones::WindowCreated(HWND window) noexcept
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isCandidateForLastKnownZone = FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray);
|
||||
const bool isCandidateForLastKnownZone = FancyZonesWindowUtils::IsCandidateForZoning(window);
|
||||
if (!isCandidateForLastKnownZone)
|
||||
{
|
||||
return;
|
||||
@ -477,7 +475,7 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
if (m_settings->GetSettings()->quickLayoutSwitch)
|
||||
if (FancyZonesSettings::settings().quickLayoutSwitch)
|
||||
{
|
||||
int digitPressed = -1;
|
||||
if ('0' <= info->vkCode && info->vkCode <= '9')
|
||||
@ -526,7 +524,7 @@ void FancyZones::ToggleEditor() noexcept
|
||||
|
||||
HMONITOR targetMonitor{};
|
||||
|
||||
const bool use_cursorpos_editor_startupscreen = m_settings->GetSettings()->use_cursorpos_editor_startupscreen;
|
||||
const bool use_cursorpos_editor_startupscreen = FancyZonesSettings::settings().use_cursorpos_editor_startupscreen;
|
||||
if (use_cursorpos_editor_startupscreen)
|
||||
{
|
||||
POINT currentCursorPos{};
|
||||
@ -569,7 +567,7 @@ void FancyZones::ToggleEditor() noexcept
|
||||
std::wstring params;
|
||||
const std::wstring divider = L"/";
|
||||
params += std::to_wstring(GetCurrentProcessId()) + divider; /* Process id */
|
||||
const bool spanZonesAcrossMonitors = m_settings->GetSettings()->spanZonesAcrossMonitors;
|
||||
const bool spanZonesAcrossMonitors = FancyZonesSettings::settings().spanZonesAcrossMonitors;
|
||||
params += std::to_wstring(spanZonesAcrossMonitors) + divider; /* Span zones */
|
||||
std::vector<std::pair<HMONITOR, MONITORINFOEX>> allMonitors;
|
||||
|
||||
@ -794,7 +792,7 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
}
|
||||
else if (message == WM_PRIV_SETTINGS_CHANGED)
|
||||
{
|
||||
OnSettingsChanged();
|
||||
FancyZonesSettings::instance().LoadSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -845,7 +843,7 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
|
||||
|
||||
if ((changeType == DisplayChangeType::WorkArea) || (changeType == DisplayChangeType::DisplayChange))
|
||||
{
|
||||
if (m_settings->GetSettings()->displayChange_moveWindows)
|
||||
if (FancyZonesSettings::settings().displayChange_moveWindows)
|
||||
{
|
||||
UpdateWindowsPositions();
|
||||
}
|
||||
@ -895,7 +893,7 @@ void FancyZones::AddWorkArea(HMONITOR monitor, const std::wstring& deviceId) noe
|
||||
parentId = parentArea->UniqueId();
|
||||
}
|
||||
|
||||
auto workArea = MakeWorkArea(m_hinstance, monitor, uniqueId, parentId, GetZoneColors(), m_settings->GetSettings()->overlappingZonesAlgorithm, m_settings->GetSettings()->showZoneNumber);
|
||||
auto workArea = MakeWorkArea(m_hinstance, monitor, uniqueId, parentId);
|
||||
if (workArea)
|
||||
{
|
||||
m_workAreaHandler.AddWorkArea(m_currentDesktopId, monitor, workArea);
|
||||
@ -920,7 +918,7 @@ LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam,
|
||||
|
||||
void FancyZones::UpdateWorkAreas() noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
|
||||
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
||||
{
|
||||
AddWorkArea(nullptr, {});
|
||||
}
|
||||
@ -984,7 +982,7 @@ bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexce
|
||||
HMONITOR current = WorkAreaKeyFromWindow(window);
|
||||
|
||||
std::vector<HMONITOR> monitorInfo = GetMonitorsSorted();
|
||||
if (current && monitorInfo.size() > 1 && m_settings->GetSettings()->moveWindowAcrossMonitors)
|
||||
if (current && monitorInfo.size() > 1 && FancyZonesSettings::settings().moveWindowAcrossMonitors)
|
||||
{
|
||||
// Multi monitor environment.
|
||||
auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current);
|
||||
@ -1019,13 +1017,13 @@ bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexce
|
||||
{
|
||||
auto workArea = m_workAreaHandler.GetWorkArea(m_currentDesktopId, current);
|
||||
// Single monitor environment, or combined multi-monitor environment.
|
||||
if (m_settings->GetSettings()->restoreSize)
|
||||
if (FancyZonesSettings::settings().restoreSize)
|
||||
{
|
||||
bool moved = m_windowMoveHandler.MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, false /* cycle through zones */, workArea);
|
||||
if (!moved)
|
||||
{
|
||||
FancyZonesUtils::RestoreWindowOrigin(window);
|
||||
FancyZonesUtils::RestoreWindowSize(window);
|
||||
FancyZonesWindowUtils::RestoreWindowOrigin(window);
|
||||
FancyZonesWindowUtils::RestoreWindowSize(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1053,7 +1051,7 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept
|
||||
|
||||
auto allMonitors = FancyZonesUtils::GetAllMonitorRects<&MONITORINFOEX::rcWork>();
|
||||
|
||||
if (current && allMonitors.size() > 1 && m_settings->GetSettings()->moveWindowAcrossMonitors)
|
||||
if (current && allMonitors.size() > 1 && FancyZonesSettings::settings().moveWindowAcrossMonitors)
|
||||
{
|
||||
// Multi monitor environment.
|
||||
// First, try to stay on the same monitor
|
||||
@ -1179,7 +1177,7 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
|
||||
{
|
||||
// We already checked in ShouldProcessSnapHotkey whether the foreground window is a candidate for zoning
|
||||
auto window = GetForegroundWindow();
|
||||
if (m_settings->GetSettings()->moveWindowsBasedOnPosition)
|
||||
if (FancyZonesSettings::settings().moveWindowsBasedOnPosition)
|
||||
{
|
||||
return OnSnapHotkeyBasedOnPosition(window, vkCode);
|
||||
}
|
||||
@ -1231,6 +1229,11 @@ void FancyZones::RegisterVirtualDesktopUpdates() noexcept
|
||||
|
||||
void FancyZones::UpdateHotkey(int hotkeyId, const PowerToysSettings::HotkeyObject& hotkeyObject, bool enable) noexcept
|
||||
{
|
||||
if (!m_window)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UnregisterHotKey(m_window, hotkeyId);
|
||||
|
||||
if (!enable)
|
||||
@ -1248,28 +1251,34 @@ void FancyZones::UpdateHotkey(int hotkeyId, const PowerToysSettings::HotkeyObjec
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::OnSettingsChanged() noexcept
|
||||
void FancyZones::SettingsUpdate(SettingId id)
|
||||
{
|
||||
_TRACER_;
|
||||
m_settings->ReloadSettings();
|
||||
|
||||
// Update the hotkeys
|
||||
UpdateHotkey(static_cast<int>(HotkeyId::Editor), m_settings->GetSettings()->editorHotkey, true);
|
||||
|
||||
auto windowSwitching = m_settings->GetSettings()->windowSwitching;
|
||||
UpdateHotkey(static_cast<int>(HotkeyId::NextTab), m_settings->GetSettings()->nextTabHotkey, windowSwitching);
|
||||
UpdateHotkey(static_cast<int>(HotkeyId::PrevTab), m_settings->GetSettings()->prevTabHotkey, windowSwitching);
|
||||
|
||||
// Needed if we toggled spanZonesAcrossMonitors
|
||||
m_workAreaHandler.Clear();
|
||||
|
||||
// update zone colors
|
||||
m_workAreaHandler.UpdateZoneColors(GetZoneColors());
|
||||
|
||||
// update overlapping algorithm
|
||||
m_workAreaHandler.UpdateOverlappingAlgorithm(m_settings->GetSettings()->overlappingZonesAlgorithm);
|
||||
|
||||
PostMessageW(m_window, WM_PRIV_VD_INIT, NULL, NULL);
|
||||
switch (id)
|
||||
{
|
||||
case SettingId::EditorHotkey:
|
||||
{
|
||||
UpdateHotkey(static_cast<int>(HotkeyId::Editor), FancyZonesSettings::settings().editorHotkey, true);
|
||||
}
|
||||
break;
|
||||
case SettingId::PrevTabHotkey:
|
||||
{
|
||||
UpdateHotkey(static_cast<int>(HotkeyId::PrevTab), FancyZonesSettings::settings().prevTabHotkey, FancyZonesSettings::settings().windowSwitching);
|
||||
}
|
||||
break;
|
||||
case SettingId::NextTabHotkey:
|
||||
{
|
||||
UpdateHotkey(static_cast<int>(HotkeyId::NextTab), FancyZonesSettings::settings().nextTabHotkey, FancyZonesSettings::settings().windowSwitching);
|
||||
}
|
||||
break;
|
||||
case SettingId::SpanZonesAcrossMonitors:
|
||||
{
|
||||
m_workAreaHandler.Clear();
|
||||
PostMessageW(m_window, WM_PRIV_VD_INIT, NULL, NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::OnEditorExitEvent() noexcept
|
||||
@ -1287,14 +1296,14 @@ void FancyZones::UpdateZoneSets() noexcept
|
||||
workArea->UpdateActiveZoneSet();
|
||||
}
|
||||
|
||||
auto moveWindows = m_settings->GetSettings()->zoneSetChange_moveWindows;
|
||||
auto moveWindows = FancyZonesSettings::settings().zoneSetChange_moveWindows;
|
||||
UpdateWindowsPositions(!moveWindows);
|
||||
}
|
||||
|
||||
bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
|
||||
{
|
||||
auto window = GetForegroundWindow();
|
||||
if (m_settings->GetSettings()->overrideSnapHotkeys && FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
if (FancyZonesSettings::settings().overrideSnapHotkeys && FancyZonesWindowUtils::IsCandidateForZoning(window))
|
||||
{
|
||||
HMONITOR monitor = WorkAreaKeyFromWindow(window);
|
||||
|
||||
@ -1303,7 +1312,7 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
|
||||
{
|
||||
if (vkCode == VK_UP || vkCode == VK_DOWN)
|
||||
{
|
||||
return m_settings->GetSettings()->moveWindowsBasedOnPosition;
|
||||
return FancyZonesSettings::settings().moveWindowsBasedOnPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1346,7 +1355,7 @@ void FancyZones::ApplyQuickLayout(int key) noexcept
|
||||
|
||||
void FancyZones::FlashZones() noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->flashZonesOnQuickSwitch && !m_windowMoveHandler.IsDragEnabled())
|
||||
if (FancyZonesSettings::settings().flashZonesOnQuickSwitch && !m_windowMoveHandler.IsDragEnabled())
|
||||
{
|
||||
for (auto [monitor, workArea] : m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId))
|
||||
{
|
||||
@ -1385,7 +1394,7 @@ std::vector<std::pair<HMONITOR, RECT>> FancyZones::GetRawMonitorData() noexcept
|
||||
|
||||
HMONITOR FancyZones::WorkAreaKeyFromWindow(HWND window) noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
|
||||
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -1395,61 +1404,7 @@ HMONITOR FancyZones::WorkAreaKeyFromWindow(HWND window) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
bool FancyZones::GetSystemTheme() const noexcept
|
||||
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, std::function<void()> disableCallback) noexcept
|
||||
{
|
||||
winrt::Windows::UI::ViewManagement::UISettings settings;
|
||||
auto accentValue = settings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Accent);
|
||||
auto accentColor = RGB(accentValue.R, accentValue.G, accentValue.B);
|
||||
|
||||
auto backgroundValue = settings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Background);
|
||||
auto backgroundColor = RGB(backgroundValue.R, backgroundValue.G, backgroundValue.B);
|
||||
|
||||
if (currentAccentColor != accentColor || currentBackgroundColor != backgroundColor)
|
||||
{
|
||||
currentAccentColor = accentColor;
|
||||
currentBackgroundColor = backgroundColor;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ZoneColors FancyZones::GetZoneColors() const noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->systemTheme)
|
||||
{
|
||||
GetSystemTheme();
|
||||
auto numberColor = currentBackgroundColor == RGB(0, 0, 0) ? RGB(255, 255, 255) : RGB(0, 0, 0);
|
||||
|
||||
|
||||
return ZoneColors{
|
||||
.primaryColor = currentBackgroundColor,
|
||||
.borderColor = currentAccentColor,
|
||||
.highlightColor = currentAccentColor,
|
||||
.numberColor = numberColor,
|
||||
.highlightOpacity = m_settings->GetSettings()->zoneHighlightOpacity
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return ZoneColors{
|
||||
.primaryColor = FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneColor),
|
||||
.borderColor = FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneBorderColor),
|
||||
.highlightColor = FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneHighlightColor),
|
||||
.numberColor = FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneNumberColor),
|
||||
.highlightOpacity = m_settings->GetSettings()->zoneHighlightOpacity
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance,
|
||||
const winrt::com_ptr<IFancyZonesSettings>& settings,
|
||||
std::function<void()> disableCallback) noexcept
|
||||
{
|
||||
if (!settings)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return winrt::make_self<FancyZones>(hinstance, settings, disableCallback);
|
||||
return winrt::make_self<FancyZones>(hinstance, disableCallback);
|
||||
}
|
||||
|
@ -52,4 +52,4 @@ interface __declspec(uuid("{2CB37E8F-87E6-4AEC-B4B2-E0FDC873343F}")) IFancyZones
|
||||
(PKBDLLHOOKSTRUCT info) = 0;
|
||||
};
|
||||
|
||||
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings, std::function<void()> disableCallback) noexcept;
|
||||
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, std::function<void()> disableCallback) noexcept;
|
||||
|
@ -66,19 +66,23 @@
|
||||
<None Include="resource.base.h" />
|
||||
<ClInclude Include="SecondaryMouseButtonsHook.h" />
|
||||
<ClInclude Include="Settings.h" />
|
||||
<ClInclude Include="SettingsConstants.h" />
|
||||
<ClInclude Include="SettingsObserver.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
<ClInclude Include="VirtualDesktop.h" />
|
||||
<ClInclude Include="WindowMoveHandler.h" />
|
||||
<ClInclude Include="FancyZonesWindowProperties.h" />
|
||||
<ClInclude Include="WindowUtils.h" />
|
||||
<ClInclude Include="Zone.h" />
|
||||
<ClInclude Include="ZoneColors.h" />
|
||||
<ClInclude Include="Colors.h" />
|
||||
<ClInclude Include="ZoneIndexSetBitmask.h" />
|
||||
<ClInclude Include="ZoneSet.h" />
|
||||
<ClInclude Include="WorkArea.h" />
|
||||
<ClInclude Include="ZonesOverlay.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Colors.cpp" />
|
||||
<ClCompile Include="FancyZonesData\AppZoneHistory.cpp">
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
|
||||
@ -117,6 +121,7 @@
|
||||
<ClCompile Include="util.cpp" />
|
||||
<ClCompile Include="VirtualDesktop.cpp" />
|
||||
<ClCompile Include="WindowMoveHandler.cpp" />
|
||||
<ClCompile Include="WindowUtils.cpp" />
|
||||
<ClCompile Include="Zone.cpp" />
|
||||
<ClCompile Include="ZoneSet.cpp" />
|
||||
<ClCompile Include="WorkArea.cpp" />
|
||||
|
@ -81,7 +81,7 @@
|
||||
<ClInclude Include="MonitorUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ZoneColors.h">
|
||||
<ClInclude Include="Colors.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZonesWindowProperties.h">
|
||||
@ -117,6 +117,15 @@
|
||||
<ClInclude Include="ZoneIndexSetBitmask.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsObserver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsConstants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@ -194,6 +203,12 @@
|
||||
<ClCompile Include="FancyZonesWindowProperties.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Colors.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WindowUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "MonitorUtils.h"
|
||||
|
||||
#include <FancyZonesLib/util.h>
|
||||
#include <FancyZonesLib/WindowUtils.h>
|
||||
|
||||
namespace MonitorUtils
|
||||
{
|
||||
@ -68,7 +68,7 @@ namespace MonitorUtils
|
||||
if (GetMonitorInfo(monitor, &destMi))
|
||||
{
|
||||
RECT newPosition = FitOnScreen(placement.rcNormalPosition, originMi.rcWork, destMi.rcWork);
|
||||
FancyZonesUtils::SizeWindowToRect(window, newPosition);
|
||||
FancyZonesWindowUtils::SizeWindowToRect(window, newPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,25 +129,3 @@ void MonitorWorkAreaHandler::Clear()
|
||||
{
|
||||
workAreaMap.clear();
|
||||
}
|
||||
|
||||
void MonitorWorkAreaHandler::UpdateZoneColors(const ZoneColors& colors)
|
||||
{
|
||||
for (const auto& workArea : workAreaMap)
|
||||
{
|
||||
for (const auto& workAreaPtr : workArea.second)
|
||||
{
|
||||
workAreaPtr.second->SetZoneColors(colors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonitorWorkAreaHandler::UpdateOverlappingAlgorithm(OverlappingZonesAlgorithm overlappingAlgorithm)
|
||||
{
|
||||
for (const auto& workArea : workAreaMap)
|
||||
{
|
||||
for (const auto& workAreaPtr : workArea.second)
|
||||
{
|
||||
workAreaPtr.second->SetOverlappingZonesAlgorithm(overlappingAlgorithm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,16 +86,6 @@ public:
|
||||
* Clear all persisted work area related data.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* Update zone colors after settings changed
|
||||
*/
|
||||
void UpdateZoneColors(const ZoneColors& colors);
|
||||
|
||||
/**
|
||||
* Update overlapping algorithm after settings changed
|
||||
*/
|
||||
void UpdateOverlappingAlgorithm(OverlappingZonesAlgorithm overlappingAlgorithm);
|
||||
|
||||
private:
|
||||
// Work area is uniquely defined by monitor and virtual desktop id.
|
||||
|
@ -1,10 +1,15 @@
|
||||
#include "pch.h"
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include "Settings.h"
|
||||
|
||||
#include "FancyZonesLib/Settings.h"
|
||||
#include "FancyZonesLib/FancyZones.h"
|
||||
#include "trace.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
|
||||
@ -27,6 +32,8 @@ namespace NonLocalizable
|
||||
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 SystemThemeID[] = L"fancyzones_systemTheme";
|
||||
const wchar_t ZoneColorID[] = L"fancyzones_zoneColor";
|
||||
@ -40,214 +47,208 @@ namespace NonLocalizable
|
||||
const wchar_t ExcludedAppsID[] = L"fancyzones_excluded_apps";
|
||||
const wchar_t ZoneHighlightOpacityID[] = L"fancyzones_highlight_opacity";
|
||||
const wchar_t ShowZoneNumberID[] = L"fancyzones_showZoneNumber";
|
||||
|
||||
const wchar_t ToggleEditorActionID[] = L"ToggledFZEditor";
|
||||
const wchar_t IconKeyID[] = L"pt-fancy-zones";
|
||||
const wchar_t OverviewURL[] = L"https://aka.ms/PowerToysOverview_FancyZones";
|
||||
const wchar_t VideoURL[] = L"https://youtu.be/rTtGzZYAXgY";
|
||||
const wchar_t PowerToysIssuesURL[] = L"https://aka.ms/powerToysReportBug";
|
||||
}
|
||||
|
||||
struct FancyZonesSettings : winrt::implements<FancyZonesSettings, IFancyZonesSettings>
|
||||
FancyZonesSettings::FancyZonesSettings()
|
||||
{
|
||||
public:
|
||||
FancyZonesSettings(HINSTANCE hinstance, PCWSTR name, PCWSTR key) :
|
||||
m_hinstance(hinstance),
|
||||
m_moduleName(name),
|
||||
m_moduleKey(key)
|
||||
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())
|
||||
{
|
||||
LoadSettings(name, true);
|
||||
m_observers.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
GetConfig(_Out_ PWSTR buffer, _Out_ int* buffer_sizeg) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
SetConfig(PCWSTR config) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
ReloadSettings() noexcept;
|
||||
IFACEMETHODIMP_(const Settings*)
|
||||
GetSettings() const noexcept { return &m_settings; }
|
||||
|
||||
private:
|
||||
void LoadSettings(PCWSTR config, bool fromFile) noexcept;
|
||||
void SaveSettings() noexcept;
|
||||
|
||||
const HINSTANCE m_hinstance;
|
||||
std::wstring m_moduleName{};
|
||||
std::wstring m_moduleKey{};
|
||||
|
||||
Settings m_settings;
|
||||
|
||||
struct
|
||||
{
|
||||
PCWSTR name;
|
||||
bool* value;
|
||||
int resourceId;
|
||||
} m_configBools[19] = {
|
||||
{ NonLocalizable::ShiftDragID, &m_settings.shiftDrag, IDS_SETTING_DESCRIPTION_SHIFTDRAG },
|
||||
{ NonLocalizable::MouseSwitchID, &m_settings.mouseSwitch, IDS_SETTING_DESCRIPTION_MOUSESWITCH },
|
||||
{ NonLocalizable::OverrideSnapHotKeysID, &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS },
|
||||
{ NonLocalizable::MoveWindowAcrossMonitorsID, &m_settings.moveWindowAcrossMonitors, IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS },
|
||||
{ NonLocalizable::MoveWindowsBasedOnPositionID, &m_settings.moveWindowsBasedOnPosition, IDS_SETTING_DESCRIPTION_MOVE_WINDOWS_BASED_ON_POSITION },
|
||||
{ NonLocalizable::DisplayChangeMoveWindowsID, &m_settings.displayChange_moveWindows, IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS },
|
||||
{ NonLocalizable::ZoneSetChangeMoveWindowsID, &m_settings.zoneSetChange_moveWindows, IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS },
|
||||
{ NonLocalizable::AppLastZoneMoveWindowsID, &m_settings.appLastZone_moveWindows, IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS },
|
||||
{ NonLocalizable::OpenWindowOnActiveMonitorID, &m_settings.openWindowOnActiveMonitor, IDS_SETTING_DESCRIPTION_OPEN_WINDOW_ON_ACTIVE_MONITOR },
|
||||
{ NonLocalizable::RestoreSizeID, &m_settings.restoreSize, IDS_SETTING_DESCRIPTION_RESTORESIZE },
|
||||
{ NonLocalizable::QuickLayoutSwitch, &m_settings.quickLayoutSwitch, IDS_SETTING_DESCRIPTION_QUICKLAYOUTSWITCH },
|
||||
{ NonLocalizable::FlashZonesOnQuickSwitch, &m_settings.flashZonesOnQuickSwitch, IDS_SETTING_DESCRIPTION_FLASHZONESONQUICKSWITCH },
|
||||
{ NonLocalizable::UseCursorPosEditorStartupScreenID, &m_settings.use_cursorpos_editor_startupscreen, IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN },
|
||||
{ NonLocalizable::ShowOnAllMonitorsID, &m_settings.showZonesOnAllMonitors, IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS },
|
||||
{ NonLocalizable::SpanZonesAcrossMonitorsID, &m_settings.spanZonesAcrossMonitors, IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS },
|
||||
{ NonLocalizable::MakeDraggedWindowTransparentID, &m_settings.makeDraggedWindowTransparent, IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT },
|
||||
{ NonLocalizable::WindowSwitchingToggleID, &m_settings.windowSwitching, IDS_SETTING_WINDOW_SWITCHING_TOGGLE_LABEL },
|
||||
{ NonLocalizable::SystemThemeID, &m_settings.systemTheme, IDS_SETTING_DESCRIPTION_SYSTEM_THEME },
|
||||
{ NonLocalizable::ShowZoneNumberID, &m_settings.showZoneNumber, IDS_SETTING_DESCRIPTION_SHOW_ZONE_NUMBER },
|
||||
};
|
||||
};
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
FancyZonesSettings::GetConfig(_Out_ PWSTR buffer, _Out_ int* buffer_size) noexcept
|
||||
void FancyZonesSettings::SetBoolFlag(const PowerToysSettings::PowerToyValues& values, const wchar_t* id, SettingId notificationId, bool& out)
|
||||
{
|
||||
PowerToysSettings::Settings settings(m_hinstance, m_moduleName);
|
||||
|
||||
// Pass a string literal or a resource id to Settings::set_description().
|
||||
settings.set_description(IDS_SETTING_DESCRIPTION);
|
||||
settings.set_icon_key(NonLocalizable::IconKeyID);
|
||||
settings.set_overview_link(NonLocalizable::OverviewURL);
|
||||
settings.set_video_link(NonLocalizable::VideoURL);
|
||||
|
||||
// Add a custom action property. When using this settings type, the "PowertoyModuleIface::call_custom_action()"
|
||||
// method should be overridden as well.
|
||||
settings.add_custom_action(
|
||||
NonLocalizable::ToggleEditorActionID, // action name.
|
||||
IDS_SETTING_LAUNCH_EDITOR_LABEL,
|
||||
IDS_SETTING_LAUNCH_EDITOR_BUTTON,
|
||||
IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION);
|
||||
settings.add_hotkey(NonLocalizable::EditorHotkeyID, IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, m_settings.editorHotkey);
|
||||
settings.add_hotkey(NonLocalizable::NextTabHotkeyID, IDS_SETTING_NEXT_TAB_HOTKEY_LABEL, m_settings.nextTabHotkey);
|
||||
settings.add_hotkey(NonLocalizable::PrevTabHotkeyID, IDS_SETTING_PREV_TAB_HOTKEY_LABEL, m_settings.prevTabHotkey);
|
||||
|
||||
for (auto const& setting : m_configBools)
|
||||
if (const auto val = values.get_bool_value(id))
|
||||
{
|
||||
settings.add_bool_toggle(setting.name, setting.resourceId, *setting.value);
|
||||
if (out != *val)
|
||||
{
|
||||
out = *val;
|
||||
NotifyObservers(notificationId);
|
||||
}
|
||||
}
|
||||
|
||||
settings.add_color_picker(NonLocalizable::ZoneHighlightColorID, IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR, m_settings.zoneHighlightColor);
|
||||
settings.add_color_picker(NonLocalizable::ZoneColorID, IDS_SETTING_DESCRIPTION_ZONECOLOR, m_settings.zoneColor);
|
||||
settings.add_color_picker(NonLocalizable::ZoneBorderColorID, IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR, m_settings.zoneBorderColor);
|
||||
|
||||
settings.add_int_spinner(NonLocalizable::ZoneHighlightOpacityID, IDS_SETTINGS_HIGHLIGHT_OPACITY, m_settings.zoneHighlightOpacity, 0, 100, 1);
|
||||
|
||||
settings.add_multiline_string(NonLocalizable::ExcludedAppsID, IDS_SETTING_EXCLUDED_APPS_DESCRIPTION, m_settings.excludedApps);
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZonesSettings::SetConfig(PCWSTR serializedPowerToysSettingsJson) noexcept
|
||||
void FancyZonesSettings::LoadSettings()
|
||||
{
|
||||
LoadSettings(serializedPowerToysSettingsJson, false /*fromFile*/);
|
||||
SaveSettings();
|
||||
}
|
||||
_TRACER_;
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZonesSettings::ReloadSettings() noexcept
|
||||
{
|
||||
LoadSettings(m_moduleKey.c_str(), true /*fromFile*/);
|
||||
}
|
||||
|
||||
void FancyZonesSettings::LoadSettings(PCWSTR config, bool fromFile) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues values = fromFile ?
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(m_moduleKey) :
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, m_moduleKey);
|
||||
|
||||
for (auto const& setting : m_configBools)
|
||||
auto jsonOpt = json::from_file(GetSettingsFileName());
|
||||
if (!jsonOpt)
|
||||
{
|
||||
if (const auto val = values.get_bool_value(setting.name))
|
||||
{
|
||||
*setting.value = *val;
|
||||
}
|
||||
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);
|
||||
|
||||
// colors
|
||||
if (auto val = values.get_string_value(NonLocalizable::ZoneColorID))
|
||||
{
|
||||
m_settings.zoneColor = std::move(*val);
|
||||
if (m_settings.zoneColor != *val)
|
||||
{
|
||||
m_settings.zoneColor = std::move(*val);
|
||||
NotifyObservers(SettingId::ZoneColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto val = values.get_string_value(NonLocalizable::ZoneBorderColorID))
|
||||
{
|
||||
m_settings.zoneBorderColor = std::move(*val);
|
||||
if (m_settings.zoneBorderColor != *val)
|
||||
{
|
||||
m_settings.zoneBorderColor = std::move(*val);
|
||||
NotifyObservers(SettingId::ZoneBorderColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto val = values.get_string_value(NonLocalizable::ZoneHighlightColorID))
|
||||
{
|
||||
m_settings.zoneHighlightColor = std::move(*val);
|
||||
if (m_settings.zoneHighlightColor != *val)
|
||||
{
|
||||
m_settings.zoneHighlightColor = std::move(*val);
|
||||
NotifyObservers(SettingId::ZoneHighlightColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto val = values.get_string_value(NonLocalizable::ZoneNumberColorID))
|
||||
{
|
||||
m_settings.zoneNumberColor = std::move(*val);
|
||||
}
|
||||
|
||||
if (const auto val = values.get_json(NonLocalizable::EditorHotkeyID))
|
||||
{
|
||||
m_settings.editorHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
||||
}
|
||||
|
||||
if (const auto val = values.get_json(NonLocalizable::NextTabHotkeyID))
|
||||
{
|
||||
m_settings.nextTabHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
||||
}
|
||||
|
||||
if (const auto val = values.get_json(NonLocalizable::PrevTabHotkeyID))
|
||||
{
|
||||
m_settings.prevTabHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
||||
}
|
||||
|
||||
if (auto val = values.get_string_value(NonLocalizable::ExcludedAppsID))
|
||||
{
|
||||
m_settings.excludedApps = std::move(*val);
|
||||
m_settings.excludedAppsArray.clear();
|
||||
auto excludedUppercase = m_settings.excludedApps;
|
||||
CharUpperBuffW(excludedUppercase.data(), (DWORD)excludedUppercase.length());
|
||||
std::wstring_view view(excludedUppercase);
|
||||
while (view.starts_with('\n') || view.starts_with('\r'))
|
||||
if (m_settings.zoneNumberColor != *val)
|
||||
{
|
||||
view.remove_prefix(1);
|
||||
}
|
||||
while (!view.empty())
|
||||
{
|
||||
auto pos = (std::min)(view.find_first_of(L"\r\n"), view.length());
|
||||
m_settings.excludedAppsArray.emplace_back(view.substr(0, pos));
|
||||
view.remove_prefix(pos);
|
||||
while (view.starts_with('\n') || view.starts_with('\r'))
|
||||
{
|
||||
view.remove_prefix(1);
|
||||
}
|
||||
m_settings.zoneNumberColor = std::move(*val);
|
||||
NotifyObservers(SettingId::ZoneNumberColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto val = values.get_int_value(NonLocalizable::ZoneHighlightOpacityID))
|
||||
{
|
||||
m_settings.zoneHighlightOpacity = *val;
|
||||
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)
|
||||
{
|
||||
m_settings.overlappingZonesAlgorithm = (OverlappingZonesAlgorithm)*val;
|
||||
auto algorithm = (OverlappingZonesAlgorithm)*val;
|
||||
if (m_settings.overlappingZonesAlgorithm != algorithm)
|
||||
{
|
||||
m_settings.overlappingZonesAlgorithm = algorithm;
|
||||
NotifyObservers(SettingId::OverlappingZonesAlgorithm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
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(),
|
||||
@ -255,42 +256,13 @@ void FancyZonesSettings::LoadSettings(PCWSTR config, bool fromFile) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesSettings::SaveSettings() noexcept
|
||||
void FancyZonesSettings::NotifyObservers(SettingId id) const
|
||||
{
|
||||
try
|
||||
for (auto observer : m_observers)
|
||||
{
|
||||
PowerToysSettings::PowerToyValues values(m_moduleName, m_moduleKey);
|
||||
|
||||
for (auto const& setting : m_configBools)
|
||||
if (observer->WantsToBeNotified(id))
|
||||
{
|
||||
values.add_property(setting.name, *setting.value);
|
||||
observer->SettingsUpdate(id);
|
||||
}
|
||||
|
||||
values.add_property(NonLocalizable::ZoneColorID, m_settings.zoneColor);
|
||||
values.add_property(NonLocalizable::ZoneBorderColorID, m_settings.zoneBorderColor);
|
||||
values.add_property(NonLocalizable::ZoneHighlightColorID, m_settings.zoneHighlightColor);
|
||||
values.add_property(NonLocalizable::ZoneNumberColorID, m_settings.zoneNumberColor);
|
||||
values.add_property(NonLocalizable::ZoneHighlightOpacityID, m_settings.zoneHighlightOpacity);
|
||||
values.add_property(NonLocalizable::OverlappingZonesAlgorithmID, (int)m_settings.overlappingZonesAlgorithm);
|
||||
values.add_property(NonLocalizable::EditorHotkeyID, m_settings.editorHotkey.get_json());
|
||||
values.add_property(NonLocalizable::NextTabHotkeyID, m_settings.nextTabHotkey.get_json());
|
||||
values.add_property(NonLocalizable::PrevTabHotkeyID, m_settings.prevTabHotkey.get_json());
|
||||
values.add_property(NonLocalizable::ExcludedAppsID, m_settings.excludedApps);
|
||||
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Failure to save settings does not break FancyZones functionality. Display error message and continue with currently cached settings.
|
||||
std::wstring errorMessage = GET_RESOURCE_STRING(IDS_FANCYZONES_SETTINGS_LOAD_ERROR) + L" " + NonLocalizable::PowerToysIssuesURL;
|
||||
MessageBox(NULL,
|
||||
errorMessage.c_str(),
|
||||
GET_RESOURCE_STRING(IDS_POWERTOYS_FANCYZONES).c_str(),
|
||||
MB_OK);
|
||||
}
|
||||
}
|
||||
|
||||
winrt::com_ptr<IFancyZonesSettings> MakeFancyZonesSettings(HINSTANCE hinstance, PCWSTR name, PCWSTR key) noexcept
|
||||
{
|
||||
return winrt::make_self<FancyZonesSettings>(hinstance, name, key);
|
||||
}
|
||||
|
@ -1,7 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
|
||||
#include <FancyZonesLib/ModuleConstants.h>
|
||||
#include <FancyZonesLib/SettingsConstants.h>
|
||||
|
||||
class SettingsObserver;
|
||||
class FileWatcher;
|
||||
|
||||
enum struct OverlappingZonesAlgorithm : int
|
||||
{
|
||||
Smallest = 0,
|
||||
@ -34,6 +43,8 @@ struct Settings
|
||||
bool makeDraggedWindowTransparent = true;
|
||||
bool systemTheme = true;
|
||||
bool showZoneNumber = true;
|
||||
bool allowSnapPopupWindows = false;
|
||||
bool allowSnapChildWindows = false;
|
||||
std::wstring zoneColor = L"#AACDFF";
|
||||
std::wstring zoneBorderColor = L"#FFFFFF";
|
||||
std::wstring zoneHighlightColor = L"#008CFF";
|
||||
@ -48,12 +59,38 @@ struct Settings
|
||||
std::vector<std::wstring> excludedAppsArray;
|
||||
};
|
||||
|
||||
interface __declspec(uuid("{BA4E77C4-6F44-4C5D-93D3-CBDE880495C2}")) IFancyZonesSettings : public IUnknown
|
||||
class FancyZonesSettings
|
||||
{
|
||||
IFACEMETHOD_(bool, GetConfig)(_Out_ PWSTR buffer, _Out_ int *buffer_size) = 0;
|
||||
IFACEMETHOD_(void, SetConfig)(PCWSTR serializedPowerToysSettings) = 0;
|
||||
IFACEMETHOD_(void, ReloadSettings)() = 0;
|
||||
IFACEMETHOD_(const Settings*, GetSettings)() const = 0;
|
||||
};
|
||||
public:
|
||||
static FancyZonesSettings& instance();
|
||||
static inline const Settings& settings()
|
||||
{
|
||||
return instance().m_settings;
|
||||
}
|
||||
|
||||
winrt::com_ptr<IFancyZonesSettings> MakeFancyZonesSettings(HINSTANCE hinstance, PCWSTR name, PCWSTR key) noexcept;
|
||||
inline static std::wstring GetSettingsFileName()
|
||||
{
|
||||
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
|
||||
#if defined(UNIT_TESTS)
|
||||
return saveFolderPath + L"\\test-settings.json";
|
||||
#endif
|
||||
return saveFolderPath + L"\\settings.json";
|
||||
}
|
||||
|
||||
void AddObserver(SettingsObserver& observer);
|
||||
void RemoveObserver(SettingsObserver& observer);
|
||||
|
||||
void LoadSettings();
|
||||
|
||||
private:
|
||||
FancyZonesSettings();
|
||||
~FancyZonesSettings() = default;
|
||||
|
||||
Settings m_settings;
|
||||
std::unique_ptr<FileWatcher> m_settingsFileWatcher;
|
||||
std::unordered_set<SettingsObserver*> m_observers;
|
||||
|
||||
void SetBoolFlag(const PowerToysSettings::PowerToyValues& values, const wchar_t* id, SettingId notificationId, bool& out);
|
||||
|
||||
void NotifyObservers(SettingId id) const;
|
||||
};
|
||||
|
36
src/modules/fancyzones/FancyZonesLib/SettingsConstants.h
Normal file
36
src/modules/fancyzones/FancyZonesLib/SettingsConstants.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
enum class SettingId
|
||||
{
|
||||
ShiftDrag = 0,
|
||||
MouseSwitch,
|
||||
OverrideSnapHotkeys,
|
||||
MoveWindowAcrossMonitors,
|
||||
MoveWindowsBasedOnPosition,
|
||||
OverlappingZonesAlgorithm,
|
||||
DisplayChangeMoveWindows,
|
||||
ZoneSetChangeMoveWindows,
|
||||
AppLastZoneMoveWindows,
|
||||
OpenWindowOnActiveMonitor,
|
||||
RestoreWindowSize,
|
||||
QuickLayoutSwitch,
|
||||
FlashZonesOnQuickSwitch,
|
||||
LaunchEditorOnScreenWhereCursorPlaced,
|
||||
ShowOnAllMonitors,
|
||||
SpanZonesAcrossMonitors,
|
||||
MakeDraggedWindowsTransparent,
|
||||
ZoneHighlightColor,
|
||||
ZoneHighlightOpacity,
|
||||
ZoneBorderColor,
|
||||
ZoneColor,
|
||||
ZoneNumberColor,
|
||||
SystemTheme,
|
||||
ShowZoneNumber,
|
||||
EditorHotkey,
|
||||
WindowSwitching,
|
||||
NextTabHotkey,
|
||||
PrevTabHotkey,
|
||||
ExcludedApps,
|
||||
AllowSnapPopupWindows,
|
||||
AllowSnapChildWindows,
|
||||
};
|
31
src/modules/fancyzones/FancyZonesLib/SettingsObserver.h
Normal file
31
src/modules/fancyzones/FancyZonesLib/SettingsObserver.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <FancyZonesLib/Settings.h>
|
||||
#include <FancyZonesLib/SettingsConstants.h>
|
||||
|
||||
class SettingsObserver
|
||||
{
|
||||
public:
|
||||
SettingsObserver(std::unordered_set<SettingId> observedSettings) :
|
||||
m_observedSettings(std::move(observedSettings))
|
||||
{
|
||||
FancyZonesSettings::instance().AddObserver(*this);
|
||||
}
|
||||
|
||||
virtual ~SettingsObserver()
|
||||
{
|
||||
FancyZonesSettings::instance().RemoveObserver(*this);
|
||||
}
|
||||
|
||||
virtual void SettingsUpdate(SettingId type) {}
|
||||
|
||||
bool WantsToBeNotified(SettingId type) const noexcept
|
||||
{
|
||||
return m_observedSettings.contains(type);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unordered_set<SettingId> m_observedSettings;
|
||||
};
|
@ -10,7 +10,7 @@
|
||||
#include "FancyZonesData/AppZoneHistory.h"
|
||||
#include "Settings.h"
|
||||
#include "WorkArea.h"
|
||||
#include "util.h"
|
||||
#include <FancyZonesLib/WindowUtils.h>
|
||||
|
||||
// Non-Localizable strings
|
||||
namespace NonLocalizable
|
||||
@ -49,8 +49,7 @@ namespace WindowMoveHandlerUtils
|
||||
}
|
||||
}
|
||||
|
||||
WindowMoveHandler::WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>& settings, const std::function<void()>& keyUpdateCallback) :
|
||||
m_settings(settings),
|
||||
WindowMoveHandler::WindowMoveHandler(const std::function<void()>& keyUpdateCallback) :
|
||||
m_mouseState(false),
|
||||
m_mouseHook(std::bind(&WindowMoveHandler::OnMouseDown, this)),
|
||||
m_shiftKeyState(keyUpdateCallback),
|
||||
@ -61,13 +60,13 @@ WindowMoveHandler::WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>&
|
||||
|
||||
void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& workAreaMap) noexcept
|
||||
{
|
||||
if (!FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray) || WindowMoveHandlerUtils::IsCursorTypeIndicatingSizeEvent())
|
||||
if (!FancyZonesWindowUtils::IsCandidateForZoning(window) || WindowMoveHandlerUtils::IsCursorTypeIndicatingSizeEvent())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_draggedWindowInfo.hasNoVisibleOwner = FancyZonesUtils::HasNoVisibleOwner(window);
|
||||
m_draggedWindowInfo.isStandardWindow = FancyZonesUtils::IsStandardWindow(window);
|
||||
m_draggedWindowInfo.hasNoVisibleOwner = !FancyZonesWindowUtils::HasVisibleOwner(window);
|
||||
m_draggedWindowInfo.isStandardWindow = FancyZonesWindowUtils::IsStandardWindow(window) && (!FancyZonesWindowUtils::IsPopupWindow(window) || FancyZonesSettings::settings().allowSnapPopupWindows);
|
||||
m_inDragging = true;
|
||||
|
||||
auto iter = workAreaMap.find(monitor);
|
||||
@ -78,7 +77,7 @@ void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const
|
||||
|
||||
m_draggedWindow = window;
|
||||
|
||||
if (m_settings->GetSettings()->mouseSwitch)
|
||||
if (FancyZonesSettings::settings().mouseSwitch)
|
||||
{
|
||||
m_mouseHook.enable();
|
||||
}
|
||||
@ -97,7 +96,7 @@ void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const
|
||||
m_draggedWindowWorkArea = iter->second;
|
||||
SetWindowTransparency(m_draggedWindow);
|
||||
m_draggedWindowWorkArea->MoveSizeEnter(m_draggedWindow);
|
||||
if (m_settings->GetSettings()->showZonesOnAllMonitors)
|
||||
if (FancyZonesSettings::settings().showZonesOnAllMonitors)
|
||||
{
|
||||
for (auto [keyMonitor, workArea] : workAreaMap)
|
||||
{
|
||||
@ -172,7 +171,7 @@ void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen,
|
||||
{
|
||||
// The drag has moved to a different monitor.
|
||||
m_draggedWindowWorkArea->ClearSelectedZones();
|
||||
if (!m_settings->GetSettings()->showZonesOnAllMonitors)
|
||||
if (!FancyZonesSettings::settings().showZonesOnAllMonitors)
|
||||
{
|
||||
m_draggedWindowWorkArea->HideZonesOverlay();
|
||||
}
|
||||
@ -219,12 +218,12 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st
|
||||
auto workArea = std::move(m_draggedWindowWorkArea);
|
||||
ResetWindowTransparency();
|
||||
|
||||
bool hasNoVisibleOwner = FancyZonesUtils::HasNoVisibleOwner(window);
|
||||
bool isStandardWindow = FancyZonesUtils::IsStandardWindow(window);
|
||||
bool hasNoVisibleOwner = !FancyZonesWindowUtils::HasVisibleOwner(window);
|
||||
bool isStandardWindow = FancyZonesWindowUtils::IsStandardWindow(window);
|
||||
|
||||
if ((isStandardWindow == false && hasNoVisibleOwner == true &&
|
||||
m_draggedWindowInfo.isStandardWindow == true && m_draggedWindowInfo.hasNoVisibleOwner == true) ||
|
||||
FancyZonesUtils::IsWindowMaximized(window))
|
||||
FancyZonesWindowUtils::IsWindowMaximized(window))
|
||||
{
|
||||
// Abort the zoning, this is a Chromium based tab that is merged back with an existing window
|
||||
// or if the window is maximized by Windows when the cursor hits the screen top border
|
||||
@ -236,15 +235,15 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_settings->GetSettings()->restoreSize)
|
||||
if (FancyZonesSettings::settings().restoreSize)
|
||||
{
|
||||
if (WindowMoveHandlerUtils::IsCursorTypeIndicatingSizeEvent())
|
||||
{
|
||||
::RemoveProp(window, ZonedWindowProperties::PropertyRestoreSizeID);
|
||||
}
|
||||
else if (!FancyZonesUtils::IsWindowMaximized(window))
|
||||
else if (!FancyZonesWindowUtils::IsWindowMaximized(window))
|
||||
{
|
||||
FancyZonesUtils::RestoreWindowSize(window);
|
||||
FancyZonesWindowUtils::RestoreWindowSize(window);
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,10 +311,9 @@ void WindowMoveHandler::WarnIfElevationIsRequired(HWND window) noexcept
|
||||
{
|
||||
using namespace notifications;
|
||||
using namespace NonLocalizable;
|
||||
using namespace FancyZonesUtils;
|
||||
|
||||
static bool warning_shown = false;
|
||||
if (!is_process_elevated() && IsProcessOfWindowElevated(window))
|
||||
if (!is_process_elevated() && FancyZonesWindowUtils::IsProcessOfWindowElevated(window))
|
||||
{
|
||||
m_dragEnabled = false;
|
||||
if (!warning_shown && !is_toast_disabled(CantDragElevatedDontShowAgainRegistryPath, CantDragElevatedDisableIntervalInDays))
|
||||
@ -335,7 +333,7 @@ void WindowMoveHandler::WarnIfElevationIsRequired(HWND window) noexcept
|
||||
|
||||
void WindowMoveHandler::UpdateDragState() noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->shiftDrag)
|
||||
if (FancyZonesSettings::settings().shiftDrag)
|
||||
{
|
||||
m_dragEnabled = (m_shiftKeyState.state() ^ m_mouseState);
|
||||
}
|
||||
@ -347,7 +345,7 @@ void WindowMoveHandler::UpdateDragState() noexcept
|
||||
|
||||
void WindowMoveHandler::SetWindowTransparency(HWND window) noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->makeDraggedWindowTransparent)
|
||||
if (FancyZonesSettings::settings().makeDraggedWindowTransparent)
|
||||
{
|
||||
m_windowTransparencyProperties.draggedWindowExstyle = GetWindowLong(window, GWL_EXSTYLE);
|
||||
|
||||
@ -364,7 +362,7 @@ void WindowMoveHandler::SetWindowTransparency(HWND window) noexcept
|
||||
|
||||
void WindowMoveHandler::ResetWindowTransparency() noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->makeDraggedWindowTransparent && m_windowTransparencyProperties.draggedWindow != nullptr)
|
||||
if (FancyZonesSettings::settings().makeDraggedWindowTransparent && m_windowTransparencyProperties.draggedWindow != nullptr)
|
||||
{
|
||||
SetLayeredWindowAttributes(m_windowTransparencyProperties.draggedWindow, m_windowTransparencyProperties.draggedWindowCrKey, m_windowTransparencyProperties.draggedWindowInitialAlpha, m_windowTransparencyProperties.draggedWindowDwFlags);
|
||||
SetWindowLong(m_windowTransparencyProperties.draggedWindow, GWL_EXSTYLE, m_windowTransparencyProperties.draggedWindowExstyle);
|
||||
|
@ -12,7 +12,7 @@ interface IWorkArea;
|
||||
class WindowMoveHandler
|
||||
{
|
||||
public:
|
||||
WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>& settings, const std::function<void()>& keyUpdateCallback);
|
||||
WindowMoveHandler(const std::function<void()>& keyUpdateCallback);
|
||||
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& workAreaMap) noexcept;
|
||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& workAreaMap) noexcept;
|
||||
@ -64,8 +64,6 @@ private:
|
||||
void SetWindowTransparency(HWND window) noexcept;
|
||||
void ResetWindowTransparency() noexcept;
|
||||
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings{};
|
||||
|
||||
bool m_inDragging{}; // Whether or not a move/size operation is currently active
|
||||
HWND m_draggedWindow{}; // The window that is being moved/sized
|
||||
MoveSizeWindowInfo m_draggedWindowInfo; // MoveSizeWindowInfo of the window at the moment when dragging started
|
||||
|
448
src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp
Normal file
448
src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp
Normal file
@ -0,0 +1,448 @@
|
||||
#include "pch.h"
|
||||
#include "WindowUtils.h"
|
||||
|
||||
#include <common/display/dpi_aware.h>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/window.h>
|
||||
#include <common/utils/excluded_apps.h>
|
||||
|
||||
#include <FancyZonesLib/FancyZonesWindowProperties.h>
|
||||
#include <FancyZonesLib/Settings.h>
|
||||
|
||||
// Non-Localizable strings
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t PowerToysAppFZEditor[] = L"POWERTOYS.FANCYZONESEDITOR.EXE";
|
||||
const wchar_t SplashClassName[] = L"MsoSplash";
|
||||
const wchar_t CoreWindow[] = L"Windows.UI.Core.CoreWindow";
|
||||
const wchar_t SearchUI[] = L"SearchUI.exe";
|
||||
const wchar_t SystemAppsFolder[] = L"SYSTEMAPPS";
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
BOOL CALLBACK saveDisplayToVector(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
|
||||
{
|
||||
reinterpret_cast<std::vector<HMONITOR>*>(data)->emplace_back(monitor);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool allMonitorsHaveSameDpiScaling()
|
||||
{
|
||||
std::vector<HMONITOR> monitors;
|
||||
EnumDisplayMonitors(NULL, NULL, saveDisplayToVector, reinterpret_cast<LPARAM>(&monitors));
|
||||
|
||||
if (monitors.size() < 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
UINT firstMonitorDpiX;
|
||||
UINT firstMonitorDpiY;
|
||||
|
||||
if (S_OK != GetDpiForMonitor(monitors[0], MDT_EFFECTIVE_DPI, &firstMonitorDpiX, &firstMonitorDpiY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 1; i < monitors.size(); i++)
|
||||
{
|
||||
UINT iteratedMonitorDpiX;
|
||||
UINT iteratedMonitorDpiY;
|
||||
|
||||
if (S_OK != GetDpiForMonitor(monitors[i], MDT_EFFECTIVE_DPI, &iteratedMonitorDpiX, &iteratedMonitorDpiY) ||
|
||||
iteratedMonitorDpiX != firstMonitorDpiX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScreenToWorkAreaCoords(HWND window, RECT& rect)
|
||||
{
|
||||
// First, find the correct monitor. The monitor cannot be found using the given rect itself, we must first
|
||||
// translate it to relative workspace coordinates.
|
||||
HMONITOR monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFOEXW monitorInfo{ sizeof(MONITORINFOEXW) };
|
||||
GetMonitorInfoW(monitor, &monitorInfo);
|
||||
|
||||
auto xOffset = monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;
|
||||
auto yOffset = monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;
|
||||
|
||||
auto referenceRect = rect;
|
||||
|
||||
referenceRect.left -= xOffset;
|
||||
referenceRect.right -= xOffset;
|
||||
referenceRect.top -= yOffset;
|
||||
referenceRect.bottom -= yOffset;
|
||||
|
||||
// Now, this rect should be used to determine the monitor and thus taskbar size. This fixes
|
||||
// scenarios where the zone lies approximately between two monitors, and the taskbar is on the left.
|
||||
monitor = MonitorFromRect(&referenceRect, MONITOR_DEFAULTTOPRIMARY);
|
||||
GetMonitorInfoW(monitor, &monitorInfo);
|
||||
|
||||
xOffset = monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;
|
||||
yOffset = monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;
|
||||
|
||||
rect.left -= xOffset;
|
||||
rect.right -= xOffset;
|
||||
rect.top -= yOffset;
|
||||
rect.bottom -= yOffset;
|
||||
|
||||
const auto level = DPIAware::GetAwarenessLevel(GetWindowDpiAwarenessContext(window));
|
||||
const bool accountForUnawareness = level < DPIAware::PER_MONITOR_AWARE;
|
||||
|
||||
if (accountForUnawareness && !allMonitorsHaveSameDpiScaling())
|
||||
{
|
||||
rect.left = max(monitorInfo.rcMonitor.left, rect.left);
|
||||
rect.right = min(monitorInfo.rcMonitor.right - xOffset, rect.right);
|
||||
rect.top = max(monitorInfo.rcMonitor.top, rect.top);
|
||||
rect.bottom = min(monitorInfo.rcMonitor.bottom - yOffset, rect.bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FancyZonesWindowUtils::IsSplashScreen(HWND window)
|
||||
{
|
||||
wchar_t className[MAX_PATH];
|
||||
if (GetClassName(window, className, MAX_PATH) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return wcscmp(NonLocalizable::SplashClassName, className) == 0;
|
||||
}
|
||||
|
||||
bool FancyZonesWindowUtils::IsWindowMaximized(HWND window) noexcept
|
||||
{
|
||||
WINDOWPLACEMENT placement{};
|
||||
if (GetWindowPlacement(window, &placement) &&
|
||||
placement.showCmd == SW_SHOWMAXIMIZED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FancyZonesWindowUtils::HasVisibleOwner(HWND window) noexcept
|
||||
{
|
||||
auto owner = GetWindow(window, GW_OWNER);
|
||||
if (owner == nullptr)
|
||||
{
|
||||
return false; // There is no owner at all
|
||||
}
|
||||
if (!IsWindowVisible(owner))
|
||||
{
|
||||
return false; // Owner is invisible
|
||||
}
|
||||
RECT rect;
|
||||
if (!GetWindowRect(owner, &rect))
|
||||
{
|
||||
return true; // Could not get the rect, return true (and filter out the window) just in case
|
||||
}
|
||||
// It is enough that the window is zero-sized in one dimension only.
|
||||
return rect.top != rect.bottom && rect.left != rect.right;
|
||||
}
|
||||
|
||||
bool FancyZonesWindowUtils::IsStandardWindow(HWND window)
|
||||
{
|
||||
if (GetAncestor(window, GA_ROOT) != window)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto style = GetWindowLong(window, GWL_STYLE);
|
||||
auto exStyle = GetWindowLong(window, GWL_EXSTYLE);
|
||||
|
||||
bool isToolWindow = (exStyle & WS_EX_TOOLWINDOW) == WS_EX_TOOLWINDOW;
|
||||
bool isVisible = (style & WS_VISIBLE) == WS_VISIBLE;
|
||||
if (isToolWindow || !isVisible)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::array<char, 256> class_name;
|
||||
GetClassNameA(window, class_name.data(), static_cast<int>(class_name.size()));
|
||||
if (is_system_window(window, class_name.data()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FancyZonesWindowUtils::IsPopupWindow(HWND window) noexcept
|
||||
{
|
||||
auto style = GetWindowLong(window, GWL_STYLE);
|
||||
return ((style & WS_POPUP) == WS_POPUP);
|
||||
}
|
||||
|
||||
bool FancyZonesWindowUtils::HasThickFrameAndMinimizeMaximizeButtons(HWND window) noexcept
|
||||
{
|
||||
auto style = GetWindowLong(window, GWL_STYLE);
|
||||
return ((style & WS_THICKFRAME) == WS_THICKFRAME
|
||||
&& (style & WS_MINIMIZEBOX) == WS_MINIMIZEBOX
|
||||
&& (style & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX);
|
||||
}
|
||||
|
||||
bool FancyZonesWindowUtils::IsCandidateForZoning(HWND window)
|
||||
{
|
||||
bool isStandard = IsStandardWindow(window);
|
||||
if (!isStandard)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// popup could be the window we don't want to snap: start menu, notification popup, tray window, etc.
|
||||
// also, popup could be the windows we want to snap disregarding the "allowSnapPopupWindows" setting, e.g. Telegram
|
||||
bool isPopup = IsPopupWindow(window);
|
||||
if (isPopup && !HasThickFrameAndMinimizeMaximizeButtons(window) && !FancyZonesSettings::settings().allowSnapPopupWindows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// allow child windows
|
||||
auto hasOwner = HasVisibleOwner(window);
|
||||
if (hasOwner && !FancyZonesSettings::settings().allowSnapChildWindows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring processPath = get_process_path(window);
|
||||
CharUpperBuffW(const_cast<std::wstring&>(processPath).data(), (DWORD)processPath.length());
|
||||
if (IsExcludedByUser(processPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsExcludedByDefault(processPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FancyZonesWindowUtils::IsProcessOfWindowElevated(HWND window)
|
||||
{
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(window, &pid);
|
||||
if (!pid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wil::unique_handle hProcess{ OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
|
||||
FALSE,
|
||||
pid) };
|
||||
|
||||
wil::unique_handle token;
|
||||
bool elevated = false;
|
||||
|
||||
if (OpenProcessToken(hProcess.get(), TOKEN_QUERY, &token))
|
||||
{
|
||||
TOKEN_ELEVATION elevation;
|
||||
DWORD size;
|
||||
if (GetTokenInformation(token.get(), TokenElevation, &elevation, sizeof(elevation), &size))
|
||||
{
|
||||
return elevation.TokenIsElevated != 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FancyZonesWindowUtils::IsExcludedByUser(const std::wstring& processPath) noexcept
|
||||
{
|
||||
return (find_app_name_in_path(processPath, FancyZonesSettings::settings().excludedAppsArray));
|
||||
}
|
||||
|
||||
bool FancyZonesWindowUtils::IsExcludedByDefault(const std::wstring& processPath) noexcept
|
||||
{
|
||||
static std::vector<std::wstring> defaultExcludedFolders = { NonLocalizable::SystemAppsFolder };
|
||||
if (find_folder_in_path(processPath, defaultExcludedFolders))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<std::wstring> defaultExcludedApps = { NonLocalizable::PowerToysAppFZEditor, NonLocalizable::CoreWindow, NonLocalizable::SearchUI };
|
||||
return (find_app_name_in_path(processPath, defaultExcludedApps));
|
||||
}
|
||||
|
||||
void FancyZonesWindowUtils::SwitchToWindow(HWND window) noexcept
|
||||
{
|
||||
// Check if the window is minimized
|
||||
if (IsIconic(window))
|
||||
{
|
||||
// Show the window since SetForegroundWindow fails on minimized windows
|
||||
ShowWindow(window, SW_RESTORE);
|
||||
}
|
||||
|
||||
// This is a hack to bypass the restriction on setting the foreground window
|
||||
INPUT inputs[1] = { { .type = INPUT_MOUSE } };
|
||||
SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
|
||||
|
||||
SetForegroundWindow(window);
|
||||
}
|
||||
|
||||
void FancyZonesWindowUtils::SizeWindowToRect(HWND window, RECT rect) noexcept
|
||||
{
|
||||
WINDOWPLACEMENT placement{};
|
||||
::GetWindowPlacement(window, &placement);
|
||||
|
||||
// Wait if SW_SHOWMINIMIZED would be removed from window (Issue #1685)
|
||||
for (int i = 0; i < 5 && (placement.showCmd == SW_SHOWMINIMIZED); ++i)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
::GetWindowPlacement(window, &placement);
|
||||
}
|
||||
|
||||
// Do not restore minimized windows. We change their placement though so they restore to the correct zone.
|
||||
if ((placement.showCmd != SW_SHOWMINIMIZED) &&
|
||||
(placement.showCmd != SW_MINIMIZE))
|
||||
{
|
||||
placement.showCmd = SW_RESTORE;
|
||||
}
|
||||
|
||||
// Remove maximized show command to make sure window is moved to the correct zone.
|
||||
if (placement.showCmd == SW_SHOWMAXIMIZED)
|
||||
{
|
||||
placement.showCmd = SW_RESTORE;
|
||||
placement.flags &= ~WPF_RESTORETOMAXIMIZED;
|
||||
}
|
||||
|
||||
ScreenToWorkAreaCoords(window, rect);
|
||||
|
||||
placement.rcNormalPosition = rect;
|
||||
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
|
||||
|
||||
::SetWindowPlacement(window, &placement);
|
||||
// Do it again, allowing Windows to resize the window and set correct scaling
|
||||
// This fixes Issue #365
|
||||
::SetWindowPlacement(window, &placement);
|
||||
}
|
||||
|
||||
void FancyZonesWindowUtils::SaveWindowSizeAndOrigin(HWND window) noexcept
|
||||
{
|
||||
HANDLE handle = GetPropW(window, ZonedWindowProperties::PropertyRestoreSizeID);
|
||||
if (handle)
|
||||
{
|
||||
// Size already set, skip
|
||||
return;
|
||||
}
|
||||
|
||||
RECT rect;
|
||||
if (GetWindowRect(window, &rect))
|
||||
{
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
int originX = rect.left;
|
||||
int originY = rect.top;
|
||||
|
||||
DPIAware::InverseConvert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), width, height);
|
||||
DPIAware::InverseConvert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), originX, originY);
|
||||
|
||||
std::array<int, 2> windowSizeData = { width, height };
|
||||
std::array<int, 2> windowOriginData = { originX, originY };
|
||||
HANDLE rawData;
|
||||
memcpy(&rawData, windowSizeData.data(), sizeof rawData);
|
||||
SetPropW(window, ZonedWindowProperties::PropertyRestoreSizeID, rawData);
|
||||
memcpy(&rawData, windowOriginData.data(), sizeof rawData);
|
||||
SetPropW(window, ZonedWindowProperties::PropertyRestoreOriginID, rawData);
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesWindowUtils::RestoreWindowSize(HWND window) noexcept
|
||||
{
|
||||
auto windowSizeData = GetPropW(window, ZonedWindowProperties::PropertyRestoreSizeID);
|
||||
if (windowSizeData)
|
||||
{
|
||||
std::array<int, 2> windowSize;
|
||||
memcpy(windowSize.data(), &windowSizeData, sizeof windowSize);
|
||||
|
||||
// {width, height}
|
||||
DPIAware::Convert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), windowSize[0], windowSize[1]);
|
||||
|
||||
RECT rect;
|
||||
if (GetWindowRect(window, &rect))
|
||||
{
|
||||
rect.right = rect.left + windowSize[0];
|
||||
rect.bottom = rect.top + windowSize[1];
|
||||
SizeWindowToRect(window, rect);
|
||||
}
|
||||
|
||||
::RemoveProp(window, ZonedWindowProperties::PropertyRestoreSizeID);
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesWindowUtils::RestoreWindowOrigin(HWND window) noexcept
|
||||
{
|
||||
auto windowOriginData = GetPropW(window, ZonedWindowProperties::PropertyRestoreOriginID);
|
||||
if (windowOriginData)
|
||||
{
|
||||
std::array<int, 2> windowOrigin;
|
||||
memcpy(windowOrigin.data(), &windowOriginData, sizeof windowOrigin);
|
||||
|
||||
// {width, height}
|
||||
DPIAware::Convert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), windowOrigin[0], windowOrigin[1]);
|
||||
|
||||
RECT rect;
|
||||
if (GetWindowRect(window, &rect))
|
||||
{
|
||||
int xOffset = windowOrigin[0] - rect.left;
|
||||
int yOffset = windowOrigin[1] - rect.top;
|
||||
|
||||
rect.left += xOffset;
|
||||
rect.right += xOffset;
|
||||
rect.top += yOffset;
|
||||
rect.bottom += yOffset;
|
||||
SizeWindowToRect(window, rect);
|
||||
}
|
||||
|
||||
::RemoveProp(window, ZonedWindowProperties::PropertyRestoreOriginID);
|
||||
}
|
||||
}
|
||||
|
||||
RECT FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(HWND window, RECT rect, HWND windowOfRect) noexcept
|
||||
{
|
||||
RECT newWindowRect = rect;
|
||||
|
||||
RECT windowRect{};
|
||||
::GetWindowRect(window, &windowRect);
|
||||
|
||||
// Take care of borders
|
||||
RECT frameRect{};
|
||||
if (SUCCEEDED(DwmGetWindowAttribute(window, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRect, sizeof(frameRect))))
|
||||
{
|
||||
LONG leftMargin = frameRect.left - windowRect.left;
|
||||
LONG rightMargin = frameRect.right - windowRect.right;
|
||||
LONG bottomMargin = frameRect.bottom - windowRect.bottom;
|
||||
newWindowRect.left -= leftMargin;
|
||||
newWindowRect.right -= rightMargin;
|
||||
newWindowRect.bottom -= bottomMargin;
|
||||
}
|
||||
|
||||
// Take care of windows that cannot be resized
|
||||
if ((::GetWindowLong(window, GWL_STYLE) & WS_SIZEBOX) == 0)
|
||||
{
|
||||
newWindowRect.right = newWindowRect.left + (windowRect.right - windowRect.left);
|
||||
newWindowRect.bottom = newWindowRect.top + (windowRect.bottom - windowRect.top);
|
||||
}
|
||||
|
||||
// Convert to screen coordinates
|
||||
MapWindowRect(windowOfRect, nullptr, &newWindowRect);
|
||||
|
||||
return newWindowRect;
|
||||
}
|
||||
|
||||
void FancyZonesWindowUtils::MakeWindowTransparent(HWND window)
|
||||
{
|
||||
int const pos = -GetSystemMetrics(SM_CXVIRTUALSCREEN) - 8;
|
||||
if (wil::unique_hrgn hrgn{ CreateRectRgn(pos, 0, (pos + 1), 1) })
|
||||
{
|
||||
DWM_BLURBEHIND bh = { DWM_BB_ENABLE | DWM_BB_BLURREGION, TRUE, hrgn.get(), FALSE };
|
||||
DwmEnableBlurBehindWindow(window, &bh);
|
||||
}
|
||||
}
|
30
src/modules/fancyzones/FancyZonesLib/WindowUtils.h
Normal file
30
src/modules/fancyzones/FancyZonesLib/WindowUtils.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "gdiplus.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace FancyZonesWindowUtils
|
||||
{
|
||||
bool IsSplashScreen(HWND window);
|
||||
bool IsWindowMaximized(HWND window) noexcept;
|
||||
bool HasVisibleOwner(HWND window) noexcept;
|
||||
bool IsStandardWindow(HWND window);
|
||||
bool IsPopupWindow(HWND window) noexcept;
|
||||
bool HasThickFrameAndMinimizeMaximizeButtons(HWND window) noexcept;
|
||||
bool IsCandidateForZoning(HWND window);
|
||||
bool IsProcessOfWindowElevated(HWND window); // If HWND is already dead, we assume it wasn't elevated
|
||||
bool IsExcludedByUser(const std::wstring& processPath) noexcept;
|
||||
bool IsExcludedByDefault(const std::wstring& processPath) noexcept;
|
||||
|
||||
void SwitchToWindow(HWND window) noexcept;
|
||||
void SizeWindowToRect(HWND window, RECT rect) noexcept; // Parameter rect must be in screen coordinates (e.g. obtained from GetWindowRect)
|
||||
void SaveWindowSizeAndOrigin(HWND window) noexcept;
|
||||
void RestoreWindowSize(HWND window) noexcept;
|
||||
void RestoreWindowOrigin(HWND window) noexcept;
|
||||
void MakeWindowTransparent(HWND window);
|
||||
RECT AdjustRectForSizeWindowToRect(HWND window, RECT rect, HWND windowOfRect) noexcept; // Parameter rect is in windowOfRect coordinates
|
||||
}
|
@ -7,11 +7,12 @@
|
||||
#include "FancyZonesData/AppliedLayouts.h"
|
||||
#include "FancyZonesData/AppZoneHistory.h"
|
||||
#include "FancyZonesDataTypes.h"
|
||||
#include "SettingsObserver.h"
|
||||
#include "ZonesOverlay.h"
|
||||
#include "trace.h"
|
||||
#include "util.h"
|
||||
#include "on_thread_executor.h"
|
||||
#include "Settings.h"
|
||||
#include <FancyZonesLib/WindowUtils.h>
|
||||
|
||||
#include <ShellScalingApi.h>
|
||||
#include <mutex>
|
||||
@ -65,7 +66,7 @@ namespace
|
||||
{
|
||||
HWND window = CreateWindowExW(WS_EX_TOOLWINDOW, NonLocalizable::ToolWindowClassName, L"", WS_POPUP, position.left(), position.top(), position.width(), position.height(), nullptr, nullptr, hinstance, owner);
|
||||
Logger::info("Creating new ZonesOverlay window, hWnd = {}", (void*)window);
|
||||
MakeWindowTransparent(window);
|
||||
FancyZonesWindowUtils::MakeWindowTransparent(window);
|
||||
|
||||
// According to ShowWindow docs, we must call it with SW_SHOWNORMAL the first time
|
||||
ShowWindow(window, SW_SHOWNORMAL);
|
||||
@ -110,7 +111,7 @@ public:
|
||||
WorkArea(HINSTANCE hinstance);
|
||||
~WorkArea();
|
||||
|
||||
bool Init(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm, const bool showZoneText);
|
||||
bool Init(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId);
|
||||
|
||||
IFACEMETHODIMP MoveSizeEnter(HWND window) noexcept;
|
||||
IFACEMETHODIMP MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) noexcept;
|
||||
@ -145,10 +146,6 @@ public:
|
||||
ClearSelectedZones() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
FlashZones() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
SetZoneColors(const ZoneColors& colors) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
SetOverlappingZonesAlgorithm(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept;
|
||||
|
||||
protected:
|
||||
static LRESULT CALLBACK s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept;
|
||||
@ -171,9 +168,6 @@ private:
|
||||
WPARAM m_keyLast{};
|
||||
size_t m_keyCycle{};
|
||||
std::unique_ptr<ZonesOverlay> m_zonesOverlay;
|
||||
ZoneColors m_zoneColors;
|
||||
OverlappingZonesAlgorithm m_overlappingAlgorithm;
|
||||
bool m_showZoneText;
|
||||
};
|
||||
|
||||
WorkArea::WorkArea(HINSTANCE hinstance)
|
||||
@ -192,12 +186,8 @@ WorkArea::~WorkArea()
|
||||
windowPool.FreeZonesOverlayWindow(m_window);
|
||||
}
|
||||
|
||||
bool WorkArea::Init(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm, const bool showZoneText)
|
||||
bool WorkArea::Init(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId)
|
||||
{
|
||||
m_zoneColors = zoneColors;
|
||||
m_overlappingAlgorithm = overlappingAlgorithm;
|
||||
m_showZoneText = showZoneText;
|
||||
|
||||
Rect workAreaRect;
|
||||
m_monitor = monitor;
|
||||
if (monitor)
|
||||
@ -278,7 +268,7 @@ IFACEMETHODIMP WorkArea::MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled,
|
||||
|
||||
if (redraw)
|
||||
{
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors, m_showZoneText);
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, Colors::GetZoneColors(), FancyZonesSettings::settings().showZoneNumber);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
@ -297,7 +287,7 @@ IFACEMETHODIMP WorkArea::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcep
|
||||
MapWindowPoints(nullptr, m_window, &ptClient, 1);
|
||||
m_zoneSet->MoveWindowIntoZoneByIndexSet(window, m_window, m_highlightZone);
|
||||
|
||||
if (FancyZonesUtils::HasNoVisibleOwner(window))
|
||||
if (!FancyZonesWindowUtils::HasVisibleOwner(window))
|
||||
{
|
||||
SaveWindowProcessToZoneIndex(window);
|
||||
}
|
||||
@ -331,7 +321,7 @@ WorkArea::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool
|
||||
{
|
||||
if (m_zoneSet->MoveWindowIntoZoneByDirectionAndIndex(window, m_window, vkCode, cycle))
|
||||
{
|
||||
if (FancyZonesUtils::HasNoVisibleOwner(window))
|
||||
if (!FancyZonesWindowUtils::HasVisibleOwner(window))
|
||||
{
|
||||
SaveWindowProcessToZoneIndex(window);
|
||||
}
|
||||
@ -408,7 +398,7 @@ WorkArea::ShowZonesOverlay() noexcept
|
||||
if (m_window)
|
||||
{
|
||||
SetAsTopmostWindow();
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors, m_showZoneText);
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, Colors::GetZoneColors(), FancyZonesSettings::settings().showZoneNumber);
|
||||
m_zonesOverlay->Show();
|
||||
}
|
||||
}
|
||||
@ -428,11 +418,11 @@ WorkArea::HideZonesOverlay() noexcept
|
||||
IFACEMETHODIMP_(void)
|
||||
WorkArea::UpdateActiveZoneSet() noexcept
|
||||
{
|
||||
CalculateZoneSet(m_overlappingAlgorithm);
|
||||
CalculateZoneSet(FancyZonesSettings::settings().overlappingZonesAlgorithm);
|
||||
if (m_window)
|
||||
{
|
||||
m_highlightZone.clear();
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors, m_showZoneText);
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, Colors::GetZoneColors(), FancyZonesSettings::settings().showZoneNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,7 +441,7 @@ WorkArea::ClearSelectedZones() noexcept
|
||||
if (m_highlightZone.size())
|
||||
{
|
||||
m_highlightZone.clear();
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, m_zoneColors, m_showZoneText);
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), m_highlightZone, Colors::GetZoneColors(), FancyZonesSettings::settings().showZoneNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@ -461,24 +451,11 @@ WorkArea::FlashZones() noexcept
|
||||
if (m_window)
|
||||
{
|
||||
SetAsTopmostWindow();
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), {}, m_zoneColors, m_showZoneText);
|
||||
m_zonesOverlay->DrawActiveZoneSet(m_zoneSet->GetZones(), {}, Colors::GetZoneColors(), FancyZonesSettings::settings().showZoneNumber);
|
||||
m_zonesOverlay->Flash();
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
WorkArea::SetZoneColors(const ZoneColors& colors) noexcept
|
||||
{
|
||||
m_zoneColors = colors;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
WorkArea::SetOverlappingZonesAlgorithm(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept
|
||||
{
|
||||
m_overlappingAlgorithm = overlappingAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
#pragma region private
|
||||
|
||||
void WorkArea::InitializeZoneSets(const FancyZonesDataTypes::DeviceIdData& parentUniqueId) noexcept
|
||||
@ -502,7 +479,7 @@ void WorkArea::InitializeZoneSets(const FancyZonesDataTypes::DeviceIdData& paren
|
||||
}
|
||||
}
|
||||
|
||||
CalculateZoneSet(m_overlappingAlgorithm);
|
||||
CalculateZoneSet(FancyZonesSettings::settings().overlappingZonesAlgorithm);
|
||||
}
|
||||
|
||||
void WorkArea::CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept
|
||||
@ -631,10 +608,10 @@ LRESULT CALLBACK WorkArea::s_WndProc(HWND window, UINT message, WPARAM wparam, L
|
||||
DefWindowProc(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
winrt::com_ptr<IWorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm, const bool showZoneText) noexcept
|
||||
winrt::com_ptr<IWorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId) noexcept
|
||||
{
|
||||
auto self = winrt::make_self<WorkArea>(hinstance);
|
||||
if (self->Init(hinstance, monitor, uniqueId, parentUniqueId, zoneColors, overlappingAlgorithm, showZoneText))
|
||||
if (self->Init(hinstance, monitor, uniqueId, parentUniqueId))
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "FancyZones.h"
|
||||
#include "FancyZonesLib/ZoneSet.h"
|
||||
#include "FancyZonesLib/ZoneColors.h"
|
||||
#include "FancyZonesLib/FancyZonesDataTypes.h"
|
||||
|
||||
/**
|
||||
@ -135,14 +134,6 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IWorkArea :
|
||||
* Display the layout on the screen and then hide it.
|
||||
*/
|
||||
IFACEMETHOD_(void, FlashZones)() = 0;
|
||||
/*
|
||||
* Set zone colors
|
||||
*/
|
||||
IFACEMETHOD_(void, SetZoneColors)(const ZoneColors& colors) = 0;
|
||||
/*
|
||||
* Set overlapping algorithm
|
||||
*/
|
||||
IFACEMETHOD_(void, SetOverlappingZonesAlgorithm)(OverlappingZonesAlgorithm overlappingAlgorithm) = 0;
|
||||
};
|
||||
|
||||
winrt::com_ptr<IWorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm, const bool showZoneText) noexcept;
|
||||
winrt::com_ptr<IWorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId) noexcept;
|
||||
|
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
#include <windef.h>
|
||||
|
||||
struct ZoneColors
|
||||
{
|
||||
COLORREF primaryColor;
|
||||
COLORREF borderColor;
|
||||
COLORREF highlightColor;
|
||||
COLORREF numberColor;
|
||||
int highlightOpacity;
|
||||
};
|
@ -7,7 +7,8 @@
|
||||
#include "FancyZonesWindowProperties.h"
|
||||
#include "Settings.h"
|
||||
#include "Zone.h"
|
||||
#include "util.h"
|
||||
#include <FancyZonesLib/util.h>
|
||||
#include <FancyZonesLib/WindowUtils.h>
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/display/dpi_aware.h>
|
||||
@ -344,10 +345,10 @@ ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND workAreaWindow, const Zo
|
||||
{
|
||||
if (!suppressMove)
|
||||
{
|
||||
SaveWindowSizeAndOrigin(window);
|
||||
FancyZonesWindowUtils::SaveWindowSizeAndOrigin(window);
|
||||
|
||||
auto rect = AdjustRectForSizeWindowToRect(window, size, workAreaWindow);
|
||||
SizeWindowToRect(window, rect);
|
||||
auto rect = FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(window, size, workAreaWindow);
|
||||
FancyZonesWindowUtils::SizeWindowToRect(window, rect);
|
||||
}
|
||||
|
||||
FancyZonesWindowProperties::StampZoneIndexProperty(window, indexSet);
|
||||
@ -597,7 +598,7 @@ ZoneSet::CycleTabs(HWND window, bool reverse) noexcept
|
||||
continue;
|
||||
}
|
||||
|
||||
SwitchToWindow(next);
|
||||
FancyZonesWindowUtils::SwitchToWindow(next);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ void ZonesOverlay::Flash()
|
||||
|
||||
void ZonesOverlay::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
|
||||
const ZoneIndexSet& highlightZones,
|
||||
const ZoneColors& colors,
|
||||
const Colors::ZoneColors& colors,
|
||||
const bool showZoneText)
|
||||
{
|
||||
_TRACER_;
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "Zone.h"
|
||||
#include "ZoneSet.h"
|
||||
#include "FancyZones.h"
|
||||
#include "ZoneColors.h"
|
||||
#include "Colors.h"
|
||||
|
||||
class ZonesOverlay
|
||||
{
|
||||
@ -68,6 +68,6 @@ public:
|
||||
void Flash();
|
||||
void DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
|
||||
const ZoneIndexSet& highlightZones,
|
||||
const ZoneColors& colors,
|
||||
const Colors::ZoneColors& colors,
|
||||
const bool showZoneText);
|
||||
};
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "pch.h"
|
||||
#include "util.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include <common/display/dpi_aware.h>
|
||||
#include <common/utils/process_path.h>
|
||||
@ -9,35 +8,10 @@
|
||||
|
||||
#include <array>
|
||||
#include <complex>
|
||||
#include <wil/Resource.h>
|
||||
|
||||
#include <fancyzones/FancyZonesLib/FancyZonesDataTypes.h>
|
||||
#include <fancyzones/FancyZonesLib/FancyZonesWindowProperties.h>
|
||||
#include <common/display/dpi_aware.h>
|
||||
|
||||
// Non-Localizable strings
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t PowerToysAppFZEditor[] = L"POWERTOYS.FANCYZONESEDITOR.EXE";
|
||||
const wchar_t SplashClassName[] = L"MsoSplash";
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool IsZonableByProcessPath(const std::wstring& processPath, const std::vector<std::wstring>& excludedApps)
|
||||
{
|
||||
// Filter out user specified apps
|
||||
CharUpperBuffW(const_cast<std::wstring&>(processPath).data(), (DWORD)processPath.length());
|
||||
if (find_app_name_in_path(processPath, excludedApps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (find_app_name_in_path(processPath, { NonLocalizable::PowerToysAppFZEditor }))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#include <FancyZonesLib/FancyZonesWindowProperties.h>
|
||||
|
||||
namespace FancyZonesUtils
|
||||
{
|
||||
@ -200,337 +174,6 @@ namespace FancyZonesUtils
|
||||
monitorInfo = std::move(sortedMonitorInfo);
|
||||
}
|
||||
|
||||
BOOL CALLBACK saveDisplayToVector(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
|
||||
{
|
||||
reinterpret_cast<std::vector<HMONITOR>*>(data)->emplace_back(monitor);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool allMonitorsHaveSameDpiScaling()
|
||||
{
|
||||
std::vector<HMONITOR> monitors;
|
||||
EnumDisplayMonitors(NULL, NULL, saveDisplayToVector, reinterpret_cast<LPARAM>(&monitors));
|
||||
|
||||
if (monitors.size() < 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
UINT firstMonitorDpiX;
|
||||
UINT firstMonitorDpiY;
|
||||
|
||||
if (S_OK != GetDpiForMonitor(monitors[0], MDT_EFFECTIVE_DPI, &firstMonitorDpiX, &firstMonitorDpiY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 1; i < monitors.size(); i++)
|
||||
{
|
||||
UINT iteratedMonitorDpiX;
|
||||
UINT iteratedMonitorDpiY;
|
||||
|
||||
if (S_OK != GetDpiForMonitor(monitors[i], MDT_EFFECTIVE_DPI, &iteratedMonitorDpiX, &iteratedMonitorDpiY) ||
|
||||
iteratedMonitorDpiX != firstMonitorDpiX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScreenToWorkAreaCoords(HWND window, RECT& rect)
|
||||
{
|
||||
// First, find the correct monitor. The monitor cannot be found using the given rect itself, we must first
|
||||
// translate it to relative workspace coordinates.
|
||||
HMONITOR monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFOEXW monitorInfo{ sizeof(MONITORINFOEXW) };
|
||||
GetMonitorInfoW(monitor, &monitorInfo);
|
||||
|
||||
auto xOffset = monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;
|
||||
auto yOffset = monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;
|
||||
|
||||
auto referenceRect = rect;
|
||||
|
||||
referenceRect.left -= xOffset;
|
||||
referenceRect.right -= xOffset;
|
||||
referenceRect.top -= yOffset;
|
||||
referenceRect.bottom -= yOffset;
|
||||
|
||||
// Now, this rect should be used to determine the monitor and thus taskbar size. This fixes
|
||||
// scenarios where the zone lies approximately between two monitors, and the taskbar is on the left.
|
||||
monitor = MonitorFromRect(&referenceRect, MONITOR_DEFAULTTOPRIMARY);
|
||||
GetMonitorInfoW(monitor, &monitorInfo);
|
||||
|
||||
xOffset = monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;
|
||||
yOffset = monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;
|
||||
|
||||
rect.left -= xOffset;
|
||||
rect.right -= xOffset;
|
||||
rect.top -= yOffset;
|
||||
rect.bottom -= yOffset;
|
||||
|
||||
const auto level = DPIAware::GetAwarenessLevel(GetWindowDpiAwarenessContext(window));
|
||||
const bool accountForUnawareness = level < DPIAware::PER_MONITOR_AWARE;
|
||||
|
||||
if (accountForUnawareness && !allMonitorsHaveSameDpiScaling())
|
||||
{
|
||||
rect.left = max(monitorInfo.rcMonitor.left, rect.left);
|
||||
rect.right = min(monitorInfo.rcMonitor.right - xOffset, rect.right);
|
||||
rect.top = max(monitorInfo.rcMonitor.top, rect.top);
|
||||
rect.bottom = min(monitorInfo.rcMonitor.bottom - yOffset, rect.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
RECT AdjustRectForSizeWindowToRect(HWND window, RECT rect, HWND windowOfRect) noexcept
|
||||
{
|
||||
RECT newWindowRect = rect;
|
||||
|
||||
RECT windowRect{};
|
||||
::GetWindowRect(window, &windowRect);
|
||||
|
||||
// Take care of borders
|
||||
RECT frameRect{};
|
||||
if (SUCCEEDED(DwmGetWindowAttribute(window, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRect, sizeof(frameRect))))
|
||||
{
|
||||
LONG leftMargin = frameRect.left - windowRect.left;
|
||||
LONG rightMargin = frameRect.right - windowRect.right;
|
||||
LONG bottomMargin = frameRect.bottom - windowRect.bottom;
|
||||
newWindowRect.left -= leftMargin;
|
||||
newWindowRect.right -= rightMargin;
|
||||
newWindowRect.bottom -= bottomMargin;
|
||||
}
|
||||
|
||||
// Take care of windows that cannot be resized
|
||||
if ((::GetWindowLong(window, GWL_STYLE) & WS_SIZEBOX) == 0)
|
||||
{
|
||||
newWindowRect.right = newWindowRect.left + (windowRect.right - windowRect.left);
|
||||
newWindowRect.bottom = newWindowRect.top + (windowRect.bottom - windowRect.top);
|
||||
}
|
||||
|
||||
// Convert to screen coordinates
|
||||
MapWindowRect(windowOfRect, nullptr, &newWindowRect);
|
||||
|
||||
return newWindowRect;
|
||||
}
|
||||
|
||||
void SizeWindowToRect(HWND window, RECT rect) noexcept
|
||||
{
|
||||
WINDOWPLACEMENT placement{};
|
||||
::GetWindowPlacement(window, &placement);
|
||||
|
||||
// Wait if SW_SHOWMINIMIZED would be removed from window (Issue #1685)
|
||||
for (int i = 0; i < 5 && (placement.showCmd == SW_SHOWMINIMIZED); ++i)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
::GetWindowPlacement(window, &placement);
|
||||
}
|
||||
|
||||
// Do not restore minimized windows. We change their placement though so they restore to the correct zone.
|
||||
if ((placement.showCmd != SW_SHOWMINIMIZED) &&
|
||||
(placement.showCmd != SW_MINIMIZE))
|
||||
{
|
||||
placement.showCmd = SW_RESTORE;
|
||||
}
|
||||
|
||||
// Remove maximized show command to make sure window is moved to the correct zone.
|
||||
if (placement.showCmd == SW_SHOWMAXIMIZED)
|
||||
{
|
||||
placement.showCmd = SW_RESTORE;
|
||||
placement.flags &= ~WPF_RESTORETOMAXIMIZED;
|
||||
}
|
||||
|
||||
ScreenToWorkAreaCoords(window, rect);
|
||||
|
||||
placement.rcNormalPosition = rect;
|
||||
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
|
||||
|
||||
::SetWindowPlacement(window, &placement);
|
||||
// Do it again, allowing Windows to resize the window and set correct scaling
|
||||
// This fixes Issue #365
|
||||
::SetWindowPlacement(window, &placement);
|
||||
}
|
||||
|
||||
void SwitchToWindow(HWND window) noexcept
|
||||
{
|
||||
// Check if the window is minimized
|
||||
if (IsIconic(window))
|
||||
{
|
||||
// Show the window since SetForegroundWindow fails on minimized windows
|
||||
ShowWindow(window, SW_RESTORE);
|
||||
}
|
||||
|
||||
// This is a hack to bypass the restriction on setting the foreground window
|
||||
INPUT inputs[1] = { { .type = INPUT_MOUSE } };
|
||||
SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
|
||||
|
||||
SetForegroundWindow(window);
|
||||
}
|
||||
|
||||
bool HasNoVisibleOwner(HWND window) noexcept
|
||||
{
|
||||
auto owner = GetWindow(window, GW_OWNER);
|
||||
if (owner == nullptr)
|
||||
{
|
||||
return true; // There is no owner at all
|
||||
}
|
||||
if (!IsWindowVisible(owner))
|
||||
{
|
||||
return true; // Owner is invisible
|
||||
}
|
||||
RECT rect;
|
||||
if (!GetWindowRect(owner, &rect))
|
||||
{
|
||||
return false; // Could not get the rect, return true (and filter out the window) just in case
|
||||
}
|
||||
// It is enough that the window is zero-sized in one dimension only.
|
||||
return rect.top == rect.bottom || rect.left == rect.right;
|
||||
}
|
||||
|
||||
bool IsStandardWindow(HWND window)
|
||||
{
|
||||
if (GetAncestor(window, GA_ROOT) != window || !IsWindowVisible(window))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto style = GetWindowLong(window, GWL_STYLE);
|
||||
auto exStyle = GetWindowLong(window, GWL_EXSTYLE);
|
||||
// WS_POPUP need to have a border or minimize/maximize buttons,
|
||||
// otherwise the window is "not interesting"
|
||||
if ((style & WS_POPUP) == WS_POPUP &&
|
||||
(style & WS_THICKFRAME) == 0 &&
|
||||
(style & WS_MINIMIZEBOX) == 0 &&
|
||||
(style & WS_MAXIMIZEBOX) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((style & WS_CHILD) == WS_CHILD ||
|
||||
(style & WS_DISABLED) == WS_DISABLED ||
|
||||
(exStyle & WS_EX_TOOLWINDOW) == WS_EX_TOOLWINDOW ||
|
||||
(exStyle & WS_EX_NOACTIVATE) == WS_EX_NOACTIVATE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::array<char, 256> class_name;
|
||||
GetClassNameA(window, class_name.data(), static_cast<int>(class_name.size()));
|
||||
if (is_system_window(window, class_name.data()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto process_path = get_process_path(window);
|
||||
// Check for Cortana:
|
||||
if (strcmp(class_name.data(), "Windows.UI.Core.CoreWindow") == 0 &&
|
||||
process_path.ends_with(L"SearchUI.exe"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsCandidateForZoning(HWND window, const std::vector<std::wstring>& excludedApps) noexcept
|
||||
{
|
||||
auto zonable = IsStandardWindow(window) && HasNoVisibleOwner(window);
|
||||
if (!zonable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsZonableByProcessPath(get_process_path(window), excludedApps);
|
||||
}
|
||||
|
||||
bool IsWindowMaximized(HWND window) noexcept
|
||||
{
|
||||
WINDOWPLACEMENT placement{};
|
||||
if (GetWindowPlacement(window, &placement) &&
|
||||
placement.showCmd == SW_SHOWMAXIMIZED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SaveWindowSizeAndOrigin(HWND window) noexcept
|
||||
{
|
||||
HANDLE handle = GetPropW(window, ZonedWindowProperties::PropertyRestoreSizeID);
|
||||
if (handle)
|
||||
{
|
||||
// Size already set, skip
|
||||
return;
|
||||
}
|
||||
|
||||
RECT rect;
|
||||
if (GetWindowRect(window, &rect))
|
||||
{
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
int originX = rect.left;
|
||||
int originY = rect.top;
|
||||
|
||||
DPIAware::InverseConvert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), width, height);
|
||||
DPIAware::InverseConvert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), originX, originY);
|
||||
|
||||
std::array<int, 2> windowSizeData = { width, height };
|
||||
std::array<int, 2> windowOriginData = { originX, originY };
|
||||
HANDLE rawData;
|
||||
memcpy(&rawData, windowSizeData.data(), sizeof rawData);
|
||||
SetPropW(window, ZonedWindowProperties::PropertyRestoreSizeID, rawData);
|
||||
memcpy(&rawData, windowOriginData.data(), sizeof rawData);
|
||||
SetPropW(window, ZonedWindowProperties::PropertyRestoreOriginID, rawData);
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreWindowSize(HWND window) noexcept
|
||||
{
|
||||
auto windowSizeData = GetPropW(window, ZonedWindowProperties::PropertyRestoreSizeID);
|
||||
if (windowSizeData)
|
||||
{
|
||||
std::array<int, 2> windowSize;
|
||||
memcpy(windowSize.data(), &windowSizeData, sizeof windowSize);
|
||||
|
||||
// {width, height}
|
||||
DPIAware::Convert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), windowSize[0], windowSize[1]);
|
||||
|
||||
RECT rect;
|
||||
if (GetWindowRect(window, &rect))
|
||||
{
|
||||
rect.right = rect.left + windowSize[0];
|
||||
rect.bottom = rect.top + windowSize[1];
|
||||
SizeWindowToRect(window, rect);
|
||||
}
|
||||
|
||||
::RemoveProp(window, ZonedWindowProperties::PropertyRestoreSizeID);
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreWindowOrigin(HWND window) noexcept
|
||||
{
|
||||
auto windowOriginData = GetPropW(window, ZonedWindowProperties::PropertyRestoreOriginID);
|
||||
if (windowOriginData)
|
||||
{
|
||||
std::array<int, 2> windowOrigin;
|
||||
memcpy(windowOrigin.data(), &windowOriginData, sizeof windowOrigin);
|
||||
|
||||
// {width, height}
|
||||
DPIAware::Convert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), windowOrigin[0], windowOrigin[1]);
|
||||
|
||||
RECT rect;
|
||||
if (GetWindowRect(window, &rect))
|
||||
{
|
||||
int xOffset = windowOrigin[0] - rect.left;
|
||||
int yOffset = windowOrigin[1] - rect.top;
|
||||
|
||||
rect.left += xOffset;
|
||||
rect.right += xOffset;
|
||||
rect.top += yOffset;
|
||||
rect.bottom += yOffset;
|
||||
SizeWindowToRect(window, rect);
|
||||
}
|
||||
|
||||
::RemoveProp(window, ZonedWindowProperties::PropertyRestoreOriginID);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidGuid(const std::wstring& str)
|
||||
{
|
||||
GUID id;
|
||||
@ -716,44 +359,4 @@ namespace FancyZonesUtils
|
||||
|
||||
return windowRect;
|
||||
}
|
||||
|
||||
bool IsProcessOfWindowElevated(HWND window)
|
||||
{
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(window, &pid);
|
||||
if (!pid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wil::unique_handle hProcess{ OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
|
||||
FALSE,
|
||||
pid) };
|
||||
|
||||
wil::unique_handle token;
|
||||
bool elevated = false;
|
||||
|
||||
if (OpenProcessToken(hProcess.get(), TOKEN_QUERY, &token))
|
||||
{
|
||||
TOKEN_ELEVATION elevation;
|
||||
DWORD size;
|
||||
if (GetTokenInformation(token.get(), TokenElevation, &elevation, sizeof(elevation), &size))
|
||||
{
|
||||
return elevation.TokenIsElevated != 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsSplashScreen(HWND window)
|
||||
{
|
||||
wchar_t className[MAX_PATH];
|
||||
if (GetClassName(window, className, MAX_PATH) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return wcscmp(NonLocalizable::SplashClassName, className) == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "gdiplus.h"
|
||||
#include <common/utils/string_utils.h>
|
||||
|
||||
namespace FancyZonesDataTypes
|
||||
{
|
||||
struct DeviceIdData;
|
||||
}
|
||||
|
||||
namespace FancyZonesUtils
|
||||
{
|
||||
struct Rect
|
||||
@ -40,16 +34,6 @@ namespace FancyZonesUtils
|
||||
RECT m_rect{};
|
||||
};
|
||||
|
||||
inline void MakeWindowTransparent(HWND window)
|
||||
{
|
||||
int const pos = -GetSystemMetrics(SM_CXVIRTUALSCREEN) - 8;
|
||||
if (wil::unique_hrgn hrgn{ CreateRectRgn(pos, 0, (pos + 1), 1) })
|
||||
{
|
||||
DWM_BLURBEHIND bh = { DWM_BB_ENABLE | DWM_BB_BLURREGION, TRUE, hrgn.get(), FALSE };
|
||||
DwmEnableBlurBehindWindow(window, &bh);
|
||||
}
|
||||
}
|
||||
|
||||
inline void InitRGB(_Out_ RGBQUAD* quad, BYTE alpha, COLORREF color)
|
||||
{
|
||||
ZeroMemory(quad, sizeof(*quad));
|
||||
@ -189,23 +173,6 @@ namespace FancyZonesUtils
|
||||
UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
|
||||
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
|
||||
|
||||
// Parameter rect is in windowOfRect coordinates
|
||||
RECT AdjustRectForSizeWindowToRect(HWND window, RECT rect, HWND windowOfRect) noexcept;
|
||||
|
||||
// Parameter rect must be in screen coordinates (e.g. obtained from GetWindowRect)
|
||||
void SizeWindowToRect(HWND window, RECT rect) noexcept;
|
||||
|
||||
void SwitchToWindow(HWND window) noexcept;
|
||||
|
||||
bool HasNoVisibleOwner(HWND window) noexcept;
|
||||
bool IsStandardWindow(HWND window);
|
||||
bool IsCandidateForZoning(HWND window, const std::vector<std::wstring>& excludedApps) noexcept;
|
||||
|
||||
bool IsWindowMaximized(HWND window) noexcept;
|
||||
void SaveWindowSizeAndOrigin(HWND window) noexcept;
|
||||
void RestoreWindowSize(HWND window) noexcept;
|
||||
void RestoreWindowOrigin(HWND window) noexcept;
|
||||
|
||||
bool IsValidGuid(const std::wstring& str);
|
||||
std::optional<GUID> GuidFromString(const std::wstring& str) noexcept;
|
||||
std::optional<std::wstring> GuidToString(const GUID& guid) noexcept;
|
||||
@ -215,10 +182,5 @@ namespace FancyZonesUtils
|
||||
std::wstring TrimDeviceId(const std::wstring& deviceId);
|
||||
|
||||
RECT PrepareRectForCycling(RECT windowRect, RECT workAreaRect, DWORD vkCode) noexcept;
|
||||
size_t ChooseNextZoneByPosition(DWORD vkCode, RECT windowRect, const std::vector<RECT>& zoneRects) noexcept;
|
||||
|
||||
// If HWND is already dead, we assume it wasn't elevated
|
||||
bool IsProcessOfWindowElevated(HWND window);
|
||||
|
||||
bool IsSplashScreen(HWND window);
|
||||
size_t ChooseNextZoneByPosition(DWORD vkCode, RECT windowRect, const std::vector<RECT>& zoneRects) noexcept;
|
||||
}
|
||||
|
@ -55,14 +55,13 @@ public:
|
||||
// These are the settings shown on the settings page along with their current values.
|
||||
virtual bool get_config(_Out_ PWSTR buffer, _Out_ int* buffer_size) override
|
||||
{
|
||||
return m_settings->GetConfig(buffer, buffer_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Passes JSON with the configuration settings for the powertoy.
|
||||
// This is called when the user hits Save on the settings page.
|
||||
virtual void set_config(PCWSTR config) override
|
||||
{
|
||||
m_settings->SetConfig(config);
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
@ -111,15 +110,15 @@ public:
|
||||
virtual void send_settings_telemetry() override
|
||||
{
|
||||
Logger::info("Send settings telemetry");
|
||||
Trace::SettingsTelemetry(*m_settings->GetSettings());
|
||||
FancyZonesSettings::instance().LoadSettings();
|
||||
Trace::SettingsTelemetry(FancyZonesSettings::settings());
|
||||
}
|
||||
|
||||
FancyZonesModuleInterface()
|
||||
{
|
||||
app_name = GET_RESOURCE_STRING(IDS_FANCYZONES);
|
||||
app_key = NonLocalizable::ModuleKey;
|
||||
m_settings = MakeFancyZonesSettings(reinterpret_cast<HINSTANCE>(&__ImageBase), FancyZonesModuleInterface::get_name(), FancyZonesModuleInterface::get_key());
|
||||
|
||||
|
||||
m_toggleEditorEvent = CreateDefaultEvent(CommonSharedConstants::FANCY_ZONES_EDITOR_TOGGLE_EVENT);
|
||||
if (!m_toggleEditorEvent)
|
||||
{
|
||||
@ -215,8 +214,6 @@ private:
|
||||
|
||||
// Handle to event used to invoke FancyZones Editor
|
||||
HANDLE m_toggleEditorEvent;
|
||||
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings;
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
|
@ -16,44 +16,29 @@ namespace FancyZonesUnitTests
|
||||
TEST_CLASS (FancyZonesUnitTests)
|
||||
{
|
||||
HINSTANCE m_hInst;
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings;
|
||||
const std::wstring_view m_moduleName = L"FancyZonesUnitTests";
|
||||
const std::wstring_view m_modulekey = L"FancyZonesUnitTests";
|
||||
|
||||
TEST_METHOD_INITIALIZE(Init)
|
||||
{
|
||||
m_hInst = (HINSTANCE)GetModuleHandleW(nullptr);
|
||||
m_settings = MakeFancyZonesSettings(m_hInst, m_moduleName.data(), m_modulekey.data());
|
||||
Assert::IsTrue(m_settings != nullptr);
|
||||
}
|
||||
|
||||
TEST_METHOD_CLEANUP(CleanUp)
|
||||
{
|
||||
std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_moduleName));
|
||||
m_hInst = (HINSTANCE)GetModuleHandleW(nullptr);
|
||||
}
|
||||
|
||||
TEST_METHOD (Create)
|
||||
{
|
||||
auto actual = MakeFancyZones(m_hInst, m_settings, nullptr);
|
||||
Assert::IsNotNull(actual.get());
|
||||
}
|
||||
TEST_METHOD (CreateWithEmptyHinstance)
|
||||
{
|
||||
auto actual = MakeFancyZones({}, m_settings, nullptr);
|
||||
Assert::IsNotNull(actual.get());
|
||||
}
|
||||
TEST_METHOD (Create)
|
||||
{
|
||||
auto actual = MakeFancyZones(m_hInst, nullptr);
|
||||
Assert::IsNotNull(actual.get());
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithNullHinstance)
|
||||
{
|
||||
auto actual = MakeFancyZones(nullptr, m_settings, nullptr);
|
||||
Assert::IsNotNull(actual.get());
|
||||
}
|
||||
TEST_METHOD (CreateWithEmptyHinstance)
|
||||
{
|
||||
auto actual = MakeFancyZones({}, nullptr);
|
||||
Assert::IsNotNull(actual.get());
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithNullSettings)
|
||||
{
|
||||
auto actual = MakeFancyZones(m_hInst, nullptr, nullptr);
|
||||
Assert::IsNull(actual.get());
|
||||
}
|
||||
TEST_METHOD (CreateWithNullHinstance)
|
||||
{
|
||||
auto actual = MakeFancyZones(nullptr, nullptr);
|
||||
Assert::IsNotNull(actual.get());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS (FancyZonesIFancyZonesCallbackUnitTests)
|
||||
@ -61,7 +46,6 @@ namespace FancyZonesUnitTests
|
||||
HINSTANCE m_hInst{};
|
||||
std::wstring m_moduleName = L"FancyZonesUnitTests";
|
||||
std::wstring m_moduleKey = L"FancyZonesUnitTests";
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings = nullptr;
|
||||
winrt::com_ptr<IFancyZonesCallback> m_fzCallback = nullptr;
|
||||
|
||||
std::wstring serializedPowerToySettings(const Settings& settings)
|
||||
@ -112,10 +96,7 @@ namespace FancyZonesUnitTests
|
||||
TEST_METHOD_INITIALIZE(Init)
|
||||
{
|
||||
m_hInst = (HINSTANCE)GetModuleHandleW(nullptr);
|
||||
m_settings = MakeFancyZonesSettings(m_hInst, m_moduleName.c_str(), m_moduleKey.c_str());
|
||||
Assert::IsTrue(m_settings != nullptr);
|
||||
|
||||
auto fancyZones = MakeFancyZones(m_hInst, m_settings, nullptr);
|
||||
auto fancyZones = MakeFancyZones(m_hInst, nullptr);
|
||||
Assert::IsTrue(fancyZones != nullptr);
|
||||
|
||||
m_fzCallback = fancyZones.as<IFancyZonesCallback>();
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <FancyZonesLib/Settings.h>
|
||||
#include <FancyZonesLib/FancyZones.h>
|
||||
#include <FancyZonesLib/ModuleConstants.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
@ -58,503 +59,106 @@ namespace FancyZonesUnitTests
|
||||
compareHotkeyObjects(expected.prevTabHotkey, actual.prevTabHotkey);
|
||||
}
|
||||
|
||||
TEST_CLASS (FancyZonesSettingsCreationUnitTest)
|
||||
TEST_CLASS (FancyZonesSettingsUnitTest)
|
||||
{
|
||||
HINSTANCE m_hInst;
|
||||
PCWSTR m_moduleName = L"FancyZonesUnitTests";
|
||||
PCWSTR m_moduleKey = L"FancyZonesUnitTests";
|
||||
std::wstring m_tmpName;
|
||||
|
||||
const Settings m_defaultSettings;
|
||||
|
||||
TEST_METHOD_INITIALIZE(Init)
|
||||
{
|
||||
m_hInst = (HINSTANCE)GetModuleHandleW(nullptr);
|
||||
m_tmpName = PTSettingsHelper::get_module_save_folder_location(m_moduleName) + L"\\settings.json";
|
||||
}
|
||||
TEST_METHOD_CLEANUP(Cleanup)
|
||||
{
|
||||
std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_moduleName));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithHinstanceDefault)
|
||||
{
|
||||
auto actual = MakeFancyZonesSettings({}, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(m_defaultSettings, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithHinstanceNullptr)
|
||||
{
|
||||
auto actual = MakeFancyZonesSettings(nullptr, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(m_defaultSettings, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithNameEmpty)
|
||||
{
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, L"", m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(m_defaultSettings, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (Create)
|
||||
{
|
||||
//prepare data
|
||||
const Settings expected;
|
||||
|
||||
PowerToysSettings::PowerToyValues values(m_moduleName, m_moduleKey);
|
||||
values.add_property(L"fancyzones_shiftDrag", expected.shiftDrag);
|
||||
values.add_property(L"fancyzones_mouseSwitch", expected.mouseSwitch);
|
||||
values.add_property(L"fancyzones_displayChange_moveWindows", expected.displayChange_moveWindows);
|
||||
values.add_property(L"fancyzones_zoneSetChange_flashZones", expected.zoneSetChange_flashZones);
|
||||
values.add_property(L"fancyzones_zoneSetChange_moveWindows", expected.zoneSetChange_moveWindows);
|
||||
values.add_property(L"fancyzones_overrideSnapHotkeys", expected.overrideSnapHotkeys);
|
||||
values.add_property(L"fancyzones_moveWindowAcrossMonitors", expected.moveWindowAcrossMonitors);
|
||||
values.add_property(L"fancyzones_moveWindowsBasedOnPosition", expected.moveWindowsBasedOnPosition);
|
||||
values.add_property(L"fancyzones_appLastZone_moveWindows", expected.appLastZone_moveWindows);
|
||||
values.add_property(L"fancyzones_openWindowOnActiveMonitor", expected.openWindowOnActiveMonitor);
|
||||
values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
|
||||
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
|
||||
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
|
||||
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
|
||||
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
|
||||
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
|
||||
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
|
||||
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
|
||||
values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity);
|
||||
values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json());
|
||||
values.add_property(L"fancyzones_windowSwitching", expected.windowSwitching);
|
||||
values.add_property(L"fancyzones_nextTab_hotkey", expected.nextTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_prevTab_hotkey", expected.prevTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_excluded_apps", expected.excludedApps);
|
||||
|
||||
values.save_to_settings_file();
|
||||
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(expected, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithMultipleApps)
|
||||
{
|
||||
//prepare data
|
||||
const Settings expected{
|
||||
.excludedApps = L"app\r\napp1\r\napp2\r\nanother app",
|
||||
.excludedAppsArray = { L"APP", L"APP1", L"APP2", L"ANOTHER APP" },
|
||||
};
|
||||
|
||||
PowerToysSettings::PowerToyValues values(m_moduleName, m_moduleKey);
|
||||
values.add_property(L"fancyzones_shiftDrag", expected.shiftDrag);
|
||||
values.add_property(L"fancyzones_mouseSwitch", expected.mouseSwitch);
|
||||
values.add_property(L"fancyzones_displayChange_moveWindows", expected.displayChange_moveWindows);
|
||||
values.add_property(L"fancyzones_zoneSetChange_flashZones", expected.zoneSetChange_flashZones);
|
||||
values.add_property(L"fancyzones_zoneSetChange_moveWindows", expected.zoneSetChange_moveWindows);
|
||||
values.add_property(L"fancyzones_overrideSnapHotkeys", expected.overrideSnapHotkeys);
|
||||
values.add_property(L"fancyzones_moveWindowAcrossMonitors", expected.moveWindowAcrossMonitors);
|
||||
values.add_property(L"fancyzones_moveWindowsBasedOnPosition", expected.moveWindowsBasedOnPosition);
|
||||
values.add_property(L"fancyzones_appLastZone_moveWindows", expected.appLastZone_moveWindows);
|
||||
values.add_property(L"fancyzones_openWindowOnActiveMonitor", expected.openWindowOnActiveMonitor);
|
||||
values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
|
||||
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
|
||||
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
|
||||
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
|
||||
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
|
||||
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
|
||||
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
|
||||
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
|
||||
values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity);
|
||||
values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json());
|
||||
values.add_property(L"fancyzones_windowSwitching", expected.windowSwitching);
|
||||
values.add_property(L"fancyzones_nextTab_hotkey", expected.nextTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_prevTab_hotkey", expected.prevTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_excluded_apps", expected.excludedApps);
|
||||
|
||||
values.save_to_settings_file();
|
||||
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(expected, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithBoolValuesMissed)
|
||||
{
|
||||
const Settings expected{
|
||||
.shiftDrag = m_defaultSettings.shiftDrag,
|
||||
.mouseSwitch = m_defaultSettings.mouseSwitch,
|
||||
.displayChange_moveWindows = m_defaultSettings.displayChange_moveWindows,
|
||||
.zoneSetChange_flashZones = m_defaultSettings.zoneSetChange_flashZones,
|
||||
.zoneSetChange_moveWindows = m_defaultSettings.zoneSetChange_moveWindows,
|
||||
.overrideSnapHotkeys = m_defaultSettings.overrideSnapHotkeys,
|
||||
.moveWindowAcrossMonitors = m_defaultSettings.moveWindowAcrossMonitors,
|
||||
.moveWindowsBasedOnPosition = m_defaultSettings.moveWindowsBasedOnPosition,
|
||||
.appLastZone_moveWindows = m_defaultSettings.appLastZone_moveWindows,
|
||||
.openWindowOnActiveMonitor = m_defaultSettings.openWindowOnActiveMonitor,
|
||||
.restoreSize = m_defaultSettings.restoreSize,
|
||||
.use_cursorpos_editor_startupscreen = m_defaultSettings.use_cursorpos_editor_startupscreen,
|
||||
.showZonesOnAllMonitors = m_defaultSettings.showZonesOnAllMonitors,
|
||||
.spanZonesAcrossMonitors = m_defaultSettings.spanZonesAcrossMonitors,
|
||||
.makeDraggedWindowTransparent = m_defaultSettings.makeDraggedWindowTransparent,
|
||||
.zoneColor = L"FAFAFA",
|
||||
.zoneBorderColor = L"CCDDEE",
|
||||
.zoneHighlightColor = L"#00FFD7",
|
||||
.zoneHighlightOpacity = 45,
|
||||
.editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, true, true, false, VK_OEM_3),
|
||||
.nextTabHotkey = PowerToysSettings::HotkeyObject::from_settings(false, true, true, false, VK_NEXT),
|
||||
.prevTabHotkey = PowerToysSettings::HotkeyObject::from_settings(false, true, true, false, VK_PRIOR),
|
||||
.excludedApps = L"app",
|
||||
.excludedAppsArray = { L"APP" },
|
||||
};
|
||||
|
||||
PowerToysSettings::PowerToyValues values(m_moduleName, m_moduleKey);
|
||||
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
|
||||
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
|
||||
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
|
||||
values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity);
|
||||
values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json());
|
||||
values.add_property(L"fancyzones_windowSwitching", expected.windowSwitching);
|
||||
values.add_property(L"fancyzones_nextTab_hotkey", expected.nextTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_prevTab_hotkey", expected.prevTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_excluded_apps", expected.excludedApps);
|
||||
|
||||
values.save_to_settings_file();
|
||||
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(expected, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateColorMissed)
|
||||
{
|
||||
//prepare data
|
||||
const Settings expected;
|
||||
|
||||
PowerToysSettings::PowerToyValues values(m_moduleName, m_moduleKey);
|
||||
values.add_property(L"fancyzones_shiftDrag", expected.shiftDrag);
|
||||
values.add_property(L"fancyzones_mouseSwitch", expected.mouseSwitch);
|
||||
values.add_property(L"fancyzones_displayChange_moveWindows", expected.displayChange_moveWindows);
|
||||
values.add_property(L"fancyzones_zoneSetChange_flashZones", expected.zoneSetChange_flashZones);
|
||||
values.add_property(L"fancyzones_zoneSetChange_moveWindows", expected.zoneSetChange_moveWindows);
|
||||
values.add_property(L"fancyzones_overrideSnapHotkeys", expected.overrideSnapHotkeys);
|
||||
values.add_property(L"fancyzones_moveWindowAcrossMonitors", expected.moveWindowAcrossMonitors);
|
||||
values.add_property(L"fancyzones_moveWindowsBasedOnPosition", expected.moveWindowsBasedOnPosition);
|
||||
values.add_property(L"fancyzones_appLastZone_moveWindows", expected.appLastZone_moveWindows);
|
||||
values.add_property(L"fancyzones_openWindowOnActiveMonitor", expected.openWindowOnActiveMonitor);
|
||||
values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
|
||||
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
|
||||
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
|
||||
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
|
||||
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
|
||||
values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity);
|
||||
values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json());
|
||||
values.add_property(L"fancyzones_windowSwitching", expected.windowSwitching);
|
||||
values.add_property(L"fancyzones_nextTab_hotkey", expected.nextTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_prevTab_hotkey", expected.prevTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_excluded_apps", expected.excludedApps);
|
||||
|
||||
values.save_to_settings_file();
|
||||
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(expected, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateOpacityMissed)
|
||||
{
|
||||
//prepare data
|
||||
const Settings expected;
|
||||
|
||||
PowerToysSettings::PowerToyValues values(m_moduleName, m_moduleKey);
|
||||
values.add_property(L"fancyzones_shiftDrag", expected.shiftDrag);
|
||||
values.add_property(L"fancyzones_mouseSwitch", expected.mouseSwitch);
|
||||
values.add_property(L"fancyzones_displayChange_moveWindows", expected.displayChange_moveWindows);
|
||||
values.add_property(L"fancyzones_zoneSetChange_flashZones", expected.zoneSetChange_flashZones);
|
||||
values.add_property(L"fancyzones_zoneSetChange_moveWindows", expected.zoneSetChange_moveWindows);
|
||||
values.add_property(L"fancyzones_overrideSnapHotkeys", expected.overrideSnapHotkeys);
|
||||
values.add_property(L"fancyzones_moveWindowAcrossMonitors", expected.moveWindowAcrossMonitors);
|
||||
values.add_property(L"fancyzones_moveWindowsBasedOnPosition", expected.moveWindowsBasedOnPosition);
|
||||
values.add_property(L"fancyzones_appLastZone_moveWindows", expected.appLastZone_moveWindows);
|
||||
values.add_property(L"fancyzones_openWindowOnActiveMonitor", expected.openWindowOnActiveMonitor);
|
||||
values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
|
||||
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
|
||||
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
|
||||
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
|
||||
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
|
||||
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
|
||||
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
|
||||
values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json());
|
||||
values.add_property(L"fancyzones_windowSwitching", expected.windowSwitching);
|
||||
values.add_property(L"fancyzones_nextTab_hotkey", expected.nextTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_prevTab_hotkey", expected.prevTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_excluded_apps", expected.excludedApps);
|
||||
|
||||
values.save_to_settings_file();
|
||||
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(expected, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateHotkeyMissed)
|
||||
{
|
||||
//prepare data
|
||||
const Settings expected;
|
||||
|
||||
PowerToysSettings::PowerToyValues values(m_moduleName, m_moduleKey);
|
||||
values.add_property(L"fancyzones_shiftDrag", expected.shiftDrag);
|
||||
values.add_property(L"fancyzones_mouseSwitch", expected.mouseSwitch);
|
||||
values.add_property(L"fancyzones_displayChange_moveWindows", expected.displayChange_moveWindows);
|
||||
values.add_property(L"fancyzones_zoneSetChange_flashZones", expected.zoneSetChange_flashZones);
|
||||
values.add_property(L"fancyzones_zoneSetChange_moveWindows", expected.zoneSetChange_moveWindows);
|
||||
values.add_property(L"fancyzones_overrideSnapHotkeys", expected.overrideSnapHotkeys);
|
||||
values.add_property(L"fancyzones_moveWindowAcrossMonitors", expected.moveWindowAcrossMonitors);
|
||||
values.add_property(L"fancyzones_moveWindowsBasedOnPosition", expected.moveWindowsBasedOnPosition);
|
||||
values.add_property(L"fancyzones_appLastZone_moveWindows", expected.appLastZone_moveWindows);
|
||||
values.add_property(L"fancyzones_openWindowOnActiveMonitor", expected.openWindowOnActiveMonitor);
|
||||
values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
|
||||
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
|
||||
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
|
||||
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
|
||||
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
|
||||
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
|
||||
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
|
||||
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
|
||||
values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity);
|
||||
values.add_property(L"fancyzones_excluded_apps", expected.excludedApps);
|
||||
|
||||
values.save_to_settings_file();
|
||||
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(expected, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateAppsMissed)
|
||||
{
|
||||
//prepare data
|
||||
const Settings expected;
|
||||
|
||||
PowerToysSettings::PowerToyValues values(m_moduleName, m_moduleKey);
|
||||
values.add_property(L"fancyzones_shiftDrag", expected.shiftDrag);
|
||||
values.add_property(L"fancyzones_mouseSwitch", expected.mouseSwitch);
|
||||
values.add_property(L"fancyzones_displayChange_moveWindows", expected.displayChange_moveWindows);
|
||||
values.add_property(L"fancyzones_zoneSetChange_flashZones", expected.zoneSetChange_flashZones);
|
||||
values.add_property(L"fancyzones_zoneSetChange_moveWindows", expected.zoneSetChange_moveWindows);
|
||||
values.add_property(L"fancyzones_overrideSnapHotkeys", expected.overrideSnapHotkeys);
|
||||
values.add_property(L"fancyzones_moveWindowAcrossMonitors", expected.moveWindowAcrossMonitors);
|
||||
values.add_property(L"fancyzones_moveWindowsBasedOnPosition", expected.moveWindowsBasedOnPosition);
|
||||
values.add_property(L"fancyzones_appLastZone_moveWindows", expected.appLastZone_moveWindows);
|
||||
values.add_property(L"fancyzones_openWindowOnActiveMonitor", expected.openWindowOnActiveMonitor);
|
||||
values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
|
||||
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
|
||||
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
|
||||
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
|
||||
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
|
||||
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
|
||||
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
|
||||
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
|
||||
values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity);
|
||||
values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json());
|
||||
values.add_property(L"fancyzones_windowSwitching", expected.windowSwitching);
|
||||
values.add_property(L"fancyzones_nextTab_hotkey", expected.nextTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_prevTab_hotkey", expected.prevTabHotkey.get_json());
|
||||
|
||||
values.save_to_settings_file();
|
||||
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(expected, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithEmptyJson)
|
||||
{
|
||||
json::to_file(m_tmpName, json::JsonObject());
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(m_defaultSettings, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithCorruptedJson)
|
||||
{
|
||||
std::wofstream{ m_tmpName.data(), std::ios::binary } << L"{ \"version\": \"1.0\", \"name\": \"";
|
||||
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(m_defaultSettings, *actualSettings);
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateWithCyrillicSymbolsInJson)
|
||||
{
|
||||
std::wofstream{ m_tmpName.data(), std::ios::binary } << L"{ \"version\": \"1.0\", \"name\": \"ФансиЗонс\"}";
|
||||
auto actual = MakeFancyZonesSettings(m_hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(actual != nullptr);
|
||||
|
||||
auto actualSettings = actual->GetSettings();
|
||||
compareSettings(m_defaultSettings, *actualSettings);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS (FancyZonesSettingsUnitTests)
|
||||
{
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings = nullptr;
|
||||
PCWSTR m_moduleName = L"FancyZonesUnitTests";
|
||||
PCWSTR m_moduleKey = L"FancyZonesUnitTests";
|
||||
|
||||
std::wstring serializedPowerToySettings(const Settings& settings)
|
||||
{
|
||||
PowerToysSettings::Settings ptSettings(HINSTANCE{}, m_moduleName);
|
||||
ptSettings.set_description(IDS_SETTING_DESCRIPTION);
|
||||
ptSettings.set_icon_key(L"pt-fancy-zones");
|
||||
ptSettings.set_overview_link(L"https://aka.ms/PowerToysOverview_FancyZones");
|
||||
ptSettings.set_video_link(L"https://youtu.be/rTtGzZYAXgY");
|
||||
// reset to defaults
|
||||
PowerToysSettings::PowerToyValues values(NonLocalizable::ModuleKey, NonLocalizable::ModuleKey);
|
||||
values.add_property(L"fancyzones_shiftDrag", m_defaultSettings.shiftDrag);
|
||||
values.add_property(L"fancyzones_mouseSwitch", m_defaultSettings.mouseSwitch);
|
||||
values.add_property(L"fancyzones_displayChange_moveWindows", m_defaultSettings.displayChange_moveWindows);
|
||||
values.add_property(L"fancyzones_zoneSetChange_flashZones", m_defaultSettings.zoneSetChange_flashZones);
|
||||
values.add_property(L"fancyzones_zoneSetChange_moveWindows", m_defaultSettings.zoneSetChange_moveWindows);
|
||||
values.add_property(L"fancyzones_overrideSnapHotkeys", m_defaultSettings.overrideSnapHotkeys);
|
||||
values.add_property(L"fancyzones_moveWindowAcrossMonitors", m_defaultSettings.moveWindowAcrossMonitors);
|
||||
values.add_property(L"fancyzones_moveWindowsBasedOnPosition", m_defaultSettings.moveWindowsBasedOnPosition);
|
||||
values.add_property(L"fancyzones_appLastZone_moveWindows", m_defaultSettings.appLastZone_moveWindows);
|
||||
values.add_property(L"fancyzones_openWindowOnActiveMonitor", m_defaultSettings.openWindowOnActiveMonitor);
|
||||
values.add_property(L"fancyzones_restoreSize", m_defaultSettings.restoreSize);
|
||||
values.add_property(L"use_cursorpos_editor_startupscreen", m_defaultSettings.use_cursorpos_editor_startupscreen);
|
||||
values.add_property(L"fancyzones_show_on_all_monitors", m_defaultSettings.showZonesOnAllMonitors);
|
||||
values.add_property(L"fancyzones_multi_monitor_mode", m_defaultSettings.spanZonesAcrossMonitors);
|
||||
values.add_property(L"fancyzones_makeDraggedWindowTransparent", m_defaultSettings.makeDraggedWindowTransparent);
|
||||
values.add_property(L"fancyzones_zoneColor", m_defaultSettings.zoneColor);
|
||||
values.add_property(L"fancyzones_zoneBorderColor", m_defaultSettings.zoneBorderColor);
|
||||
values.add_property(L"fancyzones_zoneHighlightColor", m_defaultSettings.zoneHighlightColor);
|
||||
values.add_property(L"fancyzones_highlight_opacity", m_defaultSettings.zoneHighlightOpacity);
|
||||
values.add_property(L"fancyzones_editor_hotkey", m_defaultSettings.editorHotkey.get_json());
|
||||
values.add_property(L"fancyzones_windowSwitching", m_defaultSettings.windowSwitching);
|
||||
values.add_property(L"fancyzones_nextTab_hotkey", m_defaultSettings.nextTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_prevTab_hotkey", m_defaultSettings.prevTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_excluded_apps", m_defaultSettings.excludedApps);
|
||||
|
||||
ptSettings.add_custom_action(
|
||||
L"ToggledFZEditor", // action name.
|
||||
IDS_SETTING_LAUNCH_EDITOR_LABEL,
|
||||
IDS_SETTING_LAUNCH_EDITOR_BUTTON,
|
||||
IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION);
|
||||
ptSettings.add_hotkey(L"fancyzones_editor_hotkey", IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, settings.editorHotkey);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_windowSwitching", IDS_SETTING_WINDOW_SWITCHING_TOGGLE_LABEL, settings.windowSwitching);
|
||||
ptSettings.add_hotkey(L"fancyzones_nextTab_hotkey", IDS_SETTING_NEXT_TAB_HOTKEY_LABEL, settings.nextTabHotkey);
|
||||
ptSettings.add_hotkey(L"fancyzones_prevTab_hotkey", IDS_SETTING_PREV_TAB_HOTKEY_LABEL, settings.prevTabHotkey);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_shiftDrag", IDS_SETTING_DESCRIPTION_SHIFTDRAG, settings.shiftDrag);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_mouseSwitch", IDS_SETTING_DESCRIPTION_MOUSESWITCH, settings.mouseSwitch);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_overrideSnapHotkeys", IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS, settings.overrideSnapHotkeys);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_moveWindowAcrossMonitors", IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS, settings.moveWindowAcrossMonitors);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_moveWindowsBasedOnPosition", IDS_SETTING_DESCRIPTION_MOVE_WINDOWS_BASED_ON_POSITION, settings.moveWindowsBasedOnPosition);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_zoneSetChange_flashZones", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES, settings.zoneSetChange_flashZones);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_displayChange_moveWindows", IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS, settings.displayChange_moveWindows);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_zoneSetChange_moveWindows", IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS, settings.zoneSetChange_moveWindows);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_appLastZone_moveWindows", IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS, settings.appLastZone_moveWindows);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_openWindowOnActiveMonitor", IDS_SETTING_DESCRIPTION_OPEN_WINDOW_ON_ACTIVE_MONITOR, settings.openWindowOnActiveMonitor);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, settings.restoreSize);
|
||||
ptSettings.add_bool_toggle(L"use_cursorpos_editor_startupscreen", IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN, settings.use_cursorpos_editor_startupscreen);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_show_on_all_monitors", IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS, settings.showZonesOnAllMonitors);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_multi_monitor_mode", IDS_SETTING_DESCRIPTION_SPAN_ZONES_ACROSS_MONITORS, settings.spanZonesAcrossMonitors);
|
||||
ptSettings.add_bool_toggle(L"fancyzones_makeDraggedWindowTransparent", IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT, settings.makeDraggedWindowTransparent);
|
||||
ptSettings.add_int_spinner(L"fancyzones_highlight_opacity", IDS_SETTINGS_HIGHLIGHT_OPACITY, settings.zoneHighlightOpacity, 0, 100, 1);
|
||||
ptSettings.add_color_picker(L"fancyzones_zoneColor", IDS_SETTING_DESCRIPTION_ZONECOLOR, settings.zoneColor);
|
||||
ptSettings.add_color_picker(L"fancyzones_zoneBorderColor", IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR, settings.zoneBorderColor);
|
||||
ptSettings.add_color_picker(L"fancyzones_zoneHighlightColor", IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR, settings.zoneHighlightColor);
|
||||
ptSettings.add_multiline_string(L"fancyzones_excluded_apps", IDS_SETTING_EXCLUDED_APPS_DESCRIPTION, settings.excludedApps);
|
||||
|
||||
return ptSettings.serialize();
|
||||
json::to_file(FancyZonesSettings::GetSettingsFileName(), values.get_raw_json());
|
||||
FancyZonesSettings::instance().LoadSettings();
|
||||
}
|
||||
|
||||
TEST_METHOD_CLEANUP(Cleanup)
|
||||
{
|
||||
std::filesystem::remove(FancyZonesSettings::GetSettingsFileName());
|
||||
}
|
||||
|
||||
TEST_METHOD_INITIALIZE(Init)
|
||||
{
|
||||
HINSTANCE hInst = (HINSTANCE)GetModuleHandleW(nullptr);
|
||||
TEST_METHOD (Parse)
|
||||
{
|
||||
//prepare data
|
||||
const Settings expected{
|
||||
.excludedApps = L"app\r\napp1\r\napp2\r\nanother app",
|
||||
.excludedAppsArray = { L"APP", L"APP1", L"APP2", L"ANOTHER APP" },
|
||||
};
|
||||
|
||||
m_settings = MakeFancyZonesSettings(hInst, m_moduleName, m_moduleKey);
|
||||
Assert::IsTrue(m_settings != nullptr);
|
||||
}
|
||||
PowerToysSettings::PowerToyValues values(NonLocalizable::ModuleKey, NonLocalizable::ModuleKey);
|
||||
values.add_property(L"fancyzones_shiftDrag", expected.shiftDrag);
|
||||
values.add_property(L"fancyzones_mouseSwitch", expected.mouseSwitch);
|
||||
values.add_property(L"fancyzones_displayChange_moveWindows", expected.displayChange_moveWindows);
|
||||
values.add_property(L"fancyzones_zoneSetChange_flashZones", expected.zoneSetChange_flashZones);
|
||||
values.add_property(L"fancyzones_zoneSetChange_moveWindows", expected.zoneSetChange_moveWindows);
|
||||
values.add_property(L"fancyzones_overrideSnapHotkeys", expected.overrideSnapHotkeys);
|
||||
values.add_property(L"fancyzones_moveWindowAcrossMonitors", expected.moveWindowAcrossMonitors);
|
||||
values.add_property(L"fancyzones_moveWindowsBasedOnPosition", expected.moveWindowsBasedOnPosition);
|
||||
values.add_property(L"fancyzones_appLastZone_moveWindows", expected.appLastZone_moveWindows);
|
||||
values.add_property(L"fancyzones_openWindowOnActiveMonitor", expected.openWindowOnActiveMonitor);
|
||||
values.add_property(L"fancyzones_restoreSize", expected.restoreSize);
|
||||
values.add_property(L"use_cursorpos_editor_startupscreen", expected.use_cursorpos_editor_startupscreen);
|
||||
values.add_property(L"fancyzones_show_on_all_monitors", expected.showZonesOnAllMonitors);
|
||||
values.add_property(L"fancyzones_multi_monitor_mode", expected.spanZonesAcrossMonitors);
|
||||
values.add_property(L"fancyzones_makeDraggedWindowTransparent", expected.makeDraggedWindowTransparent);
|
||||
values.add_property(L"fancyzones_zoneColor", expected.zoneColor);
|
||||
values.add_property(L"fancyzones_zoneBorderColor", expected.zoneBorderColor);
|
||||
values.add_property(L"fancyzones_zoneHighlightColor", expected.zoneHighlightColor);
|
||||
values.add_property(L"fancyzones_highlight_opacity", expected.zoneHighlightOpacity);
|
||||
values.add_property(L"fancyzones_editor_hotkey", expected.editorHotkey.get_json());
|
||||
values.add_property(L"fancyzones_windowSwitching", expected.windowSwitching);
|
||||
values.add_property(L"fancyzones_nextTab_hotkey", expected.nextTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_prevTab_hotkey", expected.prevTabHotkey.get_json());
|
||||
values.add_property(L"fancyzones_excluded_apps", expected.excludedApps);
|
||||
|
||||
TEST_METHOD_CLEANUP(Cleanup)
|
||||
{
|
||||
std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_moduleName));
|
||||
}
|
||||
json::to_file(FancyZonesSettings::GetSettingsFileName(), values.get_raw_json());
|
||||
|
||||
FancyZonesSettings::instance().LoadSettings();
|
||||
auto actual = FancyZonesSettings::settings();
|
||||
compareSettings(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (GetConfig)
|
||||
{
|
||||
int expectedSize = 0;
|
||||
m_settings->GetConfig(nullptr, &expectedSize);
|
||||
Assert::AreNotEqual(0, expectedSize);
|
||||
TEST_METHOD (ParseInvalid)
|
||||
{
|
||||
PowerToysSettings::PowerToyValues values(NonLocalizable::ModuleKey, NonLocalizable::ModuleKey);
|
||||
values.add_property(L"non_fancyzones_value", false);
|
||||
|
||||
int actualBufferSize = expectedSize;
|
||||
PWSTR actualBuffer = new wchar_t[actualBufferSize];
|
||||
json::to_file(FancyZonesSettings::GetSettingsFileName(), values.get_raw_json());
|
||||
|
||||
Assert::IsTrue(m_settings->GetConfig(actualBuffer, &actualBufferSize));
|
||||
Assert::AreEqual(expectedSize, actualBufferSize);
|
||||
}
|
||||
FancyZonesSettings::instance().LoadSettings();
|
||||
auto actual = FancyZonesSettings::settings();
|
||||
compareSettings(m_defaultSettings, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD (GetConfigSmallBuffer)
|
||||
{
|
||||
int size = 0;
|
||||
m_settings->GetConfig(nullptr, &size);
|
||||
Assert::AreNotEqual(0, size);
|
||||
|
||||
int actualBufferSize = size - 1;
|
||||
PWSTR actualBuffer = new wchar_t[actualBufferSize];
|
||||
|
||||
Assert::IsFalse(m_settings->GetConfig(actualBuffer, &actualBufferSize));
|
||||
Assert::AreEqual(size, actualBufferSize);
|
||||
}
|
||||
|
||||
TEST_METHOD (GetConfigNullBuffer)
|
||||
{
|
||||
int expectedSize = 0;
|
||||
m_settings->GetConfig(nullptr, &expectedSize);
|
||||
Assert::AreNotEqual(0, expectedSize);
|
||||
|
||||
int actualBufferSize = 0;
|
||||
|
||||
Assert::IsFalse(m_settings->GetConfig(nullptr, &actualBufferSize));
|
||||
Assert::AreEqual(expectedSize, actualBufferSize);
|
||||
}
|
||||
|
||||
TEST_METHOD (SetConfig)
|
||||
{
|
||||
//cleanup file before call set config
|
||||
const auto settingsFile = PTSettingsHelper::get_module_save_folder_location(m_moduleName) + L"\\settings.json";
|
||||
std::filesystem::remove(settingsFile);
|
||||
|
||||
const Settings expected{
|
||||
.shiftDrag = true,
|
||||
.mouseSwitch = true,
|
||||
.displayChange_moveWindows = true,
|
||||
.zoneSetChange_flashZones = false,
|
||||
.zoneSetChange_moveWindows = true,
|
||||
.overrideSnapHotkeys = false,
|
||||
.moveWindowAcrossMonitors = false,
|
||||
.appLastZone_moveWindows = true,
|
||||
.openWindowOnActiveMonitor = false,
|
||||
.restoreSize = false,
|
||||
.use_cursorpos_editor_startupscreen = true,
|
||||
.showZonesOnAllMonitors = false,
|
||||
.spanZonesAcrossMonitors = false,
|
||||
.makeDraggedWindowTransparent = true,
|
||||
.zoneColor = L"#FAFAFA",
|
||||
.zoneBorderColor = L"CCDDEE",
|
||||
.zoneHighlightColor = L"#00AABB",
|
||||
.zoneHighlightOpacity = 45,
|
||||
.editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3),
|
||||
.nextTabHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_NEXT),
|
||||
.prevTabHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_PRIOR),
|
||||
.excludedApps = L"app\r\napp2",
|
||||
.excludedAppsArray = { L"APP", L"APP2" },
|
||||
};
|
||||
|
||||
auto config = serializedPowerToySettings(expected);
|
||||
m_settings->SetConfig(config.c_str());
|
||||
|
||||
auto actual = m_settings->GetSettings();
|
||||
compareSettings(expected, *actual);
|
||||
|
||||
Assert::IsTrue(std::filesystem::exists(settingsFile));
|
||||
}
|
||||
TEST_METHOD (ParseEmpty)
|
||||
{
|
||||
FancyZonesSettings::instance().LoadSettings();
|
||||
auto actual = FancyZonesSettings::settings();
|
||||
compareSettings(m_defaultSettings, actual);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <FancyZonesLib/FancyZonesData/AppZoneHistory.h>
|
||||
#include <FancyZonesLib/FancyZonesDataTypes.h>
|
||||
#include <FancyZonesLib/JsonHelpers.h>
|
||||
#include <FancyZonesLib/ZoneColors.h>
|
||||
#include "Util.h"
|
||||
|
||||
#include <common/utils/process_path.h>
|
||||
@ -31,9 +30,6 @@ namespace FancyZonesUnitTests
|
||||
HMONITOR m_monitor{};
|
||||
MONITORINFOEX m_monitorInfo{};
|
||||
GUID m_virtualDesktopGuid{};
|
||||
ZoneColors m_zoneColors{};
|
||||
OverlappingZonesAlgorithm m_overlappingAlgorithm = OverlappingZonesAlgorithm::Positional;
|
||||
bool m_showZoneText = true;
|
||||
|
||||
void testWorkArea(winrt::com_ptr<IWorkArea> workArea)
|
||||
{
|
||||
@ -65,13 +61,6 @@ namespace FancyZonesUnitTests
|
||||
Assert::IsTrue(guid.has_value());
|
||||
m_virtualDesktopGuid = *guid;
|
||||
|
||||
m_zoneColors = ZoneColors{
|
||||
.primaryColor = FancyZonesUtils::HexToRGB(L"#4287f5"),
|
||||
.borderColor = FancyZonesUtils::HexToRGB(L"#FFFFFF"),
|
||||
.highlightColor = FancyZonesUtils::HexToRGB(L"#42eff5"),
|
||||
.highlightOpacity = 50,
|
||||
};
|
||||
|
||||
AppZoneHistory::instance().LoadData();
|
||||
AppliedLayouts::instance().LoadData();
|
||||
}
|
||||
@ -84,7 +73,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (CreateWorkArea)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
testWorkArea(workArea);
|
||||
|
||||
auto* zoneSet{ workArea->ZoneSet() };
|
||||
@ -95,7 +84,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (CreateWorkAreaNoHinst)
|
||||
{
|
||||
auto workArea = MakeWorkArea({}, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea({}, m_monitor, m_uniqueId, {});
|
||||
testWorkArea(workArea);
|
||||
|
||||
auto* zoneSet{ workArea->ZoneSet() };
|
||||
@ -106,7 +95,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (CreateWorkAreaNoHinstFlashZones)
|
||||
{
|
||||
auto workArea = MakeWorkArea({}, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea({}, m_monitor, m_uniqueId, {});
|
||||
testWorkArea(workArea);
|
||||
|
||||
auto* zoneSet{ workArea->ZoneSet() };
|
||||
@ -117,7 +106,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (CreateWorkAreaNoMonitor)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, {}, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, {}, m_uniqueId, {});
|
||||
testWorkArea(workArea);
|
||||
}
|
||||
|
||||
@ -136,7 +125,7 @@ namespace FancyZonesUnitTests
|
||||
uniqueIdData.height = monitorRect.height();
|
||||
}
|
||||
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, uniqueIdData, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, uniqueIdData, {});
|
||||
|
||||
const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom);
|
||||
const FancyZonesDataTypes::DeviceIdData expectedUniqueId{ L"FallbackDevice", m_monitorInfo.rcMonitor.right - m_monitorInfo.rcMonitor.left, m_monitorInfo.rcMonitor.bottom - m_monitorInfo.rcMonitor.top, m_virtualDesktopGuid };
|
||||
@ -165,7 +154,7 @@ namespace FancyZonesUnitTests
|
||||
uniqueId.height = monitorRect.height();
|
||||
}
|
||||
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, uniqueId, {});
|
||||
|
||||
const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom);
|
||||
Assert::IsNotNull(workArea.get());
|
||||
@ -185,10 +174,10 @@ namespace FancyZonesUnitTests
|
||||
const int zoneCount = 5;
|
||||
const auto customSetGuid = Helpers::CreateGuidString();
|
||||
|
||||
auto parentWorkArea = MakeWorkArea(m_hInst, m_monitor, m_parentUniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto parentWorkArea = MakeWorkArea(m_hInst, m_monitor, m_parentUniqueId, {});
|
||||
|
||||
// newWorkArea = false - workArea won't be cloned from parent
|
||||
auto actualWorkArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto actualWorkArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
Assert::IsNotNull(actualWorkArea->ZoneSet());
|
||||
|
||||
@ -209,9 +198,6 @@ namespace FancyZonesUnitTests
|
||||
HINSTANCE m_hInst{};
|
||||
HMONITOR m_monitor{};
|
||||
MONITORINFO m_monitorInfo{};
|
||||
ZoneColors m_zoneColors{};
|
||||
OverlappingZonesAlgorithm m_overlappingAlgorithm = OverlappingZonesAlgorithm::Positional;
|
||||
bool m_showZoneText = true;
|
||||
|
||||
TEST_METHOD_INITIALIZE(Init)
|
||||
{
|
||||
@ -225,13 +211,6 @@ namespace FancyZonesUnitTests
|
||||
m_uniqueId.width = m_monitorInfo.rcMonitor.right - m_monitorInfo.rcMonitor.left;
|
||||
m_uniqueId.height = m_monitorInfo.rcMonitor.bottom - m_monitorInfo.rcMonitor.top;
|
||||
CLSIDFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", &m_uniqueId.virtualDesktopId);
|
||||
|
||||
m_zoneColors = ZoneColors{
|
||||
.primaryColor = FancyZonesUtils::HexToRGB(L"#4287f5"),
|
||||
.borderColor = FancyZonesUtils::HexToRGB(L"#FFFFFF"),
|
||||
.highlightColor = FancyZonesUtils::HexToRGB(L"#42eff5"),
|
||||
.highlightOpacity = 50,
|
||||
};
|
||||
|
||||
AppZoneHistory::instance().LoadData();
|
||||
AppliedLayouts::instance().LoadData();
|
||||
@ -246,7 +225,7 @@ namespace FancyZonesUnitTests
|
||||
public:
|
||||
TEST_METHOD (MoveSizeEnter)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = workArea->MoveSizeEnter(Mocks::Window());
|
||||
@ -256,7 +235,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeEnterTwice)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto expected = S_OK;
|
||||
|
||||
@ -268,7 +247,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeUpdate)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = workArea->MoveSizeUpdate(POINT{ 0, 0 }, true, false);
|
||||
@ -278,7 +257,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeUpdatePointNegativeCoordinates)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = workArea->MoveSizeUpdate(POINT{ -10, -10 }, true, false);
|
||||
@ -288,7 +267,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeUpdatePointBigCoordinates)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto expected = S_OK;
|
||||
const auto actual = workArea->MoveSizeUpdate(POINT{ m_monitorInfo.rcMonitor.right + 1, m_monitorInfo.rcMonitor.bottom + 1 }, true, false);
|
||||
@ -298,7 +277,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeEnd)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto window = Mocks::Window();
|
||||
workArea->MoveSizeEnter(window);
|
||||
@ -315,7 +294,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeEndWindowNotAdded)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto window = Mocks::Window();
|
||||
workArea->MoveSizeEnter(window);
|
||||
@ -331,7 +310,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeEndDifferentWindows)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto window = Mocks::Window();
|
||||
workArea->MoveSizeEnter(window);
|
||||
@ -344,7 +323,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeEndWindowNotSet)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto expected = E_INVALIDARG;
|
||||
const auto actual = workArea->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 });
|
||||
@ -354,7 +333,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveSizeEndInvalidPoint)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
|
||||
const auto window = Mocks::Window();
|
||||
workArea->MoveSizeEnter(window);
|
||||
@ -371,7 +350,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveWindowIntoZoneByIndex)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
Assert::IsNotNull(workArea->ZoneSet());
|
||||
|
||||
workArea->MoveWindowIntoZoneByIndex(Mocks::Window(), 0);
|
||||
@ -381,7 +360,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveWindowIntoZoneByDirectionAndIndex)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
Assert::IsNotNull(workArea->ZoneSet());
|
||||
|
||||
const auto window = Mocks::WindowCreate(m_hInst);
|
||||
@ -396,7 +375,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (MoveWindowIntoZoneByDirectionManyTimes)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
Assert::IsNotNull(workArea->ZoneSet());
|
||||
|
||||
const auto window = Mocks::WindowCreate(m_hInst);
|
||||
@ -413,7 +392,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (SaveWindowProcessToZoneIndexNullptrWindow)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
Assert::IsNotNull(workArea->ZoneSet());
|
||||
|
||||
workArea->SaveWindowProcessToZoneIndex(nullptr);
|
||||
@ -424,7 +403,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (SaveWindowProcessToZoneIndexNoWindowAdded)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
Assert::IsNotNull(workArea->ZoneSet());
|
||||
|
||||
auto window = Mocks::WindowCreate(m_hInst);
|
||||
@ -439,7 +418,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (SaveWindowProcessToZoneIndexNoWindowAddedWithFilledAppZoneHistory)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
Assert::IsNotNull(workArea->ZoneSet());
|
||||
|
||||
const auto window = Mocks::WindowCreate(m_hInst);
|
||||
@ -467,7 +446,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (SaveWindowProcessToZoneIndexWindowAdded)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
Assert::IsNotNull(workArea->ZoneSet());
|
||||
|
||||
auto window = Mocks::WindowCreate(m_hInst);
|
||||
@ -497,7 +476,7 @@ namespace FancyZonesUnitTests
|
||||
|
||||
TEST_METHOD (WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt)
|
||||
{
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {}, m_zoneColors, m_overlappingAlgorithm, m_showZoneText);
|
||||
auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId, {});
|
||||
Assert::IsNotNull(workArea->ZoneSet());
|
||||
|
||||
auto window = Mocks::WindowCreate(m_hInst);
|
||||
|
@ -43,6 +43,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
FancyzonesNextTabHotkey = new KeyboardKeysProperty(DefaultNextTabHotkeyValue);
|
||||
FancyzonesPrevTabHotkey = new KeyboardKeysProperty(DefaultPrevTabHotkeyValue);
|
||||
FancyzonesMakeDraggedWindowTransparent = new BoolProperty();
|
||||
FancyzonesAllowPopupWindowSnap = new BoolProperty();
|
||||
FancyzonesAllowChildWindowSnap = new BoolProperty();
|
||||
FancyzonesExcludedApps = new StringProperty();
|
||||
FancyzonesInActiveColor = new StringProperty(ConfigDefaults.DefaultFancyZonesInActiveColor);
|
||||
FancyzonesBorderColor = new StringProperty(ConfigDefaults.DefaultFancyzonesBorderColor);
|
||||
@ -102,6 +104,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("fancyzones_makeDraggedWindowTransparent")]
|
||||
public BoolProperty FancyzonesMakeDraggedWindowTransparent { get; set; }
|
||||
|
||||
[JsonPropertyName("fancyzones_allowPopupWindowSnap")]
|
||||
public BoolProperty FancyzonesAllowPopupWindowSnap { get; set; }
|
||||
|
||||
[JsonPropertyName("fancyzones_allowChildWindowSnap")]
|
||||
public BoolProperty FancyzonesAllowChildWindowSnap { get; set; }
|
||||
|
||||
[JsonPropertyName("fancyzones_zoneHighlightColor")]
|
||||
public StringProperty FancyzonesZoneHighlightColor { get; set; }
|
||||
|
||||
|
@ -84,6 +84,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
_showOnAllMonitors = Settings.Properties.FancyzonesShowOnAllMonitors.Value;
|
||||
_spanZonesAcrossMonitors = Settings.Properties.FancyzonesSpanZonesAcrossMonitors.Value;
|
||||
_makeDraggedWindowTransparent = Settings.Properties.FancyzonesMakeDraggedWindowTransparent.Value;
|
||||
_allowPopupWindowSnap = Settings.Properties.FancyzonesAllowPopupWindowSnap.Value;
|
||||
_allowChildWindowSnap = Settings.Properties.FancyzonesAllowChildWindowSnap.Value;
|
||||
_highlightOpacity = Settings.Properties.FancyzonesHighlightOpacity.Value;
|
||||
_excludedApps = Settings.Properties.FancyzonesExcludedApps.Value;
|
||||
_systemTheme = Settings.Properties.FancyzonesSystemTheme.Value;
|
||||
@ -131,6 +133,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
private bool _makeDraggedWindowTransparent;
|
||||
private bool _systemTheme;
|
||||
private bool _showZoneNumber;
|
||||
private bool _allowPopupWindowSnap;
|
||||
private bool _allowChildWindowSnap;
|
||||
|
||||
private int _highlightOpacity;
|
||||
private string _excludedApps;
|
||||
@ -562,6 +566,42 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool AllowPopupWindowSnap
|
||||
{
|
||||
get
|
||||
{
|
||||
return _allowPopupWindowSnap;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _allowPopupWindowSnap)
|
||||
{
|
||||
_allowPopupWindowSnap = value;
|
||||
Settings.Properties.FancyzonesAllowPopupWindowSnap.Value = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool AllowChildWindowSnap
|
||||
{
|
||||
get
|
||||
{
|
||||
return _allowChildWindowSnap;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _allowChildWindowSnap)
|
||||
{
|
||||
_allowChildWindowSnap = value;
|
||||
Settings.Properties.FancyzonesAllowChildWindowSnap.Value = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For the following setters we use OrdinalIgnoreCase string comparison since
|
||||
// we expect value to be a hex code.
|
||||
public string ZoneHighlightColor
|
||||
|
@ -2050,4 +2050,13 @@ From there, simply click on one of the supported files in the File Explorer and
|
||||
<value>Attribution</value>
|
||||
<comment>giving credit to the projects this utility was based on</comment>
|
||||
</data>
|
||||
<data name="FancyZones_AllowPopupWindowSnap.Description" xml:space="preserve">
|
||||
<value>This setting can affect all popup windows including notifications</value>
|
||||
</data>
|
||||
<data name="FancyZones_AllowPopupWindowSnap.Header" xml:space="preserve">
|
||||
<value>Allow popup windows snapping</value>
|
||||
</data>
|
||||
<data name="FancyZones_AllowChildWindowSnap.Content" xml:space="preserve">
|
||||
<value>Allow child windows snapping</value>
|
||||
</data>
|
||||
</root>
|
||||
|
@ -183,6 +183,12 @@
|
||||
<CheckBox x:Uid="FancyZones_RestoreSize" IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.RestoreSize}" Margin="{StaticResource ExpanderSettingMargin}"/>
|
||||
<Rectangle Style="{StaticResource ExpanderSeparatorStyle}" />
|
||||
<CheckBox x:Uid="FancyZones_MakeDraggedWindowTransparentCheckBoxControl" IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.MakeDraggedWindowsTransparent}" Margin="{StaticResource ExpanderSettingMargin}"/>
|
||||
<Rectangle Style="{StaticResource ExpanderSeparatorStyle}" />
|
||||
<controls:CheckBoxWithDescriptionControl IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.AllowPopupWindowSnap}"
|
||||
Margin="56, -2, 40, 14"
|
||||
x:Uid="FancyZones_AllowPopupWindowSnap"/>
|
||||
<Rectangle Style="{StaticResource ExpanderSeparatorStyle}" />
|
||||
<CheckBox x:Uid="FancyZones_AllowChildWindowSnap" IsChecked="{x:Bind Mode=TwoWay, Path=ViewModel.AllowChildWindowSnap}" Margin="{StaticResource ExpanderSettingMargin}"/>
|
||||
</StackPanel>
|
||||
|
||||
</controls:SettingExpander.Content>
|
||||
|
Loading…
Reference in New Issue
Block a user