[FancyZones] Revisit mutexes (#12240)
* [FancyZones] Clean up (#11893) * [FancyZones] Virtual desktop utils refactoring (#11925) * [FancyZones] IFancyZonesCallback refactoring (#11932) * [FancyZones] IZoneWindowHost refactoring (#12091) * [FancyZones] Rename ZoneWindow -> WorkArea (#12223) * [FancyZones] Clean up mutexes (#12228)
This commit is contained in:
parent
3f70c8c889
commit
d85c3f8cc9
1
.github/actions/spell-check/expect.txt
vendored
1
.github/actions/spell-check/expect.txt
vendored
|
@ -1109,6 +1109,7 @@ IVirtual
|
|||
IWeb
|
||||
IWIC
|
||||
IWindows
|
||||
IWork
|
||||
IXml
|
||||
ixx
|
||||
IYUV
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <FancyZonesLib/Generated Files/resource.h>
|
||||
#include <FancyZonesLib/FancyZonesData.h>
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
#include <FancyZonesLib/Settings.h>
|
||||
#include <FancyZonesLib/trace.h>
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "pch.h"
|
||||
#include "FancyZones.h"
|
||||
|
||||
#include <common/display/dpi_aware.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
|
@ -9,17 +10,18 @@
|
|||
#include <common/utils/window.h>
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
|
||||
#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 <FancyZonesLib/FancyZonesData.h>
|
||||
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
|
||||
#include <FancyZonesLib/MonitorUtils.h>
|
||||
#include <FancyZonesLib/Settings.h>
|
||||
#include <FancyZonesLib/ZoneSet.h>
|
||||
#include <FancyZonesLib/WorkArea.h>
|
||||
#include <FancyZonesLib/WindowMoveHandler.h>
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
#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<typename T>
|
||||
require_read_lock(const std::shared_lock<T>& lock)
|
||||
{
|
||||
lock;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
require_read_lock(const std::unique_lock<T>& lock)
|
||||
{
|
||||
lock;
|
||||
}
|
||||
};
|
||||
|
||||
struct require_write_lock
|
||||
{
|
||||
template<typename T>
|
||||
require_write_lock(const std::unique_lock<T>& 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<FancyZones, IFancyZones, IFancyZonesCallback, IZoneWindowHost>
|
||||
struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZonesCallback>
|
||||
{
|
||||
public:
|
||||
FancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings, std::function<void()> 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<WPARAM>(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<IZoneWindow> zoneWindow) noexcept;
|
||||
bool ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> zoneWindow) noexcept;
|
||||
|
||||
void RegisterVirtualDesktopUpdates(std::vector<GUID>& ids) noexcept;
|
||||
void RegisterVirtualDesktopUpdates() noexcept;
|
||||
|
||||
bool IsSplashScreen(HWND window);
|
||||
bool ShouldProcessNewWindow(HWND window) noexcept;
|
||||
std::vector<size_t> GetZoneIndexSetFromWorkAreaHistory(HWND window, winrt::com_ptr<IZoneWindow> workArea) noexcept;
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& workAreaMap) noexcept;
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept;
|
||||
void MoveWindowIntoZone(HWND window, winrt::com_ptr<IZoneWindow> zoneWindow, const std::vector<size_t>& zoneIndexSet) noexcept;
|
||||
void OnSettingsChanged() noexcept;
|
||||
|
||||
void OnEditorExitEvent(require_write_lock) noexcept;
|
||||
void UpdateZoneSets(require_write_lock) noexcept;
|
||||
std::pair<winrt::com_ptr<IWorkArea>, std::vector<size_t>> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& workAreaMap) noexcept;
|
||||
std::pair<winrt::com_ptr<IWorkArea>, std::vector<size_t>> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept;
|
||||
void MoveWindowIntoZone(HWND window, winrt::com_ptr<IWorkArea> zoneWindow, const std::vector<size_t>& 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<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
|
||||
std::vector<HMONITOR> 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<void()> 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<void()> 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<size_t>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)) != 0) ||
|
||||
!IsCandidateForLastKnownZone(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<size_t> FancyZones::GetZoneIndexSetFromWorkAreaHistory(
|
||||
HWND window,
|
||||
winrt::com_ptr<IZoneWindow> 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<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> FancyZones::GetAppZoneHistoryInfo(
|
||||
std::pair<winrt::com_ptr<IWorkArea>, std::vector<size_t>> FancyZones::GetAppZoneHistoryInfo(
|
||||
HWND window,
|
||||
HMONITOR monitor,
|
||||
std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& workAreaMap) noexcept
|
||||
std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& 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<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept
|
||||
std::pair<winrt::com_ptr<IWorkArea>, std::vector<size_t>> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept
|
||||
{
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> appZoneHistoryInfo{ nullptr, {} };
|
||||
std::pair<winrt::com_ptr<IWorkArea>, std::vector<size_t>> appZoneHistoryInfo{ nullptr, {} };
|
||||
auto workAreaMap = m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId);
|
||||
|
||||
// Search application history on currently active monitor.
|
||||
|
@ -436,7 +293,7 @@ std::pair<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> 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<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> FancyZones::GetAppZo
|
|||
return appZoneHistoryInfo;
|
||||
}
|
||||
|
||||
void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr<IZoneWindow> zoneWindow, const std::vector<size_t>& zoneIndexSet) noexcept
|
||||
void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr<IWorkArea> zoneWindow, const std::vector<size_t>& zoneIndexSet) noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
auto& fancyZonesData = FancyZonesDataInstance();
|
||||
|
@ -458,88 +315,27 @@ void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr<IZoneWindow> 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<size_t>(::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<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> appZoneHistoryInfo = GetAppZoneHistoryInfo(window, active, primaryActive);
|
||||
const bool primaryActive = (primary == active);
|
||||
std::pair<winrt::com_ptr<IWorkArea>, std::vector<size_t>> 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<GUID> ids{};
|
||||
if (VirtualDesktopUtils::GetVirtualDesktopIds(ids))
|
||||
{
|
||||
RegisterVirtualDesktopUpdates(ids);
|
||||
}
|
||||
RegisterVirtualDesktopUpdates();
|
||||
}
|
||||
else if (message == WM_PRIV_EDITOR)
|
||||
{
|
||||
if (lparam == static_cast<LPARAM>(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<HWND>(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<std::wstring> 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<std::wstring, DWORD> displayDeviceIdxMap;
|
||||
|
@ -1047,7 +792,6 @@ void FancyZones::UpdateZoneWindows(require_write_lock lock) noexcept
|
|||
{
|
||||
FancyZones* fancyZones;
|
||||
std::unordered_map<std::wstring, DWORD>* 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<LPARAM>(&capture));
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::UpdateWindowsPositions(require_write_lock) noexcept
|
||||
void FancyZones::UpdateWindowsPositions() noexcept
|
||||
{
|
||||
auto callback = [](HWND window, LPARAM data) -> BOOL {
|
||||
size_t bitmask = reinterpret_cast<size_t>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID));
|
||||
|
@ -1092,11 +836,16 @@ void FancyZones::UpdateWindowsPositions(require_write_lock) noexcept
|
|||
}
|
||||
|
||||
auto strongThis = reinterpret_cast<FancyZones*>(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<RECT> zoneRects;
|
||||
std::vector<std::pair<size_t, winrt::com_ptr<IZoneWindow>>> zoneRectsInfo;
|
||||
std::vector<std::pair<size_t, winrt::com_ptr<IWorkArea>>> 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<IZoneWindow> zoneWindow) noexcept
|
||||
bool FancyZones::ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> 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<GUID>& ids) noexcept
|
||||
void FancyZones::RegisterVirtualDesktopUpdates() noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
std::unique_lock writeLock(m_lock);
|
||||
|
||||
m_workAreaHandler.RegisterUpdates(ids);
|
||||
std::vector<std::wstring> active{};
|
||||
if (VirtualDesktopUtils::GetVirtualDesktopIds(active) && !active.empty())
|
||||
auto guids = m_virtualDesktop.GetVirtualDesktopIds();
|
||||
std::vector<std::wstring> 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<HMONITOR> FancyZones::GetMonitorsSorted() noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
|
||||
auto monitorInfo = GetRawMonitorData();
|
||||
FancyZonesUtils::OrderMonitors(monitorInfo);
|
||||
std::vector<HMONITOR> output;
|
||||
|
@ -1438,8 +1212,7 @@ std::vector<HMONITOR> FancyZones::GetMonitorsSorted() noexcept
|
|||
std::vector<std::pair<HMONITOR, RECT>> FancyZones::GetRawMonitorData() noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
std::shared_lock readLock(m_lock);
|
||||
|
||||
|
||||
std::vector<std::pair<HMONITOR, RECT>> 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<IFancyZones> MakeFancyZones(HINSTANCE hinstance,
|
||||
const winrt::com_ptr<IFancyZonesSettings>& settings,
|
||||
std::function<void()> disableCallback) noexcept
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <common/hooks/WinHookEvent.h>
|
||||
#include "Settings.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
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<IFancyZones> MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings, std::function<void()> disableCallback) noexcept;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
<ClInclude Include="FancyZonesData.h" />
|
||||
<ClInclude Include="JsonHelpers.h" />
|
||||
<ClInclude Include="KeyState.h" />
|
||||
<ClInclude Include="MonitorUtils.h" />
|
||||
<ClInclude Include="MonitorWorkAreaHandler.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Generated Files/resource.h" />
|
||||
|
@ -53,11 +54,12 @@
|
|||
<ClInclude Include="Settings.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
<ClInclude Include="VirtualDesktopUtils.h" />
|
||||
<ClInclude Include="VirtualDesktop.h" />
|
||||
<ClInclude Include="WindowMoveHandler.h" />
|
||||
<ClInclude Include="Zone.h" />
|
||||
<ClInclude Include="ZoneColors.h" />
|
||||
<ClInclude Include="ZoneSet.h" />
|
||||
<ClInclude Include="ZoneWindow.h" />
|
||||
<ClInclude Include="WorkArea.h" />
|
||||
<ClInclude Include="ZoneWindowDrawing.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -67,6 +69,7 @@
|
|||
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
|
||||
<ClCompile Include="FancyZonesData.cpp" />
|
||||
<ClCompile Include="JsonHelpers.cpp" />
|
||||
<ClCompile Include="MonitorUtils.cpp" />
|
||||
<ClCompile Include="MonitorWorkAreaHandler.cpp" />
|
||||
<ClCompile Include="OnThreadExecutor.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
|
@ -76,11 +79,11 @@
|
|||
<ClCompile Include="Settings.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<ClCompile Include="util.cpp" />
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp" />
|
||||
<ClCompile Include="VirtualDesktop.cpp" />
|
||||
<ClCompile Include="WindowMoveHandler.cpp" />
|
||||
<ClCompile Include="Zone.cpp" />
|
||||
<ClCompile Include="ZoneSet.cpp" />
|
||||
<ClCompile Include="ZoneWindow.cpp" />
|
||||
<ClCompile Include="WorkArea.cpp" />
|
||||
<ClCompile Include="ZoneWindowDrawing.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<ClInclude Include="ZoneSet.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ZoneWindow.h">
|
||||
<ClInclude Include="WorkArea.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZones.h">
|
||||
|
@ -42,7 +42,7 @@
|
|||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VirtualDesktopUtils.h">
|
||||
<ClInclude Include="VirtualDesktop.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowMoveHandler.h">
|
||||
|
@ -81,6 +81,12 @@
|
|||
<ClInclude Include="CallTracer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MonitorUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ZoneColors.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
|
@ -92,7 +98,7 @@
|
|||
<ClCompile Include="ZoneSet.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZoneWindow.cpp">
|
||||
<ClCompile Include="WorkArea.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZones.cpp">
|
||||
|
@ -107,7 +113,7 @@
|
|||
<ClCompile Include="util.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp">
|
||||
<ClCompile Include="VirtualDesktop.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WindowMoveHandler.cpp">
|
||||
|
@ -140,6 +146,9 @@
|
|||
<ClCompile Include="CallTracer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MonitorUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#include "pch.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#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}");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
76
src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp
Normal file
76
src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include "pch.h"
|
||||
#include "MonitorUtils.h"
|
||||
|
||||
#include <FancyZonesLib/util.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
6
src/modules/fancyzones/FancyZonesLib/MonitorUtils.h
Normal file
6
src/modules/fancyzones/FancyZonesLib/MonitorUtils.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace MonitorUtils
|
||||
{
|
||||
void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept;
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
#include "pch.h"
|
||||
#include "MonitorWorkAreaHandler.h"
|
||||
#include "VirtualDesktopUtils.h"
|
||||
#include "VirtualDesktop.h"
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(const GUID& desktopId, HMONITOR monitor)
|
||||
winrt::com_ptr<IWorkArea> MonitorWorkAreaHandler::GetWorkArea(const GUID& desktopId, HMONITOR monitor)
|
||||
{
|
||||
auto desktopIt = workAreaMap.find(desktopId);
|
||||
if (desktopIt != std::end(workAreaMap))
|
||||
|
@ -17,7 +17,7 @@ winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(const GUID& desk
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkAreaFromCursor(const GUID& desktopId)
|
||||
winrt::com_ptr<IWorkArea> MonitorWorkAreaHandler::GetWorkAreaFromCursor(const GUID& desktopId)
|
||||
{
|
||||
auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL);
|
||||
if (allMonitorsWorkArea)
|
||||
|
@ -38,41 +38,35 @@ winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkAreaFromCursor(const
|
|||
}
|
||||
}
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MonitorWorkAreaHandler::GetWorkArea(HWND window)
|
||||
winrt::com_ptr<IWorkArea> 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<HMONITOR, winrt::com_ptr<IZoneWindow>>& MonitorWorkAreaHandler::GetWorkAreasByDesktopId(const GUID& desktopId)
|
||||
const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& MonitorWorkAreaHandler::GetWorkAreasByDesktopId(const GUID& desktopId)
|
||||
{
|
||||
if (workAreaMap.contains(desktopId))
|
||||
{
|
||||
return workAreaMap[desktopId];
|
||||
}
|
||||
static const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>> empty;
|
||||
static const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
std::vector<winrt::com_ptr<IZoneWindow>> MonitorWorkAreaHandler::GetAllWorkAreas()
|
||||
std::vector<winrt::com_ptr<IWorkArea>> MonitorWorkAreaHandler::GetAllWorkAreas()
|
||||
{
|
||||
std::vector<winrt::com_ptr<IZoneWindow>> workAreas{};
|
||||
std::vector<winrt::com_ptr<IWorkArea>> workAreas{};
|
||||
for (const auto& [desktopId, perDesktopData] : workAreaMap)
|
||||
{
|
||||
std::transform(std::begin(perDesktopData),
|
||||
|
@ -83,7 +77,7 @@ std::vector<winrt::com_ptr<IZoneWindow>> MonitorWorkAreaHandler::GetAllWorkAreas
|
|||
return workAreas;
|
||||
}
|
||||
|
||||
void MonitorWorkAreaHandler::AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr<IZoneWindow>& workArea)
|
||||
void MonitorWorkAreaHandler::AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr<IWorkArea>& 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<IZoneWindow> GetWorkArea(const GUID& desktopId, HMONITOR monitor);
|
||||
winrt::com_ptr<IWorkArea> 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<IZoneWindow> GetWorkAreaFromCursor(const GUID& desktopId);
|
||||
winrt::com_ptr<IWorkArea> 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<IZoneWindow> GetWorkArea(HWND window);
|
||||
winrt::com_ptr<IWorkArea> 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<HMONITOR, winrt::com_ptr<IZoneWindow>>& GetWorkAreasByDesktopId(const GUID& desktopId);
|
||||
const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& GetWorkAreasByDesktopId(const GUID& desktopId);
|
||||
|
||||
/**
|
||||
* @returns All registered work areas.
|
||||
*/
|
||||
std::vector<winrt::com_ptr<IZoneWindow>> GetAllWorkAreas();
|
||||
std::vector<winrt::com_ptr<IWorkArea>> 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<IZoneWindow>& workArea);
|
||||
void AddWorkArea(const GUID& desktopId, HMONITOR monitor, winrt::com_ptr<IWorkArea>& 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<GUID, std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>> workAreaMap;
|
||||
std::unordered_map<GUID, std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>> workAreaMap;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
234
src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp
Normal file
234
src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp
Normal file
|
@ -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<GUID> 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<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<GUID> 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<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool GetZoneWindowDesktopId(IWorkArea* zoneWindow, GUID* desktopId)
|
||||
{
|
||||
// Format: <device-id>_<resolution>_<virtual-desktop-id>
|
||||
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<void()>& vdInitCallback, const std::function<void()>& 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<GUID> VirtualDesktop::GetWindowDesktopId(HWND topLevelWindow) const
|
||||
{
|
||||
GUID desktopId{};
|
||||
if (m_vdManager && SUCCEEDED(m_vdManager->GetWindowDesktopId(topLevelWindow, &desktopId)))
|
||||
{
|
||||
return desktopId;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<GUID> VirtualDesktop::GetCurrentVirtualDesktopId() const
|
||||
{
|
||||
// On newer Windows builds, the current virtual desktop is persisted to
|
||||
// a totally different reg key. Look there first.
|
||||
std::optional<GUID> 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<std::vector<GUID>> 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<BYTE[]> buffer = std::make_unique<BYTE[]>(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<GUID> temp;
|
||||
temp.reserve(bufferCapacity / guidSize);
|
||||
for (size_t i = 0; i < bufferCapacity; i += guidSize)
|
||||
{
|
||||
GUID* guid = reinterpret_cast<GUID*>(buffer.get() + i);
|
||||
temp.push_back(*guid);
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
std::optional<std::vector<GUID>> 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();
|
||||
}
|
||||
}
|
30
src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h
Normal file
30
src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "WorkArea.h"
|
||||
#include "on_thread_executor.h"
|
||||
|
||||
class VirtualDesktop
|
||||
{
|
||||
public:
|
||||
VirtualDesktop(const std::function<void()>& vdInitCallback, const std::function<void()>& vdUpdatedCallback);
|
||||
~VirtualDesktop() = default;
|
||||
|
||||
void Init();
|
||||
void UnInit();
|
||||
|
||||
std::optional<GUID> GetWindowDesktopId(HWND topLevelWindow) const;
|
||||
std::optional<GUID> GetCurrentVirtualDesktopId() const;
|
||||
std::optional<std::vector<GUID>> GetVirtualDesktopIds() const;
|
||||
|
||||
private:
|
||||
std::function<void()> m_vdInitCallback;
|
||||
std::function<void()> m_vdUpdatedCallback;
|
||||
|
||||
IVirtualDesktopManager* m_vdManager;
|
||||
|
||||
OnThreadExecutor m_virtualDesktopTrackerThread;
|
||||
wil::unique_handle m_terminateVirtualDesktopTrackerEvent;
|
||||
|
||||
std::optional<std::vector<GUID>> GetVirtualDesktopIds(HKEY hKey) const;
|
||||
void HandleVirtualDesktopUpdates();
|
||||
};
|
|
@ -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: <device-id>_<resolution>_<virtual-desktop-id>
|
||||
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<BYTE*>(&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<BYTE*>(&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<GUID> ids{};
|
||||
if (GetVirtualDesktopIds(ids) && ids.size() > 0)
|
||||
{
|
||||
*desktopId = ids[0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetVirtualDesktopIds(HKEY hKey, std::vector<GUID>& 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<BYTE[]> buffer = std::make_unique<BYTE[]>(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<GUID> temp;
|
||||
temp.reserve(bufferCapacity / guidSize);
|
||||
for (size_t i = 0; i < bufferCapacity; i += guidSize)
|
||||
{
|
||||
GUID* guid = reinterpret_cast<GUID*>(buffer.get() + i);
|
||||
temp.push_back(*guid);
|
||||
}
|
||||
ids = std::move(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetVirtualDesktopIds(std::vector<GUID>& ids)
|
||||
{
|
||||
return GetVirtualDesktopIds(GetVirtualDesktopsRegKey(), ids);
|
||||
}
|
||||
|
||||
bool GetVirtualDesktopIds(std::vector<std::wstring>& ids)
|
||||
{
|
||||
std::vector<GUID> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<GUID>& ids);
|
||||
bool GetVirtualDesktopIds(std::vector<std::wstring>& ids);
|
||||
HKEY GetVirtualDesktopsRegKey();
|
||||
void HandleVirtualDesktopUpdates(HWND window, UINT message, HANDLE terminateEvent);
|
||||
}
|
|
@ -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<IFancyZonesSettings>&
|
|||
{
|
||||
}
|
||||
|
||||
void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& 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<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& 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<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& 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<size_t>& indexSet, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept
|
||||
void WindowMoveHandler::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet, winrt::com_ptr<IWorkArea> 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<IZoneWindow> zoneWindow) noexcept
|
||||
bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> zoneWindow) noexcept
|
||||
{
|
||||
return zoneWindow && zoneWindow->MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, cycle);
|
||||
}
|
||||
|
||||
bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept
|
||||
bool WindowMoveHandler::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> zoneWindow) noexcept
|
||||
{
|
||||
return zoneWindow && zoneWindow->MoveWindowIntoZoneByDirectionAndPosition(window, vkCode, cycle);
|
||||
}
|
||||
|
||||
bool WindowMoveHandler::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept
|
||||
bool WindowMoveHandler::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr<IWorkArea> zoneWindow) noexcept
|
||||
{
|
||||
return zoneWindow && zoneWindow->ExtendWindowByDirectionAndPosition(window, vkCode);
|
||||
}
|
||||
|
|
|
@ -6,21 +6,21 @@
|
|||
#include <functional>
|
||||
|
||||
interface IFancyZonesSettings;
|
||||
interface IZoneWindow;
|
||||
interface IWorkArea;
|
||||
|
||||
class WindowMoveHandler
|
||||
{
|
||||
public:
|
||||
WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>& settings, const std::function<void()>& keyUpdateCallback);
|
||||
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& zoneWindowMap) noexcept;
|
||||
|
||||
void MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept;
|
||||
bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept;
|
||||
bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept;
|
||||
bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr<IZoneWindow> zoneWindow) noexcept;
|
||||
void MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet, winrt::com_ptr<IWorkArea> zoneWindow) noexcept;
|
||||
bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> zoneWindow) noexcept;
|
||||
bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle, winrt::com_ptr<IWorkArea> zoneWindow) noexcept;
|
||||
bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode, winrt::com_ptr<IWorkArea> 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<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, where the move/size is happening. Will update as drag moves between monitors.
|
||||
winrt::com_ptr<IWorkArea> 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;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include "pch.h"
|
||||
#include "WorkArea.h"
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
|
||||
#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<ZoneWindow, IZoneWindow>
|
||||
struct WorkArea : public winrt::implements<WorkArea, IWorkArea>
|
||||
{
|
||||
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<size_t>)
|
||||
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<size_t> ZonesFromPoint(POINT pt) noexcept;
|
||||
void SetAsTopmostWindow() noexcept;
|
||||
|
||||
winrt::com_ptr<IZoneWindowHost> 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<ZoneWindowDrawing> 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<size_t>& indexSet) noexcept
|
||||
WorkArea::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>& indexSet) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
|
@ -312,7 +320,7 @@ ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>&
|
|||
}
|
||||
|
||||
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<size_t>)
|
||||
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<size_t> ZoneWindow::ZonesFromPoint(POINT pt) noexcept
|
||||
std::vector<size_t> WorkArea::ZonesFromPoint(POINT pt) noexcept
|
||||
{
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
|
@ -549,7 +584,7 @@ std::vector<size_t> 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<ZoneWindow*>(GetWindowLongPtr(window, GWLP_USERDATA));
|
||||
auto thisRef = reinterpret_cast<WorkArea*>(GetWindowLongPtr(window, GWLP_USERDATA));
|
||||
if ((thisRef == nullptr) && (message == WM_CREATE))
|
||||
{
|
||||
auto createStruct = reinterpret_cast<LPCREATESTRUCT>(lparam);
|
||||
thisRef = reinterpret_cast<ZoneWindow*>(createStruct->lpCreateParams);
|
||||
thisRef = reinterpret_cast<WorkArea*>(createStruct->lpCreateParams);
|
||||
SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(thisRef));
|
||||
}
|
||||
|
||||
|
@ -583,10 +618,10 @@ LRESULT CALLBACK ZoneWindow::s_WndProc(HWND window, UINT message, WPARAM wparam,
|
|||
DefWindowProc(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
winrt::com_ptr<IZoneWindow> MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId) noexcept
|
||||
winrt::com_ptr<IWorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm) noexcept
|
||||
{
|
||||
auto self = winrt::make_self<ZoneWindow>(hinstance);
|
||||
if (self->Init(host, hinstance, monitor, uniqueId, parentUniqueId))
|
||||
auto self = winrt::make_self<WorkArea>(hinstance);
|
||||
if (self->Init(hinstance, monitor, uniqueId, parentUniqueId, zoneColors, overlappingAlgorithm))
|
||||
{
|
||||
return self;
|
||||
}
|
|
@ -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: <device-id>_<resolution>_<virtual-desktop-id>
|
||||
*/
|
||||
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<size_t>, 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<IZoneWindow> MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor,
|
||||
const std::wstring& uniqueId, const std::wstring& parentUniqueId) noexcept;
|
||||
winrt::com_ptr<IWorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, const ZoneColors& zoneColors, OverlappingZonesAlgorithm overlappingAlgorithm) noexcept;
|
|
@ -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
|
||||
*/
|
||||
|
|
10
src/modules/fancyzones/FancyZonesLib/ZoneColors.h
Normal file
10
src/modules/fancyzones/FancyZonesLib/ZoneColors.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include <windef.h>
|
||||
|
||||
struct ZoneColors
|
||||
{
|
||||
COLORREF primaryColor;
|
||||
COLORREF borderColor;
|
||||
COLORREF highlightColor;
|
||||
int highlightOpacity;
|
||||
};
|
|
@ -254,7 +254,7 @@ ZoneSet::ZonesFromPoint(POINT pt) const noexcept
|
|||
{
|
||||
try
|
||||
{
|
||||
using Algorithm = Settings::OverlappingZonesAlgorithm;
|
||||
using Algorithm = OverlappingZonesAlgorithm;
|
||||
|
||||
switch (m_config.SelectionAlgorithm)
|
||||
{
|
||||
|
|
|
@ -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<IZoneSet> MakeZoneSet(ZoneSetConfig const& config) noexcept;
|
||||
|
|
|
@ -279,19 +279,19 @@ void ZoneWindowDrawing::Flash()
|
|||
|
||||
void ZoneWindowDrawing::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones,
|
||||
const std::vector<size_t>& highlightZones,
|
||||
winrt::com_ptr<IZoneWindowHost> 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<bool> isHighlighted(zones.size() + 1, false);
|
||||
for (size_t x : highlightZones)
|
||||
|
|
|
@ -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<size_t>& highlightZones,
|
||||
winrt::com_ptr<IZoneWindowHost> host);
|
||||
const ZoneColors& colors);
|
||||
};
|
||||
|
|
|
@ -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<IZoneSet> activeSet) noexcept
|
||||
void Trace::WorkArea::MoveSizeEnd(_In_opt_ winrt::com_ptr<IZoneSet> activeSet) noexcept
|
||||
{
|
||||
auto const zoneInfo = GetZoneSetInfo(activeSet);
|
||||
TraceLoggingWrite(
|
||||
|
@ -317,7 +317,7 @@ void Trace::ZoneWindow::MoveSizeEnd(_In_opt_ winrt::com_ptr<IZoneSet> activeSet)
|
|||
TraceLoggingValue(zoneInfo.NumberOfWindows, NumberOfWindowsKey));
|
||||
}
|
||||
|
||||
void Trace::ZoneWindow::CycleActiveZoneSet(_In_opt_ winrt::com_ptr<IZoneSet> activeSet, InputMode mode) noexcept
|
||||
void Trace::WorkArea::CycleActiveZoneSet(_In_opt_ winrt::com_ptr<IZoneSet> activeSet, InputMode mode) noexcept
|
||||
{
|
||||
auto const zoneInfo = GetZoneSetInfo(activeSet);
|
||||
TraceLoggingWrite(
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
static void SettingsTelemetry(const Settings& settings) noexcept;
|
||||
static void VirtualDesktopChanged() noexcept;
|
||||
|
||||
class ZoneWindow
|
||||
class WorkArea
|
||||
{
|
||||
public:
|
||||
enum class InputMode
|
||||
|
|
|
@ -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<std::wstring>& what)
|
||||
|
@ -604,6 +605,17 @@ namespace FancyZonesUtils
|
|||
return SUCCEEDED(CLSIDFromString(str.c_str(), &id));
|
||||
}
|
||||
|
||||
std::optional<std::wstring> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -203,6 +203,7 @@ namespace FancyZonesUtils
|
|||
void RestoreWindowOrigin(HWND window) noexcept;
|
||||
|
||||
bool IsValidGuid(const std::wstring& str);
|
||||
std::optional<std::wstring> 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);
|
||||
}
|
||||
|
|
|
@ -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<IFancyZonesSettings> m_settings = nullptr;
|
||||
winrt::com_ptr<IZoneWindowHost> 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<IZoneWindowHost>();
|
||||
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{};
|
||||
|
|
|
@ -396,160 +396,6 @@ namespace FancyZonesUnitTests
|
|||
}
|
||||
};
|
||||
|
||||
TEST_CLASS (FancyZonesSettingsCallbackUnitTests)
|
||||
{
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings = nullptr;
|
||||
PCWSTR m_moduleName = L"FancyZonesUnitTests";
|
||||
PCWSTR m_moduleKey = L"FancyZonesUnitTests";
|
||||
|
||||
struct FZCallback : public winrt::implements<FZCallback, IFancyZonesCallback>
|
||||
{
|
||||
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<FZCallback> callback = winrt::make_self<FZCallback>(&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<FZCallback> callback = winrt::make_self<FZCallback>(&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<FZCallback> callback = winrt::make_self<FZCallback>(&flag);
|
||||
|
||||
m_settings->SetCallback(callback.get());
|
||||
m_settings->GetSettings();
|
||||
|
||||
Assert::IsFalse(flag);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS (FancyZonesSettingsUnitTests)
|
||||
{
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings = nullptr;
|
||||
|
|
|
@ -49,9 +49,9 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="Util.Spec.cpp" />
|
||||
<ClCompile Include="Util.cpp" />
|
||||
<ClCompile Include="WorkArea.Spec.cpp" />
|
||||
<ClCompile Include="Zone.Spec.cpp" />
|
||||
<ClCompile Include="ZoneSet.Spec.cpp" />
|
||||
<ClCompile Include="ZoneWindow.Spec.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
<ClCompile Include="Util.Spec.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZoneWindow.Spec.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="JsonHelpers.Tests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -42,6 +39,9 @@
|
|||
<ClCompile Include="FancyZones.Spec.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WorkArea.Spec.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
|
||||
#include <FancyZonesLib/util.h>
|
||||
#include <FancyZonesLib/ZoneSet.h>
|
||||
#include <FancyZonesLib/ZoneWindow.h>
|
||||
#include <FancyZonesLib/WorkArea.h>
|
||||
#include <FancyZonesLib/FancyZones.h>
|
||||
#include <FancyZonesLib/FancyZonesData.h>
|
||||
#include <FancyZonesLib/FancyZonesDataTypes.h>
|
||||
#include <FancyZonesLib/JsonHelpers.h>
|
||||
#include <FancyZonesLib/ZoneColors.h>
|
||||
#include "Util.h"
|
||||
|
||||
#include <common/utils/process_path.h>
|
||||
|
@ -17,58 +18,10 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
|||
|
||||
namespace FancyZonesUnitTests
|
||||
{
|
||||
struct MockZoneWindowHost : public winrt::implements<MockZoneWindowHost, IZoneWindowHost>
|
||||
{
|
||||
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<IZoneWindow> zoneWindow)
|
||||
void testWorkArea(winrt::com_ptr<IWorkArea> 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<MockZoneWindowHost>().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<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowNoHinst)
|
||||
TEST_METHOD (CreateWorkAreaNoHinst)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().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<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowNoHinstFlashZones)
|
||||
TEST_METHOD (CreateWorkAreaNoHinstFlashZones)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().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<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(3));
|
||||
}
|
||||
|
||||
TEST_METHOD (CreateZoneWindowNoMonitor)
|
||||
TEST_METHOD (CreateWorkAreaNoMonitor)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().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<MockZoneWindowHost>().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<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(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<MockZoneWindowHost>().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<int>(activeZoneSet->LayoutType()), static_cast<int>(FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid));
|
||||
Assert::AreEqual(activeZoneSet->GetZones().size(), static_cast<size_t>(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<MockZoneWindowHost> zoneWindowHost = winrt::make_self<MockZoneWindowHost>();
|
||||
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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<size_t>{} == actualZoneIndexSet);
|
||||
|
@ -307,55 +276,55 @@ namespace FancyZonesUnitTests
|
|||
|
||||
TEST_METHOD (MoveSizeEndWindowNotAdded)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().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<size_t>{} == actualZoneIndexSet);
|
||||
}
|
||||
|
||||
TEST_METHOD (MoveSizeEndDifferentWindows)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<size_t>{} == actualZoneIndex); // with invalid point zone remains the same
|
||||
|
@ -363,21 +332,21 @@ namespace FancyZonesUnitTests
|
|||
|
||||
TEST_METHOD (MoveWindowIntoZoneByIndex)
|
||||
{
|
||||
auto zoneWindow = MakeZoneWindow(winrt::make_self<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<MockZoneWindowHost>().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<size_t>{ 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<MockZoneWindowHost>().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);
|
|
@ -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 <filesystem>
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue