Skip to content

Commit

Permalink
Prevent resizing terminal to a lower-than-minimum width (#8066)
Browse files Browse the repository at this point in the history
Until now, we relied on WM_SIZING to ensure that the island is not
downsized below minimal allowed dimensions. However, on some occasions
WM_WINDOWPOSCHANGED, e.g. when anchoring a window to the top/bottom of
the screen. This message will use dimensions obtained from
WM_GETMINMAXINFO. Until now we didn't override this value, falling back
to the defaults. As a result we got an inconsistent behavior (at least
when attaching the anchor).

I added logic very similar to the one we use in IslandWindow::_OnSizing
to the MINMAXINFO handler: snap the client area, add non client
exclusive are, consider DPI along the computation.

* Manual testing of minimizing, maximizing, resizing, attaching
  different anchors, etc.

Closes #8026

(cherry picked from commit e3fcfcc)
  • Loading branch information
Don-Vito authored and DHowett committed Jan 25, 2021
1 parent 431559f commit 12c100c
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 3 deletions.
4 changes: 3 additions & 1 deletion .github/actions/spell-check/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2828,4 +2828,6 @@ zy
AAAAABBBBBBCCC
AAAAA
BBBBBCCC
abcd
abcd
LPMINMAXINFO
MINMAXINFO
2 changes: 1 addition & 1 deletion src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1749,7 +1749,7 @@ namespace winrt::TerminalApp::implementation
// - See Pane::CalcSnappedDimension
float TerminalPage::CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
{
if (_settings.GlobalSettings().SnapToGridOnResize())
if (_settings && _settings.GlobalSettings().SnapToGridOnResize())
{
if (auto index{ _GetFocusedTabIndex() })
{
Expand Down
67 changes: 67 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,77 @@ void IslandWindow::OnSize(const UINT width, const UINT height)
}
}

// Method Description:
// - Handles a WM_GETMINMAXINFO message, issued before the window sizing starts.
// This message allows to modify the minimal and maximal dimensions of the window.
// We focus on minimal dimensions here
// (the maximal dimension will be calculate upon maximizing)
// Our goal is to protect against to downsizing to less than minimal allowed dimensions,
// that might occur in the scenarios where _OnSizing is bypassed.
// An example of such scenario is anchoring the window to the top/bottom screen border
// in order to maximize window height (GH# 8026).
// The computation is similar to what we do in _OnSizing:
// we need to consider both the client area and non-client exclusive area sizes,
// while taking DPI into account as well.
// Arguments:
// - lParam: Pointer to the requested MINMAXINFO struct,
// a ptMinTrackSize field of which we want to update with the computed dimensions.
// It also acts as the return value (it's a ref parameter).
// Return Value:
// - <none>

void IslandWindow::_OnGetMinMaxInfo(const WPARAM /*wParam*/, const LPARAM lParam)
{
// Without a callback we don't know to snap the dimensions of the client area.
// Should not be a problem, the callback is not set early in the startup
// The initial dimensions will be set later on
if (!_pfnSnapDimensionCallback)
{
return;
}

HMONITOR hmon = MonitorFromWindow(GetHandle(), MONITOR_DEFAULTTONEAREST);
if (hmon == NULL)
{
return;
}

UINT dpix = USER_DEFAULT_SCREEN_DPI;
UINT dpiy = USER_DEFAULT_SCREEN_DPI;
GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &dpix, &dpiy);

// From now we use dpix for all computations (same as in _OnSizing).
const auto nonClientSizeScaled = GetTotalNonClientExclusiveSize(dpix);
const auto scale = base::ClampedNumeric<float>(dpix) / USER_DEFAULT_SCREEN_DPI;

auto lpMinMaxInfo = reinterpret_cast<LPMINMAXINFO>(lParam);
lpMinMaxInfo->ptMinTrackSize.x = _calculateTotalSize(true, minimumWidth * scale, nonClientSizeScaled.cx);
lpMinMaxInfo->ptMinTrackSize.y = _calculateTotalSize(false, minimumHeight * scale, nonClientSizeScaled.cy);
}

// Method Description:
// - Helper function that calculates a singe dimension value, given initialWindow and nonClientSizes
// Arguments:
// - isWidth: parameter to pass to SnapDimensionCallback.
// True if the method is invoked for width computation, false if for height.
// - clientSize: the size of the client area (already)
// - nonClientSizeScaled: the exclusive non-client size (already scaled)
// Return Value:
// - The total dimension
long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize, const long nonClientSize)
{
return gsl::narrow_cast<int>(_pfnSnapDimensionCallback(isWidth, gsl::narrow_cast<float>(clientSize)) + nonClientSize);
}

[[nodiscard]] LRESULT IslandWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
{
switch (message)
{
case WM_GETMINMAXINFO:
{
_OnGetMinMaxInfo(wparam, lparam);
return 0;
}
case WM_CREATE:
{
_HandleCreateWindow(wparam, lparam);
Expand Down
8 changes: 8 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,15 @@ class IslandWindow :

LONG _getDesiredWindowStyle() const;

void _OnGetMinMaxInfo(const WPARAM wParam, const LPARAM lParam);
long _calculateTotalSize(const bool isWidth, const long clientSize, const long nonClientSize);

private:
// This minimum width allows for width the tabs fit
static constexpr long minimumWidth = 460L;

// We run with no height requirement for client area,
// though the total height will take into account the non-client area
// and the requirements of components hosted in the client area
static constexpr long minimumHeight = 0L;
};
2 changes: 1 addition & 1 deletion src/cascadia/WindowsTerminal/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ TRACELOGGING_DECLARE_PROVIDER(g_hWindowsTerminalProvider);
// For commandline argument processing
#include <shellapi.h>
#include <processenv.h>

#include <WinUser.h>
#include "til.h"

0 comments on commit 12c100c

Please sign in to comment.