Add desktop
param to globalSummon
; set _quake = toCurrent (#9954)
This adds support for the `desktop` param to the `globalSummon` action. It accepts 3 values: * `toCurrent` (default): The window moves to the current desktop when it's summoned * `any`: We don't care what desktop the window is on. We'll go to the desktop the window is on when we summon it. * `onCurrent`: We'll only try to summon the MRU window on this desktop when summoning a window. * When combined with `name`, if there's a window matching `name`, we'll move it to this desktop. * If there's not a window on this desktop, and `name` is omitted, then we'll make a new window. `quakeMode` was also updated to use `toCurrent` behavior by default. ## References * Original thread: #653 * Spec: #9274 * megathread: #8888 ## PR Checklist * [x] Checks some boxes in #8888 * [x] closes https://github.com/microsoft/terminal/projects/5#card-59030845 * [x] I work here * [x] Tests added * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments S/O to https://github.com/microsoft/PowerToys, who graciously let us use `VirtualDesktopUtils` for figuring out what desktop is the current desktop. Yea, that's all we needed that entire file for. No, there isn't an API for this (_surprised-pikachu.png_) ## Validation Steps Performed Played with this for a while, and it's amazing.
This commit is contained in:
parent
d08271e734
commit
65b22b9abb
30
NOTICE.md
30
NOTICE.md
|
@ -251,3 +251,33 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
```
|
||||
|
||||
## `VirtualDesktopUtils`
|
||||
|
||||
**Source**: [https://github.com/microsoft/PowerToys](https://github.com/microsoft/PowerToys)
|
||||
|
||||
### License
|
||||
|
||||
```
|
||||
The MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
```
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
<ClInclude Include="SummonWindowSelectionArgs.h">
|
||||
<DependentUpon>Monarch.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SummonWindowBehavior.h">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RenameRequestArgs.h">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
|
@ -60,6 +63,9 @@
|
|||
<ClCompile Include="SummonWindowSelectionArgs.cpp">
|
||||
<DependentUpon>Monarch.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SummonWindowBehavior.cpp">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RenameRequestArgs.cpp">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
|
|
|
@ -711,7 +711,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
// If no name was provided, then just summon the MRU window.
|
||||
if (searchedForName.empty())
|
||||
{
|
||||
windowId = _getMostRecentPeasantID(true);
|
||||
// Use the value of the `desktop` arg to determine if we should
|
||||
// limit to the current desktop (desktop:onCurrent) or not
|
||||
// (desktop:any or desktop:toCurrent)
|
||||
windowId = _getMostRecentPeasantID(args.OnCurrentDesktop());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -720,7 +723,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
}
|
||||
if (auto targetPeasant{ _getPeasant(windowId) })
|
||||
{
|
||||
targetPeasant.Summon();
|
||||
targetPeasant.Summon(args.SummonBehavior());
|
||||
args.FoundMatch(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,13 +22,15 @@ namespace Microsoft.Terminal.Remoting
|
|||
SummonWindowSelectionArgs();
|
||||
SummonWindowSelectionArgs(String windowName);
|
||||
String WindowName;
|
||||
Boolean OnCurrentDesktop;
|
||||
// TODO GH#8888 Other options:
|
||||
// * CurrentDesktop
|
||||
// * CurrentMonitor
|
||||
|
||||
Boolean FoundMatch;
|
||||
SummonWindowBehavior SummonBehavior;
|
||||
}
|
||||
|
||||
|
||||
[default_interface] runtimeclass Monarch {
|
||||
Monarch();
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "pch.h"
|
||||
#include "Peasant.h"
|
||||
#include "CommandlineArgs.h"
|
||||
#include "SummonWindowBehavior.h"
|
||||
#include "Peasant.g.cpp"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
|
@ -126,14 +127,17 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Peasant::Summon()
|
||||
void Peasant::Summon(const Remoting::SummonWindowBehavior& summonBehavior)
|
||||
{
|
||||
_SummonRequestedHandlers(*this, nullptr);
|
||||
auto localCopy = winrt::make<implementation::SummonWindowBehavior>(summonBehavior);
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Peasant_Summon",
|
||||
TraceLoggingUInt64(GetID(), "peasantID", "Our ID"),
|
||||
TraceLoggingUInt64(localCopy->MoveToCurrentDesktop(), "MoveToCurrentDesktop", "true if we should move to the current desktop"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
|
||||
_SummonRequestedHandlers(*this, localCopy);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
bool ExecuteCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args);
|
||||
void ActivateWindow(const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args);
|
||||
|
||||
void Summon();
|
||||
void Summon(const Remoting::SummonWindowBehavior& summonBehavior);
|
||||
void RequestIdentifyWindows();
|
||||
void DisplayWindowId();
|
||||
void RequestRename(const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
|
||||
|
@ -39,7 +39,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
|
||||
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior);
|
||||
|
||||
private:
|
||||
Peasant(const uint64_t testPID);
|
||||
|
|
|
@ -30,6 +30,13 @@ namespace Microsoft.Terminal.Remoting
|
|||
Windows.Foundation.DateTime ActivatedTime { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SummonWindowBehavior {
|
||||
SummonWindowBehavior();
|
||||
Boolean MoveToCurrentDesktop;
|
||||
// Other options:
|
||||
// * CurrentMonitor
|
||||
}
|
||||
|
||||
interface IPeasant
|
||||
{
|
||||
CommandlineArgs InitialArgs { get; };
|
||||
|
@ -46,14 +53,14 @@ namespace Microsoft.Terminal.Remoting
|
|||
String WindowName { get; };
|
||||
void RequestIdentifyWindows(); // Tells us to raise a IdentifyWindowsRequested
|
||||
void RequestRename(RenameRequestArgs args); // Tells us to raise a RenameRequested
|
||||
void Summon();
|
||||
void Summon(SummonWindowBehavior behavior);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, WindowActivatedArgs> WindowActivated;
|
||||
event Windows.Foundation.TypedEventHandler<Object, CommandlineArgs> ExecuteCommandlineRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> DisplayWindowIdRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameRequestArgs> RenameRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SummonRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, SummonWindowBehavior> SummonRequested;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass Peasant : IPeasant
|
||||
|
|
5
src/cascadia/Remoting/SummonWindowBehavior.cpp
Normal file
5
src/cascadia/Remoting/SummonWindowBehavior.cpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
#include "pch.h"
|
||||
#include "SummonWindowBehavior.h"
|
||||
#include "SummonWindowBehavior.g.cpp"
|
35
src/cascadia/Remoting/SummonWindowBehavior.h
Normal file
35
src/cascadia/Remoting/SummonWindowBehavior.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Class Name:
|
||||
- SummonWindowBehavior.h
|
||||
|
||||
Abstract:
|
||||
- TODO!
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SummonWindowBehavior.g.h"
|
||||
#include "../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct SummonWindowBehavior : public SummonWindowBehaviorT<SummonWindowBehavior>
|
||||
{
|
||||
public:
|
||||
SummonWindowBehavior() = default;
|
||||
WINRT_PROPERTY(bool, MoveToCurrentDesktop, true);
|
||||
|
||||
public:
|
||||
SummonWindowBehavior(const Remoting::SummonWindowBehavior& other) :
|
||||
_MoveToCurrentDesktop{ other.MoveToCurrentDesktop() } {};
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(SummonWindowBehavior);
|
||||
}
|
|
@ -30,7 +30,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
_WindowName{ name } {};
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, WindowName);
|
||||
|
||||
WINRT_PROPERTY(bool, FoundMatch, false);
|
||||
WINRT_PROPERTY(bool, OnCurrentDesktop, false);
|
||||
WINRT_PROPERTY(SummonWindowBehavior, SummonBehavior);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1044,17 +1044,20 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
{
|
||||
GlobalSummonArgs() = default;
|
||||
WINRT_PROPERTY(winrt::hstring, Name, L"");
|
||||
WINRT_PROPERTY(Model::DesktopBehavior, Desktop, Model::DesktopBehavior::ToCurrent);
|
||||
|
||||
static constexpr std::string_view NameKey{ "name" };
|
||||
static constexpr std::string_view DesktopKey{ "desktop" };
|
||||
|
||||
public:
|
||||
hstring GenerateName() const;
|
||||
|
||||
bool Equals(const IActionArgs& other)
|
||||
{
|
||||
if (auto otherAsUs = other.try_as<GlobalSummonArgs>(); otherAsUs)
|
||||
if (auto otherAsUs = other.try_as<GlobalSummonArgs>())
|
||||
{
|
||||
return otherAsUs->_Name == _Name;
|
||||
return otherAsUs->_Name == _Name &&
|
||||
otherAsUs->_Desktop == _Desktop;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
@ -1063,12 +1066,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<GlobalSummonArgs>();
|
||||
JsonUtils::GetValueForKey(json, NameKey, args->_Name);
|
||||
JsonUtils::GetValueForKey(json, DesktopKey, args->_Desktop);
|
||||
return { *args, {} };
|
||||
}
|
||||
IActionArgs Copy() const
|
||||
{
|
||||
auto copy{ winrt::make_self<GlobalSummonArgs>() };
|
||||
copy->_Name = _Name;
|
||||
copy->_Desktop = _Desktop;
|
||||
return *copy;
|
||||
}
|
||||
// SPECIAL! This deserializer creates a GlobalSummonArgs with the
|
||||
|
|
|
@ -84,6 +84,13 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
Disabled,
|
||||
};
|
||||
|
||||
enum DesktopBehavior
|
||||
{
|
||||
Any,
|
||||
ToCurrent,
|
||||
OnCurrent,
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass NewTerminalArgs {
|
||||
NewTerminalArgs();
|
||||
NewTerminalArgs(Int32 profileIndex);
|
||||
|
@ -256,5 +263,6 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
[default_interface] runtimeclass GlobalSummonArgs : IActionArgs
|
||||
{
|
||||
String Name { get; };
|
||||
DesktopBehavior Desktop { get; };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -448,3 +448,12 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::WindowingMode)
|
|||
pair_type{ "useExisting", ValueType::UseExisting },
|
||||
};
|
||||
};
|
||||
|
||||
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::DesktopBehavior)
|
||||
{
|
||||
JSON_MAPPINGS(3) = {
|
||||
pair_type{ "any", ValueType::Any },
|
||||
pair_type{ "toCurrent", ValueType::ToCurrent },
|
||||
pair_type{ "onCurrent", ValueType::OnCurrent },
|
||||
};
|
||||
};
|
||||
|
|
|
@ -36,6 +36,31 @@ using namespace winrt::Microsoft::Terminal;
|
|||
|
||||
namespace RemotingUnitTests
|
||||
{
|
||||
struct MockDesktopManager : implements<MockDesktopManager, IVirtualDesktopManager>
|
||||
{
|
||||
HRESULT 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*/)
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"We shouldn't need GetWindowDesktopId in the tests.");
|
||||
return E_FAIL;
|
||||
}
|
||||
HRESULT IsWindowOnCurrentVirtualDesktop(HWND topLevelWindow, BOOL* onCurrentDesktop)
|
||||
{
|
||||
if (pfnIsWindowOnCurrentVirtualDesktop)
|
||||
{
|
||||
return pfnIsWindowOnCurrentVirtualDesktop(topLevelWindow, onCurrentDesktop);
|
||||
}
|
||||
VERIFY_IS_TRUE(false, L"You didn't set up the pfnIsWindowOnCurrentVirtualDesktop for this test!");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
std::function<HRESULT(HWND, BOOL*)> pfnIsWindowOnCurrentVirtualDesktop;
|
||||
};
|
||||
|
||||
// This is a silly helper struct.
|
||||
// It will always throw an hresult_error on any of its methods.
|
||||
//
|
||||
|
@ -60,13 +85,13 @@ namespace RemotingUnitTests
|
|||
Remoting::CommandlineArgs InitialArgs() { throw winrt::hresult_error{}; }
|
||||
Remoting::WindowActivatedArgs GetLastActivatedArgs() { throw winrt::hresult_error{}; }
|
||||
void RequestRename(const Remoting::RenameRequestArgs& /*args*/) { throw winrt::hresult_error{}; }
|
||||
void Summon() { throw winrt::hresult_error{}; };
|
||||
void Summon(const Remoting::SummonWindowBehavior& /*args*/) { throw winrt::hresult_error{}; };
|
||||
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, Remoting::WindowActivatedArgs);
|
||||
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, Remoting::CommandlineArgs);
|
||||
TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, Remoting::RenameRequestArgs);
|
||||
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, Remoting::SummonWindowBehavior);
|
||||
};
|
||||
|
||||
class RemotingTests
|
||||
|
@ -114,6 +139,10 @@ namespace RemotingUnitTests
|
|||
TEST_METHOD(TestSummonNamedDeadWindow);
|
||||
TEST_METHOD(TestSummonMostRecentDeadWindow);
|
||||
|
||||
TEST_METHOD(TestSummonOnCurrent);
|
||||
TEST_METHOD(TestSummonOnCurrentWithName);
|
||||
TEST_METHOD(TestSummonOnCurrentDeadWindow);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
return true;
|
||||
|
@ -1945,4 +1974,554 @@ namespace RemotingUnitTests
|
|||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
}
|
||||
|
||||
void RemotingTests::TestSummonOnCurrent()
|
||||
{
|
||||
Log::Comment(L"Tests summoning a window, using OnCurrentDesktop to only"
|
||||
L"select windows on the current desktop.");
|
||||
|
||||
const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
|
||||
const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };
|
||||
|
||||
constexpr auto monarch0PID = 12345u;
|
||||
constexpr auto peasant1PID = 23456u;
|
||||
constexpr auto peasant2PID = 34567u;
|
||||
constexpr auto peasant3PID = 45678u;
|
||||
|
||||
com_ptr<Remoting::implementation::Monarch> m0;
|
||||
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p1;
|
||||
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p2;
|
||||
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p3;
|
||||
p3.attach(new Remoting::implementation::Peasant(peasant3PID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
VERIFY_IS_NOT_NULL(p3);
|
||||
p1->WindowName(L"one");
|
||||
p2->WindowName(L"two");
|
||||
p3->WindowName(L"three");
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p3->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
m0->AddPeasant(*p3);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
VERIFY_ARE_EQUAL(3, p3->GetID());
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, m0->_peasants.size());
|
||||
|
||||
bool p1ExpectedToBeSummoned = false;
|
||||
bool p2ExpectedToBeSummoned = false;
|
||||
bool p3ExpectedToBeSummoned = false;
|
||||
|
||||
p1->SummonRequested([&](auto&&, auto&&) {
|
||||
Log::Comment(L"p1 summoned");
|
||||
VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
|
||||
});
|
||||
p2->SummonRequested([&](auto&&, auto&&) {
|
||||
Log::Comment(L"p2 summoned");
|
||||
VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
|
||||
});
|
||||
p3->SummonRequested([&](auto&&, auto&&) {
|
||||
Log::Comment(L"p3 summoned");
|
||||
VERIFY_IS_TRUE(p3ExpectedToBeSummoned);
|
||||
});
|
||||
|
||||
{
|
||||
Log::Comment(L"Activate the first peasant, first desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
|
||||
p1->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid1,
|
||||
winrt::clock().now() };
|
||||
p1->ActivateWindow(activatedArgs);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Activate the second peasant, second desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
|
||||
p2->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid2,
|
||||
winrt::clock().now() };
|
||||
p2->ActivateWindow(activatedArgs);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Activate the third peasant, first desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
|
||||
p3->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid1,
|
||||
winrt::clock().now() };
|
||||
p3->ActivateWindow(activatedArgs);
|
||||
}
|
||||
|
||||
Log::Comment(L"Create a mock IVirtualDesktopManager to handle checking if a window is on a given desktop");
|
||||
winrt::com_ptr<MockDesktopManager> manager;
|
||||
manager.attach(new MockDesktopManager());
|
||||
m0->_desktopManager = manager.try_as<IVirtualDesktopManager>();
|
||||
|
||||
auto firstCallback = [&](HWND h, BOOL* result) -> HRESULT {
|
||||
Log::Comment(L"firstCallback: Checking if window is on desktop 1");
|
||||
|
||||
const uint64_t hwnd = reinterpret_cast<uint64_t>(h);
|
||||
if (hwnd == peasant1PID || hwnd == peasant3PID)
|
||||
{
|
||||
*result = true;
|
||||
}
|
||||
else if (hwnd == peasant2PID)
|
||||
{
|
||||
*result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
manager->pfnIsWindowOnCurrentVirtualDesktop = firstCallback;
|
||||
|
||||
Remoting::SummonWindowSelectionArgs args;
|
||||
|
||||
Log::Comment(L"Summon window three - it is the MRU on desktop 1");
|
||||
p3ExpectedToBeSummoned = true;
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
|
||||
{
|
||||
Log::Comment(L"Activate the first peasant, first desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
|
||||
p1->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid1,
|
||||
winrt::clock().now() };
|
||||
p1->ActivateWindow(activatedArgs);
|
||||
}
|
||||
|
||||
Log::Comment(L"Summon window one - it is the MRU on desktop 1");
|
||||
p1ExpectedToBeSummoned = true;
|
||||
p2ExpectedToBeSummoned = false;
|
||||
p3ExpectedToBeSummoned = false;
|
||||
args.FoundMatch(false);
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
|
||||
Log::Comment(L"Now we'll pretend we switched to desktop 2");
|
||||
|
||||
auto secondCallback = [&](HWND h, BOOL* result) -> HRESULT {
|
||||
Log::Comment(L"secondCallback: Checking if window is on desktop 2");
|
||||
const uint64_t hwnd = reinterpret_cast<uint64_t>(h);
|
||||
if (hwnd == peasant1PID || hwnd == peasant3PID)
|
||||
{
|
||||
*result = false;
|
||||
}
|
||||
else if (hwnd == peasant2PID)
|
||||
{
|
||||
*result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
manager->pfnIsWindowOnCurrentVirtualDesktop = secondCallback;
|
||||
|
||||
Log::Comment(L"Summon window one - it is the MRU on desktop 2");
|
||||
p1ExpectedToBeSummoned = false;
|
||||
p2ExpectedToBeSummoned = true;
|
||||
p3ExpectedToBeSummoned = false;
|
||||
args.FoundMatch(false);
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
|
||||
{
|
||||
Log::Comment(L"Activate the third peasant, second desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
|
||||
p3->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid2,
|
||||
winrt::clock().now() };
|
||||
p3->ActivateWindow(activatedArgs);
|
||||
}
|
||||
|
||||
auto thirdCallback = [&](HWND h, BOOL* result) -> HRESULT {
|
||||
Log::Comment(L"thirdCallback: Checking if window is on desktop 2. (windows 2 and 3 are)");
|
||||
const uint64_t hwnd = reinterpret_cast<uint64_t>(h);
|
||||
if (hwnd == peasant1PID)
|
||||
{
|
||||
*result = false;
|
||||
}
|
||||
else if (hwnd == peasant2PID || hwnd == peasant3PID)
|
||||
{
|
||||
*result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
manager->pfnIsWindowOnCurrentVirtualDesktop = thirdCallback;
|
||||
|
||||
Log::Comment(L"Summon window three - it is the MRU on desktop 2");
|
||||
p1ExpectedToBeSummoned = false;
|
||||
p2ExpectedToBeSummoned = false;
|
||||
p3ExpectedToBeSummoned = true;
|
||||
args.FoundMatch(false);
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
|
||||
Log::Comment(L"Now we'll pretend we switched to desktop 1");
|
||||
|
||||
auto fourthCallback = [&](HWND h, BOOL* result) -> HRESULT {
|
||||
Log::Comment(L"fourthCallback: Checking if window is on desktop 1. (window 1 is)");
|
||||
const uint64_t hwnd = reinterpret_cast<uint64_t>(h);
|
||||
if (hwnd == peasant1PID)
|
||||
{
|
||||
*result = true;
|
||||
}
|
||||
else if (hwnd == peasant2PID || hwnd == peasant3PID)
|
||||
{
|
||||
*result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
manager->pfnIsWindowOnCurrentVirtualDesktop = fourthCallback;
|
||||
|
||||
Log::Comment(L"Summon window one - it is the only window on desktop 1");
|
||||
p1ExpectedToBeSummoned = true;
|
||||
p2ExpectedToBeSummoned = false;
|
||||
p3ExpectedToBeSummoned = false;
|
||||
args.FoundMatch(false);
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
|
||||
Log::Comment(L"Now we'll pretend we switched to desktop 3");
|
||||
|
||||
auto fifthCallback = [&](HWND h, BOOL* result) -> HRESULT {
|
||||
Log::Comment(L"fifthCallback: Checking if window is on desktop 3. (none are)");
|
||||
const uint64_t hwnd = reinterpret_cast<uint64_t>(h);
|
||||
if (hwnd == peasant1PID || hwnd == peasant2PID || hwnd == peasant3PID)
|
||||
{
|
||||
*result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
manager->pfnIsWindowOnCurrentVirtualDesktop = fifthCallback;
|
||||
|
||||
Log::Comment(L"This summon won't find a window.");
|
||||
p1ExpectedToBeSummoned = false;
|
||||
p2ExpectedToBeSummoned = false;
|
||||
p3ExpectedToBeSummoned = false;
|
||||
args.FoundMatch(false);
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_FALSE(args.FoundMatch());
|
||||
}
|
||||
|
||||
void RemotingTests::TestSummonOnCurrentWithName()
|
||||
{
|
||||
Log::Comment(L"Test that specifying a WindowName forces us to ignore OnCurrentDesktop");
|
||||
|
||||
const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
|
||||
const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };
|
||||
|
||||
constexpr auto monarch0PID = 12345u;
|
||||
constexpr auto peasant1PID = 23456u;
|
||||
constexpr auto peasant2PID = 34567u;
|
||||
constexpr auto peasant3PID = 45678u;
|
||||
|
||||
com_ptr<Remoting::implementation::Monarch> m0;
|
||||
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p1;
|
||||
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p2;
|
||||
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p3;
|
||||
p3.attach(new Remoting::implementation::Peasant(peasant3PID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
VERIFY_IS_NOT_NULL(p3);
|
||||
p1->WindowName(L"one");
|
||||
p2->WindowName(L"two");
|
||||
p3->WindowName(L"three");
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p3->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
m0->AddPeasant(*p3);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
VERIFY_ARE_EQUAL(3, p3->GetID());
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, m0->_peasants.size());
|
||||
|
||||
bool p1ExpectedToBeSummoned = false;
|
||||
bool p2ExpectedToBeSummoned = false;
|
||||
bool p3ExpectedToBeSummoned = false;
|
||||
|
||||
p1->SummonRequested([&](auto&&, auto&&) {
|
||||
Log::Comment(L"p1 summoned");
|
||||
VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
|
||||
});
|
||||
p2->SummonRequested([&](auto&&, auto&&) {
|
||||
Log::Comment(L"p2 summoned");
|
||||
VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
|
||||
});
|
||||
p3->SummonRequested([&](auto&&, auto&&) {
|
||||
Log::Comment(L"p3 summoned");
|
||||
VERIFY_IS_TRUE(p3ExpectedToBeSummoned);
|
||||
});
|
||||
|
||||
{
|
||||
Log::Comment(L"Activate the first peasant, first desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
|
||||
p1->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid1,
|
||||
winrt::clock().now() };
|
||||
p1->ActivateWindow(activatedArgs);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Activate the second peasant, second desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
|
||||
p2->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid2,
|
||||
winrt::clock().now() };
|
||||
p2->ActivateWindow(activatedArgs);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Activate the third peasant, first desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
|
||||
p3->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid1,
|
||||
winrt::clock().now() };
|
||||
p3->ActivateWindow(activatedArgs);
|
||||
}
|
||||
|
||||
Log::Comment(L"Create a mock IVirtualDesktopManager to handle checking if a window is on a given desktop");
|
||||
winrt::com_ptr<MockDesktopManager> manager;
|
||||
manager.attach(new MockDesktopManager());
|
||||
m0->_desktopManager = manager.try_as<IVirtualDesktopManager>();
|
||||
|
||||
auto firstCallback = [&](HWND h, BOOL* result) -> HRESULT {
|
||||
Log::Comment(L"firstCallback: Checking if window is on desktop 1");
|
||||
|
||||
const uint64_t hwnd = reinterpret_cast<uint64_t>(h);
|
||||
if (hwnd == peasant1PID || hwnd == peasant3PID)
|
||||
{
|
||||
*result = true;
|
||||
}
|
||||
else if (hwnd == peasant2PID)
|
||||
{
|
||||
*result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
manager->pfnIsWindowOnCurrentVirtualDesktop = firstCallback;
|
||||
|
||||
Remoting::SummonWindowSelectionArgs args;
|
||||
|
||||
Log::Comment(L"Summon window three - it is the MRU on desktop 1");
|
||||
p3ExpectedToBeSummoned = true;
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
|
||||
Log::Comment(L"Look for window 1 by name. When given a name, we don't care about OnCurrentDesktop.");
|
||||
p1ExpectedToBeSummoned = true;
|
||||
p2ExpectedToBeSummoned = false;
|
||||
p3ExpectedToBeSummoned = false;
|
||||
args.FoundMatch(false);
|
||||
args.WindowName(L"one");
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
|
||||
Log::Comment(L"Look for window 2 by name. When given a name, we don't care about OnCurrentDesktop.");
|
||||
p1ExpectedToBeSummoned = false;
|
||||
p2ExpectedToBeSummoned = true;
|
||||
p3ExpectedToBeSummoned = false;
|
||||
args.FoundMatch(false);
|
||||
args.WindowName(L"two");
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
|
||||
Log::Comment(L"Look for window 3 by name. When given a name, we don't care about OnCurrentDesktop.");
|
||||
p1ExpectedToBeSummoned = false;
|
||||
p2ExpectedToBeSummoned = false;
|
||||
p3ExpectedToBeSummoned = true;
|
||||
args.FoundMatch(false);
|
||||
args.WindowName(L"three");
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
}
|
||||
|
||||
void RemotingTests::TestSummonOnCurrentDeadWindow()
|
||||
{
|
||||
Log::Comment(L"Test that we can summon a window on the current desktop,"
|
||||
L" when the MRU window on that desktop dies.");
|
||||
|
||||
const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
|
||||
const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };
|
||||
|
||||
constexpr auto monarch0PID = 12345u;
|
||||
constexpr auto peasant1PID = 23456u;
|
||||
constexpr auto peasant2PID = 34567u;
|
||||
constexpr auto peasant3PID = 45678u;
|
||||
|
||||
com_ptr<Remoting::implementation::Monarch> m0;
|
||||
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p1;
|
||||
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p2;
|
||||
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p3;
|
||||
p3.attach(new Remoting::implementation::Peasant(peasant3PID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
VERIFY_IS_NOT_NULL(p3);
|
||||
p1->WindowName(L"one");
|
||||
p2->WindowName(L"two");
|
||||
p3->WindowName(L"three");
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p3->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
m0->AddPeasant(*p3);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
VERIFY_ARE_EQUAL(3, p3->GetID());
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, m0->_peasants.size());
|
||||
|
||||
bool p1ExpectedToBeSummoned = false;
|
||||
bool p2ExpectedToBeSummoned = false;
|
||||
bool p3ExpectedToBeSummoned = false;
|
||||
|
||||
p1->SummonRequested([&](auto&&, auto&&) {
|
||||
Log::Comment(L"p1 summoned");
|
||||
VERIFY_IS_TRUE(p1ExpectedToBeSummoned);
|
||||
});
|
||||
p2->SummonRequested([&](auto&&, auto&&) {
|
||||
Log::Comment(L"p2 summoned");
|
||||
VERIFY_IS_TRUE(p2ExpectedToBeSummoned);
|
||||
});
|
||||
p3->SummonRequested([&](auto&&, auto&&) {
|
||||
Log::Comment(L"p3 summoned");
|
||||
VERIFY_IS_TRUE(p3ExpectedToBeSummoned);
|
||||
});
|
||||
|
||||
{
|
||||
Log::Comment(L"Activate the first peasant, first desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
|
||||
p1->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid1,
|
||||
winrt::clock().now() };
|
||||
p1->ActivateWindow(activatedArgs);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Activate the second peasant, second desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
|
||||
p2->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid2,
|
||||
winrt::clock().now() };
|
||||
p2->ActivateWindow(activatedArgs);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Activate the third peasant, first desktop");
|
||||
Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
|
||||
p3->GetPID(), // USE PID as HWND, because these values don't _really_ matter
|
||||
guid1,
|
||||
winrt::clock().now() };
|
||||
p3->ActivateWindow(activatedArgs);
|
||||
}
|
||||
|
||||
Log::Comment(L"Create a mock IVirtualDesktopManager to handle checking if a window is on a given desktop");
|
||||
winrt::com_ptr<MockDesktopManager> manager;
|
||||
manager.attach(new MockDesktopManager());
|
||||
m0->_desktopManager = manager.try_as<IVirtualDesktopManager>();
|
||||
|
||||
auto firstCallback = [&](HWND h, BOOL* result) -> HRESULT {
|
||||
Log::Comment(L"firstCallback: Checking if window is on desktop 1");
|
||||
|
||||
const uint64_t hwnd = reinterpret_cast<uint64_t>(h);
|
||||
if (hwnd == peasant1PID || hwnd == peasant3PID)
|
||||
{
|
||||
*result = true;
|
||||
}
|
||||
else if (hwnd == peasant2PID)
|
||||
{
|
||||
*result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_IS_TRUE(false, L"IsWindowOnCurrentVirtualDesktop called with unexpected value");
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
manager->pfnIsWindowOnCurrentVirtualDesktop = firstCallback;
|
||||
|
||||
Remoting::SummonWindowSelectionArgs args;
|
||||
|
||||
Log::Comment(L"Summon window three - it is the MRU on desktop 1");
|
||||
p3ExpectedToBeSummoned = true;
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
|
||||
Log::Comment(L"Kill window 3. Window 1 is now the MRU on desktop 1.");
|
||||
RemotingTests::_killPeasant(m0, p3->GetID());
|
||||
|
||||
Log::Comment(L"Summon window three - it is the MRU on desktop 1");
|
||||
p1ExpectedToBeSummoned = true;
|
||||
p2ExpectedToBeSummoned = false;
|
||||
p3ExpectedToBeSummoned = false;
|
||||
args.FoundMatch(false);
|
||||
args.OnCurrentDesktop(true);
|
||||
m0->SummonWindow(args);
|
||||
VERIFY_IS_TRUE(args.FoundMatch());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../types/inc/User32Utils.hpp"
|
||||
#include "../WinRTUtils/inc/WtExeUtils.h"
|
||||
#include "resource.h"
|
||||
#include "VirtualDesktopUtils.h"
|
||||
|
||||
using namespace winrt::Windows::UI;
|
||||
using namespace winrt::Windows::UI::Composition;
|
||||
|
@ -686,6 +687,12 @@ void AppHost::_GlobalHotkeyPressed(const long hotkeyIndex)
|
|||
{
|
||||
Remoting::SummonWindowSelectionArgs args{ summonArgs.Name() };
|
||||
|
||||
// desktop:any - MoveToCurrentDesktop=false, OnCurrentDesktop=false
|
||||
// desktop:toCurrent - MoveToCurrentDesktop=true, OnCurrentDesktop=false
|
||||
// desktop:onCurrent - MoveToCurrentDesktop=false, OnCurrentDesktop=true
|
||||
args.OnCurrentDesktop(summonArgs.Desktop() == Settings::Model::DesktopBehavior::OnCurrent);
|
||||
args.SummonBehavior().MoveToCurrentDesktop(summonArgs.Desktop() == Settings::Model::DesktopBehavior::ToCurrent);
|
||||
|
||||
_windowManager.SummonWindow(args);
|
||||
if (args.FoundMatch())
|
||||
{
|
||||
|
@ -740,24 +747,65 @@ winrt::fire_and_forget AppHost::_createNewTerminalWindow(Settings::Model::Global
|
|||
co_return;
|
||||
}
|
||||
|
||||
void AppHost::_HandleSummon(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
// Method Description:
|
||||
// - Helper to initialize our instance of IVirtualDesktopManager. If we already
|
||||
// got one, then this will just return true. Otherwise, we'll try and init a
|
||||
// new instance of one, and store that.
|
||||
// - This will return false if we weren't able to initialize one, which I'm not
|
||||
// sure is actually possible.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - true iff _desktopManager points to a non-null instance of IVirtualDesktopManager
|
||||
bool AppHost::_LazyLoadDesktopManager()
|
||||
{
|
||||
_window->SummonWindow();
|
||||
if (_desktopManager == nullptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
_desktopManager = winrt::create_instance<IVirtualDesktopManager>(__uuidof(VirtualDesktopManager));
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
||||
return _desktopManager != nullptr;
|
||||
}
|
||||
|
||||
void AppHost::_HandleSummon(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const Remoting::SummonWindowBehavior& args)
|
||||
{
|
||||
_window->SummonWindow();
|
||||
|
||||
if (args != nullptr && args.MoveToCurrentDesktop())
|
||||
{
|
||||
if (_LazyLoadDesktopManager())
|
||||
{
|
||||
GUID currentlyActiveDesktop{ 0 };
|
||||
if (VirtualDesktopUtils::GetCurrentVirtualDesktopId(¤tlyActiveDesktop))
|
||||
{
|
||||
LOG_IF_FAILED(_desktopManager->MoveWindowToDesktop(_window->GetHandle(), currentlyActiveDesktop));
|
||||
}
|
||||
// If GetCurrentVirtualDesktopId failed, then just leave the window
|
||||
// where it is. Nothing else to be done :/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This gets the GUID of the desktop our window is currently on. It does NOT
|
||||
// get the GUID of the desktop that's currently active.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - the GUID of the desktop our window is currently on
|
||||
GUID AppHost::_CurrentDesktopGuid()
|
||||
{
|
||||
GUID currentDesktopGuid{ 0 };
|
||||
try
|
||||
const auto manager = winrt::create_instance<IVirtualDesktopManager>(__uuidof(VirtualDesktopManager));
|
||||
if (_LazyLoadDesktopManager())
|
||||
{
|
||||
const auto manager = winrt::create_instance<IVirtualDesktopManager>(__uuidof(VirtualDesktopManager));
|
||||
if (manager)
|
||||
{
|
||||
LOG_IF_FAILED(manager->GetWindowDesktopId(_window->GetHandle(), ¤tDesktopGuid));
|
||||
}
|
||||
LOG_IF_FAILED(_desktopManager->GetWindowDesktopId(_window->GetHandle(), ¤tDesktopGuid));
|
||||
}
|
||||
CATCH_LOG();
|
||||
return currentDesktopGuid;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ private:
|
|||
std::vector<winrt::Microsoft::Terminal::Control::KeyChord> _hotkeys{};
|
||||
winrt::Windows::Foundation::Collections::IMap<winrt::Microsoft::Terminal::Control::KeyChord, winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _hotkeyActions{ nullptr };
|
||||
|
||||
winrt::com_ptr<IVirtualDesktopManager> _desktopManager{ nullptr };
|
||||
|
||||
void _HandleCommandlineArgs();
|
||||
|
||||
void _HandleCreateWindow(const HWND hwnd, RECT proposedRect, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode);
|
||||
|
@ -59,7 +61,7 @@ private:
|
|||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
void _GlobalHotkeyPressed(const long hotkeyIndex);
|
||||
void _HandleSummon(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
const winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior& args);
|
||||
|
||||
winrt::fire_and_forget _IdentifyWindowsRequested(const winrt::Windows::Foundation::IInspectable sender,
|
||||
const winrt::Windows::Foundation::IInspectable args);
|
||||
|
@ -70,6 +72,8 @@ private:
|
|||
|
||||
GUID _CurrentDesktopGuid();
|
||||
|
||||
bool _LazyLoadDesktopManager();
|
||||
|
||||
winrt::fire_and_forget _setupGlobalHotkeys();
|
||||
winrt::fire_and_forget _createNewTerminalWindow(winrt::Microsoft::Terminal::Settings::Model::GlobalSummonArgs args);
|
||||
void _HandleSettingsChanged(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
|
|
|
@ -956,9 +956,9 @@ void IslandWindow::UnsetHotkeys(const std::vector<winrt::Microsoft::Terminal::Co
|
|||
TraceLoggingInt64(hotkeyList.size(), "numHotkeys", "The number of hotkeys to unset"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
|
||||
for (size_t i = 0; i < hotkeyList.size(); i++)
|
||||
for (int i = 0; i < ::base::saturated_cast<int>(hotkeyList.size()); i++)
|
||||
{
|
||||
LOG_IF_WIN32_BOOL_FALSE(UnregisterHotKey(_window.get(), static_cast<int>(i)));
|
||||
LOG_IF_WIN32_BOOL_FALSE(UnregisterHotKey(_window.get(), i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
173
src/cascadia/WindowsTerminal/VirtualDesktopUtils.cpp
Normal file
173
src/cascadia/WindowsTerminal/VirtualDesktopUtils.cpp
Normal file
|
@ -0,0 +1,173 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Shamelessly copied from microsoft/PowerToys, at
|
||||
// https://github.com/microsoft/PowerToys/blob/master/src/modules/fancyzones/lib/VirtualDesktopUtils.cpp
|
||||
//
|
||||
// The code style is left (relatively) untouched, as to make contributions
|
||||
// from/to the upstream source easier. `NewGetCurrentDesktopId` was added in
|
||||
// April 2021.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "VirtualDesktopUtils.h"
|
||||
|
||||
// Non-Localizable strings
|
||||
namespace NonLocalizable
|
||||
{
|
||||
const wchar_t RegCurrentVirtualDesktop[] = L"CurrentVirtualDesktop";
|
||||
const wchar_t RegVirtualDesktopIds[] = L"VirtualDesktopIDs";
|
||||
const wchar_t RegKeyVirtualDesktops[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VirtualDesktops";
|
||||
const wchar_t RegKeyVirtualDesktopsFromSession[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops";
|
||||
}
|
||||
|
||||
namespace VirtualDesktopUtils
|
||||
{
|
||||
// Look for the guid stored as the value `CurrentVirtualDesktop` under the
|
||||
// key
|
||||
// `HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\VirtualDesktops`
|
||||
bool NewGetCurrentDesktopId(GUID* desktopId)
|
||||
{
|
||||
wil::unique_hkey key{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
GUID value{};
|
||||
DWORD size = sizeof(GUID);
|
||||
if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
*desktopId = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetDesktopIdFromCurrentSession(GUID* desktopId)
|
||||
{
|
||||
DWORD sessionId;
|
||||
if (!ProcessIdToSessionId(GetCurrentProcessId(), &sessionId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t sessionKeyPath[256]{};
|
||||
if (FAILED(StringCchPrintfW(sessionKeyPath, ARRAYSIZE(sessionKeyPath), NonLocalizable::RegKeyVirtualDesktopsFromSession, sessionId)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wil::unique_hkey key{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
GUID value{};
|
||||
DWORD size = sizeof(GUID);
|
||||
if (RegQueryValueExW(key.get(), NonLocalizable::RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
*desktopId = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetVirtualDesktopIds(HKEY hKey, std::vector<GUID>& ids)
|
||||
{
|
||||
if (!hKey)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DWORD bufferCapacity;
|
||||
// request regkey binary buffer capacity only
|
||||
if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, nullptr, &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<BYTE[]> buffer = std::make_unique<BYTE[]>(bufferCapacity);
|
||||
// request regkey binary content
|
||||
if (RegQueryValueExW(hKey, NonLocalizable::RegVirtualDesktopIds, 0, nullptr, buffer.get(), &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const size_t guidSize = sizeof(GUID);
|
||||
std::vector<GUID> temp;
|
||||
temp.reserve(bufferCapacity / guidSize);
|
||||
for (size_t i = 0; i < bufferCapacity; i += guidSize)
|
||||
{
|
||||
GUID* guid = reinterpret_cast<GUID*>(buffer.get() + i);
|
||||
temp.push_back(*guid);
|
||||
}
|
||||
ids = std::move(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
HKEY OpenVirtualDesktopsRegKey()
|
||||
{
|
||||
HKEY hKey{ nullptr };
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER, NonLocalizable::RegKeyVirtualDesktops, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
return hKey;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HKEY GetVirtualDesktopsRegKey()
|
||||
{
|
||||
static wil::unique_hkey virtualDesktopsKey{ OpenVirtualDesktopsRegKey() };
|
||||
return virtualDesktopsKey.get();
|
||||
}
|
||||
bool GetVirtualDesktopIds(std::vector<GUID>& ids)
|
||||
{
|
||||
return GetVirtualDesktopIds(GetVirtualDesktopsRegKey(), ids);
|
||||
}
|
||||
|
||||
bool GetVirtualDesktopIds(std::vector<std::wstring>& ids)
|
||||
{
|
||||
std::vector<GUID> guids{};
|
||||
if (GetVirtualDesktopIds(guids))
|
||||
{
|
||||
for (auto& guid : guids)
|
||||
{
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (SUCCEEDED(StringFromCLSID(guid, &guidString)))
|
||||
{
|
||||
ids.push_back(guidString.get());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetCurrentVirtualDesktopId(GUID* desktopId)
|
||||
{
|
||||
// BODGY
|
||||
// On newer Windows builds, the current virtual desktop is persisted to
|
||||
// a totally different reg key. Look there first.
|
||||
if (NewGetCurrentDesktopId(desktopId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Explorer persists current virtual desktop identifier to registry on a per session basis, but only
|
||||
// after first virtual desktop switch happens. If the user hasn't switched virtual desktops in this
|
||||
// session, value in registry will be empty.
|
||||
if (GetDesktopIdFromCurrentSession(desktopId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Fallback scenario is to get array of virtual desktops stored in registry, but not kept per session.
|
||||
// Note that we are taking first element from virtual desktop array, which is primary desktop.
|
||||
// If user has more than one virtual desktop, previous function should return correct value, as desktop
|
||||
// switch occurred in current session.
|
||||
else
|
||||
{
|
||||
std::vector<GUID> ids{};
|
||||
if (GetVirtualDesktopIds(ids) && ids.size() > 0)
|
||||
{
|
||||
*desktopId = ids[0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
11
src/cascadia/WindowsTerminal/VirtualDesktopUtils.h
Normal file
11
src/cascadia/WindowsTerminal/VirtualDesktopUtils.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// A helper function for determining the GUID of the current Virtual Desktop.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace VirtualDesktopUtils
|
||||
{
|
||||
bool GetCurrentVirtualDesktopId(GUID* desktopId);
|
||||
}
|
|
@ -48,6 +48,7 @@
|
|||
<ClInclude Include="BaseWindow.h" />
|
||||
<ClInclude Include="IslandWindow.h" />
|
||||
<ClInclude Include="NonClientIslandWindow.h" />
|
||||
<ClInclude Include="VirtualDesktopUtils.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
|
@ -57,6 +58,7 @@
|
|||
<ClCompile Include="AppHost.cpp" />
|
||||
<ClCompile Include="IslandWindow.cpp" />
|
||||
<ClCompile Include="NonClientIslandWindow.cpp" />
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp" />
|
||||
<ClCompile Include="icon.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
Loading…
Reference in a new issue