PowerToys/src/modules/fancyzones/lib/Zone.cpp

139 lines
4.4 KiB
C++
Raw Normal View History

#include "pch.h"
#include <common/dpi_aware.h>
#include <common/monitors.h>
#include "Zone.h"
#include "Settings.h"
struct Zone : winrt::implements<Zone, IZone>
{
public:
Zone(RECT zoneRect) :
m_zoneRect(zoneRect)
{
}
IFACEMETHODIMP_(RECT) GetZoneRect() noexcept { return m_zoneRect; }
IFACEMETHODIMP_(bool) IsEmpty() noexcept { return m_windows.empty(); };
IFACEMETHODIMP_(bool) ContainsWindow(HWND window) noexcept;
IFACEMETHODIMP_(void) AddWindowToZone(HWND window, HWND zoneWindow, bool stampZone) noexcept;
IFACEMETHODIMP_(void) RemoveWindowFromZone(HWND window, bool restoreSize) noexcept;
IFACEMETHODIMP_(void) SetId(size_t id) noexcept { m_id = id; }
IFACEMETHODIMP_(size_t) Id() noexcept { return m_id; }
private:
void SizeWindowToZone(HWND window, HWND zoneWindow) noexcept;
void StampZone(HWND window, bool stamp) noexcept;
RECT m_zoneRect{};
size_t m_id{};
std::map<HWND, RECT> m_windows{};
};
IFACEMETHODIMP_(bool) Zone::ContainsWindow(HWND window) noexcept
{
return (m_windows.find(window) != m_windows.end());
}
IFACEMETHODIMP_(void) Zone::AddWindowToZone(HWND window, HWND zoneWindow, bool stampZone) noexcept
{
WINDOWPLACEMENT placement;
::GetWindowPlacement(window, &placement);
::GetWindowRect(window, &placement.rcNormalPosition);
m_windows.emplace(std::pair<HWND, RECT>(window, placement.rcNormalPosition));
SizeWindowToZone(window, zoneWindow);
if (stampZone)
{
StampZone(window, true);
}
}
IFACEMETHODIMP_(void) Zone::RemoveWindowFromZone(HWND window, bool restoreSize) noexcept
{
auto iter = m_windows.find(window);
if (iter != m_windows.end())
{
m_windows.erase(iter);
StampZone(window, false);
}
}
void Zone::SizeWindowToZone(HWND window, HWND zoneWindow) noexcept
{
// Skip invisible windows
if (!IsWindowVisible(window))
{
return;
}
// Take care of 1px border
RECT zoneRect = m_zoneRect;
RECT windowRect{};
::GetWindowRect(window, &windowRect);
RECT frameRect{};
const auto level = DPIAware::GetAwarenessLevel(GetWindowDpiAwarenessContext(window));
const bool accountForUnawareness = level < DPIAware::PER_MONITOR_AWARE;
if (SUCCEEDED(DwmGetWindowAttribute(window, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRect, sizeof(frameRect))))
{
const auto left_margin = frameRect.left - windowRect.left;
const auto right_margin = frameRect.right - windowRect.right;
const auto bottom_margin = frameRect.bottom - windowRect.bottom;
zoneRect.left -= left_margin;
zoneRect.right -= right_margin;
zoneRect.bottom -= bottom_margin;
}
// Map to screen coords
MapWindowRect(zoneWindow, nullptr, &zoneRect);
MONITORINFO mi{sizeof(mi)};
if (GetMonitorInfoW(MonitorFromWindow(zoneWindow, MONITOR_DEFAULTTONEAREST), &mi))
{
const auto taskbar_left_size = std::abs(mi.rcMonitor.left - mi.rcWork.left);
const auto taskbar_top_size = std::abs(mi.rcMonitor.top - mi.rcWork.top);
OffsetRect(&zoneRect, -taskbar_left_size, -taskbar_top_size);
if (accountForUnawareness)
{
zoneRect.left = max(mi.rcMonitor.left, zoneRect.left);
zoneRect.right = min(mi.rcMonitor.right - taskbar_left_size, zoneRect.right);
zoneRect.top = max(mi.rcMonitor.top, zoneRect.top);
zoneRect.bottom = min(mi.rcMonitor.bottom - taskbar_top_size, zoneRect.bottom);
}
}
WINDOWPLACEMENT placement{};
::GetWindowPlacement(window, &placement);
placement.rcNormalPosition = zoneRect;
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
// Do not restore minimized windows. We change their placement though so they restore to the correct zone.
if ((placement.showCmd & SW_SHOWMINIMIZED) == 0)
{
placement.showCmd = SW_RESTORE | SW_SHOWNA;
}
::SetWindowPlacement(window, &placement);
// Do it again, allowing Windows to resize the window and set correct scaling
// This fixes Issue #365
::SetWindowPlacement(window, &placement);
}
void Zone::StampZone(HWND window, bool stamp) noexcept
{
if (stamp)
{
SetProp(window, ZONE_STAMP, reinterpret_cast<HANDLE>(m_id));
}
else
{
RemoveProp(window, ZONE_STAMP);
}
}
Migrate FancyZones data persisting from Registry to JSON file (#1194) * Migrate FancyZones data persisting from Registry to JSON file * Address PR comment: Remove redundant check * Addres PR comment: Remove unused Dpi and add CmdArgs enum * Address PR comment: Make methods const and inline * Address PR comments: Expose GenerateUniqueId function and use const ref instead of passing wstring by value * Address PR comment: Use lamdba as callback * Address PR comment: Move GenerateUniqueId to ZoneWindowUtils namespace * Address PR comment: Use regular comparison instead of std::wstring::compare * Address PR comment: Use std::wstring_view for tmp file paths * Address PR comment: Use scoped lock when accessing member data * Address PR comment: Remove typedefs to increase code readability * Address PR comment: removed nullptr checks with corresponding tests * Address PR comment: Move ZoneSet object instead of copying * Address PR comment: Make FancyZonesData instance const where possible * Remove unnecessary gutter variable during calculating zone coordinates * Remove uneeded subclass * Avoid unnecessary copying and reserve space for vector if possible * Save FancyZones data after exiting editor * App zone history (#18) * added window and zone set ids to app zone history * Rename JSON file * Remove AppZoneHistory migration * Move parsing of ZoneWindow independent temp files outside of it * Unit tests update (#19) * check device existence in map * updated ZoneSet tests * updated JsonHelpers tests * Use single zone count information * Remove uneeded tests * Remove one more test * Remove uneeded line * Address PR comments - Missing whitespace * Update zoneset data for new virtual desktops (#21) * update active zone set with actual data * Introduce Blank zone set (used to indicate that no layout applied yet). Move parsing completely outside of ZoneWindow. * Fix unit tests to match modifications in implementation * Fix applying layouts on startup (second monitor) Co-authored-by: vldmr11080 <57061786+vldmr11080@users.noreply.github.com> Co-authored-by: Seraphima <zykovas91@gmail.com>
2020-02-10 21:59:51 +08:00
winrt::com_ptr<IZone> MakeZone(const RECT& zoneRect) noexcept
{
return winrt::make_self<Zone>(zoneRect);
}