mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 09:28:03 +08:00
[FancyZones] Fix taskbar size issues (#9856)
* Fix taskbar size issues * Fix issue with DPI unaware apps
This commit is contained in:
parent
488ee19f93
commit
acb8595a50
@ -21,46 +21,6 @@ namespace
|
|||||||
rect.bottom >= ZoneConstants::MAX_NEGATIVE_SPACING &&
|
rect.bottom >= ZoneConstants::MAX_NEGATIVE_SPACING &&
|
||||||
width >= 0 && height >= 0;
|
width >= 0 && height >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CALLBACK saveDisplayToVector(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
|
|
||||||
{
|
|
||||||
reinterpret_cast<std::vector<HMONITOR>*>(data)->emplace_back(monitor);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool allMonitorsHaveSameDpiScaling()
|
|
||||||
{
|
|
||||||
std::vector<HMONITOR> monitors;
|
|
||||||
EnumDisplayMonitors(NULL, NULL, saveDisplayToVector, reinterpret_cast<LPARAM>(&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<Zone, IZone>
|
struct Zone : winrt::implements<Zone, IZone>
|
||||||
@ -92,9 +52,6 @@ RECT Zone::ComputeActualZoneRect(HWND window, HWND zoneWindow) const noexcept
|
|||||||
|
|
||||||
RECT frameRect{};
|
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))))
|
if (SUCCEEDED(DwmGetWindowAttribute(window, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRect, sizeof(frameRect))))
|
||||||
{
|
{
|
||||||
LONG leftMargin = frameRect.left - windowRect.left;
|
LONG leftMargin = frameRect.left - windowRect.left;
|
||||||
@ -108,22 +65,6 @@ RECT Zone::ComputeActualZoneRect(HWND window, HWND zoneWindow) const noexcept
|
|||||||
// Map to screen coords
|
// Map to screen coords
|
||||||
MapWindowRect(zoneWindow, nullptr, &newWindowRect);
|
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)
|
if ((::GetWindowLong(window, GWL_STYLE) & WS_SIZEBOX) == 0)
|
||||||
{
|
{
|
||||||
newWindowRect.right = newWindowRect.left + (windowRect.right - windowRect.left);
|
newWindowRect.right = newWindowRect.left + (windowRect.right - windowRect.left);
|
||||||
|
@ -305,6 +305,88 @@ namespace FancyZonesUtils
|
|||||||
monitorInfo = std::move(sortedMonitorInfo);
|
monitorInfo = std::move(sortedMonitorInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL CALLBACK saveDisplayToVector(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
|
||||||
|
{
|
||||||
|
reinterpret_cast<std::vector<HMONITOR>*>(data)->emplace_back(monitor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool allMonitorsHaveSameDpiScaling()
|
||||||
|
{
|
||||||
|
std::vector<HMONITOR> monitors;
|
||||||
|
EnumDisplayMonitors(NULL, NULL, saveDisplayToVector, reinterpret_cast<LPARAM>(&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
|
void SizeWindowToRect(HWND window, RECT rect) noexcept
|
||||||
{
|
{
|
||||||
WINDOWPLACEMENT placement{};
|
WINDOWPLACEMENT placement{};
|
||||||
@ -331,6 +413,8 @@ namespace FancyZonesUtils
|
|||||||
placement.flags &= ~WPF_RESTORETOMAXIMIZED;
|
placement.flags &= ~WPF_RESTORETOMAXIMIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScreenToWorkAreaCoords(window, rect);
|
||||||
|
|
||||||
placement.rcNormalPosition = rect;
|
placement.rcNormalPosition = rect;
|
||||||
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
|
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
|
||||||
|
|
||||||
|
@ -188,6 +188,8 @@ namespace FancyZonesUtils
|
|||||||
|
|
||||||
UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
|
UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
|
||||||
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
|
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
|
||||||
|
|
||||||
|
// Parameter rect must be in screen coordinates (e.g. obtained from GetWindowRect)
|
||||||
void SizeWindowToRect(HWND window, RECT rect) noexcept;
|
void SizeWindowToRect(HWND window, RECT rect) noexcept;
|
||||||
|
|
||||||
bool HasNoVisibleOwner(HWND window) noexcept;
|
bool HasNoVisibleOwner(HWND window) noexcept;
|
||||||
|
Loading…
Reference in New Issue
Block a user