When the window is summoned and is already active, minimize it. (#9963)

This adds a `toggleVisibility` parameter to `globalSummon`. 
* When `true` (default): when you press the global summon keybinding, and the window is currently the foreground window, we'll minimize the window.
* When `false`, we'll just do nothing.

## References
* Original thread: #653
* Spec: #9274 
* megathread: #8888

## PR Checklist
* [x] Checks a box in #8888
* [x] closes https://github.com/microsoft/terminal/projects/5#card-59030814
* [x] I work here
* [ ] No tests for this one.
* [ ] yes yes eventually I'll come back on the docs

## Detailed Description of the Pull Request / Additional comments

I've got nothing extra to add here. This one's pretty simple. I'm only targeting #9954 since that one laid so much foundation to build on, with the `SummonBehavior`

## Validation Steps Performed

Played with this for a while, and it's amazing.
This commit is contained in:
Mike Griese 2021-04-28 18:57:14 -05:00 committed by GitHub
parent 65b22b9abb
commit 30d2d2c76d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 66 additions and 13 deletions

View File

@ -47,6 +47,7 @@ ICustom
IDialog
IDirect
IExplorer
IFACEMETHOD
IFile
IInheritable
IMap

View File

@ -134,7 +134,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingWrite(g_hRemotingProvider,
"Peasant_Summon",
TraceLoggingUInt64(GetID(), "peasantID", "Our ID"),
TraceLoggingUInt64(localCopy->MoveToCurrentDesktop(), "MoveToCurrentDesktop", "true if we should move to the current desktop"),
TraceLoggingUInt64(localCopy.MoveToCurrentDesktop(), "MoveToCurrentDesktop", "true if we should move to the current desktop"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
_SummonRequestedHandlers(*this, localCopy);

View File

@ -33,6 +33,7 @@ namespace Microsoft.Terminal.Remoting
[default_interface] runtimeclass SummonWindowBehavior {
SummonWindowBehavior();
Boolean MoveToCurrentDesktop;
Boolean ToggleVisibility;
// Other options:
// * CurrentMonitor
}

View File

@ -22,10 +22,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
public:
SummonWindowBehavior() = default;
WINRT_PROPERTY(bool, MoveToCurrentDesktop, true);
WINRT_PROPERTY(bool, ToggleVisibility, true);
public:
SummonWindowBehavior(const Remoting::SummonWindowBehavior& other) :
_MoveToCurrentDesktop{ other.MoveToCurrentDesktop() } {};
_MoveToCurrentDesktop{ other.MoveToCurrentDesktop() },
_ToggleVisibility{ other.ToggleVisibility() } {};
};
}

View File

@ -1045,9 +1045,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
GlobalSummonArgs() = default;
WINRT_PROPERTY(winrt::hstring, Name, L"");
WINRT_PROPERTY(Model::DesktopBehavior, Desktop, Model::DesktopBehavior::ToCurrent);
WINRT_PROPERTY(bool, ToggleVisibility, true);
static constexpr std::string_view NameKey{ "name" };
static constexpr std::string_view DesktopKey{ "desktop" };
static constexpr std::string_view ToggleVisibilityKey{ "toggleVisibility" };
public:
hstring GenerateName() const;
@ -1057,7 +1059,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
if (auto otherAsUs = other.try_as<GlobalSummonArgs>())
{
return otherAsUs->_Name == _Name &&
otherAsUs->_Desktop == _Desktop;
otherAsUs->_Desktop == _Desktop &&
otherAsUs->_ToggleVisibility == _ToggleVisibility;
}
return false;
};
@ -1067,6 +1070,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
auto args = winrt::make_self<GlobalSummonArgs>();
JsonUtils::GetValueForKey(json, NameKey, args->_Name);
JsonUtils::GetValueForKey(json, DesktopKey, args->_Desktop);
JsonUtils::GetValueForKey(json, ToggleVisibilityKey, args->_ToggleVisibility);
return { *args, {} };
}
IActionArgs Copy() const
@ -1074,6 +1078,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
auto copy{ winrt::make_self<GlobalSummonArgs>() };
copy->_Name = _Name;
copy->_Desktop = _Desktop;
copy->_ToggleVisibility = _ToggleVisibility;
return *copy;
}
// SPECIAL! This deserializer creates a GlobalSummonArgs with the

View File

@ -264,5 +264,6 @@ namespace Microsoft.Terminal.Settings.Model
{
String Name { get; };
DesktopBehavior Desktop { get; };
Boolean ToggleVisibility { get; };
};
}

View File

@ -38,17 +38,20 @@ namespace RemotingUnitTests
{
struct MockDesktopManager : implements<MockDesktopManager, IVirtualDesktopManager>
{
HRESULT GetWindowDesktopId(HWND /*topLevelWindow*/, GUID* /*desktopId*/)
IFACEMETHOD(GetWindowDesktopId)
(HWND /*topLevelWindow*/, GUID* /*desktopId*/)
{
VERIFY_IS_TRUE(false, L"We shouldn't need GetWindowDesktopId in the tests.");
return E_FAIL;
}
HRESULT MoveWindowToDesktop(HWND /*topLevelWindow*/, REFGUID /*desktopId*/)
IFACEMETHOD(MoveWindowToDesktop)
(HWND /*topLevelWindow*/, REFGUID /*desktopId*/)
{
VERIFY_IS_TRUE(false, L"We shouldn't need GetWindowDesktopId in the tests.");
return E_FAIL;
}
HRESULT IsWindowOnCurrentVirtualDesktop(HWND topLevelWindow, BOOL* onCurrentDesktop)
IFACEMETHOD(IsWindowOnCurrentVirtualDesktop)
(HWND topLevelWindow, BOOL* onCurrentDesktop)
{
if (pfnIsWindowOnCurrentVirtualDesktop)
{

View File

@ -591,7 +591,7 @@ void AppHost::_DispatchCommandline(winrt::Windows::Foundation::IInspectable /*se
{
// Summon the window whenever we dispatch a commandline to it. This will
// make it obvious when a new tab/pane is created in a window.
_window->SummonWindow();
_window->SummonWindow(false);
_logic.ExecuteCommandline(args.Commandline(), args.CurrentDirectory());
}
@ -692,6 +692,7 @@ void AppHost::_GlobalHotkeyPressed(const long hotkeyIndex)
// desktop:onCurrent - MoveToCurrentDesktop=false, OnCurrentDesktop=true
args.OnCurrentDesktop(summonArgs.Desktop() == Settings::Model::DesktopBehavior::OnCurrent);
args.SummonBehavior().MoveToCurrentDesktop(summonArgs.Desktop() == Settings::Model::DesktopBehavior::ToCurrent);
args.SummonBehavior().ToggleVisibility(summonArgs.ToggleVisibility());
_windowManager.SummonWindow(args);
if (args.FoundMatch())
@ -774,7 +775,7 @@ bool AppHost::_LazyLoadDesktopManager()
void AppHost::_HandleSummon(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const Remoting::SummonWindowBehavior& args)
{
_window->SummonWindow();
_window->SummonWindow(args.ToggleVisibility());
if (args != nullptr && args.MoveToCurrentDesktop())
{

View File

@ -999,6 +999,33 @@ void IslandWindow::SetGlobalHotkeys(const std::vector<winrt::Microsoft::Terminal
}
}
// Method Description:
// - Summon the window, or possibly dismiss it. If toggleVisibility is true,
// then we'll dismiss (minimize) the window if it's currently active.
// Otherwise, we'll always just try to activate the window.
// Arguments:
// - toggleVisibility: controls how we should behave when already in the foreground.
// Return Value:
// - <none>
winrt::fire_and_forget IslandWindow::SummonWindow(const bool toggleVisibility)
{
// On the foreground thread:
co_await winrt::resume_foreground(_rootGrid.Dispatcher());
// * If the user doesn't want to toggleVisibility, then just always try to
// activate.
// * If the user does want to toggleVisibility, then dismiss the window if
// we're the current foreground window.
if (toggleVisibility && GetForegroundWindow() == _window.get())
{
_globalDismissWindow();
}
else
{
_globalActivateWindow();
}
}
// Method Description:
// - Force activate this window. This method will bring us to the foreground and
// activate us. If the window is minimized, it will restore the window. If the
@ -1007,11 +1034,8 @@ void IslandWindow::SetGlobalHotkeys(const std::vector<winrt::Microsoft::Terminal
// - <none>
// Return Value:
// - <none>
winrt::fire_and_forget IslandWindow::SummonWindow()
void IslandWindow::_globalActivateWindow()
{
// On the foreground thread:
co_await winrt::resume_foreground(_rootGrid.Dispatcher());
// From: https://stackoverflow.com/a/59659421
// > The trick is to make windows think that our process and the target
// > window (hwnd) are related by attaching the threads (using
@ -1039,6 +1063,18 @@ winrt::fire_and_forget IslandWindow::SummonWindow()
LOG_LAST_ERROR_IF_NULL(SetActiveWindow(_window.get()));
}
// Method Description:
// - Minimize the window. This is called when the window is summoned, but is
// already active
// Arguments:
// - <none>
// Return Value:
// - <none>
void IslandWindow::_globalDismissWindow()
{
LOG_IF_WIN32_BOOL_FALSE(ShowWindow(_window.get(), SW_MINIMIZE));
}
bool IslandWindow::IsQuakeWindow() const noexcept
{
return _isQuakeWindow;

View File

@ -41,7 +41,7 @@ public:
void UnsetHotkeys(const std::vector<winrt::Microsoft::Terminal::Control::KeyChord>& hotkeyList);
void SetGlobalHotkeys(const std::vector<winrt::Microsoft::Terminal::Control::KeyChord>& hotkeyList);
winrt::fire_and_forget SummonWindow();
winrt::fire_and_forget SummonWindow(const bool toggleVisibility);
bool IsQuakeWindow() const noexcept;
void IsQuakeWindow(bool isQuakeWindow) noexcept;
@ -93,6 +93,9 @@ protected:
void _OnGetMinMaxInfo(const WPARAM wParam, const LPARAM lParam);
long _calculateTotalSize(const bool isWidth, const long clientSize, const long nonClientSize);
void _globalActivateWindow();
void _globalDismissWindow();
bool _isQuakeWindow{ false };
void _enterQuakeMode();