Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ exemain
EXETYPE
exeuwp
exewin
EXITSIZEMOVE
exitwin
EXPUNGECOMMANDHISTORY
EXSTYLE
Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalSettingsModel/ApplicationState.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
X(FileSource::Shared, Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage>, DismissedMessages, "dismissedMessages") \
X(FileSource::Local, Windows::Foundation::Collections::IVector<hstring>, AllowedCommandlines, "allowedCommandlines") \
X(FileSource::Local, std::unordered_set<hstring>, DismissedBadges, "dismissedBadges") \
X(FileSource::Shared, bool, SSHFolderGenerated, "sshFolderGenerated", false)
X(FileSource::Shared, bool, SSHFolderGenerated, "sshFolderGenerated", false) \
X(FileSource::Shared, double, QuakeWindowSizePercent, "quakeWindowSizePercent", 0.5)

struct WindowLayout : WindowLayoutT<WindowLayout>
{
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettingsModel/ApplicationState.idl
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ namespace Microsoft.Terminal.Settings.Model
Windows.Foundation.Collections.IVector<String> RecentCommands;
Windows.Foundation.Collections.IVector<InfoBarMessage> DismissedMessages;
Windows.Foundation.Collections.IVector<String> AllowedCommandlines;
Double QuakeWindowSizePercent;
}
}
49 changes: 42 additions & 7 deletions src/cascadia/WindowsTerminal/AppHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ AppHost::AppHost(WindowEmperor* manager, const winrt::TerminalApp::AppLogic& log
// Update our own internal state tracking if we're in quake mode or not.
_IsQuakeWindowChanged(nullptr, nullptr);

const auto state = ApplicationState::SharedInstance();
const auto savedPercent = static_cast<float>(state.QuakeWindowSizePercent());
_window->SetQuakeWindowSizePercent(savedPercent);

#ifdef _DEBUG
OutputDebugStringW(wil::str_printf<std::wstring>(L"[IslandWindow] Loaded size percent from state: %.1f%%\n", savedPercent * 100.0f).c_str());
#endif

_window->SetMinimizeToNotificationAreaBehavior(_windowLogic.GetMinimizeToNotificationArea());

// Tell the window to callback to us when it's about to handle a WM_CREATE
Expand All @@ -75,6 +83,7 @@ AppHost::AppHost(WindowEmperor* manager, const winrt::TerminalApp::AppLogic& log
_windowCallbacks.WindowActivated = _window->WindowActivated({ this, &AppHost::_WindowActivated });
_windowCallbacks.WindowMoved = _window->WindowMoved({ this, &AppHost::_WindowMoved });
_windowCallbacks.ShouldExitFullscreen = _window->ShouldExitFullscreen({ &_windowLogic, &winrt::TerminalApp::TerminalWindow::RequestExitFullscreen });
_windowCallbacks.QuakeWindowSizeChanged = _window->QuakeWindowSizeChanged({ this, &AppHost::_QuakeWindowSizeChanged });

_window->MakeWindow();

Expand Down Expand Up @@ -391,6 +400,7 @@ void AppHost::_revokeWindowCallbacks()
_window->DragRegionClicked(_windowCallbacks.DragRegionClicked);
_window->WindowVisibilityChanged(_windowCallbacks.WindowVisibilityChanged);
_window->MaximizeChanged(_windowCallbacks.MaximizeChanged);
_window->QuakeWindowSizeChanged(_windowCallbacks.QuakeWindowSizeChanged);
}

// Method Description:
Expand Down Expand Up @@ -558,17 +568,32 @@ void AppHost::_initialResizeAndRepositionWindow(const HWND hwnd, til::rect propo

if (_windowLogic.IsQuakeWindow())
Copy link
Author

@metal-gabe metal-gabe Nov 24, 2025

Choose a reason for hiding this comment

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

The logic below was updated due to an issue where, after compiling/building, the very first activation would open on the main monitor (i.e. not on the current monitor that the cursor was on, which does not align with the behavior of the current release) at 50% (it wasn't using the stored size).

{
// If we just use rcWork by itself, we'll fail to account for the invisible
// space reserved for the resize handles. So retrieve that size here.
const auto availableSpace = desktopDimensions + nonClientSize;
// Get cursor monitor for quake windows - the window should appear
// on the monitor where the cursor is, not the proposed window location
POINT cursorPos{};
GetCursorPos(&cursorPos);
auto hmon = MonitorFromPoint(cursorPos, MONITOR_DEFAULTTONEAREST);

MONITORINFO cursorMonitorInfo{};
cursorMonitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hmon, &cursorMonitorInfo);

UINT dpiX = USER_DEFAULT_SCREEN_DPI;
UINT dpiY = USER_DEFAULT_SCREEN_DPI;
GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);

const til::rect workArea{ cursorMonitorInfo.rcWork };
const auto nonClientSize = _window->GetTotalNonClientExclusiveSize(dpiX);
const auto availableSpace = til::size{ workArea.width(), workArea.height() } + nonClientSize;
const auto savedPercent = ApplicationState::SharedInstance().QuakeWindowSizePercent();

origin = {
(nearestMonitorInfo.rcWork.left - (nonClientSize.width / 2)),
(nearestMonitorInfo.rcWork.top)
(cursorMonitorInfo.rcWork.left - (nonClientSize.width / 2)) + 1,
cursorMonitorInfo.rcWork.top
};
dimensions = {
availableSpace.width,
availableSpace.height / 2
availableSpace.width - 2,
static_cast<til::CoordType>(availableSpace.height * savedPercent)
};
launchMode = LaunchMode::FocusMode;
}
Expand Down Expand Up @@ -1030,6 +1055,16 @@ void AppHost::_IsQuakeWindowChanged(const winrt::Windows::Foundation::IInspectab
_window->IsQuakeWindow(_windowLogic.IsQuakeWindow());
}

void AppHost::_QuakeWindowSizeChanged(float sizePercent)
{
// Persist the new quake window size to ApplicationState
ApplicationState::SharedInstance().QuakeWindowSizePercent(static_cast<double>(sizePercent));

#ifdef _DEBUG
Copy link
Author

@metal-gabe metal-gabe Nov 24, 2025

Choose a reason for hiding this comment

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

All debug logs that were added can be removed once this PR is ready for final review.

OutputDebugStringW(wil::str_printf<std::wstring>(L"[IslandWindow] Persisting size percent to state: %.1f%%\n", sizePercent * 100.0f).c_str());
#endif
}

// Raised from TerminalWindow. We handle by bubbling the request to the window manager.
void AppHost::_RequestQuitAll(const winrt::Windows::Foundation::IInspectable&,
const winrt::Windows::Foundation::IInspectable&)
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/WindowsTerminal/AppHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ class AppHost : public std::enable_shared_from_this<AppHost>
void _IsQuakeWindowChanged(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& args);

void _QuakeWindowSizeChanged(float sizePercent);

void _SummonWindowRequested(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& args);

Expand Down Expand Up @@ -176,6 +178,7 @@ class AppHost : public std::enable_shared_from_this<AppHost>
winrt::event_token DragRegionClicked;
winrt::event_token WindowVisibilityChanged;
winrt::event_token MaximizeChanged;
winrt::event_token QuakeWindowSizeChanged;
// LOAD BEARING!!
//If you add events here, make sure they're revoked in AppHost::_revokeWindowCallbacks
} _windowCallbacks{};
Expand Down
50 changes: 49 additions & 1 deletion src/cascadia/WindowsTerminal/IslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,45 @@ void IslandWindow::_OnGetMinMaxInfo(const WPARAM /*wParam*/, const LPARAM lParam
WindowMoved.raise();
break;
}
case WM_EXITSIZEMOVE:
{
if (IsQuakeWindow())
{
const til::rect windowRect{ GetWindowRect() };
const auto hmon = MonitorFromWindow(_window.get(), MONITOR_DEFAULTTONEAREST);

MONITORINFO monitorInfo{};
monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hmon, &monitorInfo);

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

const auto ncSize = GetTotalNonClientExclusiveSize(dpix);
const til::size desktopDimensions{
(monitorInfo.rcWork.right - monitorInfo.rcWork.left),
(monitorInfo.rcWork.bottom - monitorInfo.rcWork.top)
};
const auto availableHeight = desktopDimensions.height + ncSize.height;
const auto currentHeight = windowRect.height();
const auto newPercent = static_cast<float>(currentHeight) / static_cast<float>(availableHeight);
const auto clampedPercent = std::clamp(newPercent, 0.1f, 1.0f);

if (clampedPercent != _quakeWindowSizePercent)
{
_quakeWindowSizePercent = clampedPercent;

#ifdef _DEBUG
OutputDebugStringW(wil::str_printf<std::wstring>(L"[IslandWindow] WM_EXITSIZEMOVE: New size percent: %.1f%% (height: %d, available: %d)\n",
clampedPercent * 100.0f, currentHeight, availableHeight).c_str());
#endif

QuakeWindowSizeChanged.raise(clampedPercent);
}
}
break;
}
case WM_CLOSE:
{
// If the user wants to close the app by clicking 'X' button,
Expand Down Expand Up @@ -1646,6 +1685,15 @@ void IslandWindow::SetAutoHideWindow(bool autoHideWindow) noexcept
_autoHideWindow = autoHideWindow;
}

void IslandWindow::SetQuakeWindowSizePercent(float percent) noexcept
{
_quakeWindowSizePercent = std::clamp(percent, 0.1f, 1.0f);

#ifdef _DEBUG
OutputDebugStringW(wil::str_printf<std::wstring>(L"[IslandWindow] Size percent set to: %.1f%%\n", _quakeWindowSizePercent * 100.0f).c_str());
#endif
}

// Method Description:
// - Enter quake mode for the monitor this window is currently on. This involves
// resizing it to the top half of the monitor.
Expand Down Expand Up @@ -1713,7 +1761,7 @@ til::rect IslandWindow::_getQuakeModeSize(HMONITOR hmon)
};
const til::size dimensions{
availableSpace.width - 2,
availableSpace.height / 2
static_cast<til::CoordType>(availableSpace.height * _quakeWindowSizePercent)
};

return { origin, dimensions };
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class IslandWindow :
bool IsQuakeWindow() const noexcept;
void IsQuakeWindow(bool isQuakeWindow) noexcept;
void SetAutoHideWindow(bool autoHideWindow) noexcept;
void SetQuakeWindowSizePercent(float percent) noexcept;

void HideWindow();

Expand All @@ -85,6 +86,7 @@ class IslandWindow :

til::event<winrt::delegate<void()>> WindowMoved;
til::event<winrt::delegate<void(bool)>> WindowVisibilityChanged;
til::event<winrt::delegate<void(float)>> QuakeWindowSizeChanged;

protected:
void ForceResize()
Expand Down Expand Up @@ -143,6 +145,7 @@ class IslandWindow :

bool _isQuakeWindow{ false };
bool _autoHideWindow{ false };
float _quakeWindowSizePercent{ 0.5f };

void _enterQuakeMode();
til::rect _getQuakeModeSize(HMONITOR hmon);
Expand Down