From acb8595a50ce1365f51de8be164d436867fee929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Sto=C5=A1i=C4=87?= Date: Thu, 11 Mar 2021 12:31:29 +0100 Subject: [PATCH] [FancyZones] Fix taskbar size issues (#9856) * Fix taskbar size issues * Fix issue with DPI unaware apps --- src/modules/fancyzones/lib/Zone.cpp | 59 -------------------- src/modules/fancyzones/lib/util.cpp | 84 +++++++++++++++++++++++++++++ src/modules/fancyzones/lib/util.h | 2 + 3 files changed, 86 insertions(+), 59 deletions(-) diff --git a/src/modules/fancyzones/lib/Zone.cpp b/src/modules/fancyzones/lib/Zone.cpp index 47da31fc3d..21ca046815 100644 --- a/src/modules/fancyzones/lib/Zone.cpp +++ b/src/modules/fancyzones/lib/Zone.cpp @@ -21,46 +21,6 @@ namespace 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 @@ -92,9 +52,6 @@ RECT Zone::ComputeActualZoneRect(HWND window, HWND zoneWindow) const noexcept 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; @@ -108,22 +65,6 @@ RECT Zone::ComputeActualZoneRect(HWND window, HWND zoneWindow) const noexcept // 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); diff --git a/src/modules/fancyzones/lib/util.cpp b/src/modules/fancyzones/lib/util.cpp index 3c64a75599..f2998a2650 100644 --- a/src/modules/fancyzones/lib/util.cpp +++ b/src/modules/fancyzones/lib/util.cpp @@ -305,6 +305,88 @@ namespace FancyZonesUtils monitorInfo = std::move(sortedMonitorInfo); } + 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; + } + + void ScreenToWorkAreaCoords(HWND window, RECT& rect) + { + // First, find the correct monitor. The monitor cannot be found using the given rect itself, we must first + // translate it to relative workspace coordinates. + HMONITOR monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY); + MONITORINFOEXW monitorInfo{ sizeof(MONITORINFOEXW) }; + GetMonitorInfoW(monitor, &monitorInfo); + + auto xOffset = monitorInfo.rcWork.left - monitorInfo.rcMonitor.left; + auto yOffset = monitorInfo.rcWork.top - monitorInfo.rcMonitor.top; + + auto referenceRect = rect; + + referenceRect.left -= xOffset; + referenceRect.right -= xOffset; + referenceRect.top -= yOffset; + referenceRect.bottom -= yOffset; + + // Now, this rect should be used to determine the monitor and thus taskbar size. This fixes + // scenarios where the zone lies approximately between two monitors, and the taskbar is on the left. + monitor = MonitorFromRect(&referenceRect, MONITOR_DEFAULTTOPRIMARY); + GetMonitorInfoW(monitor, &monitorInfo); + + xOffset = monitorInfo.rcWork.left - monitorInfo.rcMonitor.left; + yOffset = monitorInfo.rcWork.top - monitorInfo.rcMonitor.top; + + rect.left -= xOffset; + rect.right -= xOffset; + rect.top -= yOffset; + rect.bottom -= yOffset; + + const auto level = DPIAware::GetAwarenessLevel(GetWindowDpiAwarenessContext(window)); + const bool accountForUnawareness = level < DPIAware::PER_MONITOR_AWARE; + + if (accountForUnawareness && !allMonitorsHaveSameDpiScaling()) + { + rect.left = max(monitorInfo.rcMonitor.left, rect.left); + rect.right = min(monitorInfo.rcMonitor.right - xOffset, rect.right); + rect.top = max(monitorInfo.rcMonitor.top, rect.top); + rect.bottom = min(monitorInfo.rcMonitor.bottom - yOffset, rect.bottom); + } + } + void SizeWindowToRect(HWND window, RECT rect) noexcept { WINDOWPLACEMENT placement{}; @@ -331,6 +413,8 @@ namespace FancyZonesUtils placement.flags &= ~WPF_RESTORETOMAXIMIZED; } + ScreenToWorkAreaCoords(window, rect); + placement.rcNormalPosition = rect; placement.flags |= WPF_ASYNCWINDOWPLACEMENT; diff --git a/src/modules/fancyzones/lib/util.h b/src/modules/fancyzones/lib/util.h index bb09722770..08084ccd6c 100644 --- a/src/modules/fancyzones/lib/util.h +++ b/src/modules/fancyzones/lib/util.h @@ -188,6 +188,8 @@ namespace FancyZonesUtils UINT GetDpiForMonitor(HMONITOR monitor) noexcept; void OrderMonitors(std::vector>& monitorInfo); + + // Parameter rect must be in screen coordinates (e.g. obtained from GetWindowRect) void SizeWindowToRect(HWND window, RECT rect) noexcept; bool HasNoVisibleOwner(HWND window) noexcept;