зеркало из https://github.com/microsoft/terminal.git
Add support for renaming windows (#9662)
## Summary of the Pull Request This PR adds support for renaming windows. ![window-renaming-000](https://user-images.githubusercontent.com/18356694/113034344-9a30be00-9157-11eb-9443-975f3c294f56.gif) ![window-renaming-001](https://user-images.githubusercontent.com/18356694/113034452-b5033280-9157-11eb-9e35-e5ac80fef0bc.gif) It does so through two new actions: * `renameWindow` takes a `name` parameter, and attempts to set the window's name to the provided name. This is useful if you always want to hit <kbd>F3</kbd> and rename a window to "foo" (READ: probably not that useful) * `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a `TextBox`. When the user hits Ok, it'll request a rename for the provided value. This lets the user pick a new name for the window at runtime. In both cases, if there's already a window with that name, then the monarch will reject the rename, and pop a `Toast` in the window informing the user that the rename failed. Nifty! ## References * Builds on the toasts from #9523 * #5000 - process model megathread ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747 * [x] I work here * [x] Tests addded (and pass with the help of #9660) * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews. > PAIN: We can't immediately focus the textbox in the TeachingTip. It's > not technically focusable until it is opened. However, it doesn't > provide an even tto tell us when it is opened. That's tracked in > microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to > click on the text box manually. > We're also not using a ContentDialog for this, because in Xaml > Islands a text box in a ContentDialog won't recieve _any_ keypresses. > Fun! ## Validation Steps Performed I've been playing with ```json { "keys": "f1", "command": "identifyWindow" }, { "keys": "f2", "command": "identifyWindows" }, { "keys": "f3", "command": "openWindowRenamer" }, { "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } }, { "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } }, ``` and they seem to work as expected
This commit is contained in:
Родитель
4b7d955012
Коммит
fb597ed304
|
@ -85,12 +85,14 @@
|
|||
"openNewTabDropdown",
|
||||
"openSettings",
|
||||
"openTabColorPicker",
|
||||
"openWindowRenamer",
|
||||
"paste",
|
||||
"prevTab",
|
||||
"renameTab",
|
||||
"openTabRenamer",
|
||||
"resetFontSize",
|
||||
"resizePane",
|
||||
"renameWindow",
|
||||
"scrollDown",
|
||||
"scrollDownPage",
|
||||
"scrollUp",
|
||||
|
@ -651,6 +653,38 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"RenameTabAction": {
|
||||
"description": "Arguments corresponding to a renameTab Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "renameTab" },
|
||||
"title": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "A title to assign to the tab. If omitted or null, this action will restore the tab's title to the original value."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"RenameWindowAction": {
|
||||
"description": "Arguments corresponding to a renameWindow Action",
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/ShortcutAction" },
|
||||
{
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "renameWindow" },
|
||||
"name": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "A name to assign to the window."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Keybinding": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
|
@ -679,6 +713,8 @@
|
|||
{ "$ref": "#/definitions/NewWindowAction" },
|
||||
{ "$ref": "#/definitions/NextTabAction" },
|
||||
{ "$ref": "#/definitions/PrevTabAction" },
|
||||
{ "$ref": "#/definitions/RenameTabAction" },
|
||||
{ "$ref": "#/definitions/RenameWindowAction" },
|
||||
{ "type": "null" }
|
||||
]
|
||||
},
|
||||
|
|
|
@ -85,6 +85,9 @@ namespace TerminalAppLocalTests
|
|||
TEST_METHOD(NextMRUTab);
|
||||
TEST_METHOD(VerifyCommandPaletteTabSwitcherOrder);
|
||||
|
||||
TEST_METHOD(TestWindowRenameSuccessful);
|
||||
TEST_METHOD(TestWindowRenameFailure);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
return true;
|
||||
|
@ -948,4 +951,57 @@ namespace TerminalAppLocalTests
|
|||
// will also dismiss itself immediately when that's called. So we can't
|
||||
// really inspect the contents of the list in this test, unfortunately.
|
||||
}
|
||||
|
||||
void TabTests::TestWindowRenameSuccessful()
|
||||
{
|
||||
auto page = _commonSetup();
|
||||
page->RenameWindowRequested([&page](auto&&, const winrt::TerminalApp::RenameWindowRequestedArgs args) {
|
||||
// In the real terminal, this would bounce up to the monarch and
|
||||
// come back down. Instead, immediately call back and set the name.
|
||||
page->WindowName(args.ProposedName());
|
||||
});
|
||||
|
||||
bool windowNameChanged = false;
|
||||
page->PropertyChanged([&page, &windowNameChanged](auto&&, const winrt::WUX::Data::PropertyChangedEventArgs& args) mutable {
|
||||
if (args.PropertyName() == L"WindowNameForDisplay")
|
||||
{
|
||||
windowNameChanged = true;
|
||||
}
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
page->_RequestWindowRename(winrt::hstring{ L"Foo" });
|
||||
});
|
||||
TestOnUIThread([&]() {
|
||||
VERIFY_ARE_EQUAL(L"Foo", page->_WindowName);
|
||||
VERIFY_IS_TRUE(windowNameChanged,
|
||||
L"The window name should have changed, and we should have raised a notification that WindowNameForDisplay changed");
|
||||
});
|
||||
}
|
||||
void TabTests::TestWindowRenameFailure()
|
||||
{
|
||||
auto page = _commonSetup();
|
||||
page->RenameWindowRequested([&page](auto&&, auto&&) {
|
||||
// In the real terminal, this would bounce up to the monarch and
|
||||
// come back down. Instead, immediately call back to tell the terminal it failed.
|
||||
page->RenameFailed();
|
||||
});
|
||||
|
||||
bool windowNameChanged = false;
|
||||
|
||||
page->PropertyChanged([&page, &windowNameChanged](auto&&, const winrt::WUX::Data::PropertyChangedEventArgs& args) mutable {
|
||||
if (args.PropertyName() == L"WindowNameForDisplay")
|
||||
{
|
||||
windowNameChanged = true;
|
||||
}
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
page->_RequestWindowRename(winrt::hstring{ L"Foo" });
|
||||
});
|
||||
TestOnUIThread([&]() {
|
||||
VERIFY_IS_FALSE(windowNameChanged,
|
||||
L"The window name should not have changed, we should have rejected the change.");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ Author(s):
|
|||
#include <winrt/Windows.ui.input.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Windows.UI.Xaml.Data.h>
|
||||
#include <winrt/Windows.ui.xaml.media.h>
|
||||
#include <winrt/Windows.ui.xaml.input.h>
|
||||
#include <winrt/Windows.UI.Xaml.Markup.h>
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
<ClInclude Include="ProposeCommandlineResult.h">
|
||||
<DependentUpon>Monarch.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RenameRequestArgs.h">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowActivatedArgs.h">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
|
@ -51,6 +54,9 @@
|
|||
<ClCompile Include="ProposeCommandlineResult.cpp">
|
||||
<DependentUpon>Monarch.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RenameRequestArgs.cpp">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WindowActivatedArgs.cpp">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
|
|
|
@ -76,6 +76,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
// Add an event listener to the peasant's WindowActivated event.
|
||||
peasant.WindowActivated({ this, &Monarch::_peasantWindowActivated });
|
||||
peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows });
|
||||
peasant.RenameRequested({ this, &Monarch::_renameRequested });
|
||||
|
||||
_peasants[newPeasantsId] = peasant;
|
||||
|
||||
|
@ -631,4 +632,52 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
};
|
||||
_forAllPeasantsIgnoringTheDead(callback, onError);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This is an event handler for the RenameRequested event. A
|
||||
// Peasant may raise that event when they want to be renamed to something else.
|
||||
// - We will check if there are any other windows with this name. If there
|
||||
// are, then we'll reject the rename by setting args.Succeeded=false.
|
||||
// - If there aren't any other windows with this name, then we'll set
|
||||
// args.Succeeded=true, allowing the window to keep this name.
|
||||
// Arguments:
|
||||
// - args: Contains the requested window name and a boolean (Succeeded)
|
||||
// indicating if the request was successful.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Monarch::_renameRequested(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args)
|
||||
{
|
||||
bool successfullyRenamed = false;
|
||||
|
||||
try
|
||||
{
|
||||
args.Succeeded(false);
|
||||
const auto name{ args.NewName() };
|
||||
// Try to find a peasant that currently has this name
|
||||
const auto id = _lookupPeasantIdForName(name);
|
||||
if (_getPeasant(id) == nullptr)
|
||||
{
|
||||
// If there is one, then oh no! The requestor is not allowed to
|
||||
// be renamed.
|
||||
args.Succeeded(true);
|
||||
successfullyRenamed = true;
|
||||
}
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_renameRequested",
|
||||
TraceLoggingWideString(name.c_str(), "name", "The newly proposed name"),
|
||||
TraceLoggingInt64(successfullyRenamed, "successfullyRenamed", "true if the peasant is allowed to rename themselves to that name."),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
// If this fails, we don't _really_ care. The peasant died, but
|
||||
// they're the only one who cares about the result.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_renameRequested_Failed",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,11 +74,15 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
void _doHandleActivatePeasant(const winrt::com_ptr<winrt::Microsoft::Terminal::Remoting::implementation::WindowActivatedArgs>& args);
|
||||
void _clearOldMruEntries(const uint64_t peasantID);
|
||||
|
||||
void _forAllPeasantsIgnoringTheDead(std::function<void(const winrt::Microsoft::Terminal::Remoting::IPeasant&, const uint64_t)> callback,
|
||||
std::function<void(const uint64_t)> errorCallback);
|
||||
|
||||
void _identifyWindows(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
void _forAllPeasantsIgnoringTheDead(std::function<void(const winrt::Microsoft::Terminal::Remoting::IPeasant&, const uint64_t)> callback,
|
||||
std::function<void(const uint64_t)> errorCallback);
|
||||
void _renameRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
|
||||
|
||||
friend class RemotingUnitTests::RemotingTests;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -164,4 +164,34 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
|
||||
void Peasant::RequestRename(const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args)
|
||||
{
|
||||
bool successfullyNotified = false;
|
||||
const auto oldName{ _WindowName };
|
||||
try
|
||||
{
|
||||
// Try/catch this, because the other side of this event is handled
|
||||
// by the monarch. The monarch might have died. If they have, this
|
||||
// will throw an exception. Just eat it, the election thread will
|
||||
// handle hooking up the new one.
|
||||
_RenameRequestedHandlers(*this, args);
|
||||
if (args.Succeeded())
|
||||
{
|
||||
_WindowName = args.NewName();
|
||||
}
|
||||
successfullyNotified = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Peasant_RequestRename",
|
||||
TraceLoggingUInt64(GetID(), "peasantID", "Our ID"),
|
||||
TraceLoggingWideString(oldName.c_str(), "oldName", "Our old name"),
|
||||
TraceLoggingWideString(args.NewName().c_str(), "newName", "The proposed name"),
|
||||
TraceLoggingBoolean(args.Succeeded(), "succeeded", "true if the monarch ok'd this new name for us."),
|
||||
TraceLoggingBoolean(successfullyNotified, "successfullyNotified", "true if we successfully notified the monarch"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "Peasant.g.h"
|
||||
#include "../cascadia/inc/cppwinrt_utils.h"
|
||||
#include "RenameRequestArgs.h"
|
||||
|
||||
namespace RemotingUnitTests
|
||||
{
|
||||
|
@ -24,6 +25,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
void ActivateWindow(const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args);
|
||||
void RequestIdentifyWindows();
|
||||
void DisplayWindowId();
|
||||
void RequestRename(const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs();
|
||||
|
||||
|
@ -34,6 +36,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::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, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
|
||||
|
||||
private:
|
||||
Peasant(const uint64_t testPID);
|
||||
|
|
|
@ -13,6 +13,13 @@ namespace Microsoft.Terminal.Remoting
|
|||
String CurrentDirectory();
|
||||
};
|
||||
|
||||
runtimeclass RenameRequestArgs
|
||||
{
|
||||
RenameRequestArgs(String newName);
|
||||
String NewName { get; };
|
||||
Boolean Succeeded;
|
||||
};
|
||||
|
||||
runtimeclass WindowActivatedArgs
|
||||
{
|
||||
WindowActivatedArgs(UInt64 peasantID, Guid desktopID, Windows.Foundation.DateTime activatedTime);
|
||||
|
@ -37,10 +44,13 @@ namespace Microsoft.Terminal.Remoting
|
|||
void RequestIdentifyWindows(); // Tells us to raise a IdentifyWindowsRequested
|
||||
void DisplayWindowId(); // Tells us to display its own ID (which causes a DisplayWindowIdRequested to be raised)
|
||||
|
||||
void RequestRename(RenameRequestArgs args); // Tells us to raise a RenameRequested
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass Peasant : IPeasant
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
#include "pch.h"
|
||||
#include "RenameRequestArgs.h"
|
||||
#include "RenameRequestArgs.g.cpp"
|
|
@ -0,0 +1,30 @@
|
|||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Class Name:
|
||||
- RenameRequestArgs.h
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "RenameRequestArgs.g.h"
|
||||
#include "../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct RenameRequestArgs : public RenameRequestArgsT<RenameRequestArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, NewName);
|
||||
WINRT_PROPERTY(bool, Succeeded, false);
|
||||
|
||||
public:
|
||||
RenameRequestArgs(winrt::hstring newName) :
|
||||
_NewName{ newName } {};
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(RenameRequestArgs);
|
||||
}
|
|
@ -708,4 +708,47 @@ namespace winrt::TerminalApp::implementation
|
|||
IdentifyWindow();
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleRenameWindow(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<RenameWindowArgs>())
|
||||
{
|
||||
const auto newName = realArgs.Name();
|
||||
const auto request = winrt::make_self<implementation::RenameWindowRequestedArgs>(newName);
|
||||
_RenameWindowRequestedHandlers(*this, *request);
|
||||
}
|
||||
}
|
||||
args.Handled(false);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleOpenWindowRenamer(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (WindowRenamer() == nullptr)
|
||||
{
|
||||
// We need to use FindName to lazy-load this object
|
||||
if (MUX::Controls::TeachingTip tip{ FindName(L"WindowRenamer").try_as<MUX::Controls::TeachingTip>() })
|
||||
{
|
||||
tip.Closed({ get_weak(), &TerminalPage::_FocusActiveControl });
|
||||
}
|
||||
}
|
||||
|
||||
WindowRenamer().IsOpen(true);
|
||||
|
||||
// PAIN: We can't immediately focus the textbox in the TeachingTip. It's
|
||||
// not technically focusable until it is opened. However, it doesn't
|
||||
// provide an event to tell us when it is opened. That's tracked in
|
||||
// microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to
|
||||
// click on the text box manually.
|
||||
//
|
||||
// We're also not using a ContentDialog for this, because in Xaml
|
||||
// Islands a text box in a ContentDialog won't receive _any_ keypresses.
|
||||
// Fun!
|
||||
// WindowRenamerTextBox().Focus(FocusState::Programmatic);
|
||||
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1410,4 +1410,13 @@ namespace winrt::TerminalApp::implementation
|
|||
_root->WindowId(id);
|
||||
}
|
||||
}
|
||||
|
||||
void AppLogic::RenameFailed()
|
||||
{
|
||||
if (_root)
|
||||
{
|
||||
_root->RenameFailed();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace winrt::TerminalApp::implementation
|
|||
bool AlwaysOnTop() const;
|
||||
|
||||
void IdentifyWindow();
|
||||
void RenameFailed();
|
||||
winrt::hstring WindowName();
|
||||
void WindowName(const winrt::hstring& name);
|
||||
uint64_t WindowId();
|
||||
|
@ -156,6 +157,7 @@ namespace winrt::TerminalApp::implementation
|
|||
FORWARDED_TYPED_EVENT(RaiseVisualBell, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, RaiseVisualBell);
|
||||
FORWARDED_TYPED_EVENT(SetTaskbarProgress, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, SetTaskbarProgress);
|
||||
FORWARDED_TYPED_EVENT(IdentifyWindowsRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IdentifyWindowsRequested);
|
||||
FORWARDED_TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs, _root, RenameWindowRequested);
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TerminalAppLocalTests::CommandlineTest;
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace TerminalApp
|
|||
void IdentifyWindow();
|
||||
String WindowName;
|
||||
UInt64 WindowId;
|
||||
void RenameFailed();
|
||||
|
||||
Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi);
|
||||
Boolean CenterOnLaunch { get; };
|
||||
|
@ -83,5 +84,6 @@ namespace TerminalApp
|
|||
event Windows.Foundation.TypedEventHandler<Object, Object> RaiseVisualBell;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -603,10 +603,25 @@
|
|||
<value>unnamed window</value>
|
||||
<comment>text used to identify when a window hasn't been assigned a name by the user</comment>
|
||||
</data>
|
||||
<data name="WindowRenamer.Subtitle" xml:space="preserve">
|
||||
<value>Enter a new name:</value>
|
||||
</data>
|
||||
<data name="WindowRenamer.ActionButtonContent" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="WindowRenamer.CloseButtonContent" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="RenameFailedToast.Title" xml:space="preserve">
|
||||
<value>Failed to rename window</value>
|
||||
</data>
|
||||
<data name="RenameFailedToast.Subtitle" xml:space="preserve">
|
||||
<value>Another window with that name already exists</value>
|
||||
</data>
|
||||
<data name="WindowMaximizeButtonToolTip" xml:space="preserve">
|
||||
<value>Maximize</value>
|
||||
</data>
|
||||
<data name="WindowRestoreDownButtonToolTip" xml:space="preserve">
|
||||
<value>Restore Down</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
|
@ -15,6 +15,7 @@
|
|||
#include "ColorHelper.h"
|
||||
#include "DebugTapConnection.h"
|
||||
#include "SettingsTab.h"
|
||||
#include "RenameWindowRequestedArgs.g.cpp"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
|
@ -2568,7 +2569,7 @@ namespace winrt::TerminalApp::implementation
|
|||
if (_WindowName != value)
|
||||
{
|
||||
_WindowName = value;
|
||||
_PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"WindowNameForDisplay" });
|
||||
_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"WindowNameForDisplay" });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2584,7 +2585,7 @@ namespace winrt::TerminalApp::implementation
|
|||
if (_WindowId != value)
|
||||
{
|
||||
_WindowId = value;
|
||||
_PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"WindowIdForDisplay" });
|
||||
_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"WindowIdForDisplay" });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2613,4 +2614,72 @@ namespace winrt::TerminalApp::implementation
|
|||
winrt::hstring{ fmt::format(L"<{}>", RS_(L"UnnamedWindowName")) } :
|
||||
_WindowName;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when an attempt to rename the window has failed. This will open
|
||||
// the toast displaying a message to the user that the attempt to rename
|
||||
// the window has failed.
|
||||
// - This will load the RenameFailedToast TeachingTip the first time it's called.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget TerminalPage::RenameFailed()
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
co_await winrt::resume_foreground(Dispatcher());
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
// If we haven't ever loaded the TeachingTip, then do so now and
|
||||
// create the toast for it.
|
||||
if (page->_windowRenameFailedToast == nullptr)
|
||||
{
|
||||
if (MUX::Controls::TeachingTip tip{ page->FindName(L"RenameFailedToast").try_as<MUX::Controls::TeachingTip>() })
|
||||
{
|
||||
page->_windowRenameFailedToast = std::make_shared<Toast>(tip);
|
||||
// Make sure to use the weak ref when setting up this
|
||||
// callback.
|
||||
tip.Closed({ page->get_weak(), &TerminalPage::_FocusActiveControl });
|
||||
}
|
||||
}
|
||||
|
||||
if (page->_windowRenameFailedToast != nullptr)
|
||||
{
|
||||
page->_windowRenameFailedToast->Open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the user hits the "Ok" button on the WindowRenamer TeachingTip.
|
||||
// - Will raise an event that will bubble up to the monarch, asking if this
|
||||
// name is acceptable.
|
||||
// - If it is, we'll eventually get called back in TerminalPage::WindowName(hstring).
|
||||
// - If not, then TerminalPage::RenameFailed will get called.
|
||||
// Arguments:
|
||||
// - <unused>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_WindowRenamerActionClick(const IInspectable& /*sender*/,
|
||||
const IInspectable& /*eventArgs*/)
|
||||
{
|
||||
auto newName = WindowRenamerTextBox().Text();
|
||||
_RequestWindowRename(newName);
|
||||
}
|
||||
|
||||
void TerminalPage::_RequestWindowRename(const winrt::hstring& newName)
|
||||
{
|
||||
auto request = winrt::make<implementation::RenameWindowRequestedArgs>(newName);
|
||||
// The WindowRenamer is _not_ a Toast - we want it to stay open until the user dismisses it.
|
||||
WindowRenamer().IsOpen(false);
|
||||
_RenameWindowRequestedHandlers(*this, request);
|
||||
// We can't just use request.Successful here, because the handler might
|
||||
// (will) be handling this asynchronously, so when control returns to
|
||||
// us, this hasn't actually been handled yet. We'll get called back in
|
||||
// RenameFailed if this fails.
|
||||
//
|
||||
// Theoretically we could do a IAsyncOperation<RenameWindowResult> kind
|
||||
// of thing with co_return winrt::make<RenameWindowResult>(false).
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "TerminalTab.h"
|
||||
#include "AppKeyBindings.h"
|
||||
#include "AppCommandlineArgs.h"
|
||||
#include "RenameWindowRequestedArgs.g.h"
|
||||
#include "Toast.h"
|
||||
|
||||
#define DECLARE_ACTION_HANDLER(action) void _Handle##action(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
|
@ -35,6 +36,15 @@ namespace winrt::TerminalApp::implementation
|
|||
ScrollDown = 1
|
||||
};
|
||||
|
||||
struct RenameWindowRequestedArgs : RenameWindowRequestedArgsT<RenameWindowRequestedArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, ProposedName);
|
||||
|
||||
public:
|
||||
RenameWindowRequestedArgs(const winrt::hstring& name) :
|
||||
_ProposedName{ name } {};
|
||||
};
|
||||
|
||||
struct TerminalPage : TerminalPageT<TerminalPage>
|
||||
{
|
||||
public:
|
||||
|
@ -82,6 +92,7 @@ namespace winrt::TerminalApp::implementation
|
|||
winrt::hstring KeyboardServiceDisabledText();
|
||||
|
||||
winrt::fire_and_forget IdentifyWindow();
|
||||
winrt::fire_and_forget RenameFailed();
|
||||
|
||||
winrt::fire_and_forget ProcessStartupActions(Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
|
||||
const bool initial,
|
||||
|
@ -110,6 +121,7 @@ namespace winrt::TerminalApp::implementation
|
|||
TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable);
|
||||
TYPED_EVENT(Initialized, IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
TYPED_EVENT(IdentifyWindowsRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs);
|
||||
|
||||
private:
|
||||
friend struct TerminalPageT<TerminalPage>; // for Xaml to bind events
|
||||
|
@ -162,6 +174,7 @@ namespace winrt::TerminalApp::implementation
|
|||
bool _shouldStartInboundListener{ false };
|
||||
|
||||
std::shared_ptr<Toast> _windowIdToast{ nullptr };
|
||||
std::shared_ptr<Toast> _windowRenameFailedToast{ nullptr };
|
||||
|
||||
void _ShowAboutDialog();
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCloseWarningDialog();
|
||||
|
@ -311,6 +324,9 @@ namespace winrt::TerminalApp::implementation
|
|||
void _OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||
void _HandleToggleInboundPty(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
|
||||
void _WindowRenamerActionClick(const IInspectable& sender, const IInspectable& eventArgs);
|
||||
void _RequestWindowRename(const winrt::hstring& newName);
|
||||
|
||||
#pragma region ActionHandlers
|
||||
// These are all defined in AppActionHandlers.cpp
|
||||
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);
|
||||
|
|
|
@ -5,6 +5,11 @@ namespace TerminalApp
|
|||
{
|
||||
delegate void LastTabClosedEventArgs();
|
||||
|
||||
[default_interface] runtimeclass RenameWindowRequestedArgs
|
||||
{
|
||||
String ProposedName { get; };
|
||||
};
|
||||
|
||||
interface IDialogPresenter
|
||||
{
|
||||
Windows.Foundation.IAsyncOperation<Windows.UI.Xaml.Controls.ContentDialogResult> ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog);
|
||||
|
@ -27,6 +32,7 @@ namespace TerminalApp
|
|||
UInt64 WindowId;
|
||||
String WindowNameForDisplay { get; };
|
||||
String WindowIdForDisplay { get; };
|
||||
void RenameFailed();
|
||||
|
||||
// We cannot use the default XAML APIs because we want to make sure
|
||||
// that there's only one application-global dialog visible at a time,
|
||||
|
@ -47,5 +53,6 @@ namespace TerminalApp
|
|||
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.RoutedEventArgs> Initialized;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,6 +126,22 @@
|
|||
Title="{x:Bind WindowIdForDisplay}"
|
||||
x:Load="False"
|
||||
IsLightDismissEnabled="True"
|
||||
Subtitle="{x:Bind WindowNameForDisplay}" />
|
||||
Subtitle="{x:Bind WindowNameForDisplay, Mode=OneWay}" />
|
||||
|
||||
<mux:TeachingTip x:Name="RenameFailedToast"
|
||||
x:Uid="RenameFailedToast"
|
||||
x:Load="False"
|
||||
IsLightDismissEnabled="True" />
|
||||
|
||||
<mux:TeachingTip x:Name="WindowRenamer"
|
||||
x:Uid="WindowRenamer"
|
||||
Title="{x:Bind WindowIdForDisplay}"
|
||||
x:Load="False"
|
||||
ActionButtonClick="_WindowRenamerActionClick">
|
||||
<mux:TeachingTip.Content>
|
||||
<TextBox x:Name="WindowRenamerTextBox"
|
||||
Text="{x:Bind WindowName, Mode=OneWay}" />
|
||||
</mux:TeachingTip.Content>
|
||||
</mux:TeachingTip>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -55,6 +55,8 @@ static constexpr std::string_view TogglePaneReadOnlyKey{ "toggleReadOnlyMode" };
|
|||
static constexpr std::string_view NewWindowKey{ "newWindow" };
|
||||
static constexpr std::string_view IdentifyWindowKey{ "identifyWindow" };
|
||||
static constexpr std::string_view IdentifyWindowsKey{ "identifyWindows" };
|
||||
static constexpr std::string_view RenameWindowKey{ "renameWindow" };
|
||||
static constexpr std::string_view OpenWindowRenamerKey{ "openWindowRenamer" };
|
||||
|
||||
static constexpr std::string_view ActionKey{ "action" };
|
||||
|
||||
|
@ -123,6 +125,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
{ NewWindowKey, ShortcutAction::NewWindow },
|
||||
{ IdentifyWindowKey, ShortcutAction::IdentifyWindow },
|
||||
{ IdentifyWindowsKey, ShortcutAction::IdentifyWindows },
|
||||
{ RenameWindowKey, ShortcutAction::RenameWindow },
|
||||
{ OpenWindowRenamerKey, ShortcutAction::OpenWindowRenamer },
|
||||
};
|
||||
|
||||
using ParseResult = std::tuple<IActionArgs, std::vector<SettingsLoadWarnings>>;
|
||||
|
@ -157,6 +161,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
{ ShortcutAction::NewWindow, NewWindowArgs::FromJson },
|
||||
{ ShortcutAction::PrevTab, PrevTabArgs::FromJson },
|
||||
{ ShortcutAction::NextTab, NextTabArgs::FromJson },
|
||||
{ ShortcutAction::RenameWindow, RenameWindowArgs::FromJson },
|
||||
|
||||
{ ShortcutAction::Invalid, nullptr },
|
||||
};
|
||||
|
@ -330,6 +335,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
{ ShortcutAction::NewWindow, RS_(L"NewWindowCommandKey") },
|
||||
{ ShortcutAction::IdentifyWindow, RS_(L"IdentifyWindowCommandKey") },
|
||||
{ ShortcutAction::IdentifyWindows, RS_(L"IdentifyWindowsCommandKey") },
|
||||
{ ShortcutAction::RenameWindow, RS_(L"ResetWindowNameCommandKey") },
|
||||
{ ShortcutAction::OpenWindowRenamer, RS_(L"OpenWindowRenamerCommandKey") },
|
||||
};
|
||||
}();
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "NewWindowArgs.g.cpp"
|
||||
#include "PrevTabArgs.g.cpp"
|
||||
#include "NextTabArgs.g.cpp"
|
||||
#include "RenameWindowArgs.g.cpp"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
|
||||
|
@ -567,4 +568,18 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
const auto mode = _SwitcherMode.Value() == TabSwitcherMode::MostRecentlyUsed ? L"most recently used" : L"in order";
|
||||
return winrt::hstring(fmt::format(L"{}, {}", RS_(L"NextTabCommandKey"), mode));
|
||||
}
|
||||
|
||||
winrt::hstring RenameWindowArgs::GenerateName() const
|
||||
{
|
||||
// "Rename window to \"{_Name}\""
|
||||
// "Clear window name"
|
||||
if (!_Name.empty())
|
||||
{
|
||||
return winrt::hstring{
|
||||
fmt::format(std::wstring_view(RS_(L"RenameWindowCommandKey")),
|
||||
_Name.c_str())
|
||||
};
|
||||
}
|
||||
return RS_(L"ResetWindowNameCommandKey");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "NewWindowArgs.g.h"
|
||||
#include "PrevTabArgs.g.h"
|
||||
#include "NextTabArgs.g.h"
|
||||
#include "RenameWindowArgs.g.h"
|
||||
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
#include "JsonUtils.h"
|
||||
|
@ -1001,6 +1002,39 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
return *copy;
|
||||
}
|
||||
};
|
||||
|
||||
struct RenameWindowArgs : public RenameWindowArgsT<RenameWindowArgs>
|
||||
{
|
||||
RenameWindowArgs() = default;
|
||||
WINRT_PROPERTY(winrt::hstring, Name);
|
||||
static constexpr std::string_view NameKey{ "name" };
|
||||
|
||||
public:
|
||||
hstring GenerateName() const;
|
||||
|
||||
bool Equals(const IActionArgs& other)
|
||||
{
|
||||
auto otherAsUs = other.try_as<RenameWindowArgs>();
|
||||
if (otherAsUs)
|
||||
{
|
||||
return otherAsUs->_Name == _Name;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
static FromJsonResult FromJson(const Json::Value& json)
|
||||
{
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<RenameWindowArgs>();
|
||||
JsonUtils::GetValueForKey(json, NameKey, args->_Name);
|
||||
return { *args, {} };
|
||||
}
|
||||
IActionArgs Copy() const
|
||||
{
|
||||
auto copy{ winrt::make_self<RenameWindowArgs>() };
|
||||
copy->_Name = _Name;
|
||||
return *copy;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
|
||||
|
|
|
@ -246,4 +246,9 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
{
|
||||
Windows.Foundation.IReference<TabSwitcherMode> SwitcherMode;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass RenameWindowArgs : IActionArgs
|
||||
{
|
||||
String Name { get; };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -70,4 +70,6 @@
|
|||
ON_ALL_ACTIONS(FindMatch) \
|
||||
ON_ALL_ACTIONS(NewWindow) \
|
||||
ON_ALL_ACTIONS(IdentifyWindow) \
|
||||
ON_ALL_ACTIONS(IdentifyWindows)
|
||||
ON_ALL_ACTIONS(IdentifyWindows) \
|
||||
ON_ALL_ACTIONS(RenameWindow) \
|
||||
ON_ALL_ACTIONS(OpenWindowRenamer)
|
||||
|
|
|
@ -381,4 +381,14 @@
|
|||
<data name="OpenSettingsUICommandKey" xml:space="preserve">
|
||||
<value>Open Settings...</value>
|
||||
</data>
|
||||
<data name="RenameWindowCommandKey" xml:space="preserve">
|
||||
<value>Rename window to "{0}"</value>
|
||||
<comment>{0} will be replaced with a user-defined string</comment>
|
||||
</data>
|
||||
<data name="ResetWindowNameCommandKey" xml:space="preserve">
|
||||
<value>Reset window name</value>
|
||||
</data>
|
||||
<data name="OpenWindowRenamerCommandKey" xml:space="preserve">
|
||||
<value>Rename window...</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -295,8 +295,8 @@
|
|||
{ "command": "renameTab" },
|
||||
{ "command": "openTabRenamer" },
|
||||
{ "command": "commandPalette", "keys":"ctrl+shift+p" },
|
||||
|
||||
{ "command": "identifyWindow" },
|
||||
{ "command": "openWindowRenamer" },
|
||||
|
||||
// Tab Management
|
||||
// "command": "closeTab" is unbound by default.
|
||||
|
|
|
@ -59,10 +59,12 @@ namespace RemotingUnitTests
|
|||
void DisplayWindowId() { throw winrt::hresult_error{}; };
|
||||
Remoting::CommandlineArgs InitialArgs() { throw winrt::hresult_error{}; }
|
||||
Remoting::WindowActivatedArgs GetLastActivatedArgs() { throw winrt::hresult_error{}; }
|
||||
void RequestRename(const Remoting::RenameRequestArgs& /*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);
|
||||
};
|
||||
|
||||
class RemotingTests
|
||||
|
@ -99,6 +101,10 @@ namespace RemotingUnitTests
|
|||
|
||||
TEST_METHOD(ProposeCommandlineForNamedDeadWindow);
|
||||
|
||||
TEST_METHOD(TestRenameWindowSuccessfully);
|
||||
TEST_METHOD(TestRenameSameNameAsAnother);
|
||||
TEST_METHOD(TestRenameSameNameAsADeadPeasant);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
return true;
|
||||
|
@ -1212,6 +1218,7 @@ namespace RemotingUnitTests
|
|||
VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
|
||||
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
|
||||
}
|
||||
|
||||
void RemotingTests::GetMruPeasantAfterNameLookupForDeadPeasant()
|
||||
{
|
||||
// This test is trying to hit the catch in Monarch::_lookupPeasantIdForName.
|
||||
|
@ -1356,4 +1363,147 @@ namespace RemotingUnitTests
|
|||
VERIFY_ARE_EQUAL(L"two", result.WindowName());
|
||||
}
|
||||
}
|
||||
|
||||
void RemotingTests::TestRenameWindowSuccessfully()
|
||||
{
|
||||
Log::Comment(L"Attempt to rename a window. This should succeed.");
|
||||
|
||||
const auto monarch0PID = 12345u;
|
||||
const auto peasant1PID = 23456u;
|
||||
const auto peasant2PID = 34567u;
|
||||
|
||||
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));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
p1->WindowName(L"one");
|
||||
p2->WindowName(L"two");
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
|
||||
VERIFY_ARE_EQUAL(2u, m0->_peasants.size());
|
||||
|
||||
Remoting::RenameRequestArgs eventArgs{ L"foo" };
|
||||
p1->RequestRename(eventArgs);
|
||||
|
||||
VERIFY_IS_TRUE(eventArgs.Succeeded());
|
||||
VERIFY_ARE_EQUAL(L"foo", p1->WindowName());
|
||||
|
||||
VERIFY_ARE_EQUAL(0, m0->_lookupPeasantIdForName(L"one"));
|
||||
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
|
||||
VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"foo"));
|
||||
}
|
||||
|
||||
void RemotingTests::TestRenameSameNameAsAnother()
|
||||
{
|
||||
Log::Comment(L"Try renaming a window to a name used by another peasant."
|
||||
L" This should fail.");
|
||||
|
||||
const auto monarch0PID = 12345u;
|
||||
const auto peasant1PID = 23456u;
|
||||
const auto peasant2PID = 34567u;
|
||||
|
||||
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));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
p1->WindowName(L"one");
|
||||
p2->WindowName(L"two");
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
|
||||
VERIFY_ARE_EQUAL(2u, m0->_peasants.size());
|
||||
|
||||
Remoting::RenameRequestArgs eventArgs{ L"two" };
|
||||
p1->RequestRename(eventArgs);
|
||||
|
||||
VERIFY_IS_FALSE(eventArgs.Succeeded());
|
||||
VERIFY_ARE_EQUAL(L"one", p1->WindowName());
|
||||
|
||||
VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
|
||||
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
|
||||
}
|
||||
void RemotingTests::TestRenameSameNameAsADeadPeasant()
|
||||
{
|
||||
Log::Comment(L"We'll try renaming a window to the name of a window that"
|
||||
L" has died. This should succeed, without crashing.");
|
||||
|
||||
const auto monarch0PID = 12345u;
|
||||
const auto peasant1PID = 23456u;
|
||||
const auto peasant2PID = 34567u;
|
||||
|
||||
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));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
p1->WindowName(L"one");
|
||||
p2->WindowName(L"two");
|
||||
|
||||
VERIFY_ARE_EQUAL(0, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(0, p2->GetID());
|
||||
|
||||
m0->AddPeasant(*p1);
|
||||
m0->AddPeasant(*p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
|
||||
VERIFY_ARE_EQUAL(2u, m0->_peasants.size());
|
||||
|
||||
Remoting::RenameRequestArgs eventArgs{ L"two" };
|
||||
p1->RequestRename(eventArgs);
|
||||
|
||||
VERIFY_IS_FALSE(eventArgs.Succeeded());
|
||||
VERIFY_ARE_EQUAL(L"one", p1->WindowName());
|
||||
|
||||
VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
|
||||
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
|
||||
|
||||
RemotingTests::_killPeasant(m0, p2->GetID());
|
||||
|
||||
p1->RequestRename(eventArgs);
|
||||
|
||||
VERIFY_IS_TRUE(eventArgs.Succeeded());
|
||||
VERIFY_ARE_EQUAL(L"two", p1->WindowName());
|
||||
VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"two"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -250,6 +250,7 @@ void AppHost::Initialize()
|
|||
_logic.LastTabClosed({ this, &AppHost::LastTabClosed });
|
||||
_logic.SetTaskbarProgress({ this, &AppHost::SetTaskbarProgress });
|
||||
_logic.IdentifyWindowsRequested({ this, &AppHost::_IdentifyWindowsRequested });
|
||||
_logic.RenameWindowRequested({ this, &AppHost::_RenameWindowRequested });
|
||||
|
||||
_window->UpdateTitle(_logic.Title());
|
||||
|
||||
|
@ -618,8 +619,8 @@ GUID AppHost::_CurrentDesktopGuid()
|
|||
// - <unused>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget AppHost::_IdentifyWindowsRequested(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
winrt::fire_and_forget AppHost::_IdentifyWindowsRequested(const winrt::Windows::Foundation::IInspectable /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable /*args*/)
|
||||
{
|
||||
// We'll be raising an event that may result in a RPC call to the monarch -
|
||||
// make sure we're on the background thread, or this will silently fail
|
||||
|
@ -643,3 +644,33 @@ void AppHost::_DisplayWindowId(const winrt::Windows::Foundation::IInspectable& /
|
|||
{
|
||||
_logic.IdentifyWindow();
|
||||
}
|
||||
|
||||
winrt::fire_and_forget AppHost::_RenameWindowRequested(const winrt::Windows::Foundation::IInspectable /*sender*/,
|
||||
const winrt::TerminalApp::RenameWindowRequestedArgs args)
|
||||
{
|
||||
// Capture calling context.
|
||||
winrt::apartment_context ui_thread;
|
||||
|
||||
// Switch to the BG thread - anything x-proc must happen on a BG thread
|
||||
co_await winrt::resume_background();
|
||||
|
||||
if (auto peasant{ _windowManager.CurrentWindow() })
|
||||
{
|
||||
Remoting::RenameRequestArgs requestArgs{ args.ProposedName() };
|
||||
|
||||
peasant.RequestRename(requestArgs);
|
||||
|
||||
// Switch back to the UI thread. Setting the WindowName needs to happen
|
||||
// on the UI thread, because it'll raise a PropertyChanged event
|
||||
co_await ui_thread;
|
||||
|
||||
if (requestArgs.Succeeded())
|
||||
{
|
||||
_logic.WindowName(args.ProposedName());
|
||||
}
|
||||
else
|
||||
{
|
||||
_logic.RenameFailed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,9 +51,12 @@ private:
|
|||
|
||||
void _FindTargetWindow(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);
|
||||
winrt::fire_and_forget _IdentifyWindowsRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
winrt::fire_and_forget _IdentifyWindowsRequested(const winrt::Windows::Foundation::IInspectable sender,
|
||||
const winrt::Windows::Foundation::IInspectable args);
|
||||
void _DisplayWindowId(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
winrt::fire_and_forget _RenameWindowRequested(const winrt::Windows::Foundation::IInspectable sender,
|
||||
const winrt::TerminalApp::RenameWindowRequestedArgs args);
|
||||
|
||||
GUID _CurrentDesktopGuid();
|
||||
};
|
||||
|
|
|
@ -62,7 +62,7 @@ running this on save, but you can add a `git` hook to format before committing
|
|||
XSTYLER_PATH="dotnet tool run xstyler --"
|
||||
|
||||
# Define path to XAML Styler configuration
|
||||
XSTYLER_CONFIG="../../XamlStyler.json"
|
||||
XSTYLER_CONFIG="XamlStyler.json"
|
||||
|
||||
echo "Running XAML Styler on committed XAML files"
|
||||
git diff --cached --name-only --diff-filter=ACM | grep -e '\.xaml$' | \
|
||||
|
|
Загрузка…
Ссылка в новой задаче