[FancyZones] Update windows positions after changing the layout fix (#18805)

* removed IWorkArea interface

* split work area initialization

* changed rect type in zoneset

* tests


upd work area tests
removed obsolete, update others
updated work area tests

* get current vd windows

* update windows positions

* removed unused flag

* moved update window positions to work area

* check monitor

* refactoring
This commit is contained in:
Seraphima Zykova
2022-06-14 16:45:45 +02:00
committed by GitHub
parent e8bb2de8b6
commit f5f8861eac
13 changed files with 319 additions and 509 deletions

View File

@@ -1,139 +1,111 @@
#pragma once
#include "FancyZones.h"
#include "FancyZonesLib/ZoneSet.h"
#include "FancyZonesLib/FancyZonesDataTypes.h"
/**
* Class representing single work area, which is defined by monitor and virtual desktop.
*/
interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IWorkArea : public IUnknown
#include <FancyZonesLib/FancyZonesDataTypes.h>
#include <FancyZonesLib/ZoneSet.h>
#include <FancyZonesLib/util.h>
class ZonesOverlay;
class WorkArea
{
/**
* 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.
*/
IFACEMETHOD(MoveSizeEnter)(HWND window) = 0;
public:
WorkArea(HINSTANCE hinstance);
~WorkArea();
/**
* A window has changed location, shape, or size. Track down window position and give zone layout
* hints if dragging functionality is enabled.
*
* @param ptScreen Cursor coordinates.
* @param dragEnabled Boolean indicating is giving hints about active zone layout enabled.
* Hints are given while dragging window while holding SHIFT key.
* @param selectManyZones When this parameter is true, the set of highlighted zones is computed
* by finding the minimum bounding rectangle of the zone(s) from which the
* user started dragging and the zone(s) above which the user is hovering
* at the moment this function is called. Otherwise, highlight only the zone(s)
* above which the user is currently hovering.
*/
IFACEMETHOD(MoveSizeUpdate)(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) = 0;
/**
* The movement or resizing of a window has finished. Assign window to the zone of it
* is dropped within zone borders.
*
* @param window Handle of window being moved or resized.
* @param ptScreen Cursor coordinates where window is dropped.
*/
IFACEMETHOD(MoveSizeEnd)(HWND window, POINT const& ptScreen) = 0;
/**
* Assign window to the zone based on zone index inside zone layout.
*
* @param window Handle of window which should be assigned to zone.
* @param index Zone index within zone layout.
*/
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(HWND window, ZoneIndex index) = 0;
/**
* Assign window to the zones based on the set of zone indices inside zone layout.
*
* @param window Handle of window which should be assigned to zone.
* @param indexSet The set of zone indices within zone layout.
* @param suppressMove Whether we should just update the records or move window to the zone.
*/
IFACEMETHOD_(void, MoveWindowIntoZoneByIndexSet)(HWND window, const ZoneIndexSet& indexSet, bool suppressMove = false) = 0;
/**
* Assign window to the zone based on direction (using WIN + LEFT/RIGHT arrow), based on zone index numbers,
* not their on-screen position.
*
* @param window Handle of window which should be assigned to zone.
* @param vkCode Pressed arrow key.
* @param cycle Whether we should move window to the first zone if we reached last zone in layout.
*
* @returns Boolean which is always true if cycle argument is set, otherwise indicating if there is more
* zones left in the zone layout in which window can move.
*/
IFACEMETHOD_(bool, MoveWindowIntoZoneByDirectionAndIndex)(HWND window, DWORD vkCode, bool cycle) = 0;
/**
* Assign window to the zone based on direction (using WIN + LEFT/RIGHT/UP/DOWN arrow), based on
* their on-screen position.
*
* @param window Handle of window which should be assigned to zone.
* @param vkCode Pressed arrow key.
* @param cycle Whether we should move window to the first zone if we reached last zone in layout.
*
* @returns Boolean which is always true if cycle argument is set, otherwise indicating if there is more
* zones left in the zone layout in which window can move.
*/
IFACEMETHOD_(bool, MoveWindowIntoZoneByDirectionAndPosition)(HWND window, DWORD vkCode, bool cycle) = 0;
/**
* Extend or shrink the window to an adjacent zone based on direction (using CTRL+WIN+ALT + LEFT/RIGHT/UP/DOWN arrow), based on
* their on-screen position.
*
* @param window Handle of window which should be assigned to zone.
* @param vkCode Pressed arrow key.
*
* @returns Boolean indicating whether the window was rezoned. False could be returned when there are no more
* zones available in the given direction.
*/
IFACEMETHOD_(bool, ExtendWindowByDirectionAndPosition)(HWND window, DWORD vkCode) = 0;
/**
* Save information about zone in which window was assigned, when closing the window.
* Used once we open same window again to assign it to its previous zone.
*
* @param window Window handle.
*/
IFACEMETHOD_(void, SaveWindowProcessToZoneIndex)(HWND window) = 0;
/**
* @returns Unique work area identifier. Format: <device-id>_<resolution>_<virtual-desktop-id>
*/
IFACEMETHOD_(FancyZonesDataTypes::DeviceIdData, UniqueId)() const = 0;
/**
* @returns Active zone layout for this work area.
*/
IFACEMETHOD_(IZoneSet*, ZoneSet)() const = 0;
/*
* @returns Zone index of the window
*/
IFACEMETHOD_(ZoneIndexSet, GetWindowZoneIndexes)(HWND window) const = 0;
/**
* Show a drawing of the zones in the work area.
*/
IFACEMETHOD_(void, ShowZonesOverlay)() = 0;
/**
* Hide the drawing of the zones in the work area.
*/
IFACEMETHOD_(void, HideZonesOverlay)() = 0;
/**
* Update currently active zone layout for this work area.
*/
IFACEMETHOD_(void, UpdateActiveZoneSet)() = 0;
/**
* Cycle through tabs in the zone that the window is in.
*
* @param window Handle of window which is cycled from (the current tab).
* @param reverse Whether to cycle in reverse order (to the previous tab) or to move to the next tab.
*/
IFACEMETHOD_(void, CycleTabs)(HWND window, bool reverse) = 0;
/**
* Clear the selected zones when this WorkArea loses focus.
*/
IFACEMETHOD_(void, ClearSelectedZones)() = 0;
/*
* Display the layout on the screen and then hide it.
*/
IFACEMETHOD_(void, FlashZones)() = 0;
public:
bool Init(HINSTANCE hinstance, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId);
inline bool InitWorkAreaRect(HMONITOR monitor)
{
m_monitor = monitor;
#if defined(UNIT_TESTS)
m_workAreaRect = FancyZonesUtils::Rect({ 0, 0, 1920, 1080 });
return true;
#endif
if (monitor)
{
MONITORINFO mi{};
mi.cbSize = sizeof(mi);
if (!GetMonitorInfoW(monitor, &mi))
{
return false;
}
m_workAreaRect = FancyZonesUtils::Rect(mi.rcWork);
}
else
{
m_workAreaRect = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
}
return true;
}
FancyZonesDataTypes::DeviceIdData UniqueId() const noexcept { return { m_uniqueId }; }
IZoneSet* ZoneSet() const noexcept { return m_zoneSet.get(); }
ZoneIndexSet GetWindowZoneIndexes(HWND window) const noexcept;
HRESULT MoveSizeEnter(HWND window) noexcept;
HRESULT MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) noexcept;
HRESULT MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept;
void MoveWindowIntoZoneByIndex(HWND window, ZoneIndex index) noexcept;
void MoveWindowIntoZoneByIndexSet(HWND window, const ZoneIndexSet& indexSet) noexcept;
bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle) noexcept;
bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle) noexcept;
bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept;
void SaveWindowProcessToZoneIndex(HWND window) noexcept;
void UpdateActiveZoneSet() noexcept;
void ShowZonesOverlay() noexcept;
void HideZonesOverlay() noexcept;
void FlashZones() noexcept;
void ClearSelectedZones() noexcept;
void CycleTabs(HWND window, bool reverse) noexcept;
void LogInitializationError();
protected:
static LRESULT CALLBACK s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept;
private:
void InitializeZoneSets(const FancyZonesDataTypes::DeviceIdData& parentUniqueId) noexcept;
void CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept;
void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept;
LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept;
ZoneIndexSet ZonesFromPoint(POINT pt) noexcept;
void SetAsTopmostWindow() noexcept;
HMONITOR m_monitor{};
FancyZonesUtils::Rect m_workAreaRect{};
FancyZonesDataTypes::DeviceIdData m_uniqueId;
HWND m_window{}; // Hidden tool window used to represent current monitor desktop work area.
HWND m_windowMoveSize{};
winrt::com_ptr<IZoneSet> m_zoneSet;
ZoneIndexSet m_initialHighlightZone;
ZoneIndexSet m_highlightZone;
WPARAM m_keyLast{};
size_t m_keyCycle{};
std::unique_ptr<ZonesOverlay> m_zonesOverlay;
};
winrt::com_ptr<IWorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId) noexcept;
inline std::shared_ptr<WorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId) noexcept
{
auto self = std::make_shared<WorkArea>(hinstance);
if (!self->InitWorkAreaRect(monitor))
{
self->LogInitializationError();
return nullptr;
}
if (!self->Init(hinstance, uniqueId, parentUniqueId))
{
return nullptr;
}
return self;
}