merge master

This commit is contained in:
ryanbodrug-microsoft
2020-05-06 00:49:46 -07:00
183 changed files with 1973 additions and 1311 deletions

View File

@@ -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(&currentVirtualDesktopId)))
if (VirtualDesktopUtils::GetCurrentVirtualDesktopId(&currentVirtualDesktopId))
{
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)

View File

@@ -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.
*

View File

@@ -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>

View File

@@ -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">

View 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}");
});
}

View 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();

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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 },

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View 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;
}
}
}

View 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;
};

View File

@@ -2,7 +2,6 @@
#include "util.h"
#include "lib/ZoneSet.h"
#include "lib/RegistryHelpers.h"
#include <common/dpi_aware.h>

View File

@@ -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();
}

View File

@@ -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"

View File

@@ -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>

View File

@@ -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")

View File

@@ -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

View File

@@ -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"),

View File

@@ -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;
}

View File

@@ -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;