#include "pch.h" #include #include #include #include "Zone.h" #include "Settings.h" #include "util.h" namespace { bool ValidateZoneRect(const RECT& rect) { int width = rect.right - rect.left; int height = rect.bottom - rect.top; return rect.left >= ZoneConstants::MAX_NEGATIVE_SPACING && rect.right >= ZoneConstants::MAX_NEGATIVE_SPACING && rect.top >= ZoneConstants::MAX_NEGATIVE_SPACING && rect.bottom >= ZoneConstants::MAX_NEGATIVE_SPACING && width >= 0 && height >= 0; } BOOL CALLBACK saveDisplayToVector(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data) { reinterpret_cast*>(data)->emplace_back(monitor); return true; } bool allMonitorsHaveSameDpiScaling() { std::vector monitors; EnumDisplayMonitors(NULL, NULL, saveDisplayToVector, reinterpret_cast(&monitors)); if (monitors.size() < 2) { return true; } UINT firstMonitorDpiX; UINT firstMonitorDpiY; if (S_OK != GetDpiForMonitor(monitors[0], MDT_EFFECTIVE_DPI, &firstMonitorDpiX, &firstMonitorDpiY)) { return false; } for (int i = 1; i < monitors.size(); i++) { UINT iteratedMonitorDpiX; UINT iteratedMonitorDpiY; if (S_OK != GetDpiForMonitor(monitors[i], MDT_EFFECTIVE_DPI, &iteratedMonitorDpiX, &iteratedMonitorDpiY) || iteratedMonitorDpiX != firstMonitorDpiX) { return false; } } return true; } } struct Zone : winrt::implements { public: Zone(RECT zoneRect, const size_t zoneId) : m_zoneRect(zoneRect), m_id(zoneId) { } IFACEMETHODIMP_(RECT) GetZoneRect() const noexcept { return m_zoneRect; } IFACEMETHODIMP_(size_t) Id() const noexcept { return m_id; } IFACEMETHODIMP_(RECT) ComputeActualZoneRect(HWND window, HWND zoneWindow) const noexcept; private: RECT m_zoneRect{}; const size_t m_id{}; std::map m_windows{}; }; RECT Zone::ComputeActualZoneRect(HWND window, HWND zoneWindow) const noexcept { // Take care of 1px border RECT newWindowRect = 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)))) { LONG leftMargin = frameRect.left - windowRect.left; LONG rightMargin = frameRect.right - windowRect.right; LONG bottomMargin = frameRect.bottom - windowRect.bottom; newWindowRect.left -= leftMargin; newWindowRect.right -= rightMargin; newWindowRect.bottom -= bottomMargin; } // Map to screen coords MapWindowRect(zoneWindow, nullptr, &newWindowRect); 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(&newWindowRect, -taskbar_left_size, -taskbar_top_size); if (accountForUnawareness && !allMonitorsHaveSameDpiScaling()) { newWindowRect.left = max(mi.rcMonitor.left, newWindowRect.left); newWindowRect.right = min(mi.rcMonitor.right - taskbar_left_size, newWindowRect.right); newWindowRect.top = max(mi.rcMonitor.top, newWindowRect.top); newWindowRect.bottom = min(mi.rcMonitor.bottom - taskbar_top_size, newWindowRect.bottom); } } if ((::GetWindowLong(window, GWL_STYLE) & WS_SIZEBOX) == 0) { newWindowRect.right = newWindowRect.left + (windowRect.right - windowRect.left); newWindowRect.bottom = newWindowRect.top + (windowRect.bottom - windowRect.top); } return newWindowRect; } winrt::com_ptr MakeZone(const RECT& zoneRect, const size_t zoneId) noexcept { if (ValidateZoneRect(zoneRect) && zoneId > 0) { return winrt::make_self(zoneRect, zoneId); } else { return nullptr; } }