mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 03:07:04 +02:00
merge master
This commit is contained in:
@@ -1,24 +1,21 @@
|
||||
#include "pch.h"
|
||||
#include "common/dpi_aware.h"
|
||||
#include "common/on_thread_executor.h"
|
||||
|
||||
#include <common/dpi_aware.h>
|
||||
#include <common/on_thread_executor.h>
|
||||
#include <common/window_helpers.h>
|
||||
|
||||
#include "FancyZones.h"
|
||||
#include "lib/Settings.h"
|
||||
#include "lib/ZoneWindow.h"
|
||||
#include "lib/RegistryHelpers.h"
|
||||
#include "lib/JsonHelpers.h"
|
||||
#include "lib/ZoneSet.h"
|
||||
#include "lib/WindowMoveHandler.h"
|
||||
#include "lib/FancyZonesWinHookEventIDs.h"
|
||||
#include "lib/util.h"
|
||||
#include "trace.h"
|
||||
#include "VirtualDesktopUtils.h"
|
||||
|
||||
#include <functional>
|
||||
#include <common/common.h>
|
||||
#include <common/window_helpers.h>
|
||||
#include <common/notifications.h>
|
||||
#include <lib/util.h>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <common/notifications/fancyzones_notifications.h>
|
||||
#include <interface/win_hook_event_data.h>
|
||||
|
||||
enum class DisplayChangeType
|
||||
{
|
||||
@@ -29,8 +26,6 @@ enum class DisplayChangeType
|
||||
Initialization
|
||||
};
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
@@ -49,7 +44,8 @@ struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZone
|
||||
public:
|
||||
FancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings) noexcept :
|
||||
m_hinstance(hinstance),
|
||||
m_settings(settings)
|
||||
m_settings(settings),
|
||||
m_windowMoveHandler(settings)
|
||||
{
|
||||
m_settings->SetCallback(this);
|
||||
}
|
||||
@@ -65,26 +61,70 @@ public:
|
||||
InMoveSize() noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
return m_inMoveSize;
|
||||
return m_windowMoveHandler.InMoveSize();
|
||||
}
|
||||
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_windowMoveHandler.MoveSizeStart(window, monitor, ptScreen, m_zoneWindowMap);
|
||||
}
|
||||
|
||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_windowMoveHandler.MoveSizeUpdate(monitor, ptScreen, m_zoneWindowMap);
|
||||
}
|
||||
|
||||
void MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_windowMoveHandler.MoveSizeEnd(window, ptScreen, m_zoneWindowMap);
|
||||
}
|
||||
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;
|
||||
HandleWinHookEvent(const WinHookEvent* data) noexcept
|
||||
{
|
||||
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:
|
||||
PostMessageW(m_window, WM_PRIV_MOVESIZESTART, wparam, lparam);
|
||||
break;
|
||||
case EVENT_SYSTEM_MOVESIZEEND:
|
||||
PostMessageW(m_window, WM_PRIV_MOVESIZEEND, wparam, lparam);
|
||||
break;
|
||||
case EVENT_OBJECT_LOCATIONCHANGE:
|
||||
PostMessageW(m_window, WM_PRIV_LOCATIONCHANGE, wparam, lparam);
|
||||
break;
|
||||
case EVENT_OBJECT_NAMECHANGE:
|
||||
PostMessageW(m_window, WM_PRIV_NAMECHANGE, wparam, lparam);
|
||||
break;
|
||||
|
||||
case EVENT_OBJECT_UNCLOAKED:
|
||||
case EVENT_OBJECT_SHOW:
|
||||
case EVENT_OBJECT_CREATE:
|
||||
if (data->idObject == OBJID_WINDOW)
|
||||
{
|
||||
PostMessageW(m_window, WM_PRIV_WINDOWCREATED, wparam, lparam);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
VirtualDesktopChanged() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
VirtualDesktopInitialize() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
WindowCreated(HWND window) noexcept;
|
||||
IFACEMETHODIMP_(bool)
|
||||
OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
ToggleEditor() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
SettingsChanged() noexcept;
|
||||
|
||||
void WindowCreated(HWND window) noexcept;
|
||||
|
||||
// IZoneWindowHost
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -150,9 +190,6 @@ public:
|
||||
void OnDisplayChange(DisplayChangeType changeType) noexcept;
|
||||
void AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept;
|
||||
|
||||
void MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index) noexcept;
|
||||
void MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet) noexcept;
|
||||
|
||||
protected:
|
||||
static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
|
||||
|
||||
@@ -181,19 +218,12 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
bool IsInterestingWindow(HWND window) noexcept;
|
||||
bool IsCursorTypeIndicatingSizeEvent();
|
||||
void UpdateZoneWindows() noexcept;
|
||||
void MoveWindowsOnDisplayChange() noexcept;
|
||||
void UpdateDragState(HWND window, require_write_lock) noexcept;
|
||||
void CycleActiveZoneSet(DWORD vkCode) noexcept;
|
||||
bool OnSnapHotkey(DWORD vkCode) noexcept;
|
||||
void MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT const& ptScreen, require_write_lock) noexcept;
|
||||
void MoveSizeEndInternal(HWND window, POINT const& ptScreen, require_write_lock) noexcept;
|
||||
void MoveSizeUpdateInternal(HMONITOR monitor, POINT const& ptScreen, require_write_lock) noexcept;
|
||||
|
||||
void HandleVirtualDesktopUpdates(HANDLE fancyZonesDestroyedEvent) noexcept;
|
||||
void RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& currentVirtualDesktopIds) noexcept;
|
||||
void RegisterVirtualDesktopUpdates(std::vector<GUID>& ids) noexcept;
|
||||
void RegisterNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept;
|
||||
bool IsNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept;
|
||||
|
||||
@@ -201,19 +231,14 @@ private:
|
||||
|
||||
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
|
||||
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
|
||||
bool MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle);
|
||||
|
||||
const HINSTANCE m_hinstance{};
|
||||
|
||||
HKEY m_virtualDesktopsRegKey{ nullptr };
|
||||
|
||||
mutable std::shared_mutex m_lock;
|
||||
HWND m_window{};
|
||||
HWND m_windowMoveSize{}; // The window that is being moved/sized
|
||||
bool m_inMoveSize{}; // Whether or not a move/size operation is currently active
|
||||
bool m_dragEnabled{}; // True if we should be showing zone hints while dragging
|
||||
WindowMoveHandler m_windowMoveHandler;
|
||||
|
||||
std::map<HMONITOR, winrt::com_ptr<IZoneWindow>> m_zoneWindowMap; // Map of monitor to ZoneWindow (one per monitor)
|
||||
winrt::com_ptr<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, where the move/size is happening. Will update as drag moves between monitors.
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings{};
|
||||
GUID m_currentVirtualDesktopId{}; // UUID of the current virtual desktop. Is GUID_NULL until first VD switch per session.
|
||||
std::unordered_map<GUID, std::vector<HMONITOR>> m_processedWorkAreas; // Work area is defined by monitor and virtual desktop id.
|
||||
@@ -223,9 +248,12 @@ private:
|
||||
OnThreadExecutor m_dpiUnawareThread;
|
||||
OnThreadExecutor m_virtualDesktopTrackerThread;
|
||||
|
||||
static UINT WM_PRIV_VDCHANGED; // Message to get back on to the UI thread when virtual desktop changes
|
||||
static UINT WM_PRIV_VDINIT; // Message to get back to the UI thread when FancyZones are initialized
|
||||
static UINT WM_PRIV_EDITOR; // Message to get back on to the UI thread when the editor exits
|
||||
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_LOWLEVELKB; // Scheduled when we receive a key down press
|
||||
|
||||
// Did we terminate the editor or was it closed cleanly?
|
||||
enum class EditorExitKind : byte
|
||||
@@ -235,9 +263,11 @@ private:
|
||||
};
|
||||
};
|
||||
|
||||
UINT FancyZones::WM_PRIV_VDCHANGED = RegisterWindowMessage(L"{128c2cb0-6bdf-493e-abbe-f8705e04aa95}");
|
||||
UINT FancyZones::WM_PRIV_VDINIT = RegisterWindowMessage(L"{469818a8-00fa-4069-b867-a1da484fcd9a}");
|
||||
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_LOWLEVELKB = RegisterWindowMessage(L"{763c03a3-03d9-4cde-8d71-f0358b0b4b52}");
|
||||
|
||||
// IFancyZones
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -268,12 +298,8 @@ FancyZones::Run() noexcept
|
||||
} })
|
||||
.wait();
|
||||
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops", 0, KEY_ALL_ACCESS, &m_virtualDesktopsRegKey) == ERROR_SUCCESS)
|
||||
{
|
||||
m_terminateVirtualDesktopTrackerEvent.reset(CreateEvent(nullptr, FALSE, FALSE, nullptr));
|
||||
m_virtualDesktopTrackerThread.submit(
|
||||
OnThreadExecutor::task_t{ std::bind(&FancyZones::HandleVirtualDesktopUpdates, this, m_terminateVirtualDesktopTrackerEvent.get()) });
|
||||
}
|
||||
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()); } });
|
||||
}
|
||||
|
||||
// IFancyZones
|
||||
@@ -292,58 +318,23 @@ FancyZones::Destroy() noexcept
|
||||
{
|
||||
SetEvent(m_terminateVirtualDesktopTrackerEvent.get());
|
||||
}
|
||||
if (m_virtualDesktopsRegKey)
|
||||
{
|
||||
RegCloseKey(m_virtualDesktopsRegKey);
|
||||
m_virtualDesktopsRegKey = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// IFancyZonesCallback
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZones::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept
|
||||
{
|
||||
if (IsInterestingWindow(window))
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
MoveSizeStartInternal(window, monitor, ptScreen, writeLock);
|
||||
}
|
||||
}
|
||||
|
||||
// IFancyZonesCallback
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZones::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
MoveSizeUpdateInternal(monitor, ptScreen, writeLock);
|
||||
}
|
||||
|
||||
// IFancyZonesCallback
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZones::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
|
||||
{
|
||||
if (window == m_windowMoveSize || IsInterestingWindow(window))
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
MoveSizeEndInternal(window, ptScreen, writeLock);
|
||||
}
|
||||
}
|
||||
|
||||
// IFancyZonesCallback
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZones::VirtualDesktopChanged() noexcept
|
||||
{
|
||||
// VirtualDesktopChanged is called from another thread but results in new windows being created.
|
||||
// Jump over to the UI thread to handle it.
|
||||
// VirtualDesktopChanged is called from a reentrant WinHookProc function, therefore we must postpone the actual logic
|
||||
// until we're in FancyZones::WndProc, which is not reentrant.
|
||||
std::shared_lock readLock(m_lock);
|
||||
PostMessage(m_window, WM_PRIV_VDCHANGED, 0, 0);
|
||||
PostMessage(m_window, WM_PRIV_VD_SWITCH, 0, 0);
|
||||
}
|
||||
|
||||
// IFancyZonesCallback
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZones::VirtualDesktopInitialize() noexcept
|
||||
{
|
||||
PostMessage(m_window, WM_PRIV_VDINIT, 0, 0);
|
||||
PostMessage(m_window, WM_PRIV_VD_INIT, 0, 0);
|
||||
}
|
||||
|
||||
// IFancyZonesCallback
|
||||
@@ -351,7 +342,7 @@ IFACEMETHODIMP_(void)
|
||||
FancyZones::WindowCreated(HWND window) noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
if (m_settings->GetSettings()->appLastZone_moveWindows && IsInterestingWindow(window))
|
||||
if (m_settings->GetSettings()->appLastZone_moveWindows && IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
{
|
||||
for (const auto& [monitor, zoneWindow] : m_zoneWindowMap)
|
||||
{
|
||||
@@ -376,7 +367,7 @@ FancyZones::WindowCreated(HWND window) noexcept
|
||||
int zoneIndex = fancyZonesData.GetAppLastZoneIndex(window, zoneWindow->UniqueId(), guidString.get());
|
||||
if (zoneIndex != -1)
|
||||
{
|
||||
MoveWindowIntoZoneByIndex(window, monitor, zoneIndex);
|
||||
m_windowMoveHandler.MoveWindowIntoZoneByIndex(window, monitor, zoneIndex, m_zoneWindowMap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -391,7 +382,7 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
|
||||
{
|
||||
// Return true to swallow the keyboard event
|
||||
bool const shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
|
||||
bool const win = GetAsyncKeyState(VK_LWIN) & 0x8000;
|
||||
bool const win = GetAsyncKeyState(VK_LWIN) & 0x8000 || GetAsyncKeyState(VK_RWIN) & 0x8000;
|
||||
if (win && !shift)
|
||||
{
|
||||
bool const ctrl = GetAsyncKeyState(VK_CONTROL) & 0x8000;
|
||||
@@ -410,9 +401,10 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->overrideSnapHotkeys)
|
||||
{
|
||||
// Win+Left, Win+Right will cycle through Zones in the active ZoneSet
|
||||
Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/);
|
||||
return OnSnapHotkey(info->vkCode);
|
||||
// Win+Left, Win+Right will cycle through Zones in the active ZoneSet when WM_PRIV_LOWLEVELKB's handled
|
||||
PostMessageW(m_window, WM_PRIV_LOWLEVELKB, 0, info->vkCode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,7 +416,8 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
|
||||
// CycleActiveZoneSet(info->vkCode);
|
||||
// return false;
|
||||
//}
|
||||
if (m_dragEnabled && shift)
|
||||
|
||||
if (m_windowMoveHandler.IsDragEnabled() && shift)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -600,13 +593,28 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
|
||||
default:
|
||||
{
|
||||
if (message == WM_PRIV_VDCHANGED)
|
||||
POINT ptScreen;
|
||||
GetPhysicalCursorPos(&ptScreen);
|
||||
|
||||
if (message == WM_PRIV_LOWLEVELKB)
|
||||
{
|
||||
OnSnapHotkey(static_cast<DWORD>(lparam));
|
||||
}
|
||||
else if (message == WM_PRIV_VD_INIT)
|
||||
{
|
||||
OnDisplayChange(DisplayChangeType::Initialization);
|
||||
}
|
||||
else if (message == WM_PRIV_VD_SWITCH)
|
||||
{
|
||||
OnDisplayChange(DisplayChangeType::VirtualDesktop);
|
||||
}
|
||||
else if (message == WM_PRIV_VDINIT)
|
||||
else if (message == WM_PRIV_VD_UPDATE)
|
||||
{
|
||||
OnDisplayChange(DisplayChangeType::Initialization);
|
||||
std::vector<GUID> ids{};
|
||||
if (VirtualDesktopUtils::GetVirtualDesktopIds(ids))
|
||||
{
|
||||
RegisterVirtualDesktopUpdates(ids);
|
||||
}
|
||||
}
|
||||
else if (message == WM_PRIV_EDITOR)
|
||||
{
|
||||
@@ -622,6 +630,31 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
m_terminateEditorEvent.release();
|
||||
}
|
||||
}
|
||||
else if (message == WM_PRIV_MOVESIZESTART)
|
||||
{
|
||||
auto hwnd = reinterpret_cast<HWND>(wparam);
|
||||
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
|
||||
{
|
||||
MoveSizeStart(hwnd, monitor, ptScreen);
|
||||
}
|
||||
}
|
||||
else if (message == WM_PRIV_MOVESIZEEND)
|
||||
{
|
||||
auto hwnd = reinterpret_cast<HWND>(wparam);
|
||||
MoveSizeEnd(hwnd, ptScreen);
|
||||
}
|
||||
else if (message == WM_PRIV_LOCATIONCHANGE && InMoveSize())
|
||||
{
|
||||
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
|
||||
{
|
||||
MoveSizeUpdate(monitor, ptScreen);
|
||||
}
|
||||
}
|
||||
else if (message == WM_PRIV_WINDOWCREATED)
|
||||
{
|
||||
auto hwnd = reinterpret_cast<HWND>(wparam);
|
||||
WindowCreated(hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DefWindowProc(window, message, wparam, lparam);
|
||||
@@ -632,25 +665,25 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
|
||||
{
|
||||
if (changeType == DisplayChangeType::VirtualDesktop ||
|
||||
changeType == DisplayChangeType::Initialization)
|
||||
{
|
||||
// Explorer persists this value to the registry on a per session basis but only after
|
||||
// the first virtual desktop switch happens. If the user hasn't switched virtual desktops in this session
|
||||
// then this value will be empty. This means loading the first virtual desktop's configuration can be
|
||||
// funky the first time we load up at boot since the user will not have switched virtual desktops yet.
|
||||
GUID currentVirtualDesktopId{};
|
||||
if (SUCCEEDED(RegistryHelpers::GetCurrentVirtualDesktop(¤tVirtualDesktopId)))
|
||||
if (VirtualDesktopUtils::GetCurrentVirtualDesktopId(¤tVirtualDesktopId))
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_currentVirtualDesktopId = currentVirtualDesktopId;
|
||||
}
|
||||
else
|
||||
if (changeType == DisplayChangeType::Initialization)
|
||||
{
|
||||
// TODO: Use the previous "Desktop 1" fallback
|
||||
// Need to maintain a map of desktop name to virtual desktop uuid
|
||||
std::vector<std::wstring> ids{};
|
||||
if (VirtualDesktopUtils::GetVirtualDesktopIds(ids) && !ids.empty())
|
||||
{
|
||||
JSONHelpers::FancyZonesDataInstance().UpdatePrimaryDesktopData(ids[0]);
|
||||
JSONHelpers::FancyZonesDataInstance().RemoveDeletedDesktops(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,30 +740,6 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index) noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
MoveWindowIntoZoneByIndexSet(window, monitor, { index });
|
||||
}
|
||||
|
||||
void FancyZones::MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet) noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
if (window != m_windowMoveSize)
|
||||
{
|
||||
const HMONITOR hm = (monitor != nullptr) ? monitor : MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
if (hm)
|
||||
{
|
||||
auto zoneWindow = m_zoneWindowMap.find(hm);
|
||||
if (zoneWindow != m_zoneWindowMap.end())
|
||||
{
|
||||
const auto& zoneWindowPtr = zoneWindow->second;
|
||||
zoneWindowPtr->MoveWindowIntoZoneByIndexSet(window, indexSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
{
|
||||
auto thisRef = reinterpret_cast<FancyZones*>(GetWindowLongPtr(window, GWLP_USERDATA));
|
||||
@@ -745,53 +754,6 @@ LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam,
|
||||
DefWindowProc(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
bool FancyZones::IsInterestingWindow(HWND window) noexcept
|
||||
{
|
||||
auto filtered = get_fancyzones_filtered_window(window);
|
||||
if (!filtered.zonable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Filter out user specified apps
|
||||
CharUpperBuffW(filtered.process_path.data(), (DWORD)filtered.process_path.length());
|
||||
if (m_settings)
|
||||
{
|
||||
const auto& excludedAppsArray = m_settings->GetSettings()->excludedAppsArray;
|
||||
if (find_app_name_in_path(filtered.process_path, excludedAppsArray))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FancyZones::IsCursorTypeIndicatingSizeEvent()
|
||||
{
|
||||
CURSORINFO cursorInfo = { 0 };
|
||||
cursorInfo.cbSize = sizeof(cursorInfo);
|
||||
|
||||
if (::GetCursorInfo(&cursorInfo))
|
||||
{
|
||||
if (::LoadCursor(NULL, IDC_SIZENS) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (::LoadCursor(NULL, IDC_SIZEWE) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (::LoadCursor(NULL, IDC_SIZENESW) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (::LoadCursor(NULL, IDC_SIZENWSE) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FancyZones::UpdateZoneWindows() noexcept
|
||||
{
|
||||
auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM data) -> BOOL {
|
||||
@@ -842,63 +804,18 @@ void FancyZones::MoveWindowsOnDisplayChange() noexcept
|
||||
{
|
||||
// i is off by 1 since 0 is special.
|
||||
auto strongThis = reinterpret_cast<FancyZones*>(data);
|
||||
strongThis->MoveWindowIntoZoneByIndex(window, nullptr, i - 1);
|
||||
std::unique_lock writeLock(strongThis->m_lock);
|
||||
strongThis->m_windowMoveHandler.MoveWindowIntoZoneByIndex(window, nullptr, i - 1, strongThis->m_zoneWindowMap);
|
||||
}
|
||||
return TRUE;
|
||||
};
|
||||
EnumWindows(callback, reinterpret_cast<LPARAM>(this));
|
||||
}
|
||||
|
||||
void FancyZones::UpdateDragState(HWND window, require_write_lock) noexcept
|
||||
{
|
||||
const bool shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
|
||||
const bool mouseL = GetAsyncKeyState(VK_LBUTTON) & 0x8000;
|
||||
const bool mouseR = GetAsyncKeyState(VK_RBUTTON) & 0x8000;
|
||||
const bool mouseM = GetAsyncKeyState(VK_MBUTTON) & 0x8000;
|
||||
const bool mouseX1 = GetAsyncKeyState(VK_XBUTTON1) & 0x8000;
|
||||
const bool mouseX2 = GetAsyncKeyState(VK_XBUTTON2) & 0x8000;
|
||||
|
||||
// Note, Middle, X1 and X2 can also be used in addition to R/L
|
||||
bool mouse = mouseM | mouseX1 | mouseX2;
|
||||
// If the user has swapped their Right and Left Buttons, use the "Right" equivalent
|
||||
if (GetSystemMetrics(SM_SWAPBUTTON))
|
||||
{
|
||||
mouse |= mouseL;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse |= mouseR;
|
||||
}
|
||||
|
||||
if (m_settings->GetSettings()->shiftDrag)
|
||||
{
|
||||
m_dragEnabled = (shift | mouse);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dragEnabled = !(shift | mouse);
|
||||
}
|
||||
|
||||
static bool warning_shown = false;
|
||||
if (!is_process_elevated() && IsProcessOfWindowElevated(window))
|
||||
{
|
||||
m_dragEnabled = false;
|
||||
if (!warning_shown && !is_cant_drag_elevated_warning_disabled())
|
||||
{
|
||||
std::vector<notifications::action_t> actions = {
|
||||
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_LEARN_MORE), L"https://aka.ms/powertoysDetectedElevatedHelp" },
|
||||
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN), L"powertoys://cant_drag_elevated_disable/" }
|
||||
};
|
||||
notifications::show_toast_with_activations(GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED), {}, std::move(actions));
|
||||
warning_shown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::CycleActiveZoneSet(DWORD vkCode) noexcept
|
||||
{
|
||||
auto window = GetForegroundWindow();
|
||||
if (IsInterestingWindow(window))
|
||||
if (IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
{
|
||||
const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
if (monitor)
|
||||
@@ -918,19 +835,20 @@ void FancyZones::CycleActiveZoneSet(DWORD vkCode) noexcept
|
||||
bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
|
||||
{
|
||||
auto window = GetForegroundWindow();
|
||||
if (IsInterestingWindow(window))
|
||||
if (IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
{
|
||||
const HMONITOR current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
if (current)
|
||||
{
|
||||
std::vector<HMONITOR> monitorInfo = GetMonitorsSorted();
|
||||
if (monitorInfo.size() > 1)
|
||||
if (monitorInfo.size() > 1 && m_settings->GetSettings()->moveWindowAcrossMonitors)
|
||||
{
|
||||
// Multi monitor environment.
|
||||
auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current);
|
||||
do
|
||||
{
|
||||
if (MoveWindowIntoZoneByDirection(*currMonitorInfo, window, vkCode, false /* cycle through zones */))
|
||||
std::unique_lock writeLock(m_lock);
|
||||
if (m_windowMoveHandler.MoveWindowIntoZoneByDirection(*currMonitorInfo, window, vkCode, false /* cycle through zones */, m_zoneWindowMap))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -956,215 +874,23 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
|
||||
else
|
||||
{
|
||||
// Single monitor environment.
|
||||
return MoveWindowIntoZoneByDirection(current, window, vkCode, true /* cycle through zones */);
|
||||
std::unique_lock writeLock(m_lock);
|
||||
return m_windowMoveHandler.MoveWindowIntoZoneByDirection(current, window, vkCode, true /* cycle through zones */, m_zoneWindowMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FancyZones::MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT const& ptScreen, require_write_lock writeLock) noexcept
|
||||
{
|
||||
if (IsCursorTypeIndicatingSizeEvent())
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_inMoveSize = true;
|
||||
|
||||
auto iter = m_zoneWindowMap.find(monitor);
|
||||
if (iter == end(m_zoneWindowMap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_windowMoveSize = window;
|
||||
|
||||
// This updates m_dragEnabled depending on if the shift key is being held down.
|
||||
UpdateDragState(window, writeLock);
|
||||
|
||||
if (m_dragEnabled)
|
||||
{
|
||||
m_zoneWindowMoveSize = iter->second;
|
||||
m_zoneWindowMoveSize->MoveSizeEnter(window, m_dragEnabled);
|
||||
if (m_settings->GetSettings()->showZonesOnAllMonitors)
|
||||
{
|
||||
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
|
||||
{
|
||||
// Skip calling ShowZoneWindow for iter->second (m_zoneWindowMoveSize) since it
|
||||
// was already called in MoveSizeEnter
|
||||
const bool moveSizeEnterCalled = zoneWindow == m_zoneWindowMoveSize;
|
||||
if (zoneWindow && !moveSizeEnterCalled)
|
||||
{
|
||||
zoneWindow->ShowZoneWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_zoneWindowMoveSize)
|
||||
{
|
||||
m_zoneWindowMoveSize->RestoreOrginalTransparency();
|
||||
m_zoneWindowMoveSize = nullptr;
|
||||
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
|
||||
{
|
||||
if (zoneWindow)
|
||||
{
|
||||
zoneWindow->HideZoneWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::MoveSizeEndInternal(HWND window, POINT const& ptScreen, require_write_lock) noexcept
|
||||
{
|
||||
m_inMoveSize = false;
|
||||
m_dragEnabled = false;
|
||||
m_windowMoveSize = nullptr;
|
||||
if (m_zoneWindowMoveSize)
|
||||
{
|
||||
auto zoneWindow = std::move(m_zoneWindowMoveSize);
|
||||
zoneWindow->MoveSizeEnd(window, ptScreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
::RemoveProp(window, ZONE_STAMP);
|
||||
|
||||
auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
if (monitor)
|
||||
{
|
||||
auto zoneWindow = m_zoneWindowMap.find(monitor);
|
||||
if (zoneWindow != m_zoneWindowMap.end())
|
||||
{
|
||||
const auto zoneWindowPtr = zoneWindow->second;
|
||||
const auto activeZoneSet = zoneWindowPtr->ActiveZoneSet();
|
||||
if (activeZoneSet)
|
||||
{
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (SUCCEEDED_LOG(StringFromCLSID(activeZoneSet->Id(), &guidString)))
|
||||
{
|
||||
JSONHelpers::FancyZonesDataInstance().RemoveAppLastZone(window, zoneWindowPtr->UniqueId(), guidString.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also, hide all windows (regardless of settings)
|
||||
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
|
||||
{
|
||||
if (zoneWindow)
|
||||
{
|
||||
zoneWindow->HideZoneWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::MoveSizeUpdateInternal(HMONITOR monitor, POINT const& ptScreen, require_write_lock writeLock) noexcept
|
||||
{
|
||||
if (m_inMoveSize)
|
||||
{
|
||||
// This updates m_dragEnabled depending on if the shift key is being held down.
|
||||
UpdateDragState(m_windowMoveSize, writeLock);
|
||||
|
||||
if (m_zoneWindowMoveSize)
|
||||
{
|
||||
// Update the ZoneWindow already handling move/size
|
||||
if (!m_dragEnabled)
|
||||
{
|
||||
// Drag got disabled, tell it to cancel and hide all windows
|
||||
m_zoneWindowMoveSize = nullptr;
|
||||
|
||||
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
|
||||
{
|
||||
if (zoneWindow)
|
||||
{
|
||||
zoneWindow->RestoreOrginalTransparency();
|
||||
zoneWindow->HideZoneWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto iter = m_zoneWindowMap.find(monitor);
|
||||
if (iter != m_zoneWindowMap.end())
|
||||
{
|
||||
if (iter->second != m_zoneWindowMoveSize)
|
||||
{
|
||||
// The drag has moved to a different monitor.
|
||||
m_zoneWindowMoveSize->RestoreOrginalTransparency();
|
||||
|
||||
if (!m_settings->GetSettings()->showZonesOnAllMonitors)
|
||||
{
|
||||
m_zoneWindowMoveSize->HideZoneWindow();
|
||||
}
|
||||
m_zoneWindowMoveSize = iter->second;
|
||||
m_zoneWindowMoveSize->MoveSizeEnter(m_windowMoveSize, m_zoneWindowMoveSize->IsDragEnabled());
|
||||
}
|
||||
|
||||
for (auto [keyMonitor, zoneWindow] : m_zoneWindowMap)
|
||||
{
|
||||
zoneWindow->MoveSizeUpdate(ptScreen, m_dragEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
MoveSizeStartInternal(m_windowMoveSize, monitor, ptScreen, writeLock);
|
||||
MoveSizeUpdateInternal(monitor, ptScreen, writeLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::HandleVirtualDesktopUpdates(HANDLE fancyZonesDestroyedEvent) noexcept
|
||||
{
|
||||
HANDLE regKeyEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
HANDLE events[2] = { regKeyEvent, fancyZonesDestroyedEvent };
|
||||
while (1)
|
||||
{
|
||||
if (RegNotifyChangeKeyValue(HKEY_CURRENT_USER, TRUE, REG_NOTIFY_CHANGE_LAST_SET, regKeyEvent, TRUE) != ERROR_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (WaitForMultipleObjects(2, events, FALSE, INFINITE) != (WAIT_OBJECT_0 + 0))
|
||||
{
|
||||
// if fancyZonesDestroyedEvent is signalized or WaitForMultipleObjects failed, terminate thread execution
|
||||
return;
|
||||
}
|
||||
DWORD bufferCapacity;
|
||||
const WCHAR* key = L"VirtualDesktopIDs";
|
||||
// request regkey binary buffer capacity only
|
||||
if (RegQueryValueExW(m_virtualDesktopsRegKey, key, 0, nullptr, nullptr, &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<BYTE[]> buffer = std::make_unique<BYTE[]>(bufferCapacity);
|
||||
// request regkey binary content
|
||||
if (RegQueryValueExW(m_virtualDesktopsRegKey, key, 0, nullptr, buffer.get(), &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const size_t guidSize = sizeof(GUID);
|
||||
std::unordered_set<GUID> temp;
|
||||
temp.reserve(bufferCapacity / guidSize);
|
||||
for (size_t i = 0; i < bufferCapacity; i += guidSize)
|
||||
{
|
||||
GUID* guid = reinterpret_cast<GUID*>(buffer.get() + i);
|
||||
temp.insert(*guid);
|
||||
}
|
||||
RegisterVirtualDesktopUpdates(temp);
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& currentVirtualDesktopIds) noexcept
|
||||
void FancyZones::RegisterVirtualDesktopUpdates(std::vector<GUID>& ids) noexcept
|
||||
{
|
||||
std::unordered_set<GUID> activeVirtualDesktops(std::begin(ids), std::end(ids));
|
||||
std::unique_lock writeLock(m_lock);
|
||||
bool modified{ false };
|
||||
for (auto it = begin(m_processedWorkAreas); it != end(m_processedWorkAreas);)
|
||||
for (auto it = std::begin(m_processedWorkAreas); it != std::end(m_processedWorkAreas);)
|
||||
{
|
||||
auto iter = currentVirtualDesktopIds.find(it->first);
|
||||
if (iter == currentVirtualDesktopIds.end())
|
||||
auto iter = activeVirtualDesktops.find(it->first);
|
||||
if (iter == activeVirtualDesktops.end())
|
||||
{
|
||||
// if we couldn't find the GUID in currentVirtualDesktopIds, we must remove it from both m_processedWorkAreas and deviceInfoMap
|
||||
wil::unique_cotaskmem_string virtualDesktopId;
|
||||
@@ -1176,7 +902,7 @@ void FancyZones::RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& current
|
||||
}
|
||||
else
|
||||
{
|
||||
currentVirtualDesktopIds.erase(it->first); // virtual desktop already in map, skip it
|
||||
activeVirtualDesktops.erase(it->first); // virtual desktop already in map, skip it
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@@ -1185,7 +911,7 @@ void FancyZones::RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& current
|
||||
JSONHelpers::FancyZonesDataInstance().SaveFancyZonesData();
|
||||
}
|
||||
// register new virtual desktops, if any
|
||||
for (const auto& id : currentVirtualDesktopIds)
|
||||
for (const auto& id : activeVirtualDesktops)
|
||||
{
|
||||
m_processedWorkAreas[id] = std::vector<HMONITOR>();
|
||||
}
|
||||
@@ -1252,17 +978,6 @@ std::vector<std::pair<HMONITOR, RECT>> FancyZones::GetRawMonitorData() noexcept
|
||||
return monitorInfo;
|
||||
}
|
||||
|
||||
bool FancyZones::MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle)
|
||||
{
|
||||
auto iter = m_zoneWindowMap.find(monitor);
|
||||
if (iter != std::end(m_zoneWindowMap))
|
||||
{
|
||||
const auto& zoneWindowPtr = iter->second;
|
||||
return zoneWindowPtr->MoveWindowIntoZoneByDirection(window, vkCode, cycle);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings) noexcept
|
||||
{
|
||||
if (!settings)
|
||||
|
||||
@@ -4,6 +4,8 @@ interface IZoneWindow;
|
||||
interface IFancyZonesSettings;
|
||||
interface IZoneSet;
|
||||
|
||||
struct WinHookEvent;
|
||||
|
||||
interface __declspec(uuid("{50D3F0F5-736E-4186-BDF4-3D6BEE150C3A}")) IFancyZones : public IUnknown
|
||||
{
|
||||
/**
|
||||
@@ -21,47 +23,16 @@ interface __declspec(uuid("{50D3F0F5-736E-4186-BDF4-3D6BEE150C3A}")) IFancyZones
|
||||
*/
|
||||
interface __declspec(uuid("{2CB37E8F-87E6-4AEC-B4B2-E0FDC873343F}")) IFancyZonesCallback : public IUnknown
|
||||
{
|
||||
/**
|
||||
* @returns Boolean indicating whether a move/size operation is currently active.
|
||||
*/
|
||||
IFACEMETHOD_(bool, InMoveSize)() = 0;
|
||||
/**
|
||||
* A window is being moved or resized. Track down window position and give zone layout
|
||||
* hints if dragging functionality is enabled.
|
||||
*
|
||||
* @param window Handle of window being moved or resized.
|
||||
* @param monitor Handle of monitor on which windows is moving / resizing.
|
||||
* @param ptScreen Cursor coordinates.
|
||||
*/
|
||||
IFACEMETHOD_(void, MoveSizeStart)(HWND window, HMONITOR monitor, POINT const& ptScreen) = 0;
|
||||
/**
|
||||
* A window has changed location, shape, or size. Track down window position and give zone layout
|
||||
* hints if dragging functionality is enabled.
|
||||
*
|
||||
* @param monitor Handle of monitor on which windows is moving / resizing.
|
||||
* @param ptScreen Cursor coordinates.
|
||||
*/
|
||||
IFACEMETHOD_(void, MoveSizeUpdate)(HMONITOR monitor, POINT const& ptScreen) = 0;
|
||||
/**
|
||||
* The movement or resizing of a window has finished. Assign window to the zone if it
|
||||
* is dropped within zone borders.
|
||||
*
|
||||
* @param window Handle of window being moved or resized.
|
||||
* @param ptScreen Cursor coordinates where window is droped.
|
||||
*/
|
||||
IFACEMETHOD_(void, MoveSizeEnd)(HWND window, POINT const& ptScreen) = 0;
|
||||
/**
|
||||
* Inform FancyZones that user has switched between virtual desktops.
|
||||
*/
|
||||
IFACEMETHOD_(void, VirtualDesktopChanged)() = 0;
|
||||
/**
|
||||
* Inform FancyZones that new window is created. FancyZones will try to assign it to the
|
||||
* zone insde active zone layout (if information about last zone, in which window was located
|
||||
* before being closed, is available).
|
||||
* Callback from WinEventHook to FancyZones
|
||||
*
|
||||
* @param window Handle of newly created window.
|
||||
* @param data Handle of window being moved or resized.
|
||||
*/
|
||||
IFACEMETHOD_(void, WindowCreated)(HWND window) = 0;
|
||||
IFACEMETHOD_(void, HandleWinHookEvent)(const WinHookEvent* data) = 0;
|
||||
/**
|
||||
* Process keyboard event.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
@@ -15,7 +16,7 @@
|
||||
<ProjectGuid>{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>lib</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>FancyZonesLib</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
@@ -61,7 +62,6 @@
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
@@ -81,7 +81,6 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
@@ -96,20 +95,22 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="FancyZones.h" />
|
||||
<ClInclude Include="FancyZonesWinHookEventIDs.h" />
|
||||
<ClInclude Include="JsonHelpers.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="RegistryHelpers.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="Settings.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
<ClInclude Include="VirtualDesktopUtils.h" />
|
||||
<ClInclude Include="WindowMoveHandler.h" />
|
||||
<ClInclude Include="Zone.h" />
|
||||
<ClInclude Include="ZoneSet.h" />
|
||||
<ClInclude Include="ZoneWindow.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="FancyZones.cpp" />
|
||||
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
|
||||
<ClCompile Include="JsonHelpers.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
@@ -119,6 +120,7 @@
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<ClCompile Include="util.cpp" />
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp" />
|
||||
<ClCompile Include="WindowMoveHandler.cpp" />
|
||||
<ClCompile Include="Zone.cpp" />
|
||||
<ClCompile Include="ZoneSet.cpp" />
|
||||
<ClCompile Include="ZoneWindow.cpp" />
|
||||
@@ -132,11 +134,14 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -30,9 +30,6 @@
|
||||
<ClInclude Include="FancyZones.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RegistryHelpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Settings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -51,6 +48,12 @@
|
||||
<ClInclude Include="VirtualDesktopUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowMoveHandler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FancyZonesWinHookEventIDs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@@ -83,6 +86,12 @@
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WindowMoveHandler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FancyZonesWinHookEventIDs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="fancyzones.rc">
|
||||
|
||||
24
src/modules/fancyzones/lib/FancyZonesWinHookEventIDs.cpp
Normal file
24
src/modules/fancyzones/lib/FancyZonesWinHookEventIDs.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "FancyZonesWinHookEventIDs.h"
|
||||
|
||||
UINT WM_PRIV_MOVESIZESTART;
|
||||
UINT WM_PRIV_MOVESIZEEND;
|
||||
UINT WM_PRIV_LOCATIONCHANGE;
|
||||
UINT WM_PRIV_NAMECHANGE;
|
||||
UINT WM_PRIV_WINDOWCREATED;
|
||||
|
||||
std::once_flag init_flag;
|
||||
|
||||
void InitializeWinhookEventIds()
|
||||
{
|
||||
std::call_once(init_flag, [&] {
|
||||
WM_PRIV_MOVESIZESTART = RegisterWindowMessage(L"{f48def23-df42-4c0f-a13d-3eb4a9e204d4}");
|
||||
WM_PRIV_MOVESIZEEND = RegisterWindowMessage(L"{805d643c-804d-4728-b533-907d760ebaf0}");
|
||||
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}");
|
||||
});
|
||||
}
|
||||
9
src/modules/fancyzones/lib/FancyZonesWinHookEventIDs.h
Normal file
9
src/modules/fancyzones/lib/FancyZonesWinHookEventIDs.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
extern UINT WM_PRIV_MOVESIZESTART;
|
||||
extern UINT WM_PRIV_MOVESIZEEND;
|
||||
extern UINT WM_PRIV_LOCATIONCHANGE;
|
||||
extern UINT WM_PRIV_NAMECHANGE;
|
||||
extern UINT WM_PRIV_WINDOWCREATED;
|
||||
|
||||
void InitializeWinhookEventIds();
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "pch.h"
|
||||
#include "JsonHelpers.h"
|
||||
#include "RegistryHelpers.h"
|
||||
#include "ZoneSet.h"
|
||||
#include "trace.h"
|
||||
|
||||
@@ -11,22 +10,10 @@
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace
|
||||
{
|
||||
// Needed for migration of applied zonesets from registry
|
||||
struct ZoneSetPersistedDataOLD
|
||||
{
|
||||
static constexpr inline size_t MAX_ZONES = 40;
|
||||
DWORD Version{ VERSION_PERSISTEDDATA };
|
||||
WORD LayoutId{};
|
||||
DWORD ZoneCount{};
|
||||
JSONHelpers::ZoneSetLayoutType Layout{};
|
||||
DWORD PaddingInner{};
|
||||
DWORD PaddingOuter{};
|
||||
RECT Zones[MAX_ZONES]{};
|
||||
};
|
||||
|
||||
// From Settings.cs
|
||||
constexpr int c_focusModelId = 0xFFFF;
|
||||
constexpr int c_rowsModelId = 0xFFFE;
|
||||
@@ -37,6 +24,7 @@ namespace
|
||||
|
||||
const wchar_t* FANCY_ZONES_DATA_FILE = L"zones-settings.json";
|
||||
const wchar_t* DEFAULT_GUID = L"{00000000-0000-0000-0000-000000000000}";
|
||||
const wchar_t* REG_SETTINGS = L"Software\\SuperFancyZones";
|
||||
|
||||
std::wstring ExtractVirtualDesktopId(const std::wstring& deviceId)
|
||||
{
|
||||
@@ -321,6 +309,65 @@ namespace JSONHelpers
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesData::UpdatePrimaryDesktopData(const std::wstring& 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 and we will use default GUID in
|
||||
// that case (00000000-0000-0000-0000-000000000000).
|
||||
// This method will go through all our persisted data with default GUID and update it with
|
||||
// valid one.
|
||||
auto replaceDesktopId = [&desktopId](const std::wstring& deviceId) {
|
||||
return deviceId.substr(0, deviceId.rfind('_') + 1) + desktopId;
|
||||
};
|
||||
std::scoped_lock lock{ dataLock };
|
||||
for (auto& [path, data] : appZoneHistoryMap)
|
||||
{
|
||||
if (ExtractVirtualDesktopId(data.deviceId) == DEFAULT_GUID)
|
||||
{
|
||||
data.deviceId = replaceDesktopId(data.deviceId);
|
||||
}
|
||||
}
|
||||
std::vector<std::wstring> toReplace{};
|
||||
for (const auto& [id, data] : deviceInfoMap)
|
||||
{
|
||||
if (ExtractVirtualDesktopId(id) == DEFAULT_GUID)
|
||||
{
|
||||
toReplace.push_back(id);
|
||||
}
|
||||
}
|
||||
for (const auto& id : toReplace)
|
||||
{
|
||||
auto mapEntry = deviceInfoMap.extract(id);
|
||||
mapEntry.key() = replaceDesktopId(id);
|
||||
deviceInfoMap.insert(std::move(mapEntry));
|
||||
}
|
||||
if (activeDeviceId == DEFAULT_GUID)
|
||||
{
|
||||
activeDeviceId = replaceDesktopId(activeDeviceId);
|
||||
}
|
||||
SaveFancyZonesData();
|
||||
}
|
||||
|
||||
void FancyZonesData::RemoveDeletedDesktops(const std::vector<std::wstring>& activeDesktops)
|
||||
{
|
||||
std::unordered_set<std::wstring> active(std::begin(activeDesktops), std::end(activeDesktops));
|
||||
std::scoped_lock lock{ dataLock };
|
||||
for (auto it = std::begin(deviceInfoMap); it != std::end(deviceInfoMap);)
|
||||
{
|
||||
auto foundId = active.find(ExtractVirtualDesktopId(it->first));
|
||||
if (foundId == std::end(active))
|
||||
{
|
||||
it = deviceInfoMap.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
SaveFancyZonesData();
|
||||
}
|
||||
|
||||
int FancyZonesData::GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
@@ -640,7 +687,7 @@ namespace JSONHelpers
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
wchar_t key[256];
|
||||
StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", RegistryHelpers::REG_SETTINGS, L"Layouts");
|
||||
StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", REG_SETTINGS, L"Layouts");
|
||||
HKEY hkey;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS)
|
||||
{
|
||||
|
||||
@@ -233,6 +233,8 @@ namespace JSONHelpers
|
||||
void AddDevice(const std::wstring& deviceId);
|
||||
bool RemoveDevicesByVirtualDesktopId(const std::wstring& virtualDesktopId);
|
||||
void CloneDeviceInfo(const std::wstring& source, const std::wstring& destination);
|
||||
void UpdatePrimaryDesktopData(const std::wstring& desktopId);
|
||||
void RemoveDeletedDesktops(const std::vector<std::wstring>& activeDesktops);
|
||||
|
||||
int GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const;
|
||||
bool RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId);
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
namespace RegistryHelpers
|
||||
{
|
||||
static PCWSTR REG_SETTINGS = L"Software\\SuperFancyZones";
|
||||
static PCWSTR APP_ZONE_HISTORY_SUBKEY = L"AppZoneHistory";
|
||||
|
||||
inline HRESULT GetCurrentVirtualDesktop(_Out_ GUID* id)
|
||||
{
|
||||
*id = GUID_NULL;
|
||||
|
||||
DWORD sessionId;
|
||||
ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
|
||||
wchar_t sessionKeyPath[256]{};
|
||||
RETURN_IF_FAILED(
|
||||
StringCchPrintfW(
|
||||
sessionKeyPath,
|
||||
ARRAYSIZE(sessionKeyPath),
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops",
|
||||
sessionId));
|
||||
wil::unique_hkey key{};
|
||||
GUID value{};
|
||||
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD size = sizeof(value);
|
||||
if (RegQueryValueExW(key.get(), L"CurrentVirtualDesktop", 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
*id = value;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
@@ -36,9 +36,10 @@ private:
|
||||
PCWSTR name;
|
||||
bool* value;
|
||||
int resourceId;
|
||||
} m_configBools[9 /* 10 */] = { // "Turning FLASHING_ZONE option off"
|
||||
} m_configBools[10 /* 11 */] = { // "Turning FLASHING_ZONE option off"
|
||||
{ L"fancyzones_shiftDrag", &m_settings.shiftDrag, IDS_SETTING_DESCRIPTION_SHIFTDRAG },
|
||||
{ L"fancyzones_overrideSnapHotkeys", &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS },
|
||||
{ L"fancyzones_moveWindowAcrossMonitors", &m_settings.moveWindowAcrossMonitors, IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS },
|
||||
// "Turning FLASHING_ZONE option off"
|
||||
//{ L"fancyzones_zoneSetChange_flashZones", &m_settings.zoneSetChange_flashZones, IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES },
|
||||
{ L"fancyzones_displayChange_moveWindows", &m_settings.displayChange_moveWindows, IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS },
|
||||
|
||||
@@ -12,6 +12,7 @@ struct Settings
|
||||
bool zoneSetChange_flashZones = false;
|
||||
bool zoneSetChange_moveWindows = false;
|
||||
bool overrideSnapHotkeys = false;
|
||||
bool moveWindowAcrossMonitors = false;
|
||||
bool appLastZone_moveWindows = false;
|
||||
bool use_cursorpos_editor_startupscreen = true;
|
||||
bool showZonesOnAllMonitors = false;
|
||||
|
||||
@@ -7,6 +7,10 @@ namespace VirtualDesktopUtils
|
||||
const CLSID CLSID_ImmersiveShell = { 0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 };
|
||||
const wchar_t GUID_EmptyGUID[] = L"{00000000-0000-0000-0000-000000000000}";
|
||||
|
||||
const wchar_t RegCurrentVirtualDesktop[] = L"CurrentVirtualDesktop";
|
||||
const wchar_t RegVirtualDesktopIds[] = L"VirtualDesktopIDs";
|
||||
const wchar_t RegKeyVirtualDesktops[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops";
|
||||
|
||||
IServiceProvider* GetServiceProvider()
|
||||
{
|
||||
IServiceProvider* provider{ nullptr };
|
||||
@@ -46,4 +50,142 @@ namespace VirtualDesktopUtils
|
||||
}
|
||||
return SUCCEEDED(CLSIDFromString(virtualDesktopId.c_str(), desktopId));
|
||||
}
|
||||
|
||||
bool GetDesktopIdFromCurrentSession(GUID* desktopId)
|
||||
{
|
||||
DWORD sessionId;
|
||||
ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
|
||||
wchar_t sessionKeyPath[256]{};
|
||||
RETURN_IF_FAILED(
|
||||
StringCchPrintfW(
|
||||
sessionKeyPath,
|
||||
ARRAYSIZE(sessionKeyPath),
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops",
|
||||
sessionId));
|
||||
|
||||
wil::unique_hkey key{};
|
||||
GUID value{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD size = sizeof(GUID);
|
||||
if (RegQueryValueExW(key.get(), RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
*desktopId = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetCurrentVirtualDesktopId(GUID* desktopId)
|
||||
{
|
||||
if (!GetDesktopIdFromCurrentSession(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 (only primary desktop) in this session value in registry will be empty.
|
||||
// If this value is empty take first element from array of virtual desktops (not kept per session).
|
||||
std::vector<GUID> ids{};
|
||||
if (!GetVirtualDesktopIds(ids) || ids.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*desktopId = ids[0];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetVirtualDesktopIds(HKEY hKey, std::vector<GUID>& ids)
|
||||
{
|
||||
if (!hKey)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DWORD bufferCapacity;
|
||||
// request regkey binary buffer capacity only
|
||||
if (RegQueryValueExW(hKey, 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, 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, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,9 @@ 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);
|
||||
}
|
||||
|
||||
362
src/modules/fancyzones/lib/WindowMoveHandler.cpp
Normal file
362
src/modules/fancyzones/lib/WindowMoveHandler.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
#include "pch.h"
|
||||
#include "WindowMoveHandler.h"
|
||||
|
||||
#include <common/notifications.h>
|
||||
#include <common/notifications/fancyzones_notifications.h>
|
||||
#include <common/window_helpers.h>
|
||||
|
||||
#include "lib/Settings.h"
|
||||
#include "lib/ZoneWindow.h"
|
||||
#include "lib/util.h"
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
namespace WindowMoveHandlerUtils
|
||||
{
|
||||
bool IsCursorTypeIndicatingSizeEvent()
|
||||
{
|
||||
CURSORINFO cursorInfo = { 0 };
|
||||
cursorInfo.cbSize = sizeof(cursorInfo);
|
||||
|
||||
if (::GetCursorInfo(&cursorInfo))
|
||||
{
|
||||
if (::LoadCursor(NULL, IDC_SIZENS) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (::LoadCursor(NULL, IDC_SIZEWE) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (::LoadCursor(NULL, IDC_SIZENESW) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (::LoadCursor(NULL, IDC_SIZENWSE) == cursorInfo.hCursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class WindowMoveHandlerPrivate
|
||||
{
|
||||
public:
|
||||
WindowMoveHandlerPrivate(const winrt::com_ptr<IFancyZonesSettings>& settings) :
|
||||
m_settings(settings)
|
||||
{};
|
||||
|
||||
bool IsDragEnabled() const noexcept
|
||||
{
|
||||
return m_dragEnabled;
|
||||
}
|
||||
|
||||
bool InMoveSize() const noexcept
|
||||
{
|
||||
return m_inMoveSize;
|
||||
}
|
||||
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
|
||||
void MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
bool MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap);
|
||||
|
||||
private:
|
||||
void UpdateDragState(HWND window) noexcept;
|
||||
|
||||
private:
|
||||
winrt::com_ptr<IFancyZonesSettings> m_settings{};
|
||||
|
||||
HWND m_windowMoveSize{}; // The window that is being moved/sized
|
||||
bool m_inMoveSize{}; // Whether or not a move/size operation is currently active
|
||||
winrt::com_ptr<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, 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
|
||||
};
|
||||
|
||||
|
||||
WindowMoveHandler::WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>& settings) :
|
||||
pimpl(new WindowMoveHandlerPrivate(settings))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WindowMoveHandler::~WindowMoveHandler()
|
||||
{
|
||||
delete pimpl;
|
||||
}
|
||||
|
||||
bool WindowMoveHandler::InMoveSize() const noexcept
|
||||
{
|
||||
return pimpl->InMoveSize();
|
||||
}
|
||||
|
||||
bool WindowMoveHandler::IsDragEnabled() const noexcept
|
||||
{
|
||||
return pimpl->IsDragEnabled();
|
||||
}
|
||||
|
||||
void WindowMoveHandler::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
{
|
||||
pimpl->MoveSizeStart(window, monitor, ptScreen, zoneWindowMap);
|
||||
}
|
||||
|
||||
void WindowMoveHandler::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
{
|
||||
pimpl->MoveSizeUpdate(monitor, ptScreen, zoneWindowMap);
|
||||
}
|
||||
|
||||
void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
{
|
||||
pimpl->MoveSizeEnd(window, ptScreen, zoneWindowMap);
|
||||
}
|
||||
|
||||
void WindowMoveHandler::MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
{
|
||||
pimpl->MoveWindowIntoZoneByIndexSet(window, monitor, { index }, zoneWindowMap);
|
||||
}
|
||||
|
||||
bool WindowMoveHandler::MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap)
|
||||
{
|
||||
return pimpl->MoveWindowIntoZoneByDirection(monitor, window, vkCode, cycle, zoneWindowMap);
|
||||
}
|
||||
|
||||
void WindowMoveHandlerPrivate::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
{
|
||||
if (!IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray) || WindowMoveHandlerUtils::IsCursorTypeIndicatingSizeEvent())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_inMoveSize = true;
|
||||
|
||||
auto iter = zoneWindowMap.find(monitor);
|
||||
if (iter == end(zoneWindowMap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_windowMoveSize = window;
|
||||
|
||||
// This updates m_dragEnabled depending on if the shift key is being held down.
|
||||
UpdateDragState(window);
|
||||
|
||||
if (m_dragEnabled)
|
||||
{
|
||||
m_zoneWindowMoveSize = iter->second;
|
||||
m_zoneWindowMoveSize->MoveSizeEnter(window, m_dragEnabled);
|
||||
if (m_settings->GetSettings()->showZonesOnAllMonitors)
|
||||
{
|
||||
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
|
||||
{
|
||||
// Skip calling ShowZoneWindow for iter->second (m_zoneWindowMoveSize) since it
|
||||
// was already called in MoveSizeEnter
|
||||
const bool moveSizeEnterCalled = zoneWindow == m_zoneWindowMoveSize;
|
||||
if (zoneWindow && !moveSizeEnterCalled)
|
||||
{
|
||||
zoneWindow->ShowZoneWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_zoneWindowMoveSize)
|
||||
{
|
||||
m_zoneWindowMoveSize->RestoreOrginalTransparency();
|
||||
m_zoneWindowMoveSize = nullptr;
|
||||
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
|
||||
{
|
||||
if (zoneWindow)
|
||||
{
|
||||
zoneWindow->HideZoneWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMoveHandlerPrivate::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
{
|
||||
if (!m_inMoveSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// This updates m_dragEnabled depending on if the shift key is being held down.
|
||||
UpdateDragState(m_windowMoveSize);
|
||||
|
||||
if (m_zoneWindowMoveSize)
|
||||
{
|
||||
// Update the ZoneWindow already handling move/size
|
||||
if (!m_dragEnabled)
|
||||
{
|
||||
// Drag got disabled, tell it to cancel and hide all windows
|
||||
m_zoneWindowMoveSize = nullptr;
|
||||
|
||||
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
|
||||
{
|
||||
if (zoneWindow)
|
||||
{
|
||||
zoneWindow->RestoreOrginalTransparency();
|
||||
zoneWindow->HideZoneWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto iter = zoneWindowMap.find(monitor);
|
||||
if (iter != zoneWindowMap.end())
|
||||
{
|
||||
if (iter->second != m_zoneWindowMoveSize)
|
||||
{
|
||||
// The drag has moved to a different monitor.
|
||||
m_zoneWindowMoveSize->RestoreOrginalTransparency();
|
||||
|
||||
if (!m_settings->GetSettings()->showZonesOnAllMonitors)
|
||||
{
|
||||
m_zoneWindowMoveSize->HideZoneWindow();
|
||||
}
|
||||
m_zoneWindowMoveSize = iter->second;
|
||||
m_zoneWindowMoveSize->MoveSizeEnter(m_windowMoveSize, m_zoneWindowMoveSize->IsDragEnabled());
|
||||
}
|
||||
|
||||
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
|
||||
{
|
||||
zoneWindow->MoveSizeUpdate(ptScreen, m_dragEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
MoveSizeStart(m_windowMoveSize, monitor, ptScreen, zoneWindowMap);
|
||||
MoveSizeUpdate(monitor, ptScreen, zoneWindowMap);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMoveHandlerPrivate::MoveSizeEnd(HWND window, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
{
|
||||
if (window != m_windowMoveSize && !IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_inMoveSize = false;
|
||||
m_dragEnabled = false;
|
||||
m_windowMoveSize = nullptr;
|
||||
if (m_zoneWindowMoveSize)
|
||||
{
|
||||
auto zoneWindow = std::move(m_zoneWindowMoveSize);
|
||||
zoneWindow->MoveSizeEnd(window, ptScreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
::RemoveProp(window, ZONE_STAMP);
|
||||
|
||||
auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
if (monitor)
|
||||
{
|
||||
auto zoneWindow = zoneWindowMap.find(monitor);
|
||||
if (zoneWindow != zoneWindowMap.end())
|
||||
{
|
||||
const auto zoneWindowPtr = zoneWindow->second;
|
||||
const auto activeZoneSet = zoneWindowPtr->ActiveZoneSet();
|
||||
if (activeZoneSet)
|
||||
{
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (SUCCEEDED_LOG(StringFromCLSID(activeZoneSet->Id(), &guidString)))
|
||||
{
|
||||
JSONHelpers::FancyZonesDataInstance().RemoveAppLastZone(window, zoneWindowPtr->UniqueId(), guidString.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also, hide all windows (regardless of settings)
|
||||
for (auto [keyMonitor, zoneWindow] : zoneWindowMap)
|
||||
{
|
||||
if (zoneWindow)
|
||||
{
|
||||
zoneWindow->HideZoneWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMoveHandlerPrivate::MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
|
||||
{
|
||||
if (window != m_windowMoveSize)
|
||||
{
|
||||
const HMONITOR hm = (monitor != nullptr) ? monitor : MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
if (hm)
|
||||
{
|
||||
auto zoneWindow = zoneWindowMap.find(hm);
|
||||
if (zoneWindow != zoneWindowMap.end())
|
||||
{
|
||||
const auto& zoneWindowPtr = zoneWindow->second;
|
||||
zoneWindowPtr->MoveWindowIntoZoneByIndexSet(window, indexSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowMoveHandlerPrivate::MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap)
|
||||
{
|
||||
auto iter = zoneWindowMap.find(monitor);
|
||||
if (iter != std::end(zoneWindowMap))
|
||||
{
|
||||
const auto& zoneWindowPtr = iter->second;
|
||||
return zoneWindowPtr->MoveWindowIntoZoneByDirection(window, vkCode, cycle);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WindowMoveHandlerPrivate::UpdateDragState(HWND window) noexcept
|
||||
{
|
||||
const bool shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
|
||||
const bool mouseL = GetAsyncKeyState(VK_LBUTTON) & 0x8000;
|
||||
const bool mouseR = GetAsyncKeyState(VK_RBUTTON) & 0x8000;
|
||||
const bool mouseM = GetAsyncKeyState(VK_MBUTTON) & 0x8000;
|
||||
const bool mouseX1 = GetAsyncKeyState(VK_XBUTTON1) & 0x8000;
|
||||
const bool mouseX2 = GetAsyncKeyState(VK_XBUTTON2) & 0x8000;
|
||||
|
||||
// Note, Middle, X1 and X2 can also be used in addition to R/L
|
||||
bool mouse = mouseM | mouseX1 | mouseX2;
|
||||
// If the user has swapped their Right and Left Buttons, use the "Right" equivalent
|
||||
if (GetSystemMetrics(SM_SWAPBUTTON))
|
||||
{
|
||||
mouse |= mouseL;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse |= mouseR;
|
||||
}
|
||||
|
||||
if (m_settings->GetSettings()->shiftDrag)
|
||||
{
|
||||
m_dragEnabled = (shift | mouse);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dragEnabled = !(shift | mouse);
|
||||
}
|
||||
|
||||
static bool warning_shown = false;
|
||||
if (!is_process_elevated() && IsProcessOfWindowElevated(window))
|
||||
{
|
||||
m_dragEnabled = false;
|
||||
if (!warning_shown && !is_cant_drag_elevated_warning_disabled())
|
||||
{
|
||||
std::vector<notifications::action_t> actions = {
|
||||
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_LEARN_MORE), L"https://aka.ms/powertoysDetectedElevatedHelp" },
|
||||
notifications::link_button{ GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN), L"powertoys://cant_drag_elevated_disable/" }
|
||||
};
|
||||
notifications::show_toast_with_activations(GET_RESOURCE_STRING(IDS_CANT_DRAG_ELEVATED), {}, std::move(actions));
|
||||
warning_shown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/modules/fancyzones/lib/WindowMoveHandler.h
Normal file
24
src/modules/fancyzones/lib/WindowMoveHandler.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
interface IFancyZonesSettings;
|
||||
interface IZoneWindow;
|
||||
|
||||
class WindowMoveHandler
|
||||
{
|
||||
public:
|
||||
WindowMoveHandler(const winrt::com_ptr<IFancyZonesSettings>& settings);
|
||||
~WindowMoveHandler();
|
||||
|
||||
bool InMoveSize() const noexcept;
|
||||
bool IsDragEnabled() const noexcept;
|
||||
|
||||
void MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
|
||||
void MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
|
||||
bool MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap);
|
||||
|
||||
private:
|
||||
class WindowMoveHandlerPrivate* pimpl;
|
||||
};
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "lib/ZoneSet.h"
|
||||
#include "lib/RegistryHelpers.h"
|
||||
|
||||
#include <common/dpi_aware.h>
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "ZoneWindow.h"
|
||||
#include "trace.h"
|
||||
#include "util.h"
|
||||
#include "RegistryHelpers.h"
|
||||
|
||||
#include <ShellScalingApi.h>
|
||||
#include <mutex>
|
||||
@@ -213,7 +212,7 @@ public:
|
||||
IFACEMETHODIMP_(void)
|
||||
RestoreOrginalTransparency() noexcept;
|
||||
IFACEMETHODIMP_(bool)
|
||||
IsDragEnabled() noexcept;
|
||||
IsDragEnabled() noexcept { return m_dragEnabled; }
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveWindowIntoZoneByIndex(HWND window, int index) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -223,13 +222,13 @@ public:
|
||||
IFACEMETHODIMP_(void)
|
||||
CycleActiveZoneSet(DWORD vkCode) noexcept;
|
||||
IFACEMETHODIMP_(std::wstring)
|
||||
UniqueId() noexcept;
|
||||
UniqueId() noexcept { return { m_uniqueId }; }
|
||||
IFACEMETHODIMP_(std::wstring)
|
||||
WorkAreaKey() noexcept;
|
||||
WorkAreaKey() noexcept { return { m_workArea }; }
|
||||
IFACEMETHODIMP_(void)
|
||||
SaveWindowProcessToZoneIndex(HWND window) noexcept;
|
||||
IFACEMETHODIMP_(IZoneSet*)
|
||||
ActiveZoneSet() noexcept;
|
||||
ActiveZoneSet() noexcept { return m_activeZoneSet.get(); }
|
||||
IFACEMETHODIMP_(void)
|
||||
ShowZoneWindow() noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -267,15 +266,13 @@ private:
|
||||
static const UINT m_showAnimationDuration = 200; // ms
|
||||
static const UINT m_flashDuration = 700; // ms
|
||||
|
||||
HWND m_draggedWindow = nullptr;
|
||||
long m_draggedWindowExstyle = 0;
|
||||
COLORREF m_draggedWindowCrKey = RGB(0, 0, 0);
|
||||
DWORD m_draggedWindowDwFlags = 0;
|
||||
BYTE m_draggedWindowInitialAlpha = 0;
|
||||
HWND draggedWindow = nullptr;
|
||||
long draggedWindowExstyle = 0;
|
||||
COLORREF draggedWindowCrKey = RGB(0, 0, 0);
|
||||
DWORD draggedWindowDwFlags = 0;
|
||||
BYTE draggedWindowInitialAlpha = 0;
|
||||
|
||||
ULONG_PTR m_gdiplusToken;
|
||||
|
||||
mutable std::shared_mutex m_mutex;
|
||||
ULONG_PTR gdiplusToken;
|
||||
};
|
||||
|
||||
ZoneWindow::ZoneWindow(HINSTANCE hinstance)
|
||||
@@ -289,14 +286,12 @@ ZoneWindow::ZoneWindow(HINSTANCE hinstance)
|
||||
RegisterClassExW(&wcex);
|
||||
|
||||
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
||||
Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
|
||||
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
|
||||
}
|
||||
|
||||
ZoneWindow::~ZoneWindow()
|
||||
{
|
||||
RestoreOrginalTransparency();
|
||||
|
||||
Gdiplus::GdiplusShutdown(m_gdiplusToken);
|
||||
Gdiplus::GdiplusShutdown(gdiplusToken);
|
||||
}
|
||||
|
||||
bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, bool flashZones, bool newWorkArea)
|
||||
@@ -349,26 +344,13 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
|
||||
|
||||
IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window, bool dragEnabled) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto windowMoveSize = m_windowMoveSize;
|
||||
auto hostTransparentActive = m_host->isMakeDraggedWindowTransparentActive();
|
||||
lock.unlock();
|
||||
|
||||
if (windowMoveSize)
|
||||
if (m_windowMoveSize)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (hostTransparentActive)
|
||||
if (m_host->isMakeDraggedWindowTransparentActive())
|
||||
{
|
||||
decltype(m_draggedWindowExstyle) draggedWindowExstyle;
|
||||
decltype(m_draggedWindow) draggedWindow;
|
||||
decltype(m_draggedWindowCrKey) draggedWindowCrKey;
|
||||
decltype(m_draggedWindowInitialAlpha) draggedWindowInitialAlpha;
|
||||
decltype(m_draggedWindowDwFlags) draggedWindowDwFlags;
|
||||
|
||||
RestoreOrginalTransparency();
|
||||
|
||||
draggedWindowExstyle = GetWindowLong(window, GWL_EXSTYLE);
|
||||
|
||||
draggedWindow = window;
|
||||
@@ -379,45 +361,27 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window, bool dragEnabled) noexcept
|
||||
GetLayeredWindowAttributes(window, &draggedWindowCrKey, &draggedWindowInitialAlpha, &draggedWindowDwFlags);
|
||||
|
||||
SetLayeredWindowAttributes(window, 0, (255 * 50) / 100, LWA_ALPHA);
|
||||
|
||||
std::unique_lock writeLock(m_mutex);
|
||||
m_draggedWindowExstyle = draggedWindowExstyle;
|
||||
m_draggedWindow = draggedWindow;
|
||||
m_draggedWindowCrKey = draggedWindowCrKey;
|
||||
m_draggedWindowInitialAlpha = draggedWindowInitialAlpha;
|
||||
m_draggedWindowDwFlags = draggedWindowDwFlags;
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock writeLock(m_mutex);
|
||||
m_dragEnabled = dragEnabled;
|
||||
m_windowMoveSize = window;
|
||||
m_drawHints = true;
|
||||
m_highlightZone = {};
|
||||
}
|
||||
|
||||
m_dragEnabled = dragEnabled;
|
||||
m_windowMoveSize = window;
|
||||
m_drawHints = true;
|
||||
m_highlightZone = {};
|
||||
ShowZoneWindow();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto window = m_window.get();
|
||||
lock.unlock();
|
||||
|
||||
bool redraw = false;
|
||||
POINT ptClient = ptScreen;
|
||||
MapWindowPoints(nullptr, window, &ptClient, 1);
|
||||
MapWindowPoints(nullptr, m_window.get(), &ptClient, 1);
|
||||
|
||||
std::unique_lock writeLock(m_mutex);
|
||||
m_dragEnabled = dragEnabled;
|
||||
|
||||
if (dragEnabled)
|
||||
{
|
||||
writeLock.unlock();
|
||||
auto highlightZone = ZonesFromPoint(ptClient);
|
||||
writeLock.lock();
|
||||
redraw = (highlightZone != m_highlightZone);
|
||||
m_highlightZone = std::move(highlightZone);
|
||||
}
|
||||
@@ -427,11 +391,9 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
writeLock.unlock();
|
||||
|
||||
if (redraw)
|
||||
{
|
||||
InvalidateRect(window, nullptr, true);
|
||||
InvalidateRect(m_window.get(), nullptr, true);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -440,74 +402,30 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnd(HWND window, POINT const& ptScreen) noexc
|
||||
{
|
||||
RestoreOrginalTransparency();
|
||||
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto windowMoveSize = m_windowMoveSize;
|
||||
auto thisWindow = m_window.get();
|
||||
auto activeZoneSet = m_activeZoneSet;
|
||||
lock.unlock();
|
||||
|
||||
if (windowMoveSize != window)
|
||||
if (m_windowMoveSize != window)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (activeZoneSet)
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
POINT ptClient = ptScreen;
|
||||
MapWindowPoints(nullptr, thisWindow, &ptClient, 1);
|
||||
activeZoneSet->MoveWindowIntoZoneByPoint(window, thisWindow, ptClient);
|
||||
MapWindowPoints(nullptr, m_window.get(), &ptClient, 1);
|
||||
m_activeZoneSet->MoveWindowIntoZoneByPoint(window, m_window.get(), ptClient);
|
||||
|
||||
SaveWindowProcessToZoneIndex(window);
|
||||
}
|
||||
Trace::ZoneWindow::MoveSizeEnd(activeZoneSet);
|
||||
Trace::ZoneWindow::MoveSizeEnd(m_activeZoneSet);
|
||||
|
||||
HideZoneWindow();
|
||||
std::unique_lock writeLock(m_mutex);
|
||||
m_windowMoveSize = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
ZoneWindow::IsDragEnabled() noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
return m_dragEnabled;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(std::wstring)
|
||||
ZoneWindow::UniqueId() noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
return m_uniqueId;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(std::wstring)
|
||||
ZoneWindow::WorkAreaKey() noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
return m_workArea;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(IZoneSet*)
|
||||
ZoneWindow::ActiveZoneSet() noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
return m_activeZoneSet.get();
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::RestoreOrginalTransparency() noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto hostTransparentActive = m_host->isMakeDraggedWindowTransparentActive();
|
||||
auto draggedWindow = m_draggedWindow;
|
||||
auto draggedWindowCrKey = m_draggedWindowCrKey;
|
||||
auto draggedWindowInitialAlpha = m_draggedWindowInitialAlpha;
|
||||
auto draggedWindowDwFlags = m_draggedWindowDwFlags;
|
||||
auto draggedWindowExstyle = m_draggedWindowExstyle;
|
||||
lock.unlock();
|
||||
|
||||
if (hostTransparentActive && draggedWindow != nullptr)
|
||||
if (m_host->isMakeDraggedWindowTransparentActive() && draggedWindow != nullptr)
|
||||
{
|
||||
SetLayeredWindowAttributes(draggedWindow, draggedWindowCrKey, draggedWindowInitialAlpha, draggedWindowDwFlags);
|
||||
SetWindowLong(draggedWindow, GWL_EXSTYLE, draggedWindowExstyle);
|
||||
@@ -524,28 +442,18 @@ ZoneWindow::MoveWindowIntoZoneByIndex(HWND window, int index) noexcept
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<int>& indexSet) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto thisWindow = m_window.get();
|
||||
auto activeZoneSet = m_activeZoneSet;
|
||||
lock.unlock();
|
||||
|
||||
if (activeZoneSet)
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
activeZoneSet->MoveWindowIntoZoneByIndexSet(window, thisWindow, indexSet, false);
|
||||
m_activeZoneSet->MoveWindowIntoZoneByIndexSet(window, m_window.get(), indexSet, false);
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
ZoneWindow::MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode, bool cycle) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto thisWindow = m_window.get();
|
||||
auto activeZoneSet = m_activeZoneSet;
|
||||
lock.unlock();
|
||||
|
||||
if (activeZoneSet)
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
if (activeZoneSet->MoveWindowIntoZoneByDirection(window, thisWindow, vkCode, cycle))
|
||||
if (m_activeZoneSet->MoveWindowIntoZoneByDirection(window, m_window.get(), vkCode, cycle))
|
||||
{
|
||||
SaveWindowProcessToZoneIndex(window);
|
||||
return true;
|
||||
@@ -559,14 +467,9 @@ ZoneWindow::CycleActiveZoneSet(DWORD wparam) noexcept
|
||||
{
|
||||
CycleActiveZoneSetInternal(wparam, Trace::ZoneWindow::InputMode::Keyboard);
|
||||
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto windowMoveSize = m_windowMoveSize;
|
||||
auto window = m_window.get();
|
||||
lock.unlock();
|
||||
|
||||
if (windowMoveSize)
|
||||
if (m_windowMoveSize)
|
||||
{
|
||||
InvalidateRect(window, nullptr, true);
|
||||
InvalidateRect(m_window.get(), nullptr, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -577,19 +480,15 @@ ZoneWindow::CycleActiveZoneSet(DWORD wparam) noexcept
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto activeZoneSet = m_activeZoneSet;
|
||||
lock.unlock();
|
||||
|
||||
if (activeZoneSet)
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
DWORD zoneIndex = static_cast<DWORD>(activeZoneSet->GetZoneIndexFromWindow(window));
|
||||
DWORD zoneIndex = static_cast<DWORD>(m_activeZoneSet->GetZoneIndexFromWindow(window));
|
||||
if (zoneIndex != -1)
|
||||
{
|
||||
OLECHAR* guidString;
|
||||
if (StringFromCLSID(activeZoneSet->Id(), &guidString) == S_OK)
|
||||
if (StringFromCLSID(m_activeZoneSet->Id(), &guidString) == S_OK)
|
||||
{
|
||||
JSONHelpers::FancyZonesDataInstance().SetAppLastZone(window, UniqueId(), guidString, zoneIndex);
|
||||
JSONHelpers::FancyZonesDataInstance().SetAppLastZone(window, m_uniqueId, guidString, zoneIndex);
|
||||
}
|
||||
|
||||
CoTaskMemFree(guidString);
|
||||
@@ -600,43 +499,36 @@ ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::ShowZoneWindow() noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto window = m_window.get();
|
||||
HWND windowInsertAfter = m_windowMoveSize;
|
||||
lock.unlock();
|
||||
|
||||
if (window)
|
||||
if (!window)
|
||||
{
|
||||
{
|
||||
std::unique_lock writeLock(m_mutex);
|
||||
m_flashMode = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE;
|
||||
m_flashMode = false;
|
||||
|
||||
if (windowInsertAfter == nullptr)
|
||||
{
|
||||
windowInsertAfter = HWND_TOPMOST;
|
||||
}
|
||||
UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE;
|
||||
|
||||
SetWindowPos(window, windowInsertAfter, 0, 0, 0, 0, flags);
|
||||
HWND windowInsertAfter = m_windowMoveSize;
|
||||
if (windowInsertAfter == nullptr)
|
||||
{
|
||||
windowInsertAfter = HWND_TOPMOST;
|
||||
}
|
||||
|
||||
SetWindowPos(window, windowInsertAfter, 0, 0, 0, 0, flags);
|
||||
|
||||
std::thread{ [=]() {
|
||||
AnimateWindow(window, m_showAnimationDuration, AW_BLEND);
|
||||
InvalidateRect(window, nullptr, true);
|
||||
}
|
||||
} }.detach();
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneWindow::HideZoneWindow() noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto window = m_window.get();
|
||||
lock.unlock();
|
||||
|
||||
if (window)
|
||||
if (m_window)
|
||||
{
|
||||
ShowWindow(window, SW_HIDE);
|
||||
std::unique_lock writeLock(m_mutex);
|
||||
ShowWindow(m_window.get(), SW_HIDE);
|
||||
m_keyLast = 0;
|
||||
m_windowMoveSize = nullptr;
|
||||
m_drawHints = false;
|
||||
@@ -648,34 +540,27 @@ ZoneWindow::HideZoneWindow() noexcept
|
||||
|
||||
void ZoneWindow::LoadSettings() noexcept
|
||||
{
|
||||
JSONHelpers::FancyZonesDataInstance().AddDevice(UniqueId());
|
||||
JSONHelpers::FancyZonesDataInstance().AddDevice(m_uniqueId);
|
||||
}
|
||||
|
||||
void ZoneWindow::InitializeZoneSets(bool newWorkArea) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto parent = m_host->GetParentZoneWindow(m_monitor);
|
||||
lock.unlock();
|
||||
|
||||
if (newWorkArea && parent)
|
||||
{
|
||||
// Update device info with device info from parent virtual desktop (if empty).
|
||||
JSONHelpers::FancyZonesDataInstance().CloneDeviceInfo(parent->UniqueId(), UniqueId());
|
||||
JSONHelpers::FancyZonesDataInstance().CloneDeviceInfo(parent->UniqueId(), m_uniqueId);
|
||||
}
|
||||
CalculateZoneSet();
|
||||
}
|
||||
|
||||
void ZoneWindow::CalculateZoneSet() noexcept
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
auto monitor = m_monitor;
|
||||
lock.unlock();
|
||||
|
||||
const auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance();
|
||||
const auto deviceInfoData = fancyZonesData.FindDeviceInfo(UniqueId());
|
||||
const auto deviceInfoData = fancyZonesData.FindDeviceInfo(m_uniqueId);
|
||||
const auto& activeDeviceId = fancyZonesData.GetActiveDeviceId();
|
||||
|
||||
if (!activeDeviceId.empty() && activeDeviceId != UniqueId())
|
||||
if (!activeDeviceId.empty() && activeDeviceId != m_uniqueId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -698,11 +583,11 @@ void ZoneWindow::CalculateZoneSet() noexcept
|
||||
auto zoneSet = MakeZoneSet(ZoneSetConfig(
|
||||
zoneSetId,
|
||||
activeZoneSet.type,
|
||||
monitor,
|
||||
WorkAreaKey().c_str()));
|
||||
m_monitor,
|
||||
m_workArea));
|
||||
MONITORINFO monitorInfo{};
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (GetMonitorInfoW(monitor, &monitorInfo))
|
||||
if (GetMonitorInfoW(m_monitor, &monitorInfo))
|
||||
{
|
||||
bool showSpacing = deviceInfoData->showSpacing;
|
||||
int spacing = showSpacing ? deviceInfoData->spacing : 0;
|
||||
@@ -715,37 +600,30 @@ void ZoneWindow::CalculateZoneSet() noexcept
|
||||
|
||||
void ZoneWindow::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
|
||||
{
|
||||
{
|
||||
std::unique_lock writeLock(m_mutex);
|
||||
m_activeZoneSet.copy_from(zoneSet);
|
||||
}
|
||||
m_activeZoneSet.copy_from(zoneSet);
|
||||
|
||||
if (zoneSet)
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
wil::unique_cotaskmem_string zoneSetId;
|
||||
if (SUCCEEDED_LOG(StringFromCLSID(zoneSet->Id(), &zoneSetId)))
|
||||
if (SUCCEEDED_LOG(StringFromCLSID(m_activeZoneSet->Id(), &zoneSetId)))
|
||||
{
|
||||
JSONHelpers::ZoneSetData data{
|
||||
.uuid = zoneSetId.get(),
|
||||
.type = zoneSet->LayoutType()
|
||||
.type = m_activeZoneSet->LayoutType()
|
||||
};
|
||||
JSONHelpers::FancyZonesDataInstance().SetActiveZoneSet(UniqueId(), data);
|
||||
JSONHelpers::FancyZonesDataInstance().SetActiveZoneSet(m_uniqueId, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto window = m_window.get();
|
||||
lock.unlock();
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_NCDESTROY:
|
||||
{
|
||||
::DefWindowProc(window, message, wparam, lparam);
|
||||
SetWindowLongPtr(window, GWLP_USERDATA, 0);
|
||||
::DefWindowProc(m_window.get(), message, wparam, lparam);
|
||||
SetWindowLongPtr(m_window.get(), GWLP_USERDATA, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -759,14 +637,14 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
wil::unique_hdc hdc{ reinterpret_cast<HDC>(wparam) };
|
||||
if (!hdc)
|
||||
{
|
||||
hdc.reset(BeginPaint(window, &ps));
|
||||
hdc.reset(BeginPaint(m_window.get(), &ps));
|
||||
}
|
||||
|
||||
OnPaint(hdc);
|
||||
|
||||
if (wparam == 0)
|
||||
{
|
||||
EndPaint(window, &ps);
|
||||
EndPaint(m_window.get(), &ps);
|
||||
}
|
||||
|
||||
hdc.release();
|
||||
@@ -775,7 +653,7 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
|
||||
default:
|
||||
{
|
||||
return DefWindowProc(window, message, wparam, lparam);
|
||||
return DefWindowProc(m_window.get(), message, wparam, lparam);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -783,17 +661,8 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
|
||||
void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto host = m_host;
|
||||
auto highlightZone = m_highlightZone;
|
||||
auto flashMode = m_flashMode;
|
||||
auto drawHints = m_drawHints;
|
||||
HWND window = m_window.get();
|
||||
auto activeZoneSet = m_activeZoneSet;
|
||||
lock.unlock();
|
||||
|
||||
RECT clientRect;
|
||||
GetClientRect(window, &clientRect);
|
||||
GetClientRect(m_window.get(), &clientRect);
|
||||
|
||||
wil::unique_hdc hdcMem;
|
||||
HPAINTBUFFER bufferedPaint = BeginBufferedPaint(hdc.get(), &clientRect, BPBF_TOPDOWNDIB, nullptr, &hdcMem);
|
||||
@@ -801,17 +670,17 @@ void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept
|
||||
{
|
||||
ZoneWindowDrawUtils::DrawBackdrop(hdcMem, clientRect);
|
||||
|
||||
if (activeZoneSet && host)
|
||||
if (m_activeZoneSet && m_host)
|
||||
{
|
||||
ZoneWindowDrawUtils::DrawActiveZoneSet(hdcMem,
|
||||
host->GetZoneColor(),
|
||||
host->GetZoneBorderColor(),
|
||||
host->GetZoneHighlightColor(),
|
||||
host->GetZoneHighlightOpacity(),
|
||||
activeZoneSet->GetZones(),
|
||||
highlightZone,
|
||||
flashMode,
|
||||
drawHints);
|
||||
m_host->GetZoneColor(),
|
||||
m_host->GetZoneBorderColor(),
|
||||
m_host->GetZoneHighlightColor(),
|
||||
m_host->GetZoneHighlightOpacity(),
|
||||
m_activeZoneSet->GetZones(),
|
||||
m_highlightZone,
|
||||
m_flashMode,
|
||||
m_drawHints);
|
||||
}
|
||||
|
||||
EndBufferedPaint(bufferedPaint, TRUE);
|
||||
@@ -820,56 +689,43 @@ void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept
|
||||
|
||||
void ZoneWindow::OnKeyUp(WPARAM wparam) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto window = m_window.get();
|
||||
lock.unlock();
|
||||
|
||||
bool fRedraw = false;
|
||||
Trace::ZoneWindow::KeyUp(wparam);
|
||||
|
||||
if ((wparam >= '0') && (wparam <= '9'))
|
||||
{
|
||||
CycleActiveZoneSetInternal(static_cast<DWORD>(wparam), Trace::ZoneWindow::InputMode::Keyboard);
|
||||
InvalidateRect(window, nullptr, true);
|
||||
InvalidateRect(m_window.get(), nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> ZoneWindow::ZonesFromPoint(POINT pt) noexcept
|
||||
{
|
||||
auto activeZoneSet = ActiveZoneSet();
|
||||
if (activeZoneSet)
|
||||
if (m_activeZoneSet)
|
||||
{
|
||||
return activeZoneSet->ZonesFromPoint(pt);
|
||||
return m_activeZoneSet->ZonesFromPoint(pt);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto activeZoneSet = m_activeZoneSet;
|
||||
auto keyLast = m_keyLast;
|
||||
auto keyCycle = m_keyCycle;
|
||||
auto zoneSets = m_zoneSets;
|
||||
auto host = m_host;
|
||||
lock.unlock();
|
||||
|
||||
Trace::ZoneWindow::CycleActiveZoneSet(activeZoneSet, mode);
|
||||
if (keyLast != wparam)
|
||||
Trace::ZoneWindow::CycleActiveZoneSet(m_activeZoneSet, mode);
|
||||
if (m_keyLast != wparam)
|
||||
{
|
||||
keyCycle = 0;
|
||||
m_keyCycle = 0;
|
||||
}
|
||||
|
||||
keyLast = wparam;
|
||||
m_keyLast = wparam;
|
||||
|
||||
bool loopAround = true;
|
||||
size_t const val = static_cast<size_t>(wparam - L'0');
|
||||
size_t i = 0;
|
||||
for (auto zoneSet : zoneSets)
|
||||
for (auto zoneSet : m_zoneSets)
|
||||
{
|
||||
if (zoneSet->GetZones().size() == val)
|
||||
{
|
||||
if (i < keyCycle)
|
||||
if (i < m_keyCycle)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
@@ -882,25 +738,21 @@ void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::Inp
|
||||
}
|
||||
}
|
||||
|
||||
if ((keyCycle > 0) && loopAround)
|
||||
if ((m_keyCycle > 0) && loopAround)
|
||||
{
|
||||
// Cycling through a non-empty group and hit the end
|
||||
keyCycle = 0;
|
||||
m_keyCycle = 0;
|
||||
OnKeyUp(wparam);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyCycle++;
|
||||
m_keyCycle++;
|
||||
}
|
||||
|
||||
if (host)
|
||||
if (m_host)
|
||||
{
|
||||
host->MoveWindowsOnActiveZoneSetChange();
|
||||
m_host->MoveWindowsOnActiveZoneSetChange();
|
||||
}
|
||||
|
||||
std::unique_lock writeLock(m_mutex);
|
||||
m_keyLast = keyLast;
|
||||
m_keyCycle = keyCycle;
|
||||
m_highlightZone = {};
|
||||
}
|
||||
|
||||
@@ -912,13 +764,10 @@ void ZoneWindow::FlashZones() noexcept
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock writeLock(m_mutex);
|
||||
m_flashMode = true;
|
||||
auto window = m_window.get();
|
||||
writeLock.unlock();
|
||||
|
||||
ShowWindow(window, SW_SHOWNA);
|
||||
std::thread([window]() {
|
||||
ShowWindow(m_window.get(), SW_SHOWNA);
|
||||
std::thread([window = m_window.get()]() {
|
||||
AnimateWindow(window, m_flashDuration, AW_HIDE | AW_BLEND);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ BEGIN
|
||||
IDS_SETTING_DESCRIPTION "Create window layouts to help make multi-tasking easy"
|
||||
IDS_SETTING_DESCRIPTION_SHIFTDRAG "On: Hold Shift key or any non-primary mouse button to enable zones while dragging"
|
||||
IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS "Override Windows Snap hotkeys (win+arrow) to move windows between zones"
|
||||
IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS "Move windows between zones across all monitors when snapping with win+arrow"
|
||||
IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS "Keep windows in their zones when the screen resolution changes"
|
||||
IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS "During zone layout changes, windows assigned to a zone will match new size/positions"
|
||||
IDS_SETTING_DESCRIPTION_VIRTUALDESKTOPCHANGE_MOVEWINDOWS "Keep windows pinned to multiple desktops in the same zone when the active desktop changes"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200316.3" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.191107.2" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -4,6 +4,7 @@
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <Unknwn.h>
|
||||
#include <winrt/base.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <dwmapi.h>
|
||||
@@ -13,8 +14,11 @@
|
||||
#include <TraceLoggingActivity.h>
|
||||
#include <wil\resource.h>
|
||||
#include <wil\result.h>
|
||||
#include <windows.foundation.h>
|
||||
#include <winrt/windows.foundation.h>
|
||||
#include <psapi.h>
|
||||
#include <shared_mutex>
|
||||
#include <functional>
|
||||
#include <unordered_set>
|
||||
|
||||
#pragma comment(lib, "windowsapp")
|
||||
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
#define IDS_SETTING_DESCRIPTION_SHIFTDRAG 101
|
||||
#define IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS 102
|
||||
#define IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS 103
|
||||
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS 104
|
||||
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES 105
|
||||
#define IDS_SETTING_DESCRIPTION_VIRTUALDESKTOPCHANGE_MOVEWINDOWS 106
|
||||
#define IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS 107
|
||||
#define IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT 108
|
||||
#define IDS_SETTING_DESCRIPTION_ZONECOLOR 109
|
||||
#define IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR 110
|
||||
#define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 111
|
||||
#define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 112
|
||||
#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 113
|
||||
#define IDS_SETTING_DESCRIPTION 114
|
||||
#define IDS_SETTING_LAUNCH_EDITOR_LABEL 115
|
||||
#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 116
|
||||
#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 117
|
||||
#define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 118
|
||||
#define IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION 119
|
||||
#define IDS_SETTINGS_HIGHLIGHT_OPACITY 120
|
||||
#define IDS_FANCYZONES 121
|
||||
#define IDS_CANT_DRAG_ELEVATED 122
|
||||
#define IDS_CANT_DRAG_ELEVATED_LEARN_MORE 123
|
||||
#define IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN 124
|
||||
#define IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS 103
|
||||
#define IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS 104
|
||||
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS 105
|
||||
#define IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES 106
|
||||
#define IDS_SETTING_DESCRIPTION_VIRTUALDESKTOPCHANGE_MOVEWINDOWS 107
|
||||
#define IDS_SETTING_DESCRIPTION_SHOW_FANCY_ZONES_ON_ALL_MONITORS 108
|
||||
#define IDS_SETTING_DESCRIPTION_MAKE_DRAGGED_WINDOW_TRANSPARENT 109
|
||||
#define IDS_SETTING_DESCRIPTION_ZONECOLOR 110
|
||||
#define IDS_SETTING_DESCRIPTION_ZONE_BORDER_COLOR 111
|
||||
#define IDS_SETTING_DESCRIPTION_ZONEHIGHLIGHTCOLOR 112
|
||||
#define IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS 113
|
||||
#define IDS_SETTING_DESCRIPTION_USE_CURSORPOS_EDITOR_STARTUPSCREEN 114
|
||||
#define IDS_SETTING_DESCRIPTION 115
|
||||
#define IDS_SETTING_LAUNCH_EDITOR_LABEL 116
|
||||
#define IDS_SETTING_LAUNCH_EDITOR_BUTTON 117
|
||||
#define IDS_SETTING_LAUNCH_EDITOR_DESCRIPTION 118
|
||||
#define IDS_SETTING_LAUNCH_EDITOR_HOTKEY_LABEL 119
|
||||
#define IDS_SETTING_EXCLCUDED_APPS_DESCRIPTION 120
|
||||
#define IDS_SETTINGS_HIGHLIGHT_OPACITY 121
|
||||
#define IDS_FANCYZONES 122
|
||||
#define IDS_CANT_DRAG_ELEVATED 123
|
||||
#define IDS_CANT_DRAG_ELEVATED_LEARN_MORE 124
|
||||
#define IDS_CANT_DRAG_ELEVATED_DIALOG_DONT_SHOW_AGAIN 125
|
||||
|
||||
@@ -178,6 +178,7 @@ void Trace::SettingsChanged(const Settings& settings) noexcept
|
||||
TraceLoggingBoolean(settings.zoneSetChange_flashZones, "FlashZonesOnZoneSetChange"),
|
||||
TraceLoggingBoolean(settings.zoneSetChange_moveWindows, "MoveWindowsOnZoneSetChange"),
|
||||
TraceLoggingBoolean(settings.overrideSnapHotkeys, "OverrideSnapHotKeys"),
|
||||
TraceLoggingBoolean(settings.moveWindowAcrossMonitors, "MoveWindowAcrossMonitors"),
|
||||
TraceLoggingBoolean(settings.appLastZone_moveWindows, "MoveWindowsToLastZoneOnAppOpening"),
|
||||
TraceLoggingBoolean(settings.use_cursorpos_editor_startupscreen, "UseCursorPosOnEditorStartup"),
|
||||
TraceLoggingBoolean(settings.showZonesOnAllMonitors, "ShowZonesOnAllMonitors"),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <common/common.h>
|
||||
#include <common/dpi_aware.h>
|
||||
|
||||
typedef BOOL(WINAPI* GetDpiForMonitorInternalFunc)(HMONITOR, UINT, UINT*, UINT*);
|
||||
@@ -135,3 +136,19 @@ void SizeWindowToRect(HWND window, RECT rect) noexcept
|
||||
// This fixes Issue #365
|
||||
::SetWindowPlacement(window, &placement);
|
||||
}
|
||||
|
||||
bool IsInterestingWindow(HWND window, const std::vector<std::wstring>& excludedApps) noexcept
|
||||
{
|
||||
auto filtered = get_fancyzones_filtered_window(window);
|
||||
if (!filtered.zonable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Filter out user specified apps
|
||||
CharUpperBuffW(filtered.process_path.data(), (DWORD)filtered.process_path.length());
|
||||
if (find_app_name_in_path(filtered.process_path, excludedApps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -119,3 +119,5 @@ inline BYTE OpacitySettingToAlpha(int opacity)
|
||||
UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
|
||||
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
|
||||
void SizeWindowToRect(HWND window, RECT rect) noexcept;
|
||||
|
||||
bool IsInterestingWindow(HWND window, const std::vector<std::wstring>& exludedApps) noexcept;
|
||||
Reference in New Issue
Block a user