Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recalculate quake window size when snapping across monitors #10744

Merged
10 commits merged into from
Aug 2, 2021
98 changes: 89 additions & 9 deletions src/cascadia/WindowsTerminal/IslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,9 @@ LRESULT IslandWindow::_OnSizing(const WPARAM wParam, const LPARAM lParam)
LRESULT IslandWindow::_OnMoving(const WPARAM /*wParam*/, const LPARAM lParam)
{
LPRECT winRect = reinterpret_cast<LPRECT>(lParam);
// If we're the quake window, prevent moving the window

// If we're the quake window, prevent moving the window. If we don't do
// this, then Alt+Space...Move will still be able to move the window.
if (IsQuakeWindow())
{
// Stuff our current window into the lParam, and return true. This
Expand Down Expand Up @@ -506,6 +508,61 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
case WM_THEMECHANGED:
UpdateWindowIconForActiveMetrics(_window.get());
return 0;
case WM_WINDOWPOSCHANGING:
{
// GH#10274 - if the quake window gets moved to another monitor via aero
// snap (win+shift+arrows), then re-adjust the size for the new monitor.
if (IsQuakeWindow())
lhecker marked this conversation as resolved.
Show resolved Hide resolved
{
// Retrieve the suggested dimensions and make a rect and size.
LPWINDOWPOS lpwpos = (LPWINDOWPOS)lparam;

// We only need to apply restrictions if the position is changing.
// The SWP_ flags are confusing to read. This is
// "if we're not NOT moving the window"
if (!WI_IsFlagSet(lpwpos->flags, SWP_NOMOVE))
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
{
// Figure out the suggested dimensions and position.
RECT rcSuggested;
rcSuggested.left = lpwpos->x;
rcSuggested.top = lpwpos->y;
rcSuggested.right = rcSuggested.left + lpwpos->cx;
rcSuggested.bottom = rcSuggested.top + lpwpos->cy;

// Find the bounds of the current monitor, and the monitor that
// we're suggested to be on.

RECT windowRect = GetWindowRect();
HMONITOR current = MonitorFromRect(&windowRect, MONITOR_DEFAULTTONEAREST);
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
MONITORINFO currentInfo;
currentInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(current, &currentInfo);

HMONITOR proposed = MonitorFromRect(&rcSuggested, MONITOR_DEFAULTTONEAREST);
MONITORINFO proposedInfo;
proposedInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(proposed, &proposedInfo);

// If the monitor changed...
if (til::rectangle{ proposedInfo.rcMonitor } !=
til::rectangle{ currentInfo.rcMonitor })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe you have to wrap these structs first. You should be able to compare them directly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhg, it doesn't let me do that 😕 I didn't really feel like manually comparing each of .left, .top, etc, and this isn't going to be a particularly hot path

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I just wrote it because I thought it might make the code simpler. ^^

{
til::rectangle newWindowRect{ _getQuakeModeSize(proposed) };

// Inform User32 that we want to be placed at the position
// and dimensions that _getQuakeModeSize returned. When we
// snap across monitor boundaries, this will re-evaluate our
// size for the new monitor.
lpwpos->x = newWindowRect.left<int>();
lpwpos->y = newWindowRect.top<int>();
lpwpos->cx = newWindowRect.width<int>();
lpwpos->cy = newWindowRect.height<int>();

return 0;
}
}
}
}
case CM_NOTIFY_FROM_TRAY:
{
switch (LOWORD(lparam))
Expand Down Expand Up @@ -1432,6 +1489,13 @@ void IslandWindow::IsQuakeWindow(bool isQuakeWindow) noexcept
}
}

// Method Description:
// - Enter quake mode for the monitor this window is currently on. This involves
// resizing it to the top half of the monitor.
// Arguments:
// - <none>
// Return Value:
// - <none>
void IslandWindow::_enterQuakeMode()
{
if (!_window)
Expand All @@ -1441,6 +1505,29 @@ void IslandWindow::_enterQuakeMode()

RECT windowRect = GetWindowRect();
HMONITOR hmon = MonitorFromRect(&windowRect, MONITOR_DEFAULTTONEAREST);

// Get the size and position of the window that we should occupy
const auto newRect{ _getQuakeModeSize(hmon) };

SetWindowPos(GetHandle(),
HWND_TOP,
newRect.left<int>(),
newRect.top<int>(),
newRect.width<int>(),
newRect.height<int>(),
SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE);
}

// Method Description:
// - Get the size and position of the window that a "quake mode" should occupy
// on the given monitor.
// - The window will occupy the top half of the monitor.
// Arguments:
// - <none>
// Return Value:
// - <none>
til::rectangle IslandWindow::_getQuakeModeSize(HMONITOR hmon)
{
MONITORINFO nearestMonitorInfo;

UINT dpix = USER_DEFAULT_SCREEN_DPI;
Expand Down Expand Up @@ -1472,14 +1559,7 @@ void IslandWindow::_enterQuakeMode()
availableSpace.height() / 2
};

const til::rectangle newRect{ origin, dimensions };
SetWindowPos(GetHandle(),
HWND_TOP,
newRect.left<int>(),
newRect.top<int>(),
newRect.width<int>(),
newRect.height<int>(),
SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE);
return til::rectangle{ origin, dimensions };
}

DEFINE_EVENT(IslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ class IslandWindow :
void _moveToMonitor(const MONITORINFO activeMonitor);

bool _isQuakeWindow{ false };

void _enterQuakeMode();
til::rectangle _getQuakeModeSize(HMONITOR hmon);

void _summonWindowRoutineBody(winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior args);

Expand Down