diff --git a/.github/actions/spell-check/expect/expect.txt b/.github/actions/spell-check/expect/expect.txt index 47a511eefa6..24efc1f3289 100644 --- a/.github/actions/spell-check/expect/expect.txt +++ b/.github/actions/spell-check/expect/expect.txt @@ -2133,6 +2133,7 @@ SIGDN SINGLEFLAG SINGLETHREADED siup +SIZEBOX sizeof SIZESCROLL SKIPFONT diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 799a0c5fe25..98069ad8e8e 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -54,6 +54,7 @@ "scrollUpPage", "splitPane", "switchToTab", + "toggleFocusMode", "toggleFullscreen", "toggleRetroEffect", "find", diff --git a/src/cascadia/TerminalApp/ActionAndArgs.cpp b/src/cascadia/TerminalApp/ActionAndArgs.cpp index f28bd511c9e..cdb7c61eaa5 100644 --- a/src/cascadia/TerminalApp/ActionAndArgs.cpp +++ b/src/cascadia/TerminalApp/ActionAndArgs.cpp @@ -29,6 +29,7 @@ static constexpr std::string_view ResizePaneKey{ "resizePane" }; static constexpr std::string_view MoveFocusKey{ "moveFocus" }; static constexpr std::string_view FindKey{ "find" }; static constexpr std::string_view ToggleRetroEffectKey{ "toggleRetroEffect" }; +static constexpr std::string_view ToggleFocusModeKey{ "toggleFocusMode" }; static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" }; static constexpr std::string_view SetTabColorKey{ "setTabColor" }; static constexpr std::string_view OpenTabColorPickerKey{ "openTabColorPicker" }; @@ -73,6 +74,7 @@ namespace winrt::TerminalApp::implementation { MoveFocusKey, ShortcutAction::MoveFocus }, { OpenSettingsKey, ShortcutAction::OpenSettings }, { ToggleRetroEffectKey, ShortcutAction::ToggleRetroEffect }, + { ToggleFocusModeKey, ShortcutAction::ToggleFocusMode }, { ToggleFullscreenKey, ShortcutAction::ToggleFullscreen }, { SplitPaneKey, ShortcutAction::SplitPane }, { SetTabColorKey, ShortcutAction::SetTabColor }, @@ -252,6 +254,7 @@ namespace winrt::TerminalApp::implementation { ShortcutAction::MoveFocus, RS_(L"MoveFocusCommandKey") }, { ShortcutAction::OpenSettings, RS_(L"OpenSettingsCommandKey") }, { ShortcutAction::ToggleRetroEffect, RS_(L"ToggleRetroEffectCommandKey") }, + { ShortcutAction::ToggleFocusMode, RS_(L"ToggleFocusModeCommandKey") }, { ShortcutAction::ToggleFullscreen, RS_(L"ToggleFullscreenCommandKey") }, { ShortcutAction::SplitPane, RS_(L"SplitPaneCommandKey") }, { ShortcutAction::Invalid, L"" }, diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 68cea9eb89b..06f00892500 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -239,6 +239,13 @@ namespace winrt::TerminalApp::implementation args.Handled(true); } + void TerminalPage::_HandleToggleFocusMode(const IInspectable& /*sender*/, + const TerminalApp::ActionEventArgs& args) + { + ToggleFocusMode(); + args.Handled(true); + } + void TerminalPage::_HandleToggleFullscreen(const IInspectable& /*sender*/, const TerminalApp::ActionEventArgs& args) { diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index 27c3094975b..9c030b20051 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -104,6 +104,7 @@ namespace winrt::TerminalApp::implementation FORWARDED_TYPED_EVENT(SetTitleBarContent, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::UIElement, _root, SetTitleBarContent); FORWARDED_TYPED_EVENT(TitleChanged, winrt::Windows::Foundation::IInspectable, winrt::hstring, _root, TitleChanged); FORWARDED_TYPED_EVENT(LastTabClosed, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::LastTabClosedEventArgs, _root, LastTabClosed); + FORWARDED_TYPED_EVENT(ToggleFocusMode, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::ToggleFocusModeEventArgs, _root, ToggleFocusMode); FORWARDED_TYPED_EVENT(ToggleFullscreen, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::ToggleFullscreenEventArgs, _root, ToggleFullscreen); }; } diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl index aaa94f7e2c0..63441984f97 100644 --- a/src/cascadia/TerminalApp/AppLogic.idl +++ b/src/cascadia/TerminalApp/AppLogic.idl @@ -59,5 +59,6 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler LastTabClosed; event Windows.Foundation.TypedEventHandler RequestedThemeChanged; event Windows.Foundation.TypedEventHandler ToggleFullscreen; + event Windows.Foundation.TypedEventHandler ToggleFocusMode; } } diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 37cc4b2bf0e..d12934969ac 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -380,6 +380,10 @@ Close window + + Toggle focus mode + "Focus mode" is a mode with minimal UI elements, for a distraction-free experience + Toggle fullscreen diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp index 2f3198d4abc..8248d453aa8 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp @@ -159,6 +159,11 @@ namespace winrt::TerminalApp::implementation _ToggleRetroEffectHandlers(*this, *eventArgs); break; } + case ShortcutAction::ToggleFocusMode: + { + _ToggleFocusModeHandlers(*this, *eventArgs); + break; + } case ShortcutAction::ToggleFullscreen: { _ToggleFullscreenHandlers(*this, *eventArgs); diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.h b/src/cascadia/TerminalApp/ShortcutActionDispatch.h index 92da677645a..e59c8ce47cb 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.h +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.h @@ -47,6 +47,7 @@ namespace winrt::TerminalApp::implementation TYPED_EVENT(Find, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(ToggleRetroEffect, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); + TYPED_EVENT(ToggleFocusMode, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(ToggleCommandPalette, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(SetTabColor, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl index b5a7f821953..50f1bc7cd7f 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl @@ -32,6 +32,7 @@ namespace TerminalApp MoveFocus, Find, ToggleRetroEffect, + ToggleFocusMode, ToggleFullscreen, SetTabColor, OpenTabColorPicker, @@ -75,6 +76,7 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler Find; event Windows.Foundation.TypedEventHandler MoveFocus; event Windows.Foundation.TypedEventHandler ToggleRetroEffect; + event Windows.Foundation.TypedEventHandler ToggleFocusMode; event Windows.Foundation.TypedEventHandler ToggleFullscreen; event Windows.Foundation.TypedEventHandler ToggleCommandPalette; event Windows.Foundation.TypedEventHandler SetTabColor; diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 59fa97b499a..deecd34850e 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -850,6 +850,7 @@ namespace winrt::TerminalApp::implementation _actionDispatch->Find({ this, &TerminalPage::_HandleFind }); _actionDispatch->ResetFontSize({ this, &TerminalPage::_HandleResetFontSize }); _actionDispatch->ToggleRetroEffect({ this, &TerminalPage::_HandleToggleRetroEffect }); + _actionDispatch->ToggleFocusMode({ this, &TerminalPage::_HandleToggleFocusMode }); _actionDispatch->ToggleFullscreen({ this, &TerminalPage::_HandleToggleFullscreen }); _actionDispatch->ToggleCommandPalette({ this, &TerminalPage::_HandleToggleCommandPalette }); _actionDispatch->SetTabColor({ this, &TerminalPage::_HandleSetTabColor }); @@ -911,7 +912,7 @@ namespace winrt::TerminalApp::implementation // Never show the tab row when we're fullscreen. Otherwise: // Show tabs when there's more than 1, or the user has chosen to always // show the tab bar. - const bool isVisible = (!_isFullscreen) && + const bool isVisible = (!_isFullscreen && !_isInFocusMode) && (_settings->GlobalSettings().ShowTabsInTitlebar() || (_tabs.Size() > 1) || _settings->GlobalSettings().AlwaysShowTabs()); @@ -1966,6 +1967,22 @@ namespace winrt::TerminalApp::implementation termControl.CreateSearchBoxControl(); } + // Method Description: + // - Toggles borderless mode. Hides the tab row, and raises our + // ToggleFocusMode event. + // Arguments: + // - + // Return Value: + // - + void TerminalPage::ToggleFocusMode() + { + _toggleFocusModeHandlers(*this, nullptr); + + _isInFocusMode = !_isInFocusMode; + + _UpdateTabView(); + } + // Method Description: // - Toggles fullscreen mode. Hides the tab row, and raises our // ToggleFullscreen event. @@ -2176,5 +2193,6 @@ namespace winrt::TerminalApp::implementation DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, TitleChanged, _titleChangeHandlers, winrt::Windows::Foundation::IInspectable, winrt::hstring); DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, LastTabClosed, _lastTabClosedHandlers, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::LastTabClosedEventArgs); DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, SetTitleBarContent, _setTitleBarContentHandlers, winrt::Windows::Foundation::IInspectable, UIElement); + DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, ToggleFocusMode, _toggleFocusModeHandlers, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::ToggleFocusModeEventArgs); DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, ToggleFullscreen, _toggleFullscreenHandlers, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::ToggleFullscreenEventArgs); } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index d4d21c88aef..b5536b8371f 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -49,6 +49,7 @@ namespace winrt::TerminalApp::implementation void CloseWindow(); + void ToggleFocusMode(); void ToggleFullscreen(); void SetStartupActions(std::deque& actions); @@ -60,6 +61,7 @@ namespace winrt::TerminalApp::implementation DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(TitleChanged, _titleChangeHandlers, winrt::Windows::Foundation::IInspectable, winrt::hstring); DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(LastTabClosed, _lastTabClosedHandlers, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::LastTabClosedEventArgs); DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(SetTitleBarContent, _setTitleBarContentHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::UIElement); + DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(ToggleFocusMode, _toggleFocusModeHandlers, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::ToggleFocusModeEventArgs); DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(ToggleFullscreen, _toggleFullscreenHandlers, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::ToggleFullscreenEventArgs); TYPED_EVENT(Initialized, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs); @@ -83,6 +85,7 @@ namespace winrt::TerminalApp::implementation winrt::com_ptr _GetStrongTabImpl(const uint32_t index) const; winrt::com_ptr _GetStrongTabImpl(const ::winrt::TerminalApp::Tab& tab) const; + bool _isInFocusMode{ false }; bool _isFullscreen{ false }; bool _rearranging; @@ -206,6 +209,7 @@ namespace winrt::TerminalApp::implementation void _HandleFind(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleResetFontSize(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleToggleRetroEffect(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); + void _HandleToggleFocusMode(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleToggleFullscreen(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleSetTabColor(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleOpenTabColorPicker(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); diff --git a/src/cascadia/TerminalApp/TerminalPage.idl b/src/cascadia/TerminalApp/TerminalPage.idl index 6a14a9b08f7..9d5bd0aa83e 100644 --- a/src/cascadia/TerminalApp/TerminalPage.idl +++ b/src/cascadia/TerminalApp/TerminalPage.idl @@ -5,6 +5,7 @@ namespace TerminalApp { delegate void LastTabClosedEventArgs(); delegate void ToggleFullscreenEventArgs(); + delegate void ToggleFocusModeEventArgs(); interface IDialogPresenter { @@ -28,6 +29,7 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler LastTabClosed; event Windows.Foundation.TypedEventHandler SetTitleBarContent; event Windows.Foundation.TypedEventHandler ToggleFullscreen; + event Windows.Foundation.TypedEventHandler ToggleFocusMode; event Windows.Foundation.TypedEventHandler Initialized; } } diff --git a/src/cascadia/TerminalApp/defaults.json b/src/cascadia/TerminalApp/defaults.json index e5379f4507f..6022d1ad072 100644 --- a/src/cascadia/TerminalApp/defaults.json +++ b/src/cascadia/TerminalApp/defaults.json @@ -277,6 +277,7 @@ { "command": "closeWindow", "keys": "alt+f4" }, { "command": "toggleFullscreen", "keys": "alt+enter" }, { "command": "toggleFullscreen", "keys": "f11" }, + { "command": "toggleFocusMode" }, { "command": "openNewTabDropdown", "keys": "ctrl+shift+space" }, { "command": "openSettings", "keys": "ctrl+," }, { "command": { "action": "openSettings", "target": "defaultsFile" }, "keys": "ctrl+alt+," }, diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index b88a21cd9e0..4875475550e 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -157,6 +157,7 @@ void AppHost::Initialize() _logic.RequestedThemeChanged({ this, &AppHost::_UpdateTheme }); _logic.ToggleFullscreen({ this, &AppHost::_ToggleFullscreen }); + _logic.ToggleFocusMode({ this, &AppHost::_ToggleFocusMode }); _logic.Create(); @@ -352,6 +353,12 @@ void AppHost::_UpdateTheme(const winrt::Windows::Foundation::IInspectable&, cons _window->OnApplicationThemeChanged(arg); } +void AppHost::_ToggleFocusMode(const winrt::Windows::Foundation::IInspectable&, + const winrt::TerminalApp::ToggleFocusModeEventArgs&) +{ + _window->ToggleFocusMode(); +} + void AppHost::_ToggleFullscreen(const winrt::Windows::Foundation::IInspectable&, const winrt::TerminalApp::ToggleFullscreenEventArgs&) { diff --git a/src/cascadia/WindowsTerminal/AppHost.h b/src/cascadia/WindowsTerminal/AppHost.h index 4fefd567a97..842f8c19bba 100644 --- a/src/cascadia/WindowsTerminal/AppHost.h +++ b/src/cascadia/WindowsTerminal/AppHost.h @@ -33,6 +33,8 @@ class AppHost const winrt::Windows::UI::Xaml::UIElement& arg); void _UpdateTheme(const winrt::Windows::Foundation::IInspectable&, const winrt::Windows::UI::Xaml::ElementTheme& arg); + void _ToggleFocusMode(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::TerminalApp::ToggleFocusModeEventArgs& arg); void _ToggleFullscreen(const winrt::Windows::Foundation::IInspectable& sender, const winrt::TerminalApp::ToggleFullscreenEventArgs& arg); void _WindowMouseWheeled(const til::point coord, const int32_t delta); diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index 59508166e6d..3e78181d6bb 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -441,6 +441,17 @@ void IslandWindow::OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::Ele ::InvalidateRect(_window.get(), nullptr, false); } +// Method Description: +// - Toggles our focus mode state. See _SetIsBorderless for more details. +// Arguments: +// - +// Return Value: +// - +void IslandWindow::ToggleFocusMode() +{ + _SetIsBorderless(!_borderless); +} + // Method Description: // - Toggles our fullscreen state. See _SetIsFullscreen for more details. // Arguments: @@ -471,16 +482,106 @@ void _SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLo } } +// Method Description: +// - This is a helper to figure out what the window styles should be, given the +// current state of flags like borderless mode and fullscreen mode. +// Arguments: +// - +// Return Value: +// - a LONG with the appropriate flags set for our current window mode, to be used with GWL_STYLE +LONG IslandWindow::_getDesiredWindowStyle() const +{ + auto windowStyle = GetWindowLongW(GetHandle(), GWL_STYLE); + + // If we're both fullscreen and borderless, fullscreen mode takes precedence. + + if (_fullscreen) + { + // When moving to fullscreen, remove WS_OVERLAPPEDWINDOW, which specifies + // styles for non-fullscreen windows (e.g. caption bar), and add the + // WS_POPUP style to allow us to size ourselves to the monitor size. + // Do the reverse when restoring from fullscreen. + // Doing these modifications to that window will cause a vista-style + // window frame to briefly appear when entering and exiting fullscreen. + WI_ClearFlag(windowStyle, WS_BORDER); + WI_ClearFlag(windowStyle, WS_SIZEBOX); + WI_ClearAllFlags(windowStyle, WS_OVERLAPPEDWINDOW); + + WI_SetFlag(windowStyle, WS_POPUP); + return windowStyle; + } + else if (_borderless) + { + // When moving to borderless, remove WS_OVERLAPPEDWINDOW, which + // specifies styles for non-fullscreen windows (e.g. caption bar), and + // add the WS_BORDER and WS_SIZEBOX styles. This allows us to still have + // a small resizing frame, but without a full titlebar, nor caption + // buttons. + + WI_ClearAllFlags(windowStyle, WS_OVERLAPPEDWINDOW); + WI_ClearFlag(windowStyle, WS_POPUP); + + WI_SetFlag(windowStyle, WS_BORDER); + WI_SetFlag(windowStyle, WS_SIZEBOX); + return windowStyle; + } + + // Here, we're not in either fullscreen or borderless mode. Return to + // WS_OVERLAPPEDWINDOW. + WI_ClearFlag(windowStyle, WS_POPUP); + WI_ClearFlag(windowStyle, WS_BORDER); + WI_ClearFlag(windowStyle, WS_SIZEBOX); + + WI_SetAllFlags(windowStyle, WS_OVERLAPPEDWINDOW); + + return windowStyle; +} + +// Method Description: +// - Enable or disable focus mode. When entering focus mode, we'll +// need to manually hide the entire titlebar. +// - When we're entering focus we need to do some additional modification +// of our window styles. However, the NonClientIslandWindow very explicitly +// _doesn't_ need to do these steps. +// Arguments: +// - borderlessEnabled: If true, we're entering focus mode. If false, we're leaving. +// Return Value: +// - +void IslandWindow::_SetIsBorderless(const bool borderlessEnabled) +{ + _borderless = borderlessEnabled; + + HWND const hWnd = GetHandle(); + + // First, modify regular window styles as appropriate + auto windowStyle = _getDesiredWindowStyle(); + _SetWindowLongWHelper(hWnd, GWL_STYLE, windowStyle); + + // Now modify extended window styles as appropriate + // When moving to fullscreen, remove the window edge style to avoid an + // ugly border when not focused. + auto exWindowStyle = GetWindowLongW(hWnd, GWL_EXSTYLE); + WI_UpdateFlag(exWindowStyle, WS_EX_WINDOWEDGE, !_fullscreen); + _SetWindowLongWHelper(hWnd, GWL_EXSTYLE, exWindowStyle); + + // Resize the window, with SWP_FRAMECHANGED, to trigger user32 to + // recalculate the non/client areas + const til::rectangle windowPos{ GetWindowRect() }; + SetWindowPos(GetHandle(), + HWND_TOP, + windowPos.left(), + windowPos.top(), + windowPos.width(), + windowPos.height(), + SWP_SHOWWINDOW | SWP_FRAMECHANGED); +} + // Method Description: // - Controls setting us into or out of fullscreen mode. Largely taken from // Window::SetIsFullscreen in conhost. // - When entering fullscreen mode, we'll save the current window size and // location, and expand to take the entire monitor size. When leaving, we'll // use that saved size to restore back to. -// - When we're entering fullscreen we need to do some additional modification -// of our window styles. However, the NonClientIslandWindow very explicitly -// _doesn't_ need to do these steps. Subclasses should override -// _ShouldUpdateStylesOnFullscreen to disable setting these window styles. // Arguments: // - fullscreenEnabled true if we should enable fullscreen mode, false to disable. // Return Value: @@ -496,25 +597,7 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled) HWND const hWnd = GetHandle(); // First, modify regular window styles as appropriate - auto windowStyle = GetWindowLongW(hWnd, GWL_STYLE); - - // When moving to fullscreen, remove WS_OVERLAPPEDWINDOW, which specifies - // styles for non-fullscreen windows (e.g. caption bar), and add the - // WS_POPUP style to allow us to size ourselves to the monitor size. - // Do the reverse when restoring from fullscreen. - // Doing these modifications to that window will cause a vista-style - // window frame to briefly appear when entering and exiting fullscreen. - if (_fullscreen) - { - WI_ClearAllFlags(windowStyle, WS_OVERLAPPEDWINDOW); - WI_SetFlag(windowStyle, WS_POPUP); - } - else - { - WI_ClearFlag(windowStyle, WS_POPUP); - WI_SetAllFlags(windowStyle, WS_OVERLAPPEDWINDOW); - } - + auto windowStyle = _getDesiredWindowStyle(); _SetWindowLongWHelper(hWnd, GWL_STYLE, windowStyle); // Now modify extended window styles as appropriate @@ -524,6 +607,8 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled) WI_UpdateFlag(exWindowStyle, WS_EX_WINDOWEDGE, !_fullscreen); _SetWindowLongWHelper(hWnd, GWL_EXSTYLE, exWindowStyle); + // When entering/exiting fullscreen mode, we also need to backup/restore the + // current window size, and resize the window to match the new state. _BackupWindowSizes(oldIsInFullscreen); _ApplyWindowSize(); } diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h index 065d9831acc..eff8f7724a9 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.h +++ b/src/cascadia/WindowsTerminal/IslandWindow.h @@ -32,6 +32,7 @@ class IslandWindow : void SetCreateCallback(std::function pfn) noexcept; void SetSnapDimensionCallback(std::function pfn) noexcept; + void ToggleFocusMode(); void ToggleFullscreen(); #pragma endregion @@ -60,14 +61,18 @@ class IslandWindow : void _HandleCreateWindow(const WPARAM wParam, const LPARAM lParam) noexcept; [[nodiscard]] LRESULT _OnSizing(const WPARAM wParam, const LPARAM lParam); + bool _borderless{ false }; bool _fullscreen{ false }; RECT _fullscreenWindowSize; RECT _nonFullscreenWindowSize; + virtual void _SetIsBorderless(const bool borderlessEnabled); virtual void _SetIsFullscreen(const bool fullscreenEnabled); void _BackupWindowSizes(const bool currentIsInFullscreen); void _ApplyWindowSize(); + LONG _getDesiredWindowStyle() const; + private: // This minimum width allows for width the tabs fit static constexpr long minimumWidth = 460L; diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 2238cf770a3..d8e67e7dec7 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -263,9 +263,10 @@ void NonClientIslandWindow::SetTitlebarContent(winrt::Windows::UI::Xaml::UIEleme // - the height of the border above the title bar or 0 if it's disabled int NonClientIslandWindow::_GetTopBorderHeight() const noexcept { - if (_isMaximized || _fullscreen) + // No border when maximized, or when the titlebar is invisible (by being in + // fullscreen or focus mode). + if (_isMaximized || (!_IsTitlebarVisible())) { - // no border when maximized return 0; } @@ -811,6 +812,46 @@ void NonClientIslandWindow::OnApplicationThemeChanged(const ElementTheme& reques _theme = requestedTheme; } +// Method Description: +// - Enable or disable borderless mode. When entering borderless mode, we'll +// need to manually hide the entire titlebar. +// - See also IslandWindow::_SetIsBorderless, which does similar, but different work. +// Arguments: +// - borderlessEnabled: If true, we're entering borderless mode. If false, we're leaving. +// Return Value: +// - +void NonClientIslandWindow::_SetIsBorderless(const bool borderlessEnabled) +{ + _borderless = borderlessEnabled; + + // Explicitly _don't_ call IslandWindow::_SetIsBorderless. That version will + // change the window styles appropriately for the window with the default + // titlebar, but for the tabs-in-titlebar mode, we can just get rid of the + // title bar entirely. + + if (_titlebar) + { + _titlebar.Visibility(_IsTitlebarVisible() ? Visibility::Visible : Visibility::Collapsed); + } + + // GH#4224 - When the auto-hide taskbar setting is enabled, then we don't + // always get another window message to trigger us to remove the drag bar. + // So, make sure to update the size of the drag region here, so that it + // _definitely_ goes away. + _ResizeDragBarWindow(); + + // Resize the window, with SWP_FRAMECHANGED, to trigger user32 to + // recalculate the non/client areas + const til::rectangle windowPos{ GetWindowRect() }; + SetWindowPos(GetHandle(), + HWND_TOP, + windowPos.left(), + windowPos.top(), + windowPos.width(), + windowPos.height(), + SWP_SHOWWINDOW | SWP_FRAMECHANGED); +} + // Method Description: // - Enable or disable fullscreen mode. When entering fullscreen mode, we'll // need to manually hide the entire titlebar. @@ -824,7 +865,7 @@ void NonClientIslandWindow::_SetIsFullscreen(const bool fullscreenEnabled) IslandWindow::_SetIsFullscreen(fullscreenEnabled); if (_titlebar) { - _titlebar.Visibility(!fullscreenEnabled ? Visibility::Visible : Visibility::Collapsed); + _titlebar.Visibility(_IsTitlebarVisible() ? Visibility::Visible : Visibility::Collapsed); } // GH#4224 - When the auto-hide taskbar setting is enabled, then we don't // always get another window message to trigger us to remove the drag bar. @@ -835,16 +876,14 @@ void NonClientIslandWindow::_SetIsFullscreen(const bool fullscreenEnabled) // Method Description: // - Returns true if the titlebar is visible. For things like fullscreen mode, -// borderless mode, this will return false. +// borderless mode (aka "focus mode"), this will return false. // Arguments: // - // Return Value: // - true iff the titlebar is visible bool NonClientIslandWindow::_IsTitlebarVisible() const { - // TODO:GH#2238 - When we add support for titlebar-less mode, this should be - // updated to include that mode. - return !_fullscreen; + return !(_fullscreen || _borderless); } // Method Description: diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h index 792ba6272c9..10a39b4fcb1 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h @@ -79,7 +79,8 @@ class NonClientIslandWindow : public IslandWindow void _OnMaximizeChange() noexcept; void _OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs eventArgs); - void _SetIsFullscreen(const bool fFullscreenEnabled) override; + void _SetIsBorderless(const bool borderlessEnabled) override; + void _SetIsFullscreen(const bool fullscreenEnabled) override; bool _IsTitlebarVisible() const; void _UpdateFrameMargins() const noexcept;