diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index c33d8eb07b..ac5fdfb20f 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -1109,6 +1109,7 @@ IVirtual IWeb IWIC IWindows +IWork IXml ixx IYUV diff --git a/src/modules/fancyzones/FancyZones/FancyZonesApp.cpp b/src/modules/fancyzones/FancyZones/FancyZonesApp.cpp index d0730b60ce..2db09656d8 100644 --- a/src/modules/fancyzones/FancyZones/FancyZonesApp.cpp +++ b/src/modules/fancyzones/FancyZones/FancyZonesApp.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp index 1574c7f247..020852625c 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp @@ -1,4 +1,5 @@ #include "pch.h" +#include "FancyZones.h" #include #include @@ -9,17 +10,18 @@ #include #include -#include "FancyZones.h" -#include "FancyZonesLib/Settings.h" -#include "FancyZonesLib/ZoneWindow.h" -#include "FancyZonesLib/FancyZonesData.h" -#include "FancyZonesLib/ZoneSet.h" -#include "FancyZonesLib/WindowMoveHandler.h" -#include "FancyZonesLib/FancyZonesWinHookEventIDs.h" -#include "FancyZonesLib/util.h" +#include +#include +#include +#include +#include +#include +#include +#include + #include "on_thread_executor.h" #include "trace.h" -#include "VirtualDesktopUtils.h" +#include "VirtualDesktop.h" #include "MonitorWorkAreaHandler.h" #include "util.h" #include "CallTracer.h" @@ -34,44 +36,14 @@ enum class DisplayChangeType Initialization }; -namespace -{ - constexpr int CUSTOM_POSITIONING_LEFT_TOP_PADDING = 16; - - struct require_read_lock - { - template - require_read_lock(const std::shared_lock& lock) - { - lock; - } - - template - require_read_lock(const std::unique_lock& lock) - { - lock; - } - }; - - struct require_write_lock - { - template - require_write_lock(const std::unique_lock& lock) - { - lock; - } - }; -} - // Non-localizable strings namespace NonLocalizable { const wchar_t ToolWindowClassName[] = L"SuperFancyZones"; const wchar_t FZEditorExecutablePath[] = L"modules\\FancyZones\\FancyZonesEditor.exe"; - const wchar_t SplashClassName[] = L"MsoSplash"; } -struct FancyZones : public winrt::implements +struct FancyZones : public winrt::implements { public: FancyZones(HINSTANCE hinstance, const winrt::com_ptr& settings, std::function disableModuleCallback) noexcept : @@ -85,10 +57,14 @@ public: }), 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); + }, + [this]() { + PostMessage(m_window, WM_PRIV_VD_UPDATE, 0, 0); }) { - m_settings->SetCallback(this); - this->disableModuleCallback = std::move(disableModuleCallback); } @@ -100,7 +76,6 @@ public: void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept { - std::unique_lock writeLock(m_lock); if (m_settings->GetSettings()->spanZonesAcrossMonitors) { monitor = NULL; @@ -110,7 +85,6 @@ public: void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept { - std::unique_lock writeLock(m_lock); if (m_settings->GetSettings()->spanZonesAcrossMonitors) { monitor = NULL; @@ -121,7 +95,6 @@ public: void MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept { _TRACER_; - std::unique_lock writeLock(m_lock); m_windowMoveHandler.MoveSizeEnd(window, ptScreen, m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId)); } @@ -130,7 +103,6 @@ public: { const auto wparam = reinterpret_cast(data->hwnd); const LONG lparam = 0; - std::shared_lock readLock(m_lock); switch (data->event) { case EVENT_SYSTEM_MOVESIZESTART: @@ -159,100 +131,53 @@ public: IFACEMETHODIMP_(void) VirtualDesktopChanged() noexcept; - IFACEMETHODIMP_(void) - VirtualDesktopInitialize() noexcept; IFACEMETHODIMP_(bool) OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept; - IFACEMETHODIMP_(void) - ToggleEditor() noexcept; - IFACEMETHODIMP_(void) - SettingsChanged() noexcept; void WindowCreated(HWND window) noexcept; - - // IZoneWindowHost - IFACEMETHODIMP_(void) - MoveWindowsOnActiveZoneSetChange() noexcept; - IFACEMETHODIMP_(COLORREF) - GetZoneColor() noexcept - { - return (FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneColor)); - } - IFACEMETHODIMP_(COLORREF) - GetZoneBorderColor() noexcept - { - return (FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneBorderColor)); - } - IFACEMETHODIMP_(COLORREF) - GetZoneHighlightColor() noexcept - { - return (FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneHighlightColor)); - } - IFACEMETHODIMP_(int) - GetZoneHighlightOpacity() noexcept - { - return m_settings->GetSettings()->zoneHighlightOpacity; - } - - IFACEMETHODIMP_(bool) - isMakeDraggedWindowTransparentActive() noexcept - { - return m_settings->GetSettings()->makeDraggedWindowTransparent; - } - - IFACEMETHODIMP_(bool) - InMoveSize() noexcept - { - std::shared_lock readLock(m_lock); - return m_windowMoveHandler.InMoveSize(); - } - - IFACEMETHODIMP_(Settings::OverlappingZonesAlgorithm) - GetOverlappingZonesAlgorithm() noexcept - { - return m_settings->GetSettings()->overlappingZonesAlgorithm; - } + void ToggleEditor() noexcept; LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept; - void OnDisplayChange(DisplayChangeType changeType, require_write_lock) noexcept; - void AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId, require_write_lock) noexcept; + void OnDisplayChange(DisplayChangeType changeType) noexcept; + void AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId) noexcept; protected: static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept; private: - void UpdateZoneWindows(require_write_lock) noexcept; - void UpdateWindowsPositions(require_write_lock) noexcept; + void UpdateZoneWindows() noexcept; + void UpdateWindowsPositions() noexcept; bool OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexcept; bool OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept; bool OnSnapHotkey(DWORD vkCode) noexcept; - bool ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; + bool ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; - void RegisterVirtualDesktopUpdates(std::vector& ids) noexcept; + void RegisterVirtualDesktopUpdates() noexcept; - bool IsSplashScreen(HWND window); - bool ShouldProcessNewWindow(HWND window) noexcept; - std::vector GetZoneIndexSetFromWorkAreaHistory(HWND window, winrt::com_ptr workArea) noexcept; - std::pair, std::vector> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, std::unordered_map>& workAreaMap) noexcept; - std::pair, std::vector> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept; - void MoveWindowIntoZone(HWND window, winrt::com_ptr zoneWindow, const std::vector& zoneIndexSet) noexcept; + void OnSettingsChanged() noexcept; - void OnEditorExitEvent(require_write_lock) noexcept; - void UpdateZoneSets(require_write_lock) noexcept; + std::pair, std::vector> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, std::unordered_map>& workAreaMap) noexcept; + std::pair, std::vector> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept; + void MoveWindowIntoZone(HWND window, winrt::com_ptr zoneWindow, const std::vector& zoneIndexSet) noexcept; + + void OnEditorExitEvent() noexcept; + void UpdateZoneSets() noexcept; bool ShouldProcessSnapHotkey(DWORD vkCode) noexcept; void ApplyQuickLayout(int key) noexcept; - void FlashZones(require_write_lock) noexcept; + void FlashZones() noexcept; std::vector> GetRawMonitorData() noexcept; std::vector GetMonitorsSorted() noexcept; HMONITOR WorkAreaKeyFromWindow(HWND window) noexcept; + ZoneColors GetZoneColors() const noexcept; + const HINSTANCE m_hinstance{}; - mutable std::shared_mutex m_lock; HWND m_window{}; WindowMoveHandler m_windowMoveHandler; MonitorWorkAreaHandler m_workAreaHandler; + VirtualDesktop m_virtualDesktop; FileWatcher m_zonesSettingsFileWatcher; FileWatcher m_settingsFileWatcher; @@ -261,26 +186,14 @@ private: 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 - wil::unique_handle m_terminateVirtualDesktopTrackerEvent; OnThreadExecutor m_dpiUnawareThread; - OnThreadExecutor m_virtualDesktopTrackerThread; EventWaiter m_toggleEditorEventWaiter; // If non-recoverable error occurs, trigger disabling of entire FancyZones. static std::function disableModuleCallback; - static UINT WM_PRIV_VD_INIT; // Scheduled when FancyZones is initialized - static UINT WM_PRIV_VD_SWITCH; // Scheduled when virtual desktop switch occurs - static UINT WM_PRIV_VD_UPDATE; // Scheduled on virtual desktops update (creation/deletion) - static UINT WM_PRIV_EDITOR; // Scheduled when the editor exits - static UINT WM_PRIV_FILE_UPDATE; // Scheduled when the a watched file is updated - static UINT WM_PRIV_SETTINGS_CHANGED; - - static UINT WM_PRIV_SNAP_HOTKEY; // Scheduled when we receive a snap hotkey key down press - static UINT WM_PRIV_QUICK_LAYOUT_KEY; // Scheduled when we receive a key down press to quickly apply a layout - // Did we terminate the editor or was it closed cleanly? enum class EditorExitKind : byte { @@ -291,21 +204,10 @@ private: std::function FancyZones::disableModuleCallback = {}; -UINT FancyZones::WM_PRIV_VD_INIT = RegisterWindowMessage(L"{469818a8-00fa-4069-b867-a1da484fcd9a}"); -UINT FancyZones::WM_PRIV_VD_SWITCH = RegisterWindowMessage(L"{128c2cb0-6bdf-493e-abbe-f8705e04aa95}"); -UINT FancyZones::WM_PRIV_VD_UPDATE = RegisterWindowMessage(L"{b8b72b46-f42f-4c26-9e20-29336cf2f22e}"); -UINT FancyZones::WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}"); -UINT FancyZones::WM_PRIV_FILE_UPDATE = RegisterWindowMessage(L"{632f17a9-55a7-45f1-a4db-162e39271d92}"); -UINT FancyZones::WM_PRIV_SNAP_HOTKEY = RegisterWindowMessage(L"{763c03a3-03d9-4cde-8d71-f0358b0b4b52}"); -UINT FancyZones::WM_PRIV_QUICK_LAYOUT_KEY = RegisterWindowMessage(L"{72f4fd8e-23f1-43ab-bbbc-029363df9a84}"); -UINT FancyZones::WM_PRIV_SETTINGS_CHANGED = RegisterWindowMessage(L"{15baab3d-c67b-4a15-aFF0-13610e05e947}"); - // IFancyZones IFACEMETHODIMP_(void) FancyZones::Run() noexcept { - std::unique_lock writeLock(m_lock); - WNDCLASSEXW wcex{}; wcex.cbSize = sizeof(WNDCLASSEX); wcex.lpfnWndProc = s_WndProc; @@ -323,7 +225,7 @@ FancyZones::Run() noexcept RegisterHotKey(m_window, 1, m_settings->GetSettings()->editorHotkey.get_modifiers(), m_settings->GetSettings()->editorHotkey.get_code()); - VirtualDesktopInitialize(); + m_virtualDesktop.Init(); m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [] { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE); @@ -331,9 +233,6 @@ FancyZones::Run() noexcept } }) .wait(); - m_terminateVirtualDesktopTrackerEvent.reset(CreateEvent(nullptr, FALSE, FALSE, nullptr)); - m_virtualDesktopTrackerThread.submit(OnThreadExecutor::task_t{ [&] { VirtualDesktopUtils::HandleVirtualDesktopUpdates(m_window, WM_PRIV_VD_UPDATE, m_terminateVirtualDesktopTrackerEvent.get()); } }); - m_toggleEditorEventWaiter = EventWaiter(CommonSharedConstants::FANCY_ZONES_EDITOR_TOGGLE_EVENT, [&](int err) { if (err == ERROR_SUCCESS) { @@ -347,7 +246,6 @@ FancyZones::Run() noexcept IFACEMETHODIMP_(void) FancyZones::Destroy() noexcept { - std::unique_lock writeLock(m_lock); m_workAreaHandler.Clear(); BufferedPaintUnInit(); if (m_window) @@ -355,12 +253,8 @@ FancyZones::Destroy() noexcept DestroyWindow(m_window); m_window = nullptr; } - if (m_terminateVirtualDesktopTrackerEvent) - { - SetEvent(m_terminateVirtualDesktopTrackerEvent.get()); - } - m_settings->ResetCallback(); + m_virtualDesktop.UnInit(); } // IFancyZonesCallback @@ -372,60 +266,23 @@ FancyZones::VirtualDesktopChanged() noexcept PostMessage(m_window, WM_PRIV_VD_SWITCH, 0, 0); } -// IFancyZonesCallback -IFACEMETHODIMP_(void) -FancyZones::VirtualDesktopInitialize() noexcept -{ - PostMessage(m_window, WM_PRIV_VD_INIT, 0, 0); -} - -bool FancyZones::ShouldProcessNewWindow(HWND window) noexcept -{ - using namespace FancyZonesUtils; - // Avoid processing splash screens, already stamped (zoned) windows, or those windows - // that belong to excluded applications list. - if (IsSplashScreen(window) || - (reinterpret_cast(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)) != 0) || - !IsCandidateForLastKnownZone(window, m_settings->GetSettings()->excludedAppsArray)) - { - return false; - } - return true; -} - -std::vector FancyZones::GetZoneIndexSetFromWorkAreaHistory( - HWND window, - winrt::com_ptr workArea) noexcept -{ - const auto activeZoneSet = workArea->ActiveZoneSet(); - if (activeZoneSet) - { - wil::unique_cotaskmem_string zoneSetId; - if (SUCCEEDED(StringFromCLSID(activeZoneSet->Id(), &zoneSetId))) - { - return FancyZonesDataInstance().GetAppLastZoneIndexSet(window, workArea->UniqueId(), zoneSetId.get()); - } - } - return {}; -} - -std::pair, std::vector> FancyZones::GetAppZoneHistoryInfo( +std::pair, std::vector> FancyZones::GetAppZoneHistoryInfo( HWND window, HMONITOR monitor, - std::unordered_map>& workAreaMap) noexcept + std::unordered_map>& workAreaMap) noexcept { if (workAreaMap.contains(monitor)) { auto workArea = workAreaMap[monitor]; workAreaMap.erase(monitor); // monitor processed, remove entry from the map - return { workArea, GetZoneIndexSetFromWorkAreaHistory(window, workArea) }; + return { workArea, workArea->GetWindowZoneIndexes(window) }; } return { nullptr, {} }; } -std::pair, std::vector> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept +std::pair, std::vector> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept { - std::pair, std::vector> appZoneHistoryInfo{ nullptr, {} }; + std::pair, std::vector> appZoneHistoryInfo{ nullptr, {} }; auto workAreaMap = m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId); // Search application history on currently active monitor. @@ -436,7 +293,7 @@ std::pair, std::vector> FancyZones::GetAppZo // No application history on primary monitor, search on remaining monitors. for (const auto& [monitor, workArea] : workAreaMap) { - auto zoneIndexSet = GetZoneIndexSetFromWorkAreaHistory(window, workArea); + auto zoneIndexSet = workArea->GetWindowZoneIndexes(window); if (!zoneIndexSet.empty()) { return { workArea, zoneIndexSet }; @@ -447,7 +304,7 @@ std::pair, std::vector> FancyZones::GetAppZo return appZoneHistoryInfo; } -void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr zoneWindow, const std::vector& zoneIndexSet) noexcept +void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr zoneWindow, const std::vector& zoneIndexSet) noexcept { _TRACER_; auto& fancyZonesData = FancyZonesDataInstance(); @@ -458,88 +315,27 @@ void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr zon } } -inline int RectWidth(const RECT& rect) +void FancyZones::WindowCreated(HWND window) noexcept { - return rect.right - rect.left; -} - -inline int RectHeight(const RECT& rect) -{ - return rect.bottom - rect.top; -} - -RECT FitOnScreen(const RECT& windowRect, const RECT& originMonitorRect, const RECT& destMonitorRect) -{ - // New window position on active monitor. If window fits the screen, this will be final position. - int left = destMonitorRect.left + (windowRect.left - originMonitorRect.left); - int top = destMonitorRect.top + (windowRect.top - originMonitorRect.top); - int W = RectWidth(windowRect); - int H = RectHeight(windowRect); - - if ((left < destMonitorRect.left) || (left + W > destMonitorRect.right)) - { - // Set left window border to left border of screen (add padding). Resize window width if needed. - left = destMonitorRect.left + CUSTOM_POSITIONING_LEFT_TOP_PADDING; - W = min(W, RectWidth(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING); - } - if ((top < destMonitorRect.top) || (top + H > destMonitorRect.bottom)) - { - // Set top window border to top border of screen (add padding). Resize window height if needed. - top = destMonitorRect.top + CUSTOM_POSITIONING_LEFT_TOP_PADDING; - H = min(H, RectHeight(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING); - } - - return { .left = left, - .top = top, - .right = left + W, - .bottom = top + H }; -} - -void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept -{ - // By default Windows opens new window on primary monitor. - // Try to preserve window width and height, adjust top-left corner if needed. - HMONITOR origin = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); - if (origin == monitor) - { - // Certain applications by design open in last known position, regardless of FancyZones. - // If that position is on currently active monitor, skip custom positioning. - return; - } - - WINDOWPLACEMENT placement{}; - if (GetWindowPlacement(window, &placement)) - { - MONITORINFOEX originMi; - originMi.cbSize = sizeof(originMi); - if (GetMonitorInfo(origin, &originMi)) - { - MONITORINFOEX destMi; - destMi.cbSize = sizeof(destMi); - if (GetMonitorInfo(monitor, &destMi)) - { - RECT newPosition = FitOnScreen(placement.rcNormalPosition, originMi.rcWork, destMi.rcWork); - FancyZonesUtils::SizeWindowToRect(window, newPosition); - } - } - } -} - -// IFancyZonesCallback -IFACEMETHODIMP_(void) -FancyZones::WindowCreated(HWND window) noexcept -{ - std::shared_lock readLock(m_lock); - GUID desktopId{}; - if (VirtualDesktopUtils::GetWindowDesktopId(window, &desktopId) && desktopId != m_currentDesktopId) + auto desktopId = m_virtualDesktop.GetWindowDesktopId(window); + if (desktopId.has_value() && *desktopId != m_currentDesktopId) { // Switch between virtual desktops results with posting same windows messages that also indicate // creation of new window. We need to check if window being processed is on currently active desktop. return; } + const bool moveToAppLastZone = m_settings->GetSettings()->appLastZone_moveWindows; const bool openOnActiveMonitor = m_settings->GetSettings()->openWindowOnActiveMonitor; - if ((moveToAppLastZone || openOnActiveMonitor) && ShouldProcessNewWindow(window)) + + // 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 isZoned = reinterpret_cast(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)) != 0; + const bool isCandidateForLastKnownZone = FancyZonesUtils::IsCandidateForLastKnownZone(window, m_settings->GetSettings()->excludedAppsArray); + const bool shouldProcessNewWindow = !isSplashScreen && !isZoned && isCandidateForLastKnownZone; + + if ((moveToAppLastZone || openOnActiveMonitor) && shouldProcessNewWindow) { HMONITOR primary = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY); HMONITOR active = primary; @@ -553,8 +349,8 @@ FancyZones::WindowCreated(HWND window) noexcept bool windowZoned{ false }; if (moveToAppLastZone) { - const bool primaryActive = primary == active; - std::pair, std::vector> appZoneHistoryInfo = GetAppZoneHistoryInfo(window, active, primaryActive); + const bool primaryActive = (primary == active); + std::pair, std::vector> appZoneHistoryInfo = GetAppZoneHistoryInfo(window, active, primaryActive); const bool windowMinimized = IsIconic(window); if (!appZoneHistoryInfo.second.empty() && !windowMinimized) { @@ -564,7 +360,7 @@ FancyZones::WindowCreated(HWND window) noexcept } if (!windowZoned && openOnActiveMonitor) { - m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] { OpenWindowOnActiveMonitor(window, active); } }).wait(); + m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] { MonitorUtils::OpenWindowOnActiveMonitor(window, active); } }).wait(); } } } @@ -627,25 +423,17 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept return false; } -// IFancyZonesCallback void FancyZones::ToggleEditor() noexcept { _TRACER_; + + if (m_terminateEditorEvent) { - std::shared_lock readLock(m_lock); - if (m_terminateEditorEvent) - { - SetEvent(m_terminateEditorEvent.get()); - return; - } + SetEvent(m_terminateEditorEvent.get()); + return; } - { - std::unique_lock writeLock(m_lock); - m_terminateEditorEvent.reset(CreateEvent(nullptr, true, false, nullptr)); - } - - std::shared_lock readLock(m_lock); + m_terminateEditorEvent.reset(CreateEvent(nullptr, true, false, nullptr)); HMONITOR targetMonitor{}; @@ -794,38 +582,6 @@ void FancyZones::ToggleEditor() noexcept waitForEditorThread.detach(); } -void FancyZones::SettingsChanged() noexcept -{ - _TRACER_; - std::unique_lock writeLock(m_lock); - - // Update the hotkey - UnregisterHotKey(m_window, 1); - auto modifiers = m_settings->GetSettings()->editorHotkey.get_modifiers(); - auto code = m_settings->GetSettings()->editorHotkey.get_code(); - auto result = RegisterHotKey(m_window, 1, modifiers, code); - - if (!result) - { - Logger::error(L"Failed to register hotkey: {}", get_last_error_or_default(GetLastError())); - } - - // Needed if we toggled spanZonesAcrossMonitors - m_workAreaHandler.Clear(); - - PostMessageW(m_window, WM_PRIV_VD_INIT, NULL, NULL); -} - -// IZoneWindowHost -IFACEMETHODIMP_(void) -FancyZones::MoveWindowsOnActiveZoneSetChange() noexcept -{ - if (m_settings->GetSettings()->zoneSetChange_moveWindows) - { - std::unique_lock writeLock(m_lock); - UpdateWindowsPositions(writeLock); - } -} LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept { @@ -846,9 +602,8 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa { // Changes in taskbar position resulted in different size of work area. // Invalidate cached work-areas so they can be recreated with latest information. - std::unique_lock writeLock(m_lock); m_workAreaHandler.Clear(); - OnDisplayChange(DisplayChangeType::WorkArea, writeLock); + OnDisplayChange(DisplayChangeType::WorkArea); } } break; @@ -856,9 +611,8 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa case WM_DISPLAYCHANGE: { // Display resolution changed. Invalidate cached work-areas so they can be recreated with latest information. - std::unique_lock writeLock(m_lock); m_workAreaHandler.Clear(); - OnDisplayChange(DisplayChangeType::DisplayChange, writeLock); + OnDisplayChange(DisplayChangeType::DisplayChange); } break; @@ -873,33 +627,25 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa } else if (message == WM_PRIV_VD_INIT) { - std::unique_lock writeLock(m_lock); - OnDisplayChange(DisplayChangeType::Initialization, writeLock); + OnDisplayChange(DisplayChangeType::Initialization); } else if (message == WM_PRIV_VD_SWITCH) { - std::unique_lock writeLock(m_lock); - OnDisplayChange(DisplayChangeType::VirtualDesktop, writeLock); + OnDisplayChange(DisplayChangeType::VirtualDesktop); } else if (message == WM_PRIV_VD_UPDATE) { - std::vector ids{}; - if (VirtualDesktopUtils::GetVirtualDesktopIds(ids)) - { - RegisterVirtualDesktopUpdates(ids); - } + RegisterVirtualDesktopUpdates(); } else if (message == WM_PRIV_EDITOR) { if (lparam == static_cast(EditorExitKind::Exit)) { - std::unique_lock writeLock(m_lock); - OnEditorExitEvent(writeLock); + OnEditorExitEvent(); } { // Clean up the event either way - std::unique_lock writeLock(m_lock); m_terminateEditorEvent.release(); } } @@ -916,11 +662,14 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa auto hwnd = reinterpret_cast(wparam); MoveSizeEnd(hwnd, ptScreen); } - else if (message == WM_PRIV_LOCATIONCHANGE && InMoveSize()) + else if (message == WM_PRIV_LOCATIONCHANGE) { - if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL)) + if (m_windowMoveHandler.InMoveSize()) { - MoveSizeUpdate(monitor, ptScreen); + if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL)) + { + MoveSizeUpdate(monitor, ptScreen); + } } } else if (message == WM_PRIV_WINDOWCREATED) @@ -931,8 +680,7 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa else if (message == WM_PRIV_FILE_UPDATE) { FancyZonesDataInstance().LoadFancyZonesData(); - std::unique_lock writeLock(m_lock); - UpdateZoneSets(writeLock); + UpdateZoneSets(); } else if (message == WM_PRIV_QUICK_LAYOUT_KEY) { @@ -940,7 +688,7 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa } else if (message == WM_PRIV_SETTINGS_CHANGED) { - m_settings->ReloadSettings(); + OnSettingsChanged(); } else { @@ -952,45 +700,41 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa return 0; } -void FancyZones::OnDisplayChange(DisplayChangeType changeType, require_write_lock lock) noexcept +void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept { _TRACER_; if (changeType == DisplayChangeType::VirtualDesktop || changeType == DisplayChangeType::Initialization) { m_previousDesktopId = m_currentDesktopId; - GUID currentVirtualDesktopId{}; - if (VirtualDesktopUtils::GetCurrentVirtualDesktopId(¤tVirtualDesktopId)) + auto currentVirtualDesktopId = m_virtualDesktop.GetCurrentVirtualDesktopId(); + if (currentVirtualDesktopId.has_value()) { - m_currentDesktopId = currentVirtualDesktopId; + m_currentDesktopId = *currentVirtualDesktopId; if (m_previousDesktopId != GUID_NULL && m_currentDesktopId != m_previousDesktopId) { Trace::VirtualDesktopChanged(); } } + if (changeType == DisplayChangeType::Initialization) { - std::vector ids{}; - if (VirtualDesktopUtils::GetVirtualDesktopIds(ids) && !ids.empty()) - { - FancyZonesDataInstance().UpdatePrimaryDesktopData(ids[0]); - FancyZonesDataInstance().RemoveDeletedDesktops(ids); - } + RegisterVirtualDesktopUpdates(); } } - UpdateZoneWindows(lock); + UpdateZoneWindows(); if ((changeType == DisplayChangeType::WorkArea) || (changeType == DisplayChangeType::DisplayChange)) { if (m_settings->GetSettings()->displayChange_moveWindows) { - UpdateWindowsPositions(lock); + UpdateWindowsPositions(); } } } -void FancyZones::AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId, require_write_lock) noexcept +void FancyZones::AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId) noexcept { _TRACER_; if (m_workAreaHandler.IsNewWorkArea(m_currentDesktopId, monitor)) @@ -1015,7 +759,8 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId, r { parentId = parentArea->UniqueId(); } - auto workArea = MakeZoneWindow(this, m_hinstance, monitor, uniqueId, parentId); + + auto workArea = MakeWorkArea(m_hinstance, monitor, uniqueId, parentId, GetZoneColors(), m_settings->GetSettings()->overlappingZonesAlgorithm); if (workArea) { m_workAreaHandler.AddWorkArea(m_currentDesktopId, monitor, workArea); @@ -1039,7 +784,7 @@ LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam, DefWindowProc(window, message, wparam, lparam); } -void FancyZones::UpdateZoneWindows(require_write_lock lock) noexcept +void FancyZones::UpdateZoneWindows() noexcept { // Mapping between display device name and device index (operating system identifies each display device with an index value). std::unordered_map displayDeviceIdxMap; @@ -1047,7 +792,6 @@ void FancyZones::UpdateZoneWindows(require_write_lock lock) noexcept { FancyZones* fancyZones; std::unordered_map* displayDeviceIdx; - require_write_lock lock; }; auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM data) -> BOOL { @@ -1059,23 +803,23 @@ void FancyZones::UpdateZoneWindows(require_write_lock lock) noexcept FancyZones* fancyZones = params->fancyZones; std::wstring deviceId = FancyZonesUtils::GetDisplayDeviceId(mi.szDevice, displayDeviceIdxMap); - fancyZones->AddZoneWindow(monitor, deviceId, params->lock); + fancyZones->AddZoneWindow(monitor, deviceId); } return TRUE; }; if (m_settings->GetSettings()->spanZonesAcrossMonitors) { - AddZoneWindow(nullptr, {}, lock); + AddZoneWindow(nullptr, {}); } else { - capture capture{ this, &displayDeviceIdxMap, lock }; + capture capture{ this, &displayDeviceIdxMap }; EnumDisplayMonitors(nullptr, nullptr, callback, reinterpret_cast(&capture)); } } -void FancyZones::UpdateWindowsPositions(require_write_lock) noexcept +void FancyZones::UpdateWindowsPositions() noexcept { auto callback = [](HWND window, LPARAM data) -> BOOL { size_t bitmask = reinterpret_cast(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)); @@ -1092,11 +836,16 @@ void FancyZones::UpdateWindowsPositions(require_write_lock) noexcept } auto strongThis = reinterpret_cast(data); - auto zoneWindow = strongThis->m_workAreaHandler.GetWorkArea(window); - if (zoneWindow) + auto desktopId = strongThis->m_virtualDesktop.GetWindowDesktopId(window); + if (desktopId.has_value()) { - strongThis->m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, indexSet, zoneWindow); + auto zoneWindow = strongThis->m_workAreaHandler.GetWorkArea(window, *desktopId); + if (zoneWindow) + { + strongThis->m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, indexSet, zoneWindow); + } } + } return TRUE; }; @@ -1115,7 +864,6 @@ bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexce auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current); do { - std::unique_lock writeLock(m_lock); if (m_windowMoveHandler.MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, false /* cycle through zones */, m_workAreaHandler.GetWorkArea(m_currentDesktopId, *currMonitorInfo))) { return true; @@ -1142,7 +890,6 @@ bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexce else { // Single monitor environment, or combined multi-monitor environment. - std::unique_lock writeLock(m_lock); if (m_settings->GetSettings()->restoreSize) { bool moved = m_windowMoveHandler.MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, false /* cycle through zones */, m_workAreaHandler.GetWorkArea(m_currentDesktopId, current)); @@ -1180,7 +927,7 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept // If that didn't work, extract zones from all other monitors and target one of them std::vector zoneRects; - std::vector>> zoneRectsInfo; + std::vector>> zoneRectsInfo; RECT currentMonitorRect{ .top = 0, .bottom = -1 }; for (const auto& [monitor, monitorRect] : allMonitors) @@ -1303,7 +1050,7 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept return false; } -bool FancyZones::ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept +bool FancyZones::ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept { // Check whether Alt is used in the shortcut key combination if (GetAsyncKeyState(VK_MENU) & 0x8000) @@ -1316,39 +1063,70 @@ bool FancyZones::ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle } } -void FancyZones::RegisterVirtualDesktopUpdates(std::vector& ids) noexcept +void FancyZones::RegisterVirtualDesktopUpdates() noexcept { _TRACER_; - std::unique_lock writeLock(m_lock); - m_workAreaHandler.RegisterUpdates(ids); - std::vector active{}; - if (VirtualDesktopUtils::GetVirtualDesktopIds(active) && !active.empty()) + auto guids = m_virtualDesktop.GetVirtualDesktopIds(); + std::vector guidStrings{}; + if (guids.has_value()) { - FancyZonesDataInstance().UpdatePrimaryDesktopData(active[0]); - FancyZonesDataInstance().RemoveDeletedDesktops(active); + m_workAreaHandler.RegisterUpdates(*guids); + + for (auto& guid : *guids) + { + auto guidString = FancyZonesUtils::GuidToString(guid); + if (guidString.has_value()) + { + guidStrings.push_back(*guidString); + } + } + + if (!guidStrings.empty()) + { + FancyZonesDataInstance().UpdatePrimaryDesktopData(guidStrings[0]); + } + + FancyZonesDataInstance().RemoveDeletedDesktops(guidStrings); } } -bool FancyZones::IsSplashScreen(HWND window) +void FancyZones::OnSettingsChanged() noexcept { - wchar_t className[MAX_PATH]; - if (GetClassName(window, className, MAX_PATH) == 0) + _TRACER_; + m_settings->ReloadSettings(); + + // Update the hotkey + UnregisterHotKey(m_window, 1); + auto modifiers = m_settings->GetSettings()->editorHotkey.get_modifiers(); + auto code = m_settings->GetSettings()->editorHotkey.get_code(); + auto result = RegisterHotKey(m_window, 1, modifiers, code); + + if (!result) { - return false; + Logger::error(L"Failed to register hotkey: {}", get_last_error_or_default(GetLastError())); } - return wcscmp(NonLocalizable::SplashClassName, className) == 0; + // 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); } -void FancyZones::OnEditorExitEvent(require_write_lock lock) noexcept +void FancyZones::OnEditorExitEvent() noexcept { // Collect information about changes in zone layout after editor exited. FancyZonesDataInstance().LoadFancyZonesData(); - UpdateZoneSets(lock); + UpdateZoneSets(); } -void FancyZones::UpdateZoneSets(require_write_lock lock) noexcept +void FancyZones::UpdateZoneSets() noexcept { for (auto workArea : m_workAreaHandler.GetAllWorkAreas()) { @@ -1356,7 +1134,7 @@ void FancyZones::UpdateZoneSets(require_write_lock lock) noexcept } if (m_settings->GetSettings()->zoneSetChange_moveWindows) { - UpdateWindowsPositions(lock); + UpdateWindowsPositions(); } } @@ -1385,8 +1163,6 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept void FancyZones::ApplyQuickLayout(int key) noexcept { - std::unique_lock writeLock(m_lock); - std::wstring uuid; for (auto [zoneUuid, hotkey] : FancyZonesDataInstance().GetLayoutQuickKeys()) { @@ -1409,11 +1185,11 @@ void FancyZones::ApplyQuickLayout(int key) noexcept FancyZonesDataTypes::ZoneSetData data{ .uuid = uuid, .type = FancyZonesDataTypes::ZoneSetLayoutType::Custom }; FancyZonesDataInstance().SetActiveZoneSet(workArea->UniqueId(), data); FancyZonesDataInstance().SaveZoneSettings(); - UpdateZoneSets(writeLock); - FlashZones(writeLock); + UpdateZoneSets(); + FlashZones(); } -void FancyZones::FlashZones(require_write_lock) noexcept +void FancyZones::FlashZones() noexcept { if (m_settings->GetSettings()->flashZonesOnQuickSwitch && !m_windowMoveHandler.IsDragEnabled()) { @@ -1426,8 +1202,6 @@ void FancyZones::FlashZones(require_write_lock) noexcept std::vector FancyZones::GetMonitorsSorted() noexcept { - std::shared_lock readLock(m_lock); - auto monitorInfo = GetRawMonitorData(); FancyZonesUtils::OrderMonitors(monitorInfo); std::vector output; @@ -1438,8 +1212,7 @@ std::vector FancyZones::GetMonitorsSorted() noexcept std::vector> FancyZones::GetRawMonitorData() noexcept { _TRACER_; - std::shared_lock readLock(m_lock); - + std::vector> monitorInfo; const auto& activeWorkAreaMap = m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId); for (const auto& [monitor, workArea] : activeWorkAreaMap) @@ -1467,6 +1240,16 @@ HMONITOR FancyZones::WorkAreaKeyFromWindow(HWND window) noexcept } } +ZoneColors FancyZones::GetZoneColors() const noexcept +{ + return ZoneColors { + .primaryColor = FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneColor), + .borderColor = FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneBorderColor), + .highlightColor = FancyZonesUtils::HexToRGB(m_settings->GetSettings()->zoneHighlightColor), + .highlightOpacity = m_settings->GetSettings()->zoneHighlightOpacity + }; +} + winrt::com_ptr MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr& settings, std::function disableCallback) noexcept diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.h b/src/modules/fancyzones/FancyZonesLib/FancyZones.h index c1c6d0b8e9..36a196d8aa 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.h @@ -1,11 +1,10 @@ #pragma once #include -#include "Settings.h" #include -interface IZoneWindow; +interface IWorkArea; interface IFancyZonesSettings; interface IZoneSet; @@ -51,63 +50,6 @@ interface __declspec(uuid("{2CB37E8F-87E6-4AEC-B4B2-E0FDC873343F}")) IFancyZones */ IFACEMETHOD_(bool, OnKeyDown) (PKBDLLHOOKSTRUCT info) = 0; - /** - * Toggle FancyZones editor application. - */ - IFACEMETHOD_(void, ToggleEditor) - () = 0; - /** - * Callback triggered when user changes FancyZones settings. - */ - IFACEMETHOD_(void, SettingsChanged) - () = 0; -}; - -/** - * Helper functions used by each ZoneWindow (representing work area). - */ -interface __declspec(uuid("{5C8D99D6-34B2-4F4A-A8E5-7483F6869775}")) IZoneWindowHost : public IUnknown -{ - /** - * Assign window to appropriate zone inside new zone layout. - */ - IFACEMETHOD_(void, MoveWindowsOnActiveZoneSetChange) - () = 0; - /** - * @returns Basic zone color. - */ - IFACEMETHOD_(COLORREF, GetZoneColor) - () = 0; - /** - * @returns Zone border color. - */ - IFACEMETHOD_(COLORREF, GetZoneBorderColor) - () = 0; - /** - * @returns Color used to highlight zone while giving zone layout hints. - */ - IFACEMETHOD_(COLORREF, GetZoneHighlightColor) - () = 0; - /** - * @returns Integer in range [0, 100] indicating opacity of highlighted zone (while giving zone layout hints). - */ - IFACEMETHOD_(int, GetZoneHighlightOpacity) - () = 0; - /** - * @returns Boolean indicating if dragged window should be transparent. - */ - IFACEMETHOD_(bool, isMakeDraggedWindowTransparentActive) - () = 0; - /** - * @returns Boolean indicating if move/size operation is currently active. - */ - IFACEMETHOD_(bool, InMoveSize) - () = 0; - /** - * @returns Enumeration value indicating the algorithm used to choose one of multiple overlapped zones to highlight. - */ - IFACEMETHOD_(Settings::OverlappingZonesAlgorithm, GetOverlappingZonesAlgorithm) - () = 0; }; winrt::com_ptr MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr& settings, std::function disableCallback) noexcept; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp index 0e2c3d903d..835eecea23 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp @@ -196,7 +196,7 @@ bool FancyZonesData::AddDevice(const std::wstring& deviceId) std::scoped_lock lock{ dataLock }; if (!deviceInfoMap.contains(deviceId)) { - // Creates default entry in map when ZoneWindow is created + // Creates default entry in map when WorkArea is created GUID guid; auto result{ CoCreateGuid(&guid) }; wil::unique_cotaskmem_string guidString; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h index a1d6fb9809..50a17fa261 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h @@ -34,8 +34,8 @@ namespace FancyZonesUnitTests class FancyZonesDataUnitTests; class FancyZonesIFancyZonesCallbackUnitTests; class ZoneSetCalculateZonesUnitTests; - class ZoneWindowUnitTests; - class ZoneWindowCreationUnitTests; + class WorkAreaUnitTests; + class WorkAreaCreationUnitTests; } #endif @@ -96,8 +96,8 @@ private: #if defined(UNIT_TESTS) friend class FancyZonesUnitTests::FancyZonesDataUnitTests; friend class FancyZonesUnitTests::FancyZonesIFancyZonesCallbackUnitTests; - friend class FancyZonesUnitTests::ZoneWindowUnitTests; - friend class FancyZonesUnitTests::ZoneWindowCreationUnitTests; + friend class FancyZonesUnitTests::WorkAreaUnitTests; + friend class FancyZonesUnitTests::WorkAreaCreationUnitTests; friend class FancyZonesUnitTests::ZoneSetCalculateZonesUnitTests; inline void SetDeviceInfo(const std::wstring& deviceId, FancyZonesDataTypes::DeviceInfoData data) diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj index 3100570499..08c6ca5f11 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj @@ -45,6 +45,7 @@ + @@ -53,11 +54,12 @@ - + + - + @@ -67,6 +69,7 @@ + @@ -76,11 +79,11 @@ - + - + diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters index 3bcfab7d1d..b24fdf06ec 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters @@ -27,7 +27,7 @@ Header Files - + Header Files @@ -42,7 +42,7 @@ Header Files - + Header Files @@ -81,6 +81,12 @@ Header Files + + Header Files + + + Header Files + @@ -92,7 +98,7 @@ Source Files - + Source Files @@ -107,7 +113,7 @@ Source Files - + Source Files @@ -140,6 +146,9 @@ Source Files + + Source Files + diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.cpp index d3e59b4b4a..91138e2348 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.cpp @@ -1,7 +1,5 @@ #include "pch.h" -#include - #include "FancyZonesWinHookEventIDs.h" UINT WM_PRIV_MOVESIZESTART; @@ -9,6 +7,14 @@ UINT WM_PRIV_MOVESIZEEND; UINT WM_PRIV_LOCATIONCHANGE; UINT WM_PRIV_NAMECHANGE; UINT WM_PRIV_WINDOWCREATED; +UINT WM_PRIV_VD_INIT; +UINT WM_PRIV_VD_SWITCH; +UINT WM_PRIV_VD_UPDATE; +UINT WM_PRIV_EDITOR; +UINT WM_PRIV_FILE_UPDATE; +UINT WM_PRIV_SNAP_HOTKEY; +UINT WM_PRIV_QUICK_LAYOUT_KEY; +UINT WM_PRIV_SETTINGS_CHANGED; std::once_flag init_flag; @@ -20,5 +26,13 @@ void InitializeWinhookEventIds() WM_PRIV_LOCATIONCHANGE = RegisterWindowMessage(L"{d56c5ee7-58e5-481c-8c4f-8844cf4d0347}"); WM_PRIV_NAMECHANGE = RegisterWindowMessage(L"{b7b30c61-bfa0-4d95-bcde-fc4f2cbf6d76}"); WM_PRIV_WINDOWCREATED = RegisterWindowMessage(L"{bdb10669-75da-480a-9ec4-eeebf09a02d7}"); + WM_PRIV_VD_INIT = RegisterWindowMessage(L"{469818a8-00fa-4069-b867-a1da484fcd9a}"); + WM_PRIV_VD_SWITCH = RegisterWindowMessage(L"{128c2cb0-6bdf-493e-abbe-f8705e04aa95}"); + WM_PRIV_VD_UPDATE = RegisterWindowMessage(L"{b8b72b46-f42f-4c26-9e20-29336cf2f22e}"); + WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}"); + WM_PRIV_FILE_UPDATE = RegisterWindowMessage(L"{632f17a9-55a7-45f1-a4db-162e39271d92}"); + WM_PRIV_SNAP_HOTKEY = RegisterWindowMessage(L"{72f4fd8e-23f1-43ab-bbbc-029363df9a84}"); + WM_PRIV_QUICK_LAYOUT_KEY = RegisterWindowMessage(L"{15baab3d-c67b-4a15-aFF0-13610e05e947}"); + WM_PRIV_SETTINGS_CHANGED = RegisterWindowMessage(L"{89ca3Daa-bf2d-4e73-9f3f-c60716364e27}"); }); } diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.h index 3f7212fb17..77e13e854b 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesWinHookEventIDs.h @@ -5,5 +5,13 @@ extern UINT WM_PRIV_MOVESIZEEND; extern UINT WM_PRIV_LOCATIONCHANGE; extern UINT WM_PRIV_NAMECHANGE; extern UINT WM_PRIV_WINDOWCREATED; +extern UINT WM_PRIV_VD_INIT; // Scheduled when FancyZones is initialized +extern UINT WM_PRIV_VD_SWITCH; // Scheduled when virtual desktop switch occurs +extern UINT WM_PRIV_VD_UPDATE; // Scheduled on virtual desktops update (creation/deletion) +extern UINT WM_PRIV_EDITOR; // Scheduled when the editor exits +extern UINT WM_PRIV_FILE_UPDATE; // Scheduled when the a watched zone-settings file is updated +extern UINT WM_PRIV_SNAP_HOTKEY; // Scheduled when we receive a snap hotkey key down press +extern UINT WM_PRIV_QUICK_LAYOUT_KEY; // Scheduled when we receive a key down press to quickly apply a layout +extern UINT WM_PRIV_SETTINGS_CHANGED; // Scheduled when the a watched settings file is updated void InitializeWinhookEventIds(); diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp b/src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp new file mode 100644 index 0000000000..bd0d444934 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp @@ -0,0 +1,76 @@ +#include "pch.h" +#include "MonitorUtils.h" + +#include + +namespace MonitorUtils +{ + constexpr int CUSTOM_POSITIONING_LEFT_TOP_PADDING = 16; + + inline int RectWidth(const RECT& rect) + { + return rect.right - rect.left; + } + + inline int RectHeight(const RECT& rect) + { + return rect.bottom - rect.top; + } + + RECT FitOnScreen(const RECT& windowRect, const RECT& originMonitorRect, const RECT& destMonitorRect) + { + // New window position on active monitor. If window fits the screen, this will be final position. + int left = destMonitorRect.left + (windowRect.left - originMonitorRect.left); + int top = destMonitorRect.top + (windowRect.top - originMonitorRect.top); + int W = RectWidth(windowRect); + int H = RectHeight(windowRect); + + if ((left < destMonitorRect.left) || (left + W > destMonitorRect.right)) + { + // Set left window border to left border of screen (add padding). Resize window width if needed. + left = destMonitorRect.left + CUSTOM_POSITIONING_LEFT_TOP_PADDING; + W = min(W, RectWidth(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING); + } + if ((top < destMonitorRect.top) || (top + H > destMonitorRect.bottom)) + { + // Set top window border to top border of screen (add padding). Resize window height if needed. + top = destMonitorRect.top + CUSTOM_POSITIONING_LEFT_TOP_PADDING; + H = min(H, RectHeight(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING); + } + + return { .left = left, + .top = top, + .right = left + W, + .bottom = top + H }; + } + + void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept + { + // By default Windows opens new window on primary monitor. + // Try to preserve window width and height, adjust top-left corner if needed. + HMONITOR origin = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); + if (origin == monitor) + { + // Certain applications by design open in last known position, regardless of FancyZones. + // If that position is on currently active monitor, skip custom positioning. + return; + } + + WINDOWPLACEMENT placement{}; + if (GetWindowPlacement(window, &placement)) + { + MONITORINFOEX originMi; + originMi.cbSize = sizeof(originMi); + if (GetMonitorInfo(origin, &originMi)) + { + MONITORINFOEX destMi; + destMi.cbSize = sizeof(destMi); + if (GetMonitorInfo(monitor, &destMi)) + { + RECT newPosition = FitOnScreen(placement.rcNormalPosition, originMi.rcWork, destMi.rcWork); + FancyZonesUtils::SizeWindowToRect(window, newPosition); + } + } + } + } +} \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorUtils.h b/src/modules/fancyzones/FancyZonesLib/MonitorUtils.h new file mode 100644 index 0000000000..9943104fa9 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/MonitorUtils.h @@ -0,0 +1,6 @@ +#pragma once + +namespace MonitorUtils +{ + void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept; +}; diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.cpp b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.cpp index ebad94a9ae..d386b15eec 100644 --- a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.cpp +++ b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.cpp @@ -1,8 +1,8 @@ #include "pch.h" #include "MonitorWorkAreaHandler.h" -#include "VirtualDesktopUtils.h" +#include "VirtualDesktop.h" -winrt::com_ptr MonitorWorkAreaHandler::GetWorkArea(const GUID& desktopId, HMONITOR monitor) +winrt::com_ptr MonitorWorkAreaHandler::GetWorkArea(const GUID& desktopId, HMONITOR monitor) { auto desktopIt = workAreaMap.find(desktopId); if (desktopIt != std::end(workAreaMap)) @@ -17,7 +17,7 @@ winrt::com_ptr MonitorWorkAreaHandler::GetWorkArea(const GUID& desk return nullptr; } -winrt::com_ptr MonitorWorkAreaHandler::GetWorkAreaFromCursor(const GUID& desktopId) +winrt::com_ptr MonitorWorkAreaHandler::GetWorkAreaFromCursor(const GUID& desktopId) { auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL); if (allMonitorsWorkArea) @@ -38,41 +38,35 @@ winrt::com_ptr MonitorWorkAreaHandler::GetWorkAreaFromCursor(const } } -winrt::com_ptr MonitorWorkAreaHandler::GetWorkArea(HWND window) +winrt::com_ptr MonitorWorkAreaHandler::GetWorkArea(HWND window, const GUID& desktopId) { - GUID desktopId{}; - if (VirtualDesktopUtils::GetWindowDesktopId(window, &desktopId)) + auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL); + if (allMonitorsWorkArea) { - auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL); - if (allMonitorsWorkArea) - { - // First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle) - return allMonitorsWorkArea; - } - else - { - // Otherwise, look for the work area based on the window's position - HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); - return GetWorkArea(desktopId, monitor); - } + // First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle) + return allMonitorsWorkArea; + } + else + { + // Otherwise, look for the work area based on the window's position + HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); + return GetWorkArea(desktopId, monitor); } - - return nullptr; } -const std::unordered_map>& MonitorWorkAreaHandler::GetWorkAreasByDesktopId(const GUID& desktopId) +const std::unordered_map>& MonitorWorkAreaHandler::GetWorkAreasByDesktopId(const GUID& desktopId) { if (workAreaMap.contains(desktopId)) { return workAreaMap[desktopId]; } - static const std::unordered_map> empty; + static const std::unordered_map> empty; return empty; } -std::vector> MonitorWorkAreaHandler::GetAllWorkAreas() +std::vector> MonitorWorkAreaHandler::GetAllWorkAreas() { - std::vector> workAreas{}; + std::vector> workAreas{}; for (const auto& [desktopId, perDesktopData] : workAreaMap) { std::transform(std::begin(perDesktopData), @@ -83,7 +77,7 @@ std::vector> MonitorWorkAreaHandler::GetAllWorkAreas return workAreas; } -void MonitorWorkAreaHandler::AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr& workArea) +void MonitorWorkAreaHandler::AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr& workArea) { if (!workAreaMap.contains(desktopId)) { @@ -134,3 +128,25 @@ void MonitorWorkAreaHandler::Clear() { workAreaMap.clear(); } + +void MonitorWorkAreaHandler::UpdateZoneColors(const ZoneColors& colors) +{ + for (const auto& workArea : workAreaMap) + { + for (const auto& zoneWindow : workArea.second) + { + zoneWindow.second->SetZoneColors(colors); + } + } +} + +void MonitorWorkAreaHandler::UpdateOverlappingAlgorithm(OverlappingZonesAlgorithm overlappingAlgorithm) +{ + for (const auto& workArea : workAreaMap) + { + for (const auto& zoneWindow : workArea.second) + { + zoneWindow.second->SetOverlappingZonesAlgorithm(overlappingAlgorithm); + } + } +} diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.h b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.h index a876d62275..dccb226a43 100644 --- a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.h +++ b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.h @@ -1,6 +1,8 @@ #pragma once -interface IZoneWindow; +interface IWorkArea; +struct ZoneColors; +enum struct OverlappingZonesAlgorithm; namespace std { @@ -27,7 +29,7 @@ public: * @returns Object representing single work area, interface to all actions available on work area * (e.g. moving windows through zone layout specified for that work area). */ - winrt::com_ptr GetWorkArea(const GUID& desktopId, HMONITOR monitor); + winrt::com_ptr GetWorkArea(const GUID& desktopId, HMONITOR monitor); /** * Get work area based on virtual desktop id and the current cursor position. @@ -37,17 +39,18 @@ public: * @returns Object representing single work area, interface to all actions available on work area * (e.g. moving windows through zone layout specified for that work area). */ - winrt::com_ptr GetWorkAreaFromCursor(const GUID& desktopId); + winrt::com_ptr GetWorkAreaFromCursor(const GUID& desktopId); /** * Get work area on which specified window is located. * * @param[in] window Window handle. - * + * @param[in] desktopId GUID current desktop id + * * @returns Object representing single work area, interface to all actions available on work area * (e.g. moving windows through zone layout specified for that work area). */ - winrt::com_ptr GetWorkArea(HWND window); + winrt::com_ptr GetWorkArea(HWND window, const GUID& desktopId); /** * Get map of all work areas on single virtual desktop. Key in the map is monitor handle, while value @@ -57,12 +60,12 @@ public: * * @returns Map containing pairs of monitor and work area for that monitor (within same virtual desktop). */ - const std::unordered_map>& GetWorkAreasByDesktopId(const GUID& desktopId); + const std::unordered_map>& GetWorkAreasByDesktopId(const GUID& desktopId); /** * @returns All registered work areas. */ - std::vector> GetAllWorkAreas(); + std::vector> GetAllWorkAreas(); /** * Register new work area. @@ -71,7 +74,7 @@ public: * @param[in] monitor Monitor handle. * @param[in] workAra Object representing single work area. */ - void AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr& workArea); + void AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr& workArea); /** * Check if work area is already registered. @@ -95,7 +98,17 @@ public: */ 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. - std::unordered_map>> workAreaMap; + std::unordered_map>> workAreaMap; }; diff --git a/src/modules/fancyzones/FancyZonesLib/Settings.cpp b/src/modules/fancyzones/FancyZonesLib/Settings.cpp index 6445c2d8ec..e9f95ea584 100644 --- a/src/modules/fancyzones/FancyZonesLib/Settings.cpp +++ b/src/modules/fancyzones/FancyZonesLib/Settings.cpp @@ -53,10 +53,6 @@ public: LoadSettings(name, true); } - IFACEMETHODIMP_(void) - SetCallback(IFancyZonesCallback* callback) { m_callback = callback; } - IFACEMETHODIMP_(void) - ResetCallback() { m_callback = nullptr; } IFACEMETHODIMP_(bool) GetConfig(_Out_ PWSTR buffer, _Out_ int* buffer_sizeg) noexcept; IFACEMETHODIMP_(void) @@ -70,7 +66,6 @@ private: void LoadSettings(PCWSTR config, bool fromFile) noexcept; void SaveSettings() noexcept; - IFancyZonesCallback* m_callback{}; const HINSTANCE m_hinstance; std::wstring m_moduleName{}; std::wstring m_moduleKey{}; @@ -143,20 +138,12 @@ FancyZonesSettings::SetConfig(PCWSTR serializedPowerToysSettingsJson) noexcept { LoadSettings(serializedPowerToysSettingsJson, false /*fromFile*/); SaveSettings(); - if (m_callback) - { - m_callback->SettingsChanged(); - } } IFACEMETHODIMP_(void) FancyZonesSettings::ReloadSettings() noexcept { LoadSettings(m_moduleKey.c_str(), true /*fromFile*/); - if (m_callback) - { - m_callback->SettingsChanged(); - } } void FancyZonesSettings::LoadSettings(PCWSTR config, bool fromFile) noexcept @@ -226,9 +213,9 @@ void FancyZonesSettings::LoadSettings(PCWSTR config, bool fromFile) noexcept if (auto val = values.get_int_value(NonLocalizable::OverlappingZonesAlgorithmID)) { // Avoid undefined behavior - if (*val >= 0 || *val < (int)Settings::OverlappingZonesAlgorithm::EnumElements) + if (*val >= 0 || *val < (int)OverlappingZonesAlgorithm::EnumElements) { - m_settings.overlappingZonesAlgorithm = (Settings::OverlappingZonesAlgorithm)*val; + m_settings.overlappingZonesAlgorithm = (OverlappingZonesAlgorithm)*val; } } } diff --git a/src/modules/fancyzones/FancyZonesLib/Settings.h b/src/modules/fancyzones/FancyZonesLib/Settings.h index 12a9468dba..c188cbdce0 100644 --- a/src/modules/fancyzones/FancyZonesLib/Settings.h +++ b/src/modules/fancyzones/FancyZonesLib/Settings.h @@ -12,18 +12,18 @@ namespace ZonedWindowProperties const wchar_t MultiMonitorDeviceID[] = L"FancyZones#MultiMonitorDevice"; } +enum struct OverlappingZonesAlgorithm : int +{ + Smallest = 0, + Largest = 1, + Positional = 2, + ClosestCenter = 3, + EnumElements = 4, // number of elements in the enum, not counting this +}; + // in reality, this file needs to be kept in sync currently with src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/FZConfigProperties.cs struct Settings { - enum struct OverlappingZonesAlgorithm : int - { - Smallest = 0, - Largest = 1, - Positional = 2, - ClosestCenter = 3, - EnumElements = 4, // number of elements in the enum, not counting this - }; - // The values specified here are the defaults. bool shiftDrag = true; bool mouseSwitch = false; @@ -54,8 +54,6 @@ struct Settings interface __declspec(uuid("{BA4E77C4-6F44-4C5D-93D3-CBDE880495C2}")) IFancyZonesSettings : public IUnknown { - IFACEMETHOD_(void, SetCallback)(interface IFancyZonesCallback* callback) = 0; - IFACEMETHOD_(void, ResetCallback)() = 0; IFACEMETHOD_(bool, GetConfig)(_Out_ PWSTR buffer, _Out_ int *buffer_size) = 0; IFACEMETHOD_(void, SetConfig)(PCWSTR serializedPowerToysSettings) = 0; IFACEMETHOD_(void, ReloadSettings)() = 0; diff --git a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp new file mode 100644 index 0000000000..27ea00c5a9 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp @@ -0,0 +1,234 @@ +#include "pch.h" +#include "VirtualDesktop.h" + +// Non-Localizable strings +namespace NonLocalizable +{ + const wchar_t RegCurrentVirtualDesktop[] = L"CurrentVirtualDesktop"; + const wchar_t RegVirtualDesktopIds[] = L"VirtualDesktopIDs"; + const wchar_t RegKeyVirtualDesktops[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops"; + const wchar_t RegKeyVirtualDesktopsFromSession[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops"; +} + +const CLSID CLSID_ImmersiveShell = { 0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 }; + +IServiceProvider* GetServiceProvider() +{ + IServiceProvider* provider{ nullptr }; + if (FAILED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, __uuidof(provider), (PVOID*)&provider))) + { + return nullptr; + } + return provider; +} + +IVirtualDesktopManager* GetVirtualDesktopManager() +{ + IVirtualDesktopManager* manager{ nullptr }; + IServiceProvider* serviceProvider = GetServiceProvider(); + if (serviceProvider == nullptr || FAILED(serviceProvider->QueryService(__uuidof(manager), &manager))) + { + return nullptr; + } + return manager; +} + +std::optional NewGetCurrentDesktopId() +{ + wil::unique_hkey key{}; + if (RegOpenKeyExW(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS) + { + GUID value{}; + DWORD size = sizeof(GUID); + if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast(&value), &size) == ERROR_SUCCESS) + { + return value; + } + } + + return std::nullopt; +} + +std::optional GetDesktopIdFromCurrentSession() +{ + DWORD sessionId; + if (!ProcessIdToSessionId(GetCurrentProcessId(), &sessionId)) + { + return std::nullopt; + } + + wchar_t sessionKeyPath[256]{}; + if (FAILED(StringCchPrintfW(sessionKeyPath, ARRAYSIZE(sessionKeyPath), NonLocalizable::RegKeyVirtualDesktopsFromSession, sessionId))) + { + return std::nullopt; + } + + wil::unique_hkey key{}; + if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS) + { + GUID value{}; + DWORD size = sizeof(GUID); + if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast(&value), &size) == ERROR_SUCCESS) + { + return value; + } + } + + return std::nullopt; +} + +bool GetZoneWindowDesktopId(IWorkArea* zoneWindow, GUID* desktopId) +{ + // Format: __ + std::wstring uniqueId = zoneWindow->UniqueId(); + std::wstring virtualDesktopId = uniqueId.substr(uniqueId.rfind('_') + 1); + return SUCCEEDED(CLSIDFromString(virtualDesktopId.c_str(), desktopId)); +} + +HKEY OpenVirtualDesktopsRegKey() +{ + HKEY hKey{ nullptr }; + if (RegOpenKeyEx(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) + { + return hKey; + } + return nullptr; +} + +HKEY GetVirtualDesktopsRegKey() +{ + static wil::unique_hkey virtualDesktopsKey{ OpenVirtualDesktopsRegKey() }; + return virtualDesktopsKey.get(); +} + +VirtualDesktop::VirtualDesktop(const std::function& vdInitCallback, const std::function& vdUpdatedCallback) : + m_vdInitCallback(vdInitCallback), + m_vdUpdatedCallback(vdUpdatedCallback), + m_vdManager(GetVirtualDesktopManager()) +{ +} + +void VirtualDesktop::Init() +{ + m_vdInitCallback(); + + m_terminateVirtualDesktopTrackerEvent.reset(CreateEvent(nullptr, FALSE, FALSE, nullptr)); + m_virtualDesktopTrackerThread.submit(OnThreadExecutor::task_t{ [&] { HandleVirtualDesktopUpdates(); } }); +} + +void VirtualDesktop::UnInit() +{ + if (m_terminateVirtualDesktopTrackerEvent) + { + SetEvent(m_terminateVirtualDesktopTrackerEvent.get()); + } +} + +std::optional VirtualDesktop::GetWindowDesktopId(HWND topLevelWindow) const +{ + GUID desktopId{}; + if (m_vdManager && SUCCEEDED(m_vdManager->GetWindowDesktopId(topLevelWindow, &desktopId))) + { + return desktopId; + } + + return std::nullopt; +} + +std::optional VirtualDesktop::GetCurrentVirtualDesktopId() const +{ + // On newer Windows builds, the current virtual desktop is persisted to + // a totally different reg key. Look there first. + std::optional desktopId = NewGetCurrentDesktopId(); + if (desktopId.has_value()) + { + return desktopId; + } + + // Explorer persists current virtual desktop identifier to registry on a per session basis, but only + // after first virtual desktop switch happens. If the user hasn't switched virtual desktops in this + // session, value in registry will be empty. + desktopId = GetDesktopIdFromCurrentSession(); + if (desktopId.has_value()) + { + return desktopId; + } + + // Fallback scenario is to get array of virtual desktops stored in registry, but not kept per session. + // Note that we are taking first element from virtual desktop array, which is primary desktop. + // If user has more than one virtual desktop, previous function should return correct value, as desktop + // switch occurred in current session. + else + { + auto ids = GetVirtualDesktopIds(); + if (ids.has_value() && ids->size() > 0) + { + return ids->at(0); + } + } + + return std::nullopt; +} + +std::optional> VirtualDesktop::GetVirtualDesktopIds(HKEY hKey) const +{ + if (!hKey) + { + return std::nullopt; + } + + DWORD bufferCapacity; + // request regkey binary buffer capacity only + if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, nullptr, &bufferCapacity) != ERROR_SUCCESS) + { + return std::nullopt; + } + + std::unique_ptr buffer = std::make_unique(bufferCapacity); + // request regkey binary content + if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, buffer.get(), &bufferCapacity) != ERROR_SUCCESS) + { + return std::nullopt; + } + + const size_t guidSize = sizeof(GUID); + std::vector temp; + temp.reserve(bufferCapacity / guidSize); + for (size_t i = 0; i < bufferCapacity; i += guidSize) + { + GUID* guid = reinterpret_cast(buffer.get() + i); + temp.push_back(*guid); + } + + return temp; +} + +std::optional> VirtualDesktop::GetVirtualDesktopIds() const +{ + return GetVirtualDesktopIds(GetVirtualDesktopsRegKey()); +} + +void VirtualDesktop::HandleVirtualDesktopUpdates() +{ + HKEY virtualDesktopsRegKey = GetVirtualDesktopsRegKey(); + if (!virtualDesktopsRegKey) + { + return; + } + HANDLE regKeyEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + HANDLE events[2] = { regKeyEvent, m_terminateVirtualDesktopTrackerEvent.get() }; + while (1) + { + if (RegNotifyChangeKeyValue(virtualDesktopsRegKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, regKeyEvent, TRUE) != ERROR_SUCCESS) + { + return; + } + if (WaitForMultipleObjects(2, events, FALSE, INFINITE) != (WAIT_OBJECT_0 + 0)) + { + // if terminateEvent is signalized or WaitForMultipleObjects failed, terminate thread execution + return; + } + + m_vdUpdatedCallback(); + } +} \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h new file mode 100644 index 0000000000..3765a258a4 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h @@ -0,0 +1,30 @@ +#pragma once + +#include "WorkArea.h" +#include "on_thread_executor.h" + +class VirtualDesktop +{ +public: + VirtualDesktop(const std::function& vdInitCallback, const std::function& vdUpdatedCallback); + ~VirtualDesktop() = default; + + void Init(); + void UnInit(); + + std::optional GetWindowDesktopId(HWND topLevelWindow) const; + std::optional GetCurrentVirtualDesktopId() const; + std::optional> GetVirtualDesktopIds() const; + +private: + std::function m_vdInitCallback; + std::function m_vdUpdatedCallback; + + IVirtualDesktopManager* m_vdManager; + + OnThreadExecutor m_virtualDesktopTrackerThread; + wil::unique_handle m_terminateVirtualDesktopTrackerEvent; + + std::optional> GetVirtualDesktopIds(HKEY hKey) const; + void HandleVirtualDesktopUpdates(); +}; diff --git a/src/modules/fancyzones/FancyZonesLib/VirtualDesktopUtils.cpp b/src/modules/fancyzones/FancyZonesLib/VirtualDesktopUtils.cpp deleted file mode 100644 index 136eaa0d61..0000000000 --- a/src/modules/fancyzones/FancyZonesLib/VirtualDesktopUtils.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "pch.h" - -#include "VirtualDesktopUtils.h" - -// Non-Localizable strings -namespace NonLocalizable -{ - const wchar_t RegCurrentVirtualDesktop[] = L"CurrentVirtualDesktop"; - const wchar_t RegVirtualDesktopIds[] = L"VirtualDesktopIDs"; - const wchar_t RegKeyVirtualDesktops[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops"; - const wchar_t RegKeyVirtualDesktopsFromSession[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops"; -} - -namespace VirtualDesktopUtils -{ - const CLSID CLSID_ImmersiveShell = { 0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 }; - - IServiceProvider* GetServiceProvider() - { - IServiceProvider* provider{ nullptr }; - if (FAILED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, __uuidof(provider), (PVOID*)&provider))) - { - return nullptr; - } - return provider; - } - - IVirtualDesktopManager* GetVirtualDesktopManager() - { - IVirtualDesktopManager* manager{ nullptr }; - IServiceProvider* serviceProvider = GetServiceProvider(); - if (serviceProvider == nullptr || FAILED(serviceProvider->QueryService(__uuidof(manager), &manager))) - { - return nullptr; - } - return manager; - } - - bool GetWindowDesktopId(HWND topLevelWindow, GUID* desktopId) - { - static IVirtualDesktopManager* virtualDesktopManager = GetVirtualDesktopManager(); - return (virtualDesktopManager != nullptr) && - SUCCEEDED(virtualDesktopManager->GetWindowDesktopId(topLevelWindow, desktopId)); - } - - bool GetZoneWindowDesktopId(IZoneWindow* zoneWindow, GUID* desktopId) - { - // Format: __ - std::wstring uniqueId = zoneWindow->UniqueId(); - std::wstring virtualDesktopId = uniqueId.substr(uniqueId.rfind('_') + 1); - return SUCCEEDED(CLSIDFromString(virtualDesktopId.c_str(), desktopId)); - } - - bool NewGetCurrentDesktopId(GUID* desktopId) - { - wil::unique_hkey key{}; - if (RegOpenKeyExW(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS) - { - GUID value{}; - DWORD size = sizeof(GUID); - if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast(&value), &size) == ERROR_SUCCESS) - { - *desktopId = value; - return true; - } - } - - return false; - } - - bool GetDesktopIdFromCurrentSession(GUID* desktopId) - { - DWORD sessionId; - if (!ProcessIdToSessionId(GetCurrentProcessId(), &sessionId)) - { - return false; - } - - wchar_t sessionKeyPath[256]{}; - if (FAILED(StringCchPrintfW(sessionKeyPath, ARRAYSIZE(sessionKeyPath), NonLocalizable::RegKeyVirtualDesktopsFromSession, sessionId))) - { - return false; - } - - wil::unique_hkey key{}; - if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS) - { - GUID value{}; - DWORD size = sizeof(GUID); - if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast(&value), &size) == ERROR_SUCCESS) - { - *desktopId = value; - return true; - } - } - - return false; - } - - bool GetCurrentVirtualDesktopId(GUID* desktopId) - { - // On newer Windows builds, the current virtual desktop is persisted to - // a totally different reg key. Look there first. - if (NewGetCurrentDesktopId(desktopId)) - { - return true; - } - - // Explorer persists current virtual desktop identifier to registry on a per session basis, but only - // after first virtual desktop switch happens. If the user hasn't switched virtual desktops in this - // session, value in registry will be empty. - if (GetDesktopIdFromCurrentSession(desktopId)) - { - return true; - } - // Fallback scenario is to get array of virtual desktops stored in registry, but not kept per session. - // Note that we are taking first element from virtual desktop array, which is primary desktop. - // If user has more than one virtual desktop, previous function should return correct value, as desktop - // switch occurred in current session. - else - { - std::vector ids{}; - if (GetVirtualDesktopIds(ids) && ids.size() > 0) - { - *desktopId = ids[0]; - return true; - } - } - return false; - } - - bool GetVirtualDesktopIds(HKEY hKey, std::vector& ids) - { - if (!hKey) - { - return false; - } - DWORD bufferCapacity; - // request regkey binary buffer capacity only - if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, nullptr, &bufferCapacity) != ERROR_SUCCESS) - { - return false; - } - std::unique_ptr buffer = std::make_unique(bufferCapacity); - // request regkey binary content - if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, buffer.get(), &bufferCapacity) != ERROR_SUCCESS) - { - return false; - } - const size_t guidSize = sizeof(GUID); - std::vector temp; - temp.reserve(bufferCapacity / guidSize); - for (size_t i = 0; i < bufferCapacity; i += guidSize) - { - GUID* guid = reinterpret_cast(buffer.get() + i); - temp.push_back(*guid); - } - ids = std::move(temp); - return true; - } - - bool GetVirtualDesktopIds(std::vector& ids) - { - return GetVirtualDesktopIds(GetVirtualDesktopsRegKey(), ids); - } - - bool GetVirtualDesktopIds(std::vector& ids) - { - std::vector guids{}; - if (GetVirtualDesktopIds(guids)) - { - for (auto& guid : guids) - { - wil::unique_cotaskmem_string guidString; - if (SUCCEEDED(StringFromCLSID(guid, &guidString))) - { - ids.push_back(guidString.get()); - } - } - return true; - } - return false; - } - - HKEY OpenVirtualDesktopsRegKey() - { - HKEY hKey{ nullptr }; - if (RegOpenKeyEx(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) - { - return hKey; - } - return nullptr; - } - - HKEY GetVirtualDesktopsRegKey() - { - static wil::unique_hkey virtualDesktopsKey{ OpenVirtualDesktopsRegKey() }; - return virtualDesktopsKey.get(); - } - - void HandleVirtualDesktopUpdates(HWND window, UINT message, HANDLE terminateEvent) - { - HKEY virtualDesktopsRegKey = GetVirtualDesktopsRegKey(); - if (!virtualDesktopsRegKey) - { - return; - } - HANDLE regKeyEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); - HANDLE events[2] = { regKeyEvent, terminateEvent }; - while (1) - { - if (RegNotifyChangeKeyValue(virtualDesktopsRegKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, regKeyEvent, TRUE) != ERROR_SUCCESS) - { - return; - } - if (WaitForMultipleObjects(2, events, FALSE, INFINITE) != (WAIT_OBJECT_0 + 0)) - { - // if terminateEvent is signalized or WaitForMultipleObjects failed, terminate thread execution - return; - } - PostMessage(window, message, 0, 0); - } - } -} diff --git a/src/modules/fancyzones/FancyZonesLib/VirtualDesktopUtils.h b/src/modules/fancyzones/FancyZonesLib/VirtualDesktopUtils.h deleted file mode 100644 index 5bf5c1778c..0000000000 --- a/src/modules/fancyzones/FancyZonesLib/VirtualDesktopUtils.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "ZoneWindow.h" - -namespace VirtualDesktopUtils -{ - bool GetWindowDesktopId(HWND topLevelWindow, GUID* desktopId); - bool GetZoneWindowDesktopId(IZoneWindow* zoneWindow, GUID* desktopId); - bool GetCurrentVirtualDesktopId(GUID* desktopId); - bool GetVirtualDesktopIds(std::vector& ids); - bool GetVirtualDesktopIds(std::vector& ids); - HKEY GetVirtualDesktopsRegKey(); - void HandleVirtualDesktopUpdates(HWND window, UINT message, HANDLE terminateEvent); -} diff --git a/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp b/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp index 1d05f306e5..435da0b0d7 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp @@ -9,7 +9,7 @@ #include "FancyZonesData.h" #include "Settings.h" -#include "ZoneWindow.h" +#include "WorkArea.h" #include "util.h" // Non-Localizable strings @@ -59,7 +59,7 @@ WindowMoveHandler::WindowMoveHandler(const winrt::com_ptr& { } -void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept +void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept { if (!FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray) || WindowMoveHandlerUtils::IsCursorTypeIndicatingSizeEvent()) { @@ -125,7 +125,7 @@ void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const } } -void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept +void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept { if (!m_inMoveSize) { @@ -137,7 +137,7 @@ void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, if (m_zoneWindowMoveSize) { - // Update the ZoneWindow already handling move/size + // Update the WorkArea already handling move/size if (!m_dragEnabled) { // Drag got disabled, tell it to cancel and hide all windows @@ -180,7 +180,7 @@ void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, else if (m_dragEnabled) { // We'll get here if the user presses/releases shift while dragging. - // Restart the drag on the ZoneWindow that m_windowMoveSize is on + // Restart the drag on the WorkArea that m_windowMoveSize is on MoveSizeStart(m_windowMoveSize, monitor, ptScreen, zoneWindowMap); // m_dragEnabled could get set to false if we're moving an elevated window. @@ -192,7 +192,7 @@ void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, } } -void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept +void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept { if (window != m_windowMoveSize) { @@ -273,7 +273,7 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st } } -void WindowMoveHandler::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector& indexSet, winrt::com_ptr zoneWindow) noexcept +void WindowMoveHandler::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector& indexSet, winrt::com_ptr zoneWindow) noexcept { if (window != m_windowMoveSize) { @@ -281,17 +281,17 @@ void WindowMoveHandler::MoveWindowIntoZoneByIndexSet(HWND window, const std::vec } } -bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept +bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept { return zoneWindow && zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, cycle); } -bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept +bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept { return zoneWindow && zoneWindow->MoveWindowIntoZoneByDirectionAndPosition(window, vkCode, cycle); } -bool WindowMoveHandler::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr zoneWindow) noexcept +bool WindowMoveHandler::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr zoneWindow) noexcept { return zoneWindow && zoneWindow->ExtendWindowByDirectionAndPosition(window, vkCode); } diff --git a/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.h b/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.h index c81ed9fd8c..87ffeef5f1 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.h +++ b/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.h @@ -6,21 +6,21 @@ #include interface IFancyZonesSettings; -interface IZoneWindow; +interface IWorkArea; class WindowMoveHandler { public: WindowMoveHandler(const winrt::com_ptr& settings, const std::function& keyUpdateCallback); - void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept; - void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept; - void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept; + void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept; + void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept; + void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map>& zoneWindowMap) noexcept; - void MoveWindowIntoZoneByIndexSet(HWND window, const std::vector& indexSet, winrt::com_ptr zoneWindow) noexcept; - bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; - bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; - bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr zoneWindow) noexcept; + void MoveWindowIntoZoneByIndexSet(HWND window, const std::vector& indexSet, winrt::com_ptr zoneWindow) noexcept; + bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; + bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr zoneWindow) noexcept; + bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr zoneWindow) noexcept; inline void OnMouseDown() noexcept { @@ -68,7 +68,7 @@ private: HWND m_windowMoveSize{}; // The window that is being moved/sized bool m_inMoveSize{}; // Whether or not a move/size operation is currently active MoveSizeWindowInfo m_moveSizeWindowInfo; // MoveSizeWindowInfo of the window at the moment when dragging started - winrt::com_ptr m_zoneWindowMoveSize; // "Active" ZoneWindow, where the move/size is happening. Will update as drag moves between monitors. + winrt::com_ptr m_zoneWindowMoveSize; // "Active" WorkArea, where the move/size is happening. Will update as drag moves between monitors. bool m_dragEnabled{}; // True if we should be showing zone hints while dragging WindowTransparencyProperties m_windowTransparencyProperties; diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneWindow.cpp b/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp similarity index 75% rename from src/modules/fancyzones/FancyZonesLib/ZoneWindow.cpp rename to src/modules/fancyzones/FancyZonesLib/WorkArea.cpp index 0b515c111e..0f0045029e 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneWindow.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp @@ -1,10 +1,10 @@ #include "pch.h" +#include "WorkArea.h" #include #include "FancyZonesData.h" #include "FancyZonesDataTypes.h" -#include "ZoneWindow.h" #include "ZoneWindowDrawing.h" #include "trace.h" #include "util.h" @@ -26,7 +26,7 @@ namespace NonLocalizable using namespace FancyZonesUtils; -struct ZoneWindow; +struct WorkArea; namespace { @@ -57,7 +57,7 @@ namespace public: - HWND NewZoneWindow(Rect position, HINSTANCE hinstance, ZoneWindow* owner) + HWND NewZoneWindow(Rect position, HINSTANCE hinstance, WorkArea* owner) { HWND windowFromPool = ExtractWindow(); if (windowFromPool == NULL) @@ -103,13 +103,13 @@ namespace WindowPool windowPool; } -struct ZoneWindow : public winrt::implements +struct WorkArea : public winrt::implements { public: - ZoneWindow(HINSTANCE hinstance); - ~ZoneWindow(); + WorkArea(HINSTANCE hinstance); + ~WorkArea(); - bool Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId); + bool Init(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm); IFACEMETHODIMP MoveSizeEnter(HWND window) noexcept; IFACEMETHODIMP MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) noexcept; @@ -125,11 +125,13 @@ public: IFACEMETHODIMP_(bool) ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept; IFACEMETHODIMP_(std::wstring) - UniqueId() noexcept { return { m_uniqueId }; } + UniqueId() const noexcept { return { m_uniqueId }; } IFACEMETHODIMP_(void) SaveWindowProcessToZoneIndex(HWND window) noexcept; IFACEMETHODIMP_(IZoneSet*) - ActiveZoneSet() noexcept { return m_activeZoneSet.get(); } + ActiveZoneSet() const noexcept { return m_activeZoneSet.get(); } + IFACEMETHODIMP_(std::vector) + GetWindowZoneIndexes(HWND window) const noexcept; IFACEMETHODIMP_(void) ShowZoneWindow() noexcept; IFACEMETHODIMP_(void) @@ -140,19 +142,22 @@ 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; private: void InitializeZoneSets(const std::wstring& parentUniqueId) noexcept; - void CalculateZoneSet() noexcept; + void CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept; void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept; LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept; std::vector ZonesFromPoint(POINT pt) noexcept; void SetAsTopmostWindow() noexcept; - winrt::com_ptr m_host; HMONITOR m_monitor{}; std::wstring m_uniqueId; // Parsed deviceId + resolution + virtualDesktopId HWND m_window{}; // Hidden tool window used to represent current monitor desktop work area. @@ -164,9 +169,11 @@ private: WPARAM m_keyLast{}; size_t m_keyCycle{}; std::unique_ptr m_zoneWindowDrawing; + ZoneColors m_zoneColors; + OverlappingZonesAlgorithm m_overlappingAlgorithm; }; -ZoneWindow::ZoneWindow(HINSTANCE hinstance) +WorkArea::WorkArea(HINSTANCE hinstance) { WNDCLASSEXW wcex{}; wcex.cbSize = sizeof(WNDCLASSEX); @@ -177,14 +184,15 @@ ZoneWindow::ZoneWindow(HINSTANCE hinstance) RegisterClassExW(&wcex); } -ZoneWindow::~ZoneWindow() +WorkArea::~WorkArea() { windowPool.FreeZoneWindow(m_window); } -bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId) +bool WorkArea::Init(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm) { - m_host.copy_from(host); + m_zoneColors = zoneColors; + m_overlappingAlgorithm = overlappingAlgorithm; Rect workAreaRect; m_monitor = monitor; @@ -218,7 +226,7 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit return true; } -IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window) noexcept +IFACEMETHODIMP WorkArea::MoveSizeEnter(HWND window) noexcept { m_windowMoveSize = window; m_highlightZone = {}; @@ -227,7 +235,7 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window) noexcept return S_OK; } -IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) noexcept +IFACEMETHODIMP WorkArea::MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) noexcept { bool redraw = false; POINT ptClient = ptScreen; @@ -265,13 +273,13 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable if (redraw) { - m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_zoneColors); } return S_OK; } -IFACEMETHODIMP ZoneWindow::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept +IFACEMETHODIMP WorkArea::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept { if (m_windowMoveSize != window) { @@ -289,7 +297,7 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnd(HWND window, POINT const& ptScreen) noexc SaveWindowProcessToZoneIndex(window); } } - Trace::ZoneWindow::MoveSizeEnd(m_activeZoneSet); + Trace::WorkArea::MoveSizeEnd(m_activeZoneSet); HideZoneWindow(); m_windowMoveSize = nullptr; @@ -297,13 +305,13 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnd(HWND window, POINT const& ptScreen) noexc } IFACEMETHODIMP_(void) -ZoneWindow::MoveWindowIntoZoneByIndex(HWND window, size_t index) noexcept +WorkArea::MoveWindowIntoZoneByIndex(HWND window, size_t index) noexcept { MoveWindowIntoZoneByIndexSet(window, { index }); } IFACEMETHODIMP_(void) -ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector& indexSet) noexcept +WorkArea::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector& indexSet) noexcept { if (m_activeZoneSet) { @@ -312,7 +320,7 @@ ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector& } IFACEMETHODIMP_(bool) -ZoneWindow::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle) noexcept +WorkArea::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle) noexcept { if (m_activeZoneSet) { @@ -329,7 +337,7 @@ ZoneWindow::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, boo } IFACEMETHODIMP_(bool) -ZoneWindow::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle) noexcept +WorkArea::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle) noexcept { if (m_activeZoneSet) { @@ -343,7 +351,7 @@ ZoneWindow::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, } IFACEMETHODIMP_(bool) -ZoneWindow::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept +WorkArea::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept { if (m_activeZoneSet) { @@ -357,7 +365,7 @@ ZoneWindow::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexce } IFACEMETHODIMP_(void) -ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept +WorkArea::SaveWindowProcessToZoneIndex(HWND window) noexcept { if (m_activeZoneSet) { @@ -375,19 +383,33 @@ ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept } } +IFACEMETHODIMP_(std::vector) +WorkArea::GetWindowZoneIndexes(HWND window) const noexcept +{ + if (m_activeZoneSet) + { + wil::unique_cotaskmem_string zoneSetId; + if (SUCCEEDED(StringFromCLSID(m_activeZoneSet->Id(), &zoneSetId))) + { + return FancyZonesDataInstance().GetAppLastZoneIndexSet(window, m_uniqueId, zoneSetId.get()); + } + } + return {}; +} + IFACEMETHODIMP_(void) -ZoneWindow::ShowZoneWindow() noexcept +WorkArea::ShowZoneWindow() noexcept { if (m_window) { SetAsTopmostWindow(); - m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_zoneColors); m_zoneWindowDrawing->Show(); } } IFACEMETHODIMP_(void) -ZoneWindow::HideZoneWindow() noexcept +WorkArea::HideZoneWindow() noexcept { if (m_window) { @@ -399,40 +421,53 @@ ZoneWindow::HideZoneWindow() noexcept } IFACEMETHODIMP_(void) -ZoneWindow::UpdateActiveZoneSet() noexcept +WorkArea::UpdateActiveZoneSet() noexcept { - CalculateZoneSet(); + CalculateZoneSet(m_overlappingAlgorithm); if (m_window) { m_highlightZone.clear(); - m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_zoneColors); } } IFACEMETHODIMP_(void) -ZoneWindow::ClearSelectedZones() noexcept +WorkArea::ClearSelectedZones() noexcept { if (m_highlightZone.size()) { m_highlightZone.clear(); - m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_zoneColors); } } IFACEMETHODIMP_(void) -ZoneWindow::FlashZones() noexcept +WorkArea::FlashZones() noexcept { if (m_window) { SetAsTopmostWindow(); - m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), {}, m_host); + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), {}, m_zoneColors); m_zoneWindowDrawing->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 ZoneWindow::InitializeZoneSets(const std::wstring& parentUniqueId) noexcept +void WorkArea::InitializeZoneSets(const std::wstring& parentUniqueId) noexcept { bool deviceAdded = FancyZonesDataInstance().AddDevice(m_uniqueId); // If the device has been added, check if it should inherit the parent's layout @@ -440,10 +475,10 @@ void ZoneWindow::InitializeZoneSets(const std::wstring& parentUniqueId) noexcept { FancyZonesDataInstance().CloneDeviceInfo(parentUniqueId, m_uniqueId); } - CalculateZoneSet(); + CalculateZoneSet(m_overlappingAlgorithm); } -void ZoneWindow::CalculateZoneSet() noexcept +void WorkArea::CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept { const auto& fancyZonesData = FancyZonesDataInstance(); const auto deviceInfoData = fancyZonesData.FindDeviceInfo(m_uniqueId); @@ -470,7 +505,7 @@ void ZoneWindow::CalculateZoneSet() noexcept activeZoneSet.type, m_monitor, sensitivityRadius, - m_host->GetOverlappingZonesAlgorithm())); + overlappingAlgorithm)); RECT workArea; if (m_monitor) @@ -500,7 +535,7 @@ void ZoneWindow::CalculateZoneSet() noexcept } } -void ZoneWindow::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept +void WorkArea::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept { m_activeZoneSet.copy_from(zoneSet); @@ -518,7 +553,7 @@ void ZoneWindow::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept } } -LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept +LRESULT WorkArea::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept { switch (message) { @@ -540,7 +575,7 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept return 0; } -std::vector ZoneWindow::ZonesFromPoint(POINT pt) noexcept +std::vector WorkArea::ZonesFromPoint(POINT pt) noexcept { if (m_activeZoneSet) { @@ -549,7 +584,7 @@ std::vector ZoneWindow::ZonesFromPoint(POINT pt) noexcept return {}; } -void ZoneWindow::SetAsTopmostWindow() noexcept +void WorkArea::SetAsTopmostWindow() noexcept { if (!m_window) { @@ -569,13 +604,13 @@ void ZoneWindow::SetAsTopmostWindow() noexcept #pragma endregion -LRESULT CALLBACK ZoneWindow::s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept +LRESULT CALLBACK WorkArea::s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept { - auto thisRef = reinterpret_cast(GetWindowLongPtr(window, GWLP_USERDATA)); + auto thisRef = reinterpret_cast(GetWindowLongPtr(window, GWLP_USERDATA)); if ((thisRef == nullptr) && (message == WM_CREATE)) { auto createStruct = reinterpret_cast(lparam); - thisRef = reinterpret_cast(createStruct->lpCreateParams); + thisRef = reinterpret_cast(createStruct->lpCreateParams); SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast(thisRef)); } @@ -583,10 +618,10 @@ LRESULT CALLBACK ZoneWindow::s_WndProc(HWND window, UINT message, WPARAM wparam, DefWindowProc(window, message, wparam, lparam); } -winrt::com_ptr MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId) noexcept +winrt::com_ptr MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm) noexcept { - auto self = winrt::make_self(hinstance); - if (self->Init(host, hinstance, monitor, uniqueId, parentUniqueId)) + auto self = winrt::make_self(hinstance); + if (self->Init(hinstance, monitor, uniqueId, parentUniqueId, zoneColors, overlappingAlgorithm)) { return self; } diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneWindow.h b/src/modules/fancyzones/FancyZonesLib/WorkArea.h similarity index 86% rename from src/modules/fancyzones/FancyZonesLib/ZoneWindow.h rename to src/modules/fancyzones/FancyZonesLib/WorkArea.h index 4e882637f7..9f87dd0fae 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneWindow.h +++ b/src/modules/fancyzones/FancyZonesLib/WorkArea.h @@ -1,11 +1,12 @@ #pragma once #include "FancyZones.h" #include "FancyZonesLib/ZoneSet.h" +#include "FancyZonesLib/ZoneColors.h" /** * Class representing single work area, which is defined by monitor and virtual desktop. */ -interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow : public IUnknown +interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IWorkArea : public IUnknown { /** * A window is being moved or resized. Track down window position and give zone layout @@ -96,11 +97,15 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow /** * @returns Unique work area identifier. Format: __ */ - IFACEMETHOD_(std::wstring, UniqueId)() = 0; + IFACEMETHOD_(std::wstring, UniqueId)() const = 0; /** * @returns Active zone layout for this work area. */ - IFACEMETHOD_(IZoneSet*, ActiveZoneSet)() = 0; + IFACEMETHOD_(IZoneSet*, ActiveZoneSet)() const = 0; + /* + * @returns Zone index of the window + */ + IFACEMETHOD_(std::vector, GetWindowZoneIndexes)(HWND window) const = 0; IFACEMETHOD_(void, ShowZoneWindow)() = 0; IFACEMETHOD_(void, HideZoneWindow)() = 0; /** @@ -108,14 +113,21 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow */ IFACEMETHOD_(void, UpdateActiveZoneSet)() = 0; /** - * Clear the selected zones when this ZoneWindow loses focus. + * Clear the selected zones when this WorkArea loses focus. */ IFACEMETHOD_(void, ClearSelectedZones)() = 0; /* * 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 MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, - const std::wstring& uniqueId, const std::wstring& parentUniqueId) noexcept; +winrt::com_ptr MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm) noexcept; diff --git a/src/modules/fancyzones/FancyZonesLib/Zone.h b/src/modules/fancyzones/FancyZonesLib/Zone.h index f768cff14e..d1d9e92fc1 100644 --- a/src/modules/fancyzones/FancyZonesLib/Zone.h +++ b/src/modules/fancyzones/FancyZonesLib/Zone.h @@ -26,7 +26,7 @@ interface __declspec(uuid("{8228E934-B6EF-402A-9892-15A1441BF8B0}")) IZone : pub * Compute the coordinates of the rectangle to which a window should be resized. * * @param window Handle of window which should be assigned to zone. - * @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the + * @param zoneWindow The m_window of a WorkArea, it's a hidden window representing the * current monitor desktop work area. * @returns a RECT structure, describing global coordinates to which a window should be resized */ diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneColors.h b/src/modules/fancyzones/FancyZonesLib/ZoneColors.h new file mode 100644 index 0000000000..867adbe261 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/ZoneColors.h @@ -0,0 +1,10 @@ +#pragma once +#include + +struct ZoneColors +{ + COLORREF primaryColor; + COLORREF borderColor; + COLORREF highlightColor; + int highlightOpacity; +}; diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp b/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp index 44514223f9..2fc88058bc 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp +++ b/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp @@ -254,7 +254,7 @@ ZoneSet::ZonesFromPoint(POINT pt) const noexcept { try { - using Algorithm = Settings::OverlappingZonesAlgorithm; + using Algorithm = OverlappingZonesAlgorithm; switch (m_config.SelectionAlgorithm) { diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneSet.h b/src/modules/fancyzones/FancyZonesLib/ZoneSet.h index 5cacc90584..73d22e47ef 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneSet.h +++ b/src/modules/fancyzones/FancyZonesLib/ZoneSet.h @@ -53,7 +53,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * Assign window to the zone based on zone index inside zone layout. * * @param window Handle of window which should be assigned to zone. - * @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the + * @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the * current monitor desktop work area. * @param index Zone index within zone layout. */ @@ -63,7 +63,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * Assign window to the zones based on the set of zone indices inside zone layout. * * @param window Handle of window which should be assigned to zone. - * @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the + * @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the * current monitor desktop work area. * @param indexSet The set of zone indices within zone layout. */ @@ -74,7 +74,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * not their on-screen position. * * @param window Handle of window which should be assigned to zone. - * @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the + * @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the * current monitor desktop work area. * @param vkCode Pressed arrow key. * @param cycle Whether we should move window to the first zone if we reached last zone in layout. @@ -89,7 +89,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * their on-screen position. * * @param window Handle of window which should be assigned to zone. - * @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the + * @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the * current monitor desktop work area. * @param vkCode Pressed arrow key. * @param cycle Whether we should move window to the first zone if we reached last zone in layout. @@ -104,7 +104,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * their on-screen position. * * @param window Handle of window which should be assigned to zone. - * @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the + * @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the * current monitor desktop work area. * @param vkCode Pressed arrow key. * @@ -117,7 +117,7 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet : * Assign window to the zone based on cursor coordinates. * * @param window Handle of window which should be assigned to zone. - * @param workAreaWindow The m_window of a ZoneWindow, it's a hidden window representing the + * @param workAreaWindow The m_window of a WorkArea, it's a hidden window representing the * current monitor desktop work area. * @param pt Cursor coordinates. */ @@ -159,7 +159,7 @@ struct ZoneSetConfig FancyZonesDataTypes::ZoneSetLayoutType layoutType, HMONITOR monitor, int sensitivityRadius, - Settings::OverlappingZonesAlgorithm selectionAlgorithm = {}) noexcept : + OverlappingZonesAlgorithm selectionAlgorithm = {}) noexcept : Id(id), LayoutType(layoutType), Monitor(monitor), @@ -172,7 +172,7 @@ struct ZoneSetConfig FancyZonesDataTypes::ZoneSetLayoutType LayoutType{}; HMONITOR Monitor{}; int SensitivityRadius; - Settings::OverlappingZonesAlgorithm SelectionAlgorithm = Settings::OverlappingZonesAlgorithm::Smallest; + OverlappingZonesAlgorithm SelectionAlgorithm = OverlappingZonesAlgorithm::Smallest; }; winrt::com_ptr MakeZoneSet(ZoneSetConfig const& config) noexcept; diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/FancyZonesLib/ZoneWindowDrawing.cpp index 0731f184c2..5085f71e12 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/FancyZonesLib/ZoneWindowDrawing.cpp @@ -279,19 +279,19 @@ void ZoneWindowDrawing::Flash() void ZoneWindowDrawing::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones, const std::vector& highlightZones, - winrt::com_ptr host) + const ZoneColors& colors) { _TRACER_; std::unique_lock lock(m_mutex); m_sceneRects = {}; - auto borderColor = ConvertColor(host->GetZoneBorderColor()); - auto inactiveColor = ConvertColor(host->GetZoneColor()); - auto highlightColor = ConvertColor(host->GetZoneHighlightColor()); + auto borderColor = ConvertColor(colors.borderColor); + auto inactiveColor = ConvertColor(colors.primaryColor); + auto highlightColor = ConvertColor(colors.highlightColor); - inactiveColor.a = host->GetZoneHighlightOpacity() / 100.f; - highlightColor.a = host->GetZoneHighlightOpacity() / 100.f; + inactiveColor.a = colors.highlightOpacity / 100.f; + highlightColor.a = colors.highlightOpacity / 100.f; std::vector isHighlighted(zones.size() + 1, false); for (size_t x : highlightZones) diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneWindowDrawing.h b/src/modules/fancyzones/FancyZonesLib/ZoneWindowDrawing.h index 06a204ea14..e17da9f50d 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/FancyZonesLib/ZoneWindowDrawing.h @@ -11,6 +11,7 @@ #include "Zone.h" #include "ZoneSet.h" #include "FancyZones.h" +#include "ZoneColors.h" class ZoneWindowDrawing { @@ -65,5 +66,5 @@ public: void Flash(); void DrawActiveZoneSet(const IZoneSet::ZonesMap& zones, const std::vector& highlightZones, - winrt::com_ptr host); + const ZoneColors& colors); }; diff --git a/src/modules/fancyzones/FancyZonesLib/trace.cpp b/src/modules/fancyzones/FancyZonesLib/trace.cpp index 49365f2eda..12148b04b5 100644 --- a/src/modules/fancyzones/FancyZonesLib/trace.cpp +++ b/src/modules/fancyzones/FancyZonesLib/trace.cpp @@ -294,7 +294,7 @@ void Trace::VirtualDesktopChanged() noexcept TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); } -void Trace::ZoneWindow::KeyUp(WPARAM wParam) noexcept +void Trace::WorkArea::KeyUp(WPARAM wParam) noexcept { TraceLoggingWrite( g_hProvider, @@ -304,7 +304,7 @@ void Trace::ZoneWindow::KeyUp(WPARAM wParam) noexcept TraceLoggingValue(wParam, KeyboardValueKey)); } -void Trace::ZoneWindow::MoveSizeEnd(_In_opt_ winrt::com_ptr activeSet) noexcept +void Trace::WorkArea::MoveSizeEnd(_In_opt_ winrt::com_ptr activeSet) noexcept { auto const zoneInfo = GetZoneSetInfo(activeSet); TraceLoggingWrite( @@ -317,7 +317,7 @@ void Trace::ZoneWindow::MoveSizeEnd(_In_opt_ winrt::com_ptr activeSet) TraceLoggingValue(zoneInfo.NumberOfWindows, NumberOfWindowsKey)); } -void Trace::ZoneWindow::CycleActiveZoneSet(_In_opt_ winrt::com_ptr activeSet, InputMode mode) noexcept +void Trace::WorkArea::CycleActiveZoneSet(_In_opt_ winrt::com_ptr activeSet, InputMode mode) noexcept { auto const zoneInfo = GetZoneSetInfo(activeSet); TraceLoggingWrite( diff --git a/src/modules/fancyzones/FancyZonesLib/trace.h b/src/modules/fancyzones/FancyZonesLib/trace.h index ceca7c088b..9291b76ea9 100644 --- a/src/modules/fancyzones/FancyZonesLib/trace.h +++ b/src/modules/fancyzones/FancyZonesLib/trace.h @@ -23,7 +23,7 @@ public: static void SettingsTelemetry(const Settings& settings) noexcept; static void VirtualDesktopChanged() noexcept; - class ZoneWindow + class WorkArea { public: enum class InputMode diff --git a/src/modules/fancyzones/FancyZonesLib/util.cpp b/src/modules/fancyzones/FancyZonesLib/util.cpp index 438f036bfd..dcb9e93f62 100644 --- a/src/modules/fancyzones/FancyZonesLib/util.cpp +++ b/src/modules/fancyzones/FancyZonesLib/util.cpp @@ -18,6 +18,7 @@ namespace NonLocalizable { const wchar_t PowerToysAppPowerLauncher[] = L"POWERLAUNCHER.EXE"; const wchar_t PowerToysAppFZEditor[] = L"FANCYZONESEDITOR.EXE"; + const wchar_t SplashClassName[] = L"MsoSplash"; } bool find_app_name_in_path(const std::wstring& where, const std::vector& what) @@ -604,6 +605,17 @@ namespace FancyZonesUtils return SUCCEEDED(CLSIDFromString(str.c_str(), &id)); } + std::optional GuidToString(const GUID& guid) noexcept + { + wil::unique_cotaskmem_string guidString; + if (SUCCEEDED(StringFromCLSID(guid, &guidString))) + { + return guidString.get(); + } + + return std::nullopt; + } + bool IsValidDeviceId(const std::wstring& str) { std::wstring monitorName; @@ -862,4 +874,15 @@ namespace FancyZonesUtils 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; + } + } diff --git a/src/modules/fancyzones/FancyZonesLib/util.h b/src/modules/fancyzones/FancyZonesLib/util.h index 08084ccd6c..b529dd8590 100644 --- a/src/modules/fancyzones/FancyZonesLib/util.h +++ b/src/modules/fancyzones/FancyZonesLib/util.h @@ -203,6 +203,7 @@ namespace FancyZonesUtils void RestoreWindowOrigin(HWND window) noexcept; bool IsValidGuid(const std::wstring& str); + std::optional GuidToString(const GUID& guid) noexcept; std::wstring GenerateUniqueId(HMONITOR monitor, const std::wstring& devideId, const std::wstring& virtualDesktopId); std::wstring GenerateUniqueIdAllMonitorsArea(const std::wstring& virtualDesktopId); @@ -216,4 +217,6 @@ namespace FancyZonesUtils // If HWND is already dead, we assume it wasn't elevated bool IsProcessOfWindowElevated(HWND window); + + bool IsSplashScreen(HWND window); } diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/FancyZones.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/FancyZones.Spec.cpp index 10de1465b8..80c6b7d9aa 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/FancyZones.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/FancyZones.Spec.cpp @@ -55,231 +55,6 @@ namespace FancyZonesUnitTests } }; - TEST_CLASS (FancyZonesIZoneWindowHostUnitTests) - { - HINSTANCE m_hInst{}; - std::wstring m_moduleName = L"FancyZonesUnitTests"; - std::wstring m_moduleKey = L"FancyZonesUnitTests"; - winrt::com_ptr m_settings = nullptr; - winrt::com_ptr m_zoneWindowHost = nullptr; - - std::wstring serializedPowerToySettings(const Settings& settings) - { - PowerToysSettings::Settings ptSettings(HINSTANCE{}, L"FancyZonesUnitTests"); - - ptSettings.add_hotkey(L"fancyzones_editor_hotkey", IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL, settings.editorHotkey); - 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_restoreSize", IDS_SETTING_DESCRIPTION_RESTORESIZE, settings.restoreSize); - ptSettings.add_bool_toggle(L"fancyzones_quickLayoutSwitch", IDS_SETTING_DESCRIPTION_QUICKLAYOUTSWITCH, settings.quickLayoutSwitch); - ptSettings.add_bool_toggle(L"fancyzones_flashZonesOnQuickSwitch", IDS_SETTING_DESCRIPTION_FLASHZONESONQUICKSWITCH, settings.flashZonesOnQuickSwitch); - 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(); - } - - 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); - Assert::IsTrue(fancyZones != nullptr); - - m_zoneWindowHost = fancyZones.as(); - Assert::IsTrue(m_zoneWindowHost != nullptr); - } - - TEST_METHOD_CLEANUP(Cleanup) - { - auto settingsFolder = PTSettingsHelper::get_module_save_folder_location(m_moduleName); - const auto settingsFile = settingsFolder + L"\\settings.json"; - std::filesystem::remove(settingsFile); - std::filesystem::remove(settingsFolder); - } - - TEST_METHOD (GetZoneColor) - { - const auto expected = RGB(171, 175, 238); - const Settings settings{ - .shiftDrag = true, - .mouseSwitch = true, - .displayChange_moveWindows = true, - .zoneSetChange_flashZones = false, - .zoneSetChange_moveWindows = true, - .overrideSnapHotkeys = false, - .moveWindowAcrossMonitors = false, - .moveWindowsBasedOnPosition = false, - .appLastZone_moveWindows = true, - .restoreSize = false, - .use_cursorpos_editor_startupscreen = true, - .spanZonesAcrossMonitors = false, - .zoneColor = L"#abafee", - .zoneBorderColor = L"FAFAFA", - .zoneHighlightColor = L"#FAFAFA", - .zoneHighlightOpacity = 45, - .editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3), - .excludedApps = L"app\r\napp2", - .excludedAppsArray = { L"APP", L"APP2" }, - }; - - auto config = serializedPowerToySettings(settings); - m_settings->SetConfig(config.c_str()); - - const auto actual = m_zoneWindowHost->GetZoneColor(); - Assert::AreEqual(expected, actual); - } - - TEST_METHOD (GetZoneBorderColor) - { - const auto expected = RGB(171, 175, 238); - const Settings settings{ - .shiftDrag = true, - .mouseSwitch = true, - .displayChange_moveWindows = true, - .zoneSetChange_flashZones = false, - .zoneSetChange_moveWindows = true, - .overrideSnapHotkeys = false, - .moveWindowAcrossMonitors = false, - .moveWindowsBasedOnPosition = false, - .appLastZone_moveWindows = true, - .restoreSize = false, - .use_cursorpos_editor_startupscreen = true, - .spanZonesAcrossMonitors = false, - .zoneColor = L"#FAFAFA", - .zoneBorderColor = L"#abafee", - .zoneHighlightColor = L"#FAFAFA", - .zoneHighlightOpacity = 45, - .editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3), - .excludedApps = L"app\r\napp2", - .excludedAppsArray = { L"APP", L"APP2" }, - }; - - auto config = serializedPowerToySettings(settings); - m_settings->SetConfig(config.c_str()); - - const auto actual = m_zoneWindowHost->GetZoneBorderColor(); - Assert::AreEqual(expected, actual); - } - - TEST_METHOD (GetZoneHighlightColor) - { - const auto expected = RGB(171, 175, 238); - const Settings settings{ - .shiftDrag = true, - .mouseSwitch = true, - .displayChange_moveWindows = true, - .zoneSetChange_flashZones = false, - .zoneSetChange_moveWindows = true, - .overrideSnapHotkeys = false, - .moveWindowAcrossMonitors = false, - .moveWindowsBasedOnPosition = false, - .appLastZone_moveWindows = true, - .restoreSize = false, - .use_cursorpos_editor_startupscreen = true, - .showZonesOnAllMonitors = false, - .spanZonesAcrossMonitors = false, - .makeDraggedWindowTransparent = true, - .zoneColor = L"#FAFAFA", - .zoneBorderColor = L"FAFAFA", - .zoneHighlightColor = L"#abafee", - .zoneHighlightOpacity = 45, - .editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3), - .excludedApps = L"app\r\napp2", - .excludedAppsArray = { L"APP", L"APP2" }, - }; - - auto config = serializedPowerToySettings(settings); - m_settings->SetConfig(config.c_str()); - - const auto actual = m_zoneWindowHost->GetZoneHighlightColor(); - Assert::AreEqual(expected, actual); - } - - TEST_METHOD (GetZoneHighlightOpacity) - { - const auto expected = 88; - const Settings settings{ - .shiftDrag = true, - .mouseSwitch = true, - .displayChange_moveWindows = true, - .zoneSetChange_flashZones = false, - .zoneSetChange_moveWindows = true, - .overrideSnapHotkeys = false, - .moveWindowAcrossMonitors = false, - .moveWindowsBasedOnPosition = false, - .appLastZone_moveWindows = true, - .restoreSize = false, - .use_cursorpos_editor_startupscreen = true, - .showZonesOnAllMonitors = false, - .spanZonesAcrossMonitors = false, - .makeDraggedWindowTransparent = true, - .zoneColor = L"#FAFAFA", - .zoneBorderColor = L"FAFAFA", - .zoneHighlightColor = L"#abafee", - .zoneHighlightOpacity = expected, - .editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3), - .excludedApps = L"app\r\napp2", - .excludedAppsArray = { L"APP", L"APP2" }, - }; - - auto config = serializedPowerToySettings(settings); - m_settings->SetConfig(config.c_str()); - - const auto actual = m_zoneWindowHost->GetZoneHighlightOpacity(); - Assert::AreEqual(expected, actual); - } - - TEST_METHOD (IsMakeDraggenWindowTransparentActive) - { - const auto expected = true; - const Settings settings{ - .shiftDrag = true, - .mouseSwitch = true, - .displayChange_moveWindows = true, - .zoneSetChange_flashZones = false, - .zoneSetChange_moveWindows = true, - .overrideSnapHotkeys = false, - .moveWindowAcrossMonitors = false, - .moveWindowsBasedOnPosition = false, - .appLastZone_moveWindows = true, - .restoreSize = false, - .use_cursorpos_editor_startupscreen = true, - .showZonesOnAllMonitors = false, - .spanZonesAcrossMonitors = false, - .makeDraggedWindowTransparent = true, - .zoneColor = L"#FAFAFA", - .zoneBorderColor = L"FAFAFA", - .zoneHighlightColor = L"#abafee", - .zoneHighlightOpacity = expected, - .editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, false, false, false, VK_OEM_3), - .excludedApps = L"app\r\napp2", - .excludedAppsArray = { L"APP", L"APP2" }, - }; - - auto config = serializedPowerToySettings(settings); - m_settings->SetConfig(config.c_str()); - - Assert::AreEqual(expected, m_zoneWindowHost->isMakeDraggedWindowTransparentActive()); - } - }; - TEST_CLASS (FancyZonesIFancyZonesCallbackUnitTests) { HINSTANCE m_hInst{}; diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/FancyZonesSettings.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/FancyZonesSettings.Spec.cpp index 0fc8c21773..0e13a0ca69 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/FancyZonesSettings.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/FancyZonesSettings.Spec.cpp @@ -396,160 +396,6 @@ namespace FancyZonesUnitTests } }; - TEST_CLASS (FancyZonesSettingsCallbackUnitTests) - { - winrt::com_ptr m_settings = nullptr; - PCWSTR m_moduleName = L"FancyZonesUnitTests"; - PCWSTR m_moduleKey = L"FancyZonesUnitTests"; - - struct FZCallback : public winrt::implements - { - public: - FZCallback(bool* callFlag) : - m_callFlag(callFlag) - { - *m_callFlag = false; - } - - IFACEMETHODIMP_(bool) - InMoveSize() noexcept { return false; } - IFACEMETHODIMP_(void) - MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept {} - IFACEMETHODIMP_(void) - MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept {} - IFACEMETHODIMP_(void) - MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept {} - IFACEMETHODIMP_(void) - HandleWinHookEvent(const WinHookEvent* data) noexcept {} - IFACEMETHODIMP_(void) - VirtualDesktopChanged() noexcept {} - IFACEMETHODIMP_(void) - VirtualDesktopInitialize() noexcept {} - IFACEMETHODIMP_(void) - WindowCreated(HWND window) noexcept {} - IFACEMETHODIMP_(bool) - OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept { return false; } - - IFACEMETHODIMP_(void) - ToggleEditor() noexcept - { - Assert::IsNotNull(m_callFlag); - *m_callFlag = true; - } - - IFACEMETHODIMP_(void) - SettingsChanged() noexcept - { - Assert::IsNotNull(m_callFlag); - *m_callFlag = true; - } - - private: - bool* m_callFlag = nullptr; - }; - - TEST_METHOD_INITIALIZE(Init) - { - HINSTANCE hInst = (HINSTANCE)GetModuleHandleW(nullptr); - const Settings expected{ - .shiftDrag = false, - .mouseSwitch = false, - .displayChange_moveWindows = true, - .zoneSetChange_flashZones = true, - .zoneSetChange_moveWindows = true, - .overrideSnapHotkeys = false, - .moveWindowAcrossMonitors = false, - .moveWindowsBasedOnPosition = false, - .appLastZone_moveWindows = false, - .openWindowOnActiveMonitor = false, - .restoreSize = false, - .use_cursorpos_editor_startupscreen = true, - .showZonesOnAllMonitors = false, - .spanZonesAcrossMonitors = false, - .makeDraggedWindowTransparent = true, - .zoneColor = L"FAFAFA", - .zoneBorderColor = L"CCDDEE", - .zoneHighlightColor = L"#00FFD7", - .zoneHighlightOpacity = 45, - .editorHotkey = PowerToysSettings::HotkeyObject::from_settings(false, true, true, false, VK_OEM_3), - .excludedApps = L"app", - .excludedAppsArray = { L"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_excluded_apps", expected.excludedApps); - - values.save_to_settings_file(); - - m_settings = MakeFancyZonesSettings(hInst, m_moduleName, m_moduleKey); - Assert::IsTrue(m_settings != nullptr); - } - - TEST_METHOD_CLEANUP(Cleanup) - { - std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_moduleName)); - } - - TEST_METHOD (CallbackSetConfig) - { - bool flag = false; - winrt::com_ptr callback = winrt::make_self(&flag); - - json::JsonObject json{}; - json.SetNamedValue(L"name", json::JsonValue::CreateStringValue(L"name")); - - m_settings->SetCallback(callback.get()); - m_settings->SetConfig(json.Stringify().c_str()); - - Assert::IsTrue(flag); - } - - TEST_METHOD (CallbackGetConfig) - { - bool flag = false; - winrt::com_ptr callback = winrt::make_self(&flag); - - m_settings->SetCallback(callback.get()); - - int bufSize = 1; - wchar_t buffer{}; - m_settings->GetConfig(&buffer, &bufSize); - - Assert::IsFalse(flag); - } - - TEST_METHOD (CallbackGetSettings) - { - bool flag = false; - winrt::com_ptr callback = winrt::make_self(&flag); - - m_settings->SetCallback(callback.get()); - m_settings->GetSettings(); - - Assert::IsFalse(flag); - } - }; - TEST_CLASS (FancyZonesSettingsUnitTests) { winrt::com_ptr m_settings = nullptr; diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj index 3bd886d1b2..cb049e499d 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj @@ -49,9 +49,9 @@ + - diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters index 3b1df00974..d2a639f3ae 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters @@ -27,9 +27,6 @@ Source Files - - Source Files - Source Files @@ -42,6 +39,9 @@ Source Files + + Source Files + diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneWindow.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp similarity index 58% rename from src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneWindow.Spec.cpp rename to src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp index 7b858b1600..3ee4cf6d59 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneWindow.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp @@ -4,11 +4,12 @@ #include #include -#include +#include #include #include #include #include +#include #include "Util.h" #include @@ -17,58 +18,10 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework; namespace FancyZonesUnitTests { - struct MockZoneWindowHost : public winrt::implements - { - IFACEMETHODIMP_(void) - MoveWindowsOnActiveZoneSetChange() noexcept {}; - IFACEMETHODIMP_(COLORREF) - GetZoneColor() noexcept - { - return RGB(0xFF, 0xFF, 0xFF); - } - IFACEMETHODIMP_(COLORREF) - GetZoneBorderColor() noexcept - { - return RGB(0xFF, 0xFF, 0xFF); - } - IFACEMETHODIMP_(COLORREF) - GetZoneHighlightColor() noexcept - { - return RGB(0xFF, 0xFF, 0xFF); - } - IFACEMETHODIMP_(IZoneWindow*) - GetParentZoneWindow(HMONITOR monitor) noexcept - { - return m_zoneWindow; - } - IFACEMETHODIMP_(int) - GetZoneHighlightOpacity() noexcept - { - return 100; - } - IFACEMETHODIMP_(bool) - isMakeDraggedWindowTransparentActive() noexcept - { - return true; - } - IFACEMETHODIMP_(bool) - InMoveSize() noexcept - { - return false; - } - IFACEMETHODIMP_(Settings::OverlappingZonesAlgorithm) - GetOverlappingZonesAlgorithm() noexcept - { - return Settings::OverlappingZonesAlgorithm::Smallest; - } - - IZoneWindow* m_zoneWindow; - }; - const std::wstring m_deviceId = L"\\\\?\\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"; const std::wstring m_virtualDesktopId = L"MyVirtualDesktopId"; - TEST_CLASS (ZoneWindowCreationUnitTests) + TEST_CLASS (WorkAreaCreationUnitTests) { std::wstringstream m_parentUniqueId; std::wstringstream m_uniqueId; @@ -77,15 +30,17 @@ namespace FancyZonesUnitTests HMONITOR m_monitor{}; MONITORINFOEX m_monitorInfo{}; GUID m_virtualDesktopGuid{}; + ZoneColors m_zoneColors{}; + OverlappingZonesAlgorithm m_overlappingAlgorithm = OverlappingZonesAlgorithm::Positional; FancyZonesData& m_fancyZonesData = FancyZonesDataInstance(); - void testZoneWindow(winrt::com_ptr zoneWindow) + void testWorkArea(winrt::com_ptr workArea) { const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom); - Assert::IsNotNull(zoneWindow.get()); - Assert::AreEqual(m_uniqueId.str().c_str(), zoneWindow->UniqueId().c_str()); + Assert::IsNotNull(workArea.get()); + Assert::AreEqual(m_uniqueId.str().c_str(), workArea->UniqueId().c_str()); } TEST_METHOD_INITIALIZE(Init) @@ -105,82 +60,89 @@ namespace FancyZonesUnitTests auto guid = Helpers::StringToGuid(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}"); 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, + }; } - TEST_METHOD (CreateZoneWindow) + TEST_METHOD (CreateWorkArea) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - testZoneWindow(zoneWindow); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + testWorkArea(workArea); - auto* activeZoneSet{ zoneWindow->ActiveZoneSet() }; + auto* activeZoneSet{ workArea->ActiveZoneSet() }; Assert::IsNotNull(activeZoneSet); Assert::AreEqual(static_cast(activeZoneSet->LayoutType()), static_cast(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid)); Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast(3)); } - TEST_METHOD (CreateZoneWindowNoHinst) + TEST_METHOD (CreateWorkAreaNoHinst) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), {}, m_monitor, m_uniqueId.str(), {}); - testZoneWindow(zoneWindow); + auto workArea = MakeWorkArea({}, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + testWorkArea(workArea); - auto* activeZoneSet{ zoneWindow->ActiveZoneSet() }; + auto* activeZoneSet{ workArea->ActiveZoneSet() }; Assert::IsNotNull(activeZoneSet); Assert::AreEqual(static_cast(activeZoneSet->LayoutType()), static_cast(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid)); Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast(3)); } - TEST_METHOD (CreateZoneWindowNoHinstFlashZones) + TEST_METHOD (CreateWorkAreaNoHinstFlashZones) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), {}, m_monitor, m_uniqueId.str(), {}); - testZoneWindow(zoneWindow); + auto workArea = MakeWorkArea({}, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + testWorkArea(workArea); - auto* activeZoneSet{ zoneWindow->ActiveZoneSet() }; + auto* activeZoneSet{ workArea->ActiveZoneSet() }; Assert::IsNotNull(activeZoneSet); Assert::AreEqual(static_cast(activeZoneSet->LayoutType()), static_cast(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid)); Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast(3)); } - TEST_METHOD (CreateZoneWindowNoMonitor) + TEST_METHOD (CreateWorkAreaNoMonitor) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, {}, m_uniqueId.str(), {}); - testZoneWindow(zoneWindow); + auto workArea = MakeWorkArea(m_hInst, {}, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + testWorkArea(workArea); } - TEST_METHOD (CreateZoneWindowNoDeviceId) + TEST_METHOD (CreateWorkAreaNoDeviceId) { // Generate unique id without device id std::wstring uniqueId = FancyZonesUtils::GenerateUniqueId(m_monitor, {}, m_virtualDesktopId); - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, uniqueId, {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, uniqueId, {}, m_zoneColors, m_overlappingAlgorithm); const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom); const std::wstring expectedUniqueId = L"FallbackDevice_" + std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom) + L"_" + m_virtualDesktopId; - Assert::IsNotNull(zoneWindow.get()); - Assert::AreEqual(expectedUniqueId.c_str(), zoneWindow->UniqueId().c_str()); + Assert::IsNotNull(workArea.get()); + Assert::AreEqual(expectedUniqueId.c_str(), workArea->UniqueId().c_str()); - auto* activeZoneSet{ zoneWindow->ActiveZoneSet() }; + auto* activeZoneSet{ workArea->ActiveZoneSet() }; Assert::IsNotNull(activeZoneSet); Assert::AreEqual(static_cast(activeZoneSet->LayoutType()), static_cast(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid)); Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast(3)); } - TEST_METHOD (CreateZoneWindowNoDesktopId) + TEST_METHOD (CreateWorkAreaNoDesktopId) { // Generate unique id without virtual desktop id std::wstring uniqueId = FancyZonesUtils::GenerateUniqueId(m_monitor, m_deviceId, {}); - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, uniqueId, {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, uniqueId, {}, m_zoneColors, m_overlappingAlgorithm); const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom); - Assert::IsNotNull(zoneWindow.get()); - Assert::IsTrue(zoneWindow->UniqueId().empty()); + Assert::IsNotNull(workArea.get()); + Assert::IsTrue(workArea->UniqueId().empty()); - auto* activeZoneSet{ zoneWindow->ActiveZoneSet() }; + auto* activeZoneSet{ workArea->ActiveZoneSet() }; Assert::IsNotNull(activeZoneSet); Assert::AreEqual(static_cast(activeZoneSet->LayoutType()), static_cast(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid)); Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast(3)); } - TEST_METHOD (CreateZoneWindowClonedFromParent) + TEST_METHOD (CreateWorkAreaClonedFromParent) { using namespace FancyZonesDataTypes; @@ -192,14 +154,12 @@ namespace FancyZonesUnitTests const auto parentDeviceInfo = DeviceInfoData{ parentZoneSet, true, spacing, zoneCount }; m_fancyZonesData.SetDeviceInfo(m_parentUniqueId.str(), parentDeviceInfo); - winrt::com_ptr zoneWindowHost = winrt::make_self(); - auto parentZoneWindow = MakeZoneWindow(zoneWindowHost.get(), m_hInst, m_monitor, m_parentUniqueId.str(), {}); - zoneWindowHost->m_zoneWindow = parentZoneWindow.get(); + auto parentWorkArea = MakeWorkArea(m_hInst, m_monitor, m_parentUniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + + // newWorkArea = false - workArea won't be cloned from parent + auto actualWorkArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); - // newWorkArea = false - zoneWindow won't be cloned from parent - auto actualZoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - - Assert::IsNotNull(actualZoneWindow->ActiveZoneSet()); + Assert::IsNotNull(actualWorkArea->ActiveZoneSet()); Assert::IsTrue(m_fancyZonesData.GetDeviceInfoMap().contains(m_uniqueId.str())); auto currentDeviceInfo = m_fancyZonesData.GetDeviceInfoMap().at(m_uniqueId.str()); @@ -211,13 +171,15 @@ namespace FancyZonesUnitTests } }; - TEST_CLASS (ZoneWindowUnitTests) + TEST_CLASS (WorkAreaUnitTests) { std::wstringstream m_uniqueId; HINSTANCE m_hInst{}; HMONITOR m_monitor{}; MONITORINFO m_monitorInfo{}; + ZoneColors m_zoneColors{}; + OverlappingZonesAlgorithm m_overlappingAlgorithm = OverlappingZonesAlgorithm::Positional; FancyZonesData& m_fancyZonesData = FancyZonesDataInstance(); @@ -233,73 +195,80 @@ namespace FancyZonesUnitTests m_fancyZonesData.SetSettingsModulePath(L"FancyZonesUnitTests"); m_fancyZonesData.clear_data(); + + m_zoneColors = ZoneColors{ + .primaryColor = FancyZonesUtils::HexToRGB(L"#4287f5"), + .borderColor = FancyZonesUtils::HexToRGB(L"#FFFFFF"), + .highlightColor = FancyZonesUtils::HexToRGB(L"#42eff5"), + .highlightOpacity = 50, + }; } public: TEST_METHOD (MoveSizeEnter) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto expected = S_OK; - const auto actual = zoneWindow->MoveSizeEnter(Mocks::Window()); + const auto actual = workArea->MoveSizeEnter(Mocks::Window()); Assert::AreEqual(expected, actual); } TEST_METHOD (MoveSizeEnterTwice) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto expected = S_OK; - zoneWindow->MoveSizeEnter(Mocks::Window()); - const auto actual = zoneWindow->MoveSizeEnter(Mocks::Window()); + workArea->MoveSizeEnter(Mocks::Window()); + const auto actual = workArea->MoveSizeEnter(Mocks::Window()); Assert::AreEqual(expected, actual); } TEST_METHOD (MoveSizeUpdate) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto expected = S_OK; - const auto actual = zoneWindow->MoveSizeUpdate(POINT{ 0, 0 }, true, false); + const auto actual = workArea->MoveSizeUpdate(POINT{ 0, 0 }, true, false); Assert::AreEqual(expected, actual); } TEST_METHOD (MoveSizeUpdatePointNegativeCoordinates) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto expected = S_OK; - const auto actual = zoneWindow->MoveSizeUpdate(POINT{ -10, -10 }, true, false); + const auto actual = workArea->MoveSizeUpdate(POINT{ -10, -10 }, true, false); Assert::AreEqual(expected, actual); } TEST_METHOD (MoveSizeUpdatePointBigCoordinates) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto expected = S_OK; - const auto actual = zoneWindow->MoveSizeUpdate(POINT{ m_monitorInfo.rcMonitor.right + 1, m_monitorInfo.rcMonitor.bottom + 1 }, true, false); + const auto actual = workArea->MoveSizeUpdate(POINT{ m_monitorInfo.rcMonitor.right + 1, m_monitorInfo.rcMonitor.bottom + 1 }, true, false); Assert::AreEqual(expected, actual); } TEST_METHOD (MoveSizeEnd) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto window = Mocks::Window(); - zoneWindow->MoveSizeEnter(window); + workArea->MoveSizeEnter(window); const auto expected = S_OK; - const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ 0, 0 }); + const auto actual = workArea->MoveSizeEnd(window, POINT{ 0, 0 }); Assert::AreEqual(expected, actual); - const auto zoneSet = zoneWindow->ActiveZoneSet(); + const auto zoneSet = workArea->ActiveZoneSet(); zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); const auto actualZoneIndexSet = zoneSet->GetZoneIndexSetFromWindow(window); Assert::IsFalse(std::vector{} == actualZoneIndexSet); @@ -307,55 +276,55 @@ namespace FancyZonesUnitTests TEST_METHOD (MoveSizeEndWindowNotAdded) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto window = Mocks::Window(); - zoneWindow->MoveSizeEnter(window); + workArea->MoveSizeEnter(window); const auto expected = S_OK; - const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ -100, -100 }); + const auto actual = workArea->MoveSizeEnd(window, POINT{ -100, -100 }); Assert::AreEqual(expected, actual); - const auto zoneSet = zoneWindow->ActiveZoneSet(); + const auto zoneSet = workArea->ActiveZoneSet(); const auto actualZoneIndexSet = zoneSet->GetZoneIndexSetFromWindow(window); Assert::IsTrue(std::vector{} == actualZoneIndexSet); } TEST_METHOD (MoveSizeEndDifferentWindows) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto window = Mocks::Window(); - zoneWindow->MoveSizeEnter(window); + workArea->MoveSizeEnter(window); const auto expected = E_INVALIDARG; - const auto actual = zoneWindow->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 }); + const auto actual = workArea->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 }); Assert::AreEqual(expected, actual); } TEST_METHOD (MoveSizeEndWindowNotSet) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto expected = E_INVALIDARG; - const auto actual = zoneWindow->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 }); + const auto actual = workArea->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 }); Assert::AreEqual(expected, actual); } TEST_METHOD (MoveSizeEndInvalidPoint) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); const auto window = Mocks::Window(); - zoneWindow->MoveSizeEnter(window); + workArea->MoveSizeEnter(window); const auto expected = S_OK; - const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ -1, -1 }); + const auto actual = workArea->MoveSizeEnd(window, POINT{ -1, -1 }); Assert::AreEqual(expected, actual); - const auto zoneSet = zoneWindow->ActiveZoneSet(); + const auto zoneSet = workArea->ActiveZoneSet(); zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0); const auto actualZoneIndex = zoneSet->GetZoneIndexSetFromWindow(window); Assert::IsFalse(std::vector{} == actualZoneIndex); // with invalid point zone remains the same @@ -363,21 +332,21 @@ namespace FancyZonesUnitTests TEST_METHOD (MoveWindowIntoZoneByIndex) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - Assert::IsNotNull(zoneWindow->ActiveZoneSet()); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + Assert::IsNotNull(workArea->ActiveZoneSet()); - zoneWindow->MoveWindowIntoZoneByIndex(Mocks::Window(), 0); + workArea->MoveWindowIntoZoneByIndex(Mocks::Window(), 0); - const auto actual = zoneWindow->ActiveZoneSet(); + const auto actual = workArea->ActiveZoneSet(); } TEST_METHOD (MoveWindowIntoZoneByDirectionAndIndex) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - Assert::IsNotNull(zoneWindow->ActiveZoneSet()); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + Assert::IsNotNull(workArea->ActiveZoneSet()); const auto window = Mocks::WindowCreate(m_hInst); - zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); + workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); @@ -388,13 +357,13 @@ namespace FancyZonesUnitTests TEST_METHOD (MoveWindowIntoZoneByDirectionManyTimes) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - Assert::IsNotNull(zoneWindow->ActiveZoneSet()); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + Assert::IsNotNull(workArea->ActiveZoneSet()); const auto window = Mocks::WindowCreate(m_hInst); - zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); - zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); - zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); + workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); + workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); + workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); @@ -405,10 +374,10 @@ namespace FancyZonesUnitTests TEST_METHOD (SaveWindowProcessToZoneIndexNullptrWindow) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - Assert::IsNotNull(zoneWindow->ActiveZoneSet()); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + Assert::IsNotNull(workArea->ActiveZoneSet()); - zoneWindow->SaveWindowProcessToZoneIndex(nullptr); + workArea->SaveWindowProcessToZoneIndex(nullptr); const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::IsTrue(actualAppZoneHistory.empty()); @@ -416,14 +385,14 @@ namespace FancyZonesUnitTests TEST_METHOD (SaveWindowProcessToZoneIndexNoWindowAdded) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - Assert::IsNotNull(zoneWindow->ActiveZoneSet()); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + Assert::IsNotNull(workArea->ActiveZoneSet()); auto window = Mocks::WindowCreate(m_hInst); auto zone = MakeZone(RECT{ 0, 0, 100, 100 }, 1); - zoneWindow->ActiveZoneSet()->AddZone(zone); + workArea->ActiveZoneSet()->AddZone(zone); - zoneWindow->SaveWindowProcessToZoneIndex(window); + workArea->SaveWindowProcessToZoneIndex(window); const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::IsTrue(actualAppZoneHistory.empty()); @@ -431,13 +400,13 @@ namespace FancyZonesUnitTests TEST_METHOD (SaveWindowProcessToZoneIndexNoWindowAddedWithFilledAppZoneHistory) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - Assert::IsNotNull(zoneWindow->ActiveZoneSet()); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + Assert::IsNotNull(workArea->ActiveZoneSet()); const auto window = Mocks::WindowCreate(m_hInst); const auto processPath = get_process_path(window); - const auto deviceId = zoneWindow->UniqueId(); - const auto zoneSetId = zoneWindow->ActiveZoneSet()->Id(); + const auto deviceId = workArea->UniqueId(); + const auto zoneSetId = workArea->ActiveZoneSet()->Id(); // fill app zone history map Assert::IsTrue(m_fancyZonesData.SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 0 })); @@ -448,9 +417,9 @@ namespace FancyZonesUnitTests // add zone without window const auto zone = MakeZone(RECT{ 0, 0, 100, 100 }, 1); - zoneWindow->ActiveZoneSet()->AddZone(zone); + workArea->ActiveZoneSet()->AddZone(zone); - zoneWindow->SaveWindowProcessToZoneIndex(window); + workArea->SaveWindowProcessToZoneIndex(window); Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size()); const auto& appHistoryArray2 = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath); Assert::AreEqual((size_t)1, appHistoryArray2.size()); @@ -459,17 +428,17 @@ namespace FancyZonesUnitTests TEST_METHOD (SaveWindowProcessToZoneIndexWindowAdded) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - Assert::IsNotNull(zoneWindow->ActiveZoneSet()); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + Assert::IsNotNull(workArea->ActiveZoneSet()); auto window = Mocks::WindowCreate(m_hInst); const auto processPath = get_process_path(window); - const auto deviceId = zoneWindow->UniqueId(); - const auto zoneSetId = zoneWindow->ActiveZoneSet()->Id(); + const auto deviceId = workArea->UniqueId(); + const auto zoneSetId = workArea->ActiveZoneSet()->Id(); auto zone = MakeZone(RECT{ 0, 0, 100, 100 }, 1); - zoneWindow->ActiveZoneSet()->AddZone(zone); - zoneWindow->MoveWindowIntoZoneByIndex(window, 0); + workArea->ActiveZoneSet()->AddZone(zone); + workArea->MoveWindowIntoZoneByIndex(window, 0); //fill app zone history map Assert::IsTrue(m_fancyZonesData.SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 2 })); @@ -478,19 +447,19 @@ namespace FancyZonesUnitTests Assert::AreEqual((size_t)1, appHistoryArray.size()); Assert::IsTrue(std::vector{ 2 } == appHistoryArray[0].zoneIndexSet); - zoneWindow->SaveWindowProcessToZoneIndex(window); + workArea->SaveWindowProcessToZoneIndex(window); const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); - const auto& expected = zoneWindow->ActiveZoneSet()->GetZoneIndexSetFromWindow(window); + const auto& expected = workArea->ActiveZoneSet()->GetZoneIndexSetFromWindow(window); const auto& actual = appHistoryArray[0].zoneIndexSet; Assert::IsTrue(expected == actual); } TEST_METHOD (WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); - Assert::IsNotNull(zoneWindow->ActiveZoneSet()); + auto workArea = MakeWorkArea(m_hInst, m_monitor, m_uniqueId.str(), {}, m_zoneColors, m_overlappingAlgorithm); + Assert::IsNotNull(workArea->ActiveZoneSet()); auto window = Mocks::WindowCreate(m_hInst); @@ -501,9 +470,9 @@ namespace FancyZonesUnitTests SetWindowLong(window, GWL_STYLE, GetWindowLong(window, GWL_STYLE) & ~WS_SIZEBOX); auto zone = MakeZone(RECT{ 50, 50, 300, 300 }, 1); - zoneWindow->ActiveZoneSet()->AddZone(zone); + workArea->ActiveZoneSet()->AddZone(zone); - zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true); + workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true); RECT inZoneRect; GetWindowRect(window, &inZoneRect); diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp index 958b7f840b..564469e2bb 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp @@ -2,7 +2,7 @@ #include "FancyZonesLib\FancyZonesData.h" #include "FancyZonesLib\FancyZonesDataTypes.h" #include "FancyZonesLib\JsonHelpers.h" -#include "FancyZonesLib\VirtualDesktopUtils.h" +#include "FancyZonesLib\VirtualDesktop.h" #include "FancyZonesLib\ZoneSet.h" #include @@ -27,7 +27,7 @@ namespace FancyZonesUnitTests auto hres = CoCreateGuid(&m_id); Assert::AreEqual(S_OK, hres); - ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, Mocks::Monitor(), DefaultValues::SensitivityRadius, Settings::OverlappingZonesAlgorithm::Smallest); + ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, Mocks::Monitor(), DefaultValues::SensitivityRadius, OverlappingZonesAlgorithm::Smallest); m_set = MakeZoneSet(m_config); }