Repository: microsoft/terminal (language: cpp)

Issue:
Terminal should be able to auto-minimize on focus lost
Hey!

Not sure if I missed a flag for the config somewhere, but it'd be grand if the quake mode could auto minimize itself when it loses focus. As is, I have to hit the hotkey twice to hide the window.

Thanks for the hard work.

_Originally posted by @digiwombat in https://github.com/microsoft/terminal/issues/8888#issuecomment-877944744_


Discussion / hints:

Fix patch:
diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json
index 583c5f7d8b1..c72822b45cb 100644
--- a/doc/cascadia/profiles.schema.json
+++ b/doc/cascadia/profiles.schema.json
@@ -1968,6 +1968,11 @@
             "useAnyExisting"
           ],
           "type": "string"
+        },
+        "autoHideWindow": {
+          "default": false,
+          "description": "If enabled, Terminal window will be hidden as soon as it loses focus.",
+          "type": "boolean"
         }
       },
       "required": [
diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp
index 4a05ef2f21d..02bc6eddc40 100644
--- a/src/cascadia/TerminalApp/AppLogic.cpp
+++ b/src/cascadia/TerminalApp/AppLogic.cpp
@@ -1505,6 +1505,17 @@ namespace winrt::TerminalApp::implementation
         return _root ? _root->AlwaysOnTop() : false;
     }
 
+    bool AppLogic::AutoHideWindow()
+    {
+        if (!_loadedInitialSettings)
+        {
+            // Load settings if we haven't already
+            LoadSettings();
+        }
+
+        return _settings.GlobalSettings().AutoHideWindow();
+    }
+
     Windows::Foundation::Collections::IMapView<Microsoft::Terminal::Control::KeyChord, Microsoft::Terminal::Settings::Model::Command> AppLogic::GlobalHotkeys()
     {
         return _settings.GlobalSettings().ActionMap().GlobalHotkeys();
diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h
index 2ba2deaeffb..7309c1cd7e3 100644
--- a/src/cascadia/TerminalApp/AppLogic.h
+++ b/src/cascadia/TerminalApp/AppLogic.h
@@ -79,6 +79,7 @@ namespace winrt::TerminalApp::implementation
         bool Fullscreen() const;
         void Maximized(bool newMaximized);
         bool AlwaysOnTop() const;
+        bool AutoHideWindow();
 
         bool ShouldUsePersistedLayout();
         bool ShouldImmediatelyHandoffToElevated();
diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl
index 42096bd08d1..5aa0c5c99ee 100644
--- a/src/cascadia/TerminalApp/AppLogic.idl
+++ b/src/cascadia/TerminalApp/AppLogic.idl
@@ -70,6 +70,7 @@ namespace TerminalApp
         Boolean Fullscreen { get; };
         void Maximized(Boolean newMaximized); 
         Boolean AlwaysOnTop { get; };
+        Boolean AutoHideWindow { get; };
 
         void IdentifyWindow();
         String WindowName;
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml
index bf540a81465..53ea257ea68 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml
@@ -120,6 +120,12 @@
                 <ToggleSwitch IsOn="{x:Bind ViewModel.MinimizeToNotificationArea, Mode=TwoWay}"
                               Style="{StaticResource ToggleSwitchInExpanderStyle}" />
             </local:SettingContainer>
+
+            <!--  Automatically hide window  -->
+            <local:SettingContainer x:Uid="Globals_AutoHideWindow">
+                <ToggleSwitch IsOn="{x:Bind ViewModel.AutoHideWindow, Mode=TwoWay}"
+                              Style="{StaticResource ToggleSwitchInExpanderStyle}" />
+            </local:SettingContainer>
         </StackPanel>
     </ScrollViewer>
 </Page>
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearanceViewModel.h b/src/cascadia/TerminalSettingsEditor/GlobalAppearanceViewModel.h
index 9256537430f..3826afcb1eb 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearanceViewModel.h
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearanceViewModel.h
@@ -42,6 +42,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, UseAcrylicInTabRow);
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ShowTitleInTitlebar);
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, AlwaysOnTop);
+        PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, AutoHideWindow);
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, AlwaysShowNotificationIcon);
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, MinimizeToNotificationArea);
 
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearanceViewModel.idl b/src/cascadia/TerminalSettingsEditor/GlobalAppearanceViewModel.idl
index 8d14d618be1..06053e7e528 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearanceViewModel.idl
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearanceViewModel.idl
@@ -33,6 +33,7 @@ namespace Microsoft.Terminal.Settings.Editor
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, UseAcrylicInTabRow);
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ShowTitleInTitlebar);
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, AlwaysOnTop);
+        PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, AutoHideWindow);
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, AlwaysShowNotificationIcon);
         PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, MinimizeToNotificationArea);
     }
diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
index 83f32f0fca0..fe4323391ed 100644
--- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
@@ -317,7 +317,6 @@
   </data>
   <data name="Globals_FirstWindowPreference.HelpText" xml:space="preserve">
     <value>What should be shown when the first terminal is created.</value>
-    <comment></comment>
   </data>
   <data name="Globals_FirstWindowPreferenceDefaultProfile.Content" xml:space="preserve">
     <value>Open a tab with the default profile</value>
@@ -1450,4 +1449,12 @@
     <value>Bold font with bright colors</value>
     <comment>An option to choose from for the "intense text format" setting. When selected, "intense" text will be rendered as both bold text and in a brighter color</comment>
   </data>
-</root>
+  <data name="Globals_AutoHideWindow.Header" xml:space="preserve">
+    <value>Automatically hide window</value>
+    <comment>Header for a control to toggle the "Automatically hide window" setting. If enabled, the window will be hidden as soon as it loses focus.</comment>
+  </data>
+  <data name="Globals_AutoHideWindow.HelpText" xml:space="preserve">
+    <value>If enabled, the window will be hidden as soon as it loses focus.</value>
+    <comment>A description for what the "Automatically hide window" setting does.</comment>
+  </data>
+</root>
\ No newline at end of file
diff --git a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl
index 9e6564740f1..26ae0e10585 100644
--- a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl
+++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl
@@ -82,6 +82,7 @@ namespace Microsoft.Terminal.Settings.Model
         INHERITABLE_SETTING(Boolean, DebugFeaturesEnabled);
         INHERITABLE_SETTING(Boolean, StartOnUserLogin);
         INHERITABLE_SETTING(Boolean, AlwaysOnTop);
+        INHERITABLE_SETTING(Boolean, AutoHideWindow);
         INHERITABLE_SETTING(TabSwitcherMode, TabSwitcherMode);
         INHERITABLE_SETTING(Boolean, DisableAnimations);
         INHERITABLE_SETTING(String, StartupActions);
diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
index c7abda9a29a..1503c223783 100644
--- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h
+++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
@@ -51,6 +51,7 @@ Author(s):
     X(bool, DebugFeaturesEnabled, "debugFeatures", debugFeaturesDefault)                                                                                   \
     X(bool, StartOnUserLogin, "startOnUserLogin", false)                                                                                                   \
     X(bool, AlwaysOnTop, "alwaysOnTop", false)                                                                                                             \
+    X(bool, AutoHideWindow, "autoHideWindow", false)                                                                                                       \
     X(Model::TabSwitcherMode, TabSwitcherMode, "tabSwitcherMode", Model::TabSwitcherMode::InOrder)                                                         \
     X(bool, DisableAnimations, "disableAnimations", false)                                                                                                 \
     X(hstring, StartupActions, "startupActions", L"")                                                                                                      \
diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp
index 1f929efda20..8f260f47355 100644
--- a/src/cascadia/WindowsTerminal/AppHost.cpp
+++ b/src/cascadia/WindowsTerminal/AppHost.cpp
@@ -103,6 +103,7 @@ AppHost::AppHost() noexcept :
     _window->ShouldExitFullscreen({ &_logic, &winrt::TerminalApp::AppLogic::RequestExitFullscreen });
 
     _window->SetAlwaysOnTop(_logic.GetInitialAlwaysOnTop());
+    _window->SetAutoHideWindow(_logic.AutoHideWindow());
 
     _window->MakeWindow();
 
@@ -1392,6 +1393,7 @@ void AppHost::_HandleSettingsChanged(const winrt::Windows::Foundation::IInspecta
     }
 
     _window->SetMinimizeToNotificationAreaBehavior(_logic.GetMinimizeToNotificationArea());
+    _window->SetAutoHideWindow(_logic.AutoHideWindow());
     _updateTheme();
 }
 
diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp
index 6bf1bc52b8e..7464aae2382 100644
--- a/src/cascadia/WindowsTerminal/IslandWindow.cpp
+++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp
@@ -442,6 +442,18 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
         const bool activated = LOWORD(wparam) != 0;
         _WindowActivatedHandlers(activated);
 
+        if (_autoHideWindow && !activated)
+        {
+            if (_isQuakeWindow || _minimizeToNotificationArea)
+            {
+                HideWindow();
+            }
+            else
+            {
+                ShowWindow(GetHandle(), SW_MINIMIZE);
+            }
+        }
+
         break;
     }
 
@@ -1626,6 +1638,11 @@ void IslandWindow::IsQuakeWindow(bool isQuakeWindow) noexcept
     }
 }
 
+void IslandWindow::SetAutoHideWindow(bool autoHideWindow) noexcept
+{
+    _autoHideWindow = autoHideWindow;
+}
+
 // Method Description:
 // - Enter quake mode for the monitor this window is currently on. This involves
 //   resizing it to the top half of the monitor.
diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h
index 89bfcbc71fd..39e683da0b6 100644
--- a/src/cascadia/WindowsTerminal/IslandWindow.h
+++ b/src/cascadia/WindowsTerminal/IslandWindow.h
@@ -55,6 +55,7 @@ class IslandWindow :
 
     bool IsQuakeWindow() const noexcept;
     void IsQuakeWindow(bool isQuakeWindow) noexcept;
+    void SetAutoHideWindow(bool autoHideWindow) noexcept;
 
     void HideWindow();
 
@@ -135,6 +136,7 @@ class IslandWindow :
     void _moveToMonitor(const MONITORINFO activeMonitor);
 
     bool _isQuakeWindow{ false };
+    bool _autoHideWindow{ false };
 
     void _enterQuakeMode();
     til::rect _getQuakeModeSize(HMONITOR hmon);


Test patch: