mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-07 23:01:09 +00:00
Compare commits
15 Commits
dev/migrie
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1e080cf63 | ||
|
|
6711e4398c | ||
|
|
4a536a39e7 | ||
|
|
d4dbd530e9 | ||
|
|
b3601ab8d3 | ||
|
|
ca6a5fb537 | ||
|
|
c08889585b | ||
|
|
5939636182 | ||
|
|
f978a9c52c | ||
|
|
e1402d834f | ||
|
|
e101efd11d | ||
|
|
d08e65ce03 | ||
|
|
b4fe1bffbf | ||
|
|
0103331987 | ||
|
|
9c6eac4e86 |
@@ -232,9 +232,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalApp", "sr
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommandlineArgs", "src\cascadia\CommandlineArgs\CommandlineArgs.vcxproj", "{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\cascadia\TerminalApp\TerminalAppLib.vcxproj", "{CA5CAD1A-9A12-429C-B551-8562EC954746}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA} = {2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
EndProjectSection
|
||||
@@ -1607,6 +1614,30 @@ Global
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Release|x86.Build.0 = Release|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.AuditMode|x64.ActiveCfg = AuditMode|x64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.AuditMode|x86.ActiveCfg = AuditMode|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Debug|x64.Build.0 = Debug|x64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Debug|x86.Build.0 = Debug|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Release|x64.ActiveCfg = Release|x64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Release|x64.Build.0 = Release|x64
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Release|x86.ActiveCfg = Release|Win32
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.AuditMode|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.AuditMode|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
@@ -2289,6 +2320,7 @@ Global
|
||||
{84848BFA-931D-42CE-9ADF-01EE54DE7890} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{376FE273-6B84-4EB5-8B30-8DE9D21B022C} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
|
||||
{2658E9B0-BD84-48B7-BB5E-3D18F4DF07BA} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63} = {05500DEF-2294-41E3-AF9A-24E580B82836}
|
||||
|
||||
@@ -28,7 +28,7 @@ echo %TIME%
|
||||
powershell -ExecutionPolicy Bypass .\InstallTestAppDependencies.ps1
|
||||
echo %TIME%
|
||||
|
||||
set testBinaryCandidates=TerminalApp.LocalTests.dll SettingsModel.LocalTests.dll Remoting.LocalTests.dll Conhost.UIA.Tests.dll
|
||||
set testBinaryCandidates=TerminalApp.LocalTests.dll SettingsModel.LocalTests.dll Conhost.UIA.Tests.dll
|
||||
set testBinaries=
|
||||
for %%B in (%testBinaryCandidates%) do (
|
||||
if exist %%B (
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "AppLogic.h"
|
||||
#include "AppCommandlineArgs.h"
|
||||
#include "../types/inc/utils.hpp"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
using namespace winrt::TerminalApp;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace TerminalApp;
|
||||
using namespace CommandlineArgs;
|
||||
|
||||
// Either a ; at the start of a line, or a ; preceded by any non-\ char.
|
||||
const std::wregex AppCommandlineArgs::_commandDelimiterRegex{ LR"(^;|[^\\];)" };
|
||||
@@ -687,7 +685,7 @@ std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> AppComman
|
||||
// - 0 if the commandline was successfully parsed
|
||||
int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring>& args)
|
||||
{
|
||||
auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args);
|
||||
auto commands = ::CommandlineArgs::AppCommandlineArgs::BuildCommands(args);
|
||||
|
||||
for (auto& cmdBlob : commands)
|
||||
{
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
#pragma once
|
||||
|
||||
#include <CLI11/CLI11.hpp>
|
||||
#include "Commandline.h"
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
@@ -12,12 +13,12 @@ namespace TerminalAppLocalTests
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace TerminalApp
|
||||
namespace CommandlineArgs
|
||||
{
|
||||
class AppCommandlineArgs;
|
||||
};
|
||||
|
||||
class TerminalApp::AppCommandlineArgs final
|
||||
class CommandlineArgs::AppCommandlineArgs final
|
||||
{
|
||||
public:
|
||||
static constexpr std::string_view NixHelpFlag{ "-?" };
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "pch.h"
|
||||
#include "Commandline.h"
|
||||
|
||||
using namespace TerminalApp;
|
||||
using namespace CommandlineArgs;
|
||||
|
||||
size_t Commandline::Argc() const
|
||||
{
|
||||
@@ -23,12 +23,12 @@ namespace TerminalAppLocalTests
|
||||
{
|
||||
class CommandlineTest;
|
||||
};
|
||||
namespace TerminalApp
|
||||
namespace CommandlineArgs
|
||||
{
|
||||
class Commandline;
|
||||
};
|
||||
|
||||
class TerminalApp::Commandline
|
||||
class CommandlineArgs::Commandline
|
||||
{
|
||||
public:
|
||||
static constexpr std::wstring_view Delimiter{ L";" };
|
||||
119
src/cascadia/CommandlineArgs/CommandlineArgs.vcxproj
Normal file
119
src/cascadia/CommandlineArgs/CommandlineArgs.vcxproj
Normal file
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{2658e9b0-bd84-48b7-bb5e-3d18f4df07ba}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Microsoft.Terminal.CommandlineArgs</RootNamespace>
|
||||
<ProjectName>CommandlineArgs</ProjectName>
|
||||
<TargetName>CommandlineArgs</TargetName>
|
||||
<WindowsTargetPlatformMinVersion>10.0.17763.0</WindowsTargetPlatformMinVersion>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
<ClCompile>
|
||||
<!-- For CLI11: It uses dynamic_cast to cast types around, which depends
|
||||
on being compiled with RTTI (/GR). -->
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AppCommandlineArgs.h" />
|
||||
<ClInclude Include="Commandline.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AppCommandlineArgs.cpp" />
|
||||
<ClCompile Include="Commandline.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<!-- ========================= idl Files ======================== -->
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
<!--
|
||||
the packaging project won't recurse through our dependencies, you have to
|
||||
make sure that if you add a cppwinrt dependency to any of these projects,
|
||||
you also update all the consumers
|
||||
-->
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WinRTUtils\WinRTUtils.vcxproj">
|
||||
<Project>{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<!-- For whatever reason, we can't include the TerminalControl and
|
||||
TerminalSettings projects' winmds via project references. So we'll have to
|
||||
manually include the winmds as References below -->
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- This is a hack to get the ARM64 CI build working. See
|
||||
https://github.com/Microsoft/msbuild/issues/3746 - it looks like MsBuild
|
||||
just has a bug in it.-->
|
||||
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>Warning</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Manually add references to each of our dependent winmds. Mark them as
|
||||
private=false and CopyLocalSatelliteAssemblies=false, so that we don't
|
||||
propagate them upwards (which can make referencing this project result in
|
||||
duplicate type definitions)-->
|
||||
|
||||
<!-- Despite this lib only _really_ depending on the settings model, we need
|
||||
to reference Connection, Control, and MUX here, because they have types that
|
||||
TSM depends on, and the midl compiler will be mad if it can't find them. -->
|
||||
|
||||
<Reference Include="Microsoft.Terminal.TerminalConnection">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)TerminalConnection\Microsoft.Terminal.TerminalConnection.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Terminal.TerminalControl">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)TerminalControl\Microsoft.Terminal.TerminalControl.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Terminal.Settings.Model">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)Microsoft.Terminal.Settings.Model\Microsoft.Terminal.Settings.Model.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<!-- ====================== Compiler & Linker Flags ===================== -->
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<!-- Manually disable unreachable code warning, because jconcpp has a ton of that. -->
|
||||
<DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>WindowsApp.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<!-- ========================= Globals ======================== -->
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<!-- <Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" /> -->
|
||||
</Project>
|
||||
4
src/cascadia/CommandlineArgs/pch.cpp
Normal file
4
src/cascadia/CommandlineArgs/pch.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
53
src/cascadia/CommandlineArgs/pch.h
Normal file
53
src/cascadia/CommandlineArgs/pch.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// pch.h
|
||||
// Header for platform projection include files
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#define BLOCK_TIL
|
||||
#include <LibraryIncludes.h>
|
||||
// This is inexplicable, but for whatever reason, cppwinrt conflicts with the
|
||||
// SDK definition of this function, so the only fix is to undef it.
|
||||
// from WinBase.h
|
||||
// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
#include <wil/cppwinrt.h>
|
||||
|
||||
#include <unknwn.h>
|
||||
|
||||
#include <hstring.h>
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
// You might think "we're not doing any UI in this lib", and you'd be right.
|
||||
// However, we need this for Windows.UI.Color
|
||||
#include <winrt/windows.ui.h>
|
||||
|
||||
// Including TraceLogging essentials for the binary
|
||||
#include <TraceLoggingProvider.h>
|
||||
#include <winmeta.h>
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider);
|
||||
#include <telemetry/ProjectTelemetry.h>
|
||||
#include <TraceLoggingActivity.h>
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <shobjidl_core.h>
|
||||
|
||||
#include <winrt/Microsoft.Terminal.Settings.Model.h>
|
||||
|
||||
#include <CLI11/CLI11.hpp>
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
@@ -8,9 +8,10 @@ using namespace winrt::Windows::Foundation;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
// LOAD BEARING CODE
|
||||
// If you try to move this into the header, you will experience P A I N
|
||||
// It must be defined after CommandlineArgs.g.cpp, otherwise the compiler
|
||||
// will give you just the most impossible tmplate errors to try and
|
||||
// will give you just the most impossible template errors to try and
|
||||
// decipher.
|
||||
void CommandlineArgs::Args(winrt::array_view<const winrt::hstring> const& value)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,16 @@
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
<ClCompile>
|
||||
<!-- For CLI11: It uses dynamic_cast to cast types around, which depends
|
||||
on being compiled with RTTI (/GR). We need this in this project, because
|
||||
we're including the CLI11 header via the CommandlineArgs project. -->
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Monarch.h">
|
||||
@@ -74,17 +84,51 @@
|
||||
<Project>{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\CommandlineArgs\CommandlineArgs.vcxproj" >
|
||||
<Private>true</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
<!-- Make sure to set ReferenceOutputAssembly=false, or we'll try and
|
||||
MDMERGE with MUX from the CommandlineArgs output, and get duplicate type
|
||||
errors everywhere. -->
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
|
||||
<!-- This is going to turn into a disaster. We still need to reference MUX
|
||||
to get mdmerge happy, but we can't roll that up without rolling up the DLL
|
||||
and now we'll get duplicate types in WT.vcxproj. GAH. We'll need to have
|
||||
Remoting accept a callback to say "I encountered a commandline, someone,
|
||||
deal with it?", then have apphost register for that callback. So the flow
|
||||
is monarch->AppHost->AppLogic -->
|
||||
|
||||
</ProjectReference>
|
||||
<!-- For whatever reason, we can't include the TerminalControl and
|
||||
TerminalSettings projects' winmds via project references. So we'll have to
|
||||
manually include the winmds as References below -->
|
||||
|
||||
|
||||
<Reference Include="Microsoft.Terminal.TerminalConnection">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)TerminalConnection\Microsoft.Terminal.TerminalConnection.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Terminal.TerminalControl">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)TerminalControl\Microsoft.Terminal.TerminalControl.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Terminal.Settings.Model">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)Microsoft.Terminal.Settings.Model\Microsoft.Terminal.Settings.Model.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<!-- ====================== Compiler & Linker Flags ===================== -->
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..;$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<!-- Manually disable unreachable code warning, because jconcpp has a ton of that. -->
|
||||
<DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>WindowsApp.lib;user32.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#include "pch.h"
|
||||
#include "Monarch.h"
|
||||
#include "CommandlineArgs.h"
|
||||
#include "../CommandlineArgs/AppCommandlineArgs.h"
|
||||
|
||||
#include "Monarch.g.cpp"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace ::Microsoft::Console;
|
||||
|
||||
@@ -15,6 +17,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
_ourPID{ GetCurrentProcessId() }
|
||||
{
|
||||
}
|
||||
|
||||
// This is a private constructor to be used in unit tests, where we don't
|
||||
// want each Monarch to necessarily use the current PID.
|
||||
Monarch::Monarch(const uint64_t testPID) :
|
||||
_ourPID{ testPID }
|
||||
{
|
||||
@@ -22,7 +27,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
Monarch::~Monarch()
|
||||
{
|
||||
printf("~Monarch()\n");
|
||||
}
|
||||
|
||||
uint64_t Monarch::GetPID()
|
||||
@@ -30,152 +34,116 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
return _ourPID;
|
||||
}
|
||||
|
||||
uint64_t Monarch::AddPeasant(winrt::Microsoft::Terminal::Remoting::IPeasant peasant)
|
||||
// Method Description:
|
||||
// - Add the given peasant to the list of peasants we're tracking. This Peasant may have already been assigned an ID. If it hasn't, then give it an ID.
|
||||
// Arguments:
|
||||
// - peasant: the new Peasant to track.
|
||||
// Return Value:
|
||||
// - the ID assigned to the peasant.
|
||||
uint64_t Monarch::AddPeasant(Remoting::IPeasant peasant)
|
||||
{
|
||||
// TODO: This whole algorithm is terrible. There's gotta be a better way
|
||||
// TODO:projects/5 This is terrible. There's gotta be a better way
|
||||
// of finding the first opening in a non-consecutive map of int->object
|
||||
auto providedID = peasant.GetID();
|
||||
|
||||
if (providedID == 0)
|
||||
{
|
||||
// Peasant doesn't currently have an ID. Assign it a new one.
|
||||
peasant.AssignID(_nextPeasantID++);
|
||||
printf("Assigned the peasant the ID %lld\n", peasant.GetID());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Peasant already had an ID, %lld\n", peasant.GetID());
|
||||
// Peasant already had an ID (from an older monarch). Leave that one
|
||||
// be. Make sure that the next peasant's ID is higher than it.
|
||||
_nextPeasantID = providedID >= _nextPeasantID ? providedID + 1 : _nextPeasantID;
|
||||
}
|
||||
|
||||
auto newPeasantsId = peasant.GetID();
|
||||
_peasants[newPeasantsId] = peasant;
|
||||
_setMostRecentPeasant(newPeasantsId);
|
||||
printf("(the next new peasant will get the ID %lld)\n", _nextPeasantID);
|
||||
|
||||
// Add an event listener to the peasant's WindowActivated event.
|
||||
peasant.WindowActivated({ this, &Monarch::_peasantWindowActivated });
|
||||
|
||||
return newPeasantsId;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Event handler for the Peasant::WindowActivated event. Used as an
|
||||
// opportunity for us to update our internal stack of the "most recent
|
||||
// window".
|
||||
// Arguments:
|
||||
// - sender: the Peasant that raised this event. This might be out-of-proc!
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Monarch::_peasantWindowActivated(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
{
|
||||
if (auto peasant{ sender.try_as<winrt::Microsoft::Terminal::Remoting::Peasant>() })
|
||||
// TODO:projects/5 Pass the desktop and timestamp of when the window was
|
||||
// activated in `args`.
|
||||
|
||||
if (auto peasant{ sender.try_as<Remoting::Peasant>() })
|
||||
{
|
||||
auto theirID = peasant.GetID();
|
||||
_setMostRecentPeasant(theirID);
|
||||
}
|
||||
}
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::IPeasant Monarch::_getPeasant(uint64_t peasantID)
|
||||
// Method Description:
|
||||
// - Lookup a peasant by its ID.
|
||||
// Arguments:
|
||||
// - peasantID: The ID Of the peasant to find
|
||||
// Return Value:
|
||||
// - the peasant if it exists in our map, otherwise null
|
||||
Remoting::IPeasant Monarch::_getPeasant(uint64_t peasantID)
|
||||
{
|
||||
auto peasantSearch = _peasants.find(peasantID);
|
||||
return peasantSearch == _peasants.end() ? nullptr : peasantSearch->second;
|
||||
try
|
||||
{
|
||||
auto peasantSearch = _peasants.find(peasantID);
|
||||
auto maybeThePeasant = peasantSearch == _peasants.end() ? nullptr : peasantSearch->second;
|
||||
if (maybeThePeasant)
|
||||
{
|
||||
maybeThePeasant.GetPID();
|
||||
}
|
||||
return maybeThePeasant;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
// Remove the peasant from the list of peasants
|
||||
_peasants.erase(peasantID);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Monarch::_setMostRecentPeasant(const uint64_t peasantID)
|
||||
{
|
||||
// TODO:projects/5 Use a heap/priority queue per-desktop to track which
|
||||
// peasant was the most recent per-desktop. When we want to get the most
|
||||
// recent of all desktops (WindowingBehavior::UseExisting), then use the
|
||||
// most recent of all desktops.
|
||||
_mostRecentPeasant = peasantID;
|
||||
printf("\x1b[90mThe most recent peasant is now \x1b[m#%llu\n", _mostRecentPeasant);
|
||||
}
|
||||
|
||||
void Monarch::SetSelfID(const uint64_t selfID)
|
||||
// Method Description:
|
||||
// - Try to handle a commandline from a new WT invocation. We might need to
|
||||
// hand the commandline to an existing window, or we might need to tell
|
||||
// the caller that they need to become a new window to handle it themselves.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
bool Monarch::ProposeCommandline(const Remoting::CommandlineArgs& /*args*/)
|
||||
{
|
||||
this->_thisPeasantID = selfID;
|
||||
// Right now, the monarch assumes the role of the most recent
|
||||
// window. If the monarch dies, and a new monarch takes over, then the
|
||||
// entire stack of MRU windows will go with it. That's not what you
|
||||
// want!
|
||||
//
|
||||
// In the real app, we'll have each window also track the timestamp it
|
||||
// was activated at, and the monarch will cache these. So a new monarch
|
||||
// could re-query these last activated timestamps, and reconstruct the
|
||||
// MRU stack.
|
||||
//
|
||||
// This is a sample though, and we're not too worried about complete
|
||||
// correctness here.
|
||||
_setMostRecentPeasant(_thisPeasantID);
|
||||
}
|
||||
// TODO:projects/5
|
||||
// The branch dev/migrie/f/remote-commandlines has a more complete
|
||||
// version of this function, with a naive implementation. For now, we
|
||||
// always want to create a new window, so we'll just return true. This
|
||||
// will tell the caller that we didn't handle the commandline, and they
|
||||
// should open a new window to deal with it themselves.
|
||||
|
||||
bool Monarch::ProposeCommandline(array_view<const winrt::hstring> args,
|
||||
winrt::hstring cwd)
|
||||
{
|
||||
// auto argsProcessed = 0;
|
||||
// std::wstring fullCmdline;
|
||||
// for (const auto& arg : args)
|
||||
// {
|
||||
// fullCmdline += argsProcessed++ == 0 ? L"sample.exe" : arg;
|
||||
// fullCmdline += L" ";
|
||||
// }
|
||||
// wprintf(L"\x1b[36mProposed Commandline\x1b[m: \"");
|
||||
// wprintf(fullCmdline.c_str());
|
||||
// wprintf(L"\"\n");
|
||||
CommandlineArgs::AppCommandlineArgs argParser;
|
||||
|
||||
bool createNewWindow = true;
|
||||
|
||||
if (args.size() >= 3)
|
||||
{
|
||||
// We'll need three args at least - [WindowsTerminal.exe, -s,
|
||||
// id] to be able to have a session ID passed on the commandline.
|
||||
|
||||
if (args[1] == L"-w" || args[1] == L"--window")
|
||||
{
|
||||
auto sessionId = std::stoi({ args[2].data(), args[2].size() });
|
||||
printf("Found a commandline intended for session %d\n", sessionId);
|
||||
|
||||
// TODO:MG
|
||||
// HACK: do an args[2:] to slice off the `-w window` args.
|
||||
array_view<const winrt::hstring> argsNoWindow{ args.begin() + 2, args.end() };
|
||||
if (sessionId < 0)
|
||||
{
|
||||
printf("That certainly isn't a valid ID, they should make a new window.\n");
|
||||
createNewWindow = true;
|
||||
}
|
||||
else if (sessionId == 0)
|
||||
{
|
||||
printf("Session 0 is actually #%llu\n", _mostRecentPeasant);
|
||||
if (auto mruPeasant = _getPeasant(_mostRecentPeasant))
|
||||
{
|
||||
// TODO In the morning:
|
||||
// Right now, this commandline includes the "-w window" param, and CLI11 is biting it when parsing that.
|
||||
// Either:
|
||||
// * hack yank it for the time being (args[2:])
|
||||
// * actually have an AppCommandlineArgs do the parsing.
|
||||
|
||||
auto eventArgs = winrt::make_self<implementation::CommandlineArgs>(argsNoWindow, cwd);
|
||||
mruPeasant.ExecuteCommandline(*eventArgs);
|
||||
createNewWindow = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto otherPeasant = _getPeasant(sessionId))
|
||||
{
|
||||
auto eventArgs = winrt::make_self<implementation::CommandlineArgs>(argsNoWindow, cwd);
|
||||
otherPeasant.ExecuteCommandline(*eventArgs);
|
||||
createNewWindow = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("I couldn't find a peasant for that ID, they should make a new window.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_windowingBehavior == WindowingBehavior::UseExisting)
|
||||
{
|
||||
if (auto mruPeasant = _getPeasant(_mostRecentPeasant))
|
||||
{
|
||||
auto eventArgs = winrt::make_self<implementation::CommandlineArgs>(args, cwd);
|
||||
mruPeasant.ExecuteCommandline(*eventArgs);
|
||||
createNewWindow = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("They definitely weren't an existing process. They should make a new window.\n");
|
||||
}
|
||||
|
||||
return createNewWindow;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,9 +34,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
uint64_t AddPeasant(winrt::Microsoft::Terminal::Remoting::IPeasant peasant);
|
||||
|
||||
void SetSelfID(const uint64_t selfID);
|
||||
|
||||
bool ProposeCommandline(array_view<const winrt::hstring> args, winrt::hstring cwd);
|
||||
bool ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args);
|
||||
|
||||
private:
|
||||
Monarch(const uint64_t testPID);
|
||||
|
||||
@@ -7,6 +7,6 @@ namespace Microsoft.Terminal.Remoting
|
||||
|
||||
UInt64 GetPID();
|
||||
UInt64 AddPeasant(IPeasant peasant);
|
||||
Boolean ProposeCommandline(String[] args, String cwd);
|
||||
Boolean ProposeCommandline(CommandlineArgs args);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,15 @@ using namespace ::Microsoft::Console;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
Peasant::Peasant()
|
||||
Peasant::Peasant() :
|
||||
_ourPID{ GetCurrentProcessId() }
|
||||
{
|
||||
}
|
||||
|
||||
// This is a private constructor to be used in unit tests, where we don't
|
||||
// want each Peasant to necessarily use the current PID.
|
||||
Peasant::Peasant(const uint64_t testPID) :
|
||||
_ourPID{ testPID }
|
||||
{
|
||||
}
|
||||
|
||||
@@ -26,36 +34,27 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
uint64_t Peasant::GetPID()
|
||||
{
|
||||
return GetCurrentProcessId();
|
||||
return _ourPID;
|
||||
}
|
||||
|
||||
bool Peasant::ExecuteCommandline(const Remoting::CommandlineArgs& args)
|
||||
{
|
||||
// If this is the first set of args we were ever told about, stash them
|
||||
// away. We'll need to get at them later, when we setup the startup
|
||||
// actions for the window.
|
||||
if (_initialArgs == nullptr)
|
||||
{
|
||||
_initialArgs = args;
|
||||
}
|
||||
|
||||
// Raise an event with these args. The AppHost will listen for this
|
||||
// event to know when to take these args and dispatch them to a
|
||||
// currently-running window.
|
||||
_ExecuteCommandlineRequestedHandlers(*this, args);
|
||||
|
||||
// auto argsProcessed = 0;
|
||||
// std::wstring fullCmdline;
|
||||
// for (const auto& arg : args)
|
||||
// {
|
||||
// fullCmdline += argsProcessed++ == 0 ? L"sample.exe" : arg;
|
||||
// fullCmdline += L" ";
|
||||
// }
|
||||
// wprintf(L"\x1b[32mExecuted Commandline\x1b[m: \"");
|
||||
// wprintf(fullCmdline.c_str());
|
||||
// wprintf(L"\"\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Peasant::raiseActivatedEvent()
|
||||
{
|
||||
_WindowActivatedHandlers(*this, nullptr);
|
||||
}
|
||||
|
||||
Remoting::CommandlineArgs Peasant::InitialArgs()
|
||||
{
|
||||
return _initialArgs;
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
#include "Peasant.g.h"
|
||||
#include "../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace RemotingUnitTests
|
||||
{
|
||||
class RemotingTests;
|
||||
};
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct Peasant : public PeasantT<Peasant>
|
||||
@@ -15,18 +19,19 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
bool ExecuteCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args);
|
||||
|
||||
void raiseActivatedEvent();
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
|
||||
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs);
|
||||
|
||||
private:
|
||||
Peasant(const uint64_t testPID);
|
||||
uint64_t _ourPID;
|
||||
|
||||
uint64_t _id{ 0 };
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs _initialArgs{ nullptr };
|
||||
|
||||
// array_view<const winrt::hstring> _args;
|
||||
// winrt::hstring _cwd;
|
||||
friend class RemotingUnitTests::RemotingTests;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,9 +15,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
WindowManager::WindowManager()
|
||||
{
|
||||
_monarchWaitInterrupt.create();
|
||||
|
||||
// Register with COM as a server for the Monarch class
|
||||
_registerAsMonarch();
|
||||
_createMonarch();
|
||||
// Instantiate an instance of the Monarch. This may or may not be in-proc!
|
||||
_createMonarchAndCallbacks();
|
||||
}
|
||||
|
||||
WindowManager::~WindowManager()
|
||||
{
|
||||
// IMPORTANT! Tear down the registration as soon as we exit. If we're not a
|
||||
@@ -26,32 +31,39 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// monarch!
|
||||
CoRevokeClassObject(_registrationHostClass);
|
||||
_registrationHostClass = 0;
|
||||
_monarchWaitInterrupt.SetEvent();
|
||||
|
||||
if (_electionThread.joinable())
|
||||
{
|
||||
_electionThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::ProposeCommandline(array_view<const winrt::hstring> args,
|
||||
const winrt::hstring cwd)
|
||||
void WindowManager::ProposeCommandline(const Remoting::CommandlineArgs& args)
|
||||
{
|
||||
const bool isKing = _areWeTheKing();
|
||||
// If we're the king, we _definitely_ want to process the arguments, we were
|
||||
// launched with them!
|
||||
//
|
||||
// Otherwise, the King will tell us if we should make a new window
|
||||
const bool createNewWindow = isKing ||
|
||||
_monarch.ProposeCommandline(args, cwd);
|
||||
_shouldCreateWindow = isKing ||
|
||||
_monarch.ProposeCommandline(args);
|
||||
|
||||
if (createNewWindow)
|
||||
if (_shouldCreateWindow)
|
||||
{
|
||||
// If we should create a new window, then instantiate our Peasant
|
||||
// instance, and tell that peasant to handle that commandline.
|
||||
_createOurPeasant();
|
||||
|
||||
auto eventArgs = winrt::make_self<implementation::CommandlineArgs>(args, cwd);
|
||||
_peasant.ExecuteCommandline(*eventArgs);
|
||||
_shouldCreateWindow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// printf("The Monarch instructed us to not create a new window. We'll be exiting now.\n");
|
||||
_shouldCreateWindow = false;
|
||||
// TODO:MG Spawn a thread to wait on the monarch, and handle the election
|
||||
if (!isKing)
|
||||
{
|
||||
_createPeasantThread();
|
||||
}
|
||||
|
||||
_peasant.ExecuteCommandline(args);
|
||||
}
|
||||
// Otherwise, we'll do _nothing_.
|
||||
}
|
||||
|
||||
bool WindowManager::ShouldCreateWindow()
|
||||
@@ -76,12 +88,27 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// definitions for our types automatically. This only works in the following
|
||||
// cases:
|
||||
//
|
||||
// * If we're running unpackaged: the .winmd but be a sibling of the .exe
|
||||
// * If we're running unpackaged: the .winmd must be a sibling of the .exe
|
||||
// * If we're running packaged: the .winmd must be in the package root
|
||||
_monarch = create_instance<Remoting::Monarch>(Monarch_clsid,
|
||||
CLSCTX_LOCAL_SERVER);
|
||||
}
|
||||
|
||||
void WindowManager::_createMonarchAndCallbacks()
|
||||
{
|
||||
_createMonarch();
|
||||
const auto isKing = _areWeTheKing();
|
||||
if (!isKing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Here, we're the king!
|
||||
|
||||
// Wait, don't. Let's just have the monarch try/catch any accesses to
|
||||
// peasants. If the peasant dies, then it can't get the peasant's
|
||||
// anything. In that case, _remove it_.
|
||||
}
|
||||
|
||||
bool WindowManager::_areWeTheKing()
|
||||
{
|
||||
auto kingPID = _monarch.GetPID();
|
||||
@@ -93,18 +120,91 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
auto p = winrt::make_self<Remoting::implementation::Peasant>();
|
||||
_peasant = *p;
|
||||
auto ourID = _monarch.AddPeasant(_peasant);
|
||||
ourID;
|
||||
// printf("The monarch assigned us the ID %llu\n", ourID);
|
||||
|
||||
// if (areWeTheKing())
|
||||
// {
|
||||
// remindKingWhoTheyAre(*peasant);
|
||||
// }
|
||||
_monarch.AddPeasant(_peasant);
|
||||
|
||||
return _peasant;
|
||||
}
|
||||
|
||||
bool WindowManager::_electionNight2020()
|
||||
{
|
||||
_createMonarchAndCallbacks();
|
||||
|
||||
// Tell the new monarch who we are. We might be that monarch!
|
||||
_monarch.AddPeasant(_peasant);
|
||||
|
||||
if (_areWeTheKing())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WindowManager::_createPeasantThread()
|
||||
{
|
||||
// If we catch an exception trying to get at the monarch ever, we can
|
||||
// set the _monarchWaitInterrupt, and use that to trigger a new
|
||||
// election. Though, we wouldn't be able to retry the function that
|
||||
// caused the exception in the first place...
|
||||
|
||||
_electionThread = std::thread([this] {
|
||||
_waitOnMonarchThread();
|
||||
});
|
||||
}
|
||||
|
||||
void WindowManager::_waitOnMonarchThread()
|
||||
{
|
||||
HANDLE waits[2];
|
||||
waits[1] = _monarchWaitInterrupt.get();
|
||||
|
||||
bool exitRequested = false;
|
||||
while (!exitRequested)
|
||||
{
|
||||
wil::unique_handle hMonarch{ OpenProcess(PROCESS_ALL_ACCESS,
|
||||
FALSE,
|
||||
static_cast<DWORD>(_monarch.GetPID())) };
|
||||
// TODO:MG If we fail to open the monarch, then they don't exist
|
||||
// anymore! Go straight to an election.
|
||||
//
|
||||
// TODO:MG At any point in all this, the current monarch might die.
|
||||
// We go straight to a new election, right? Worst case, eventually,
|
||||
// we'll become the new monarch.
|
||||
//
|
||||
// if (hMonarch.get() == nullptr)
|
||||
// {
|
||||
// const auto gle = GetLastError();
|
||||
// return false;
|
||||
// }
|
||||
waits[0] = hMonarch.get();
|
||||
auto waitResult = WaitForMultipleObjects(2, waits, FALSE, INFINITE);
|
||||
|
||||
switch (waitResult)
|
||||
{
|
||||
case WAIT_OBJECT_0 + 0: // waits[0] was signaled
|
||||
// Connect to the new monarch, which might be us!
|
||||
// If we become the monarch, then we'll return true and exit this thread.
|
||||
exitRequested = _electionNight2020();
|
||||
break;
|
||||
case WAIT_OBJECT_0 + 1: // waits[1] was signaled
|
||||
exitRequested = true;
|
||||
break;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
printf("Wait timed out. This should be impossible.\n");
|
||||
exitRequested = true;
|
||||
break;
|
||||
|
||||
// Return value is invalid.
|
||||
default:
|
||||
{
|
||||
auto gle = GetLastError();
|
||||
printf("WaitForMultipleObjects returned: %d\n", waitResult);
|
||||
printf("Wait error: %d\n", gle);
|
||||
ExitProcess(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Remoting::Peasant WindowManager::CurrentWindow()
|
||||
{
|
||||
return _peasant;
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct WindowManager : public WindowManagerT<WindowManager>
|
||||
struct WindowManager final : public WindowManagerT<WindowManager>
|
||||
{
|
||||
WindowManager();
|
||||
~WindowManager();
|
||||
|
||||
void ProposeCommandline(array_view<const winrt::hstring> args, const winrt::hstring cwd);
|
||||
void ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args);
|
||||
bool ShouldCreateWindow();
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant CurrentWindow();
|
||||
@@ -23,10 +23,19 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
winrt::Microsoft::Terminal::Remoting::Monarch _monarch{ nullptr };
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant _peasant{ nullptr };
|
||||
|
||||
wil::unique_event _monarchWaitInterrupt;
|
||||
|
||||
std::thread _electionThread;
|
||||
|
||||
void _registerAsMonarch();
|
||||
void _createMonarch();
|
||||
void _createMonarchAndCallbacks();
|
||||
bool _areWeTheKing();
|
||||
winrt::Microsoft::Terminal::Remoting::IPeasant _createOurPeasant();
|
||||
|
||||
bool _electionNight2020();
|
||||
void _createPeasantThread();
|
||||
void _waitOnMonarchThread();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,11 @@ import "Peasant.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Remoting
|
||||
{
|
||||
|
||||
[default_interface] runtimeclass WindowManager
|
||||
{
|
||||
WindowManager();
|
||||
void ProposeCommandline(String[] commands, String cwd);
|
||||
void ProposeCommandline(CommandlineArgs args);
|
||||
Boolean ShouldCreateWindow { get; };
|
||||
Peasant CurrentWindow();
|
||||
IPeasant CurrentWindow();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,5 +44,7 @@ TRACELOGGING_DECLARE_PROVIDER(g_hSettingsModelProvider);
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <winrt/Microsoft.Terminal.Settings.Model.h>
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
|
||||
@@ -17,7 +17,6 @@ using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalConnection;
|
||||
using namespace ::TerminalApp;
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ using namespace winrt::Windows::System;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace ::TerminalApp;
|
||||
using namespace ::CommandlineArgs;
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
@@ -1113,7 +1113,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
int32_t AppLogic::ExecuteCommandline(array_view<const winrt::hstring> args)
|
||||
{
|
||||
::TerminalApp::AppCommandlineArgs appArgs;
|
||||
::CommandlineArgs::AppCommandlineArgs appArgs;
|
||||
auto result = appArgs.ParseArgs(args);
|
||||
if (result == 0)
|
||||
{
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
std::atomic<bool> _settingsReloadQueued{ false };
|
||||
|
||||
::TerminalApp::AppCommandlineArgs _appArgs;
|
||||
::CommandlineArgs::AppCommandlineArgs _appArgs;
|
||||
int _ParseArgs(winrt::array_view<const hstring>& args);
|
||||
|
||||
void _ShowLoadErrorsDialog(const winrt::hstring& titleKey, const winrt::hstring& contentKey, HRESULT settingsLoadedResult);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "FilteredCommand.h"
|
||||
#include "CommandPalette.g.h"
|
||||
#include "AppCommandlineArgs.h"
|
||||
#include "../CommandlineArgs/AppCommandlineArgs.h"
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
// fwdecl unittest classes
|
||||
@@ -130,7 +130,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
static constexpr int CommandLineHistoryLength = 10;
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _commandLineHistory{ nullptr };
|
||||
::TerminalApp::AppCommandlineArgs _appArgs;
|
||||
::CommandlineArgs::AppCommandlineArgs _appArgs;
|
||||
|
||||
friend class TerminalAppLocalTests::TabTests;
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalConnection;
|
||||
using namespace winrt::TerminalApp;
|
||||
using namespace TerminalApp;
|
||||
|
||||
|
||||
static const int PaneBorderSize = 2;
|
||||
static const int CombinedPaneBorderSize = 2 * PaneBorderSize;
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
|
||||
<ClCompile>
|
||||
<!-- For CLI11: It uses dynamic_cast to cast types around, which depends
|
||||
on being compiled with RTTI (/GR). -->
|
||||
on being compiled with RTTI (/GR). We need this in this project, because
|
||||
we're including the CLI11 header via the CommandlineArgs project. -->
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -71,8 +72,6 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ActionPaletteItem.h" />
|
||||
<ClInclude Include="App.base.h" />
|
||||
<ClInclude Include="AppCommandlineArgs.h" />
|
||||
<ClInclude Include="Commandline.h" />
|
||||
<ClInclude Include="CommandLinePaletteItem.h" />
|
||||
<ClInclude Include="Jumplist.h" />
|
||||
<ClInclude Include="MinMaxCloseControl.h">
|
||||
@@ -144,8 +143,6 @@
|
||||
<ClCompile Include="ActionPaletteItem.cpp" />
|
||||
<ClCompile Include="CommandLinePaletteItem.cpp" />
|
||||
<ClCompile Include="init.cpp" />
|
||||
<ClCompile Include="AppCommandlineArgs.cpp" />
|
||||
<ClCompile Include="Commandline.cpp" />
|
||||
<ClCompile Include="Jumplist.cpp" />
|
||||
<ClCompile Include="MinMaxCloseControl.cpp">
|
||||
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
|
||||
@@ -288,6 +285,14 @@
|
||||
you also update all the consumers
|
||||
-->
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\CommandlineArgs\CommandlineArgs.vcxproj" >
|
||||
<Private>true</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
<!-- Make sure to set ReferenceOutputAssembly=false, or we'll try and
|
||||
MDMERGE with MUX from the CommandlineArgs output, and get duplicate type
|
||||
errors everywhere. -->
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WinRTUtils\WinRTUtils.vcxproj">
|
||||
<Project>{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
|
||||
@@ -2698,7 +2698,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - an empty list if we failed to parse, otherwise a list of actions to execute.
|
||||
std::vector<ActionAndArgs> TerminalPage::ConvertExecuteCommandlineToActions(const ExecuteCommandlineArgs& args)
|
||||
{
|
||||
::TerminalApp::AppCommandlineArgs appArgs;
|
||||
::CommandlineArgs::AppCommandlineArgs appArgs;
|
||||
if (appArgs.ParseArgs(args) == 0)
|
||||
{
|
||||
return appArgs.GetStartupActions();
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <winrt/Microsoft.Terminal.TerminalControl.h>
|
||||
|
||||
#include "AppCommandlineArgs.h"
|
||||
#include "../CommandlineArgs/AppCommandlineArgs.h"
|
||||
|
||||
static constexpr uint32_t DefaultRowsToScroll{ 3 };
|
||||
static constexpr std::wstring_view TabletInputServiceKey{ L"TabletInputService" };
|
||||
|
||||
@@ -76,7 +76,5 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider);
|
||||
|
||||
#include <winrt/Windows.UI.Popups.h>
|
||||
|
||||
#include <CLI11/CLI11.hpp>
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
|
||||
@@ -12,27 +12,77 @@ using namespace WEX::Common;
|
||||
using namespace winrt;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
|
||||
// These are some gross macros that let us call a private ctor for
|
||||
// Monarch/Peasant. We can't just use make_self, because that doesn't let us
|
||||
// call a private ctor. We can use com_ptr::attach, but since we're allocating
|
||||
// the thing on the stack, we need to make sure to call detach before the object
|
||||
// is destructed.
|
||||
|
||||
#define MAKE_MONARCH(name, pid) \
|
||||
Remoting::implementation::Monarch _local_##name##{ pid }; \
|
||||
com_ptr<Remoting::implementation::Monarch> name; \
|
||||
name.attach(&_local_##name##); \
|
||||
auto cleanup = wil::scope_exit([&]() { name.detach(); });
|
||||
auto cleanup_##name## = wil::scope_exit([&]() { name.detach(); });
|
||||
|
||||
#define MAKE_PEASANT(name, pid) \
|
||||
Remoting::implementation::Peasant _local_##name##{ pid }; \
|
||||
com_ptr<Remoting::implementation::Peasant> name; \
|
||||
name.attach(&_local_##name##); \
|
||||
auto cleanup_##name## = wil::scope_exit([&]() { name.detach(); });
|
||||
|
||||
namespace RemotingUnitTests
|
||||
{
|
||||
// This is a silly helper struct.
|
||||
// It will always throw an hresult_error on any of it's methods.
|
||||
// In the tests, it's hard to emulate a peasant process being totally dead once the Monarch has captured a reference to it. Since everything's in-proc in the tests, we can't decrement the refcount in such a way that the monarch's reference will throw a catchable exception.
|
||||
// Instead, this class can be used to replace a peasant inside a Monarch, to emulate that peasant process dying. Any time the monarch tries to do something to this peasant, it'll throw an exception.
|
||||
struct DeadPeasant : implements<DeadPeasant, winrt::Microsoft::Terminal::Remoting::IPeasant>
|
||||
{
|
||||
DeadPeasant() = default;
|
||||
void AssignID(uint64_t /*id*/) { throw winrt::hresult_error{}; };
|
||||
uint64_t GetID() { throw winrt::hresult_error{}; };
|
||||
uint64_t GetPID() { throw winrt::hresult_error{}; };
|
||||
bool ExecuteCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& /*args*/) { throw winrt::hresult_error{}; }
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs() { throw winrt::hresult_error{}; }
|
||||
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs);
|
||||
};
|
||||
|
||||
class RemotingTests
|
||||
{
|
||||
BEGIN_TEST_CLASS(RemotingTests)
|
||||
END_TEST_CLASS()
|
||||
|
||||
TEST_METHOD(CreateMonarch);
|
||||
TEST_METHOD(CreatePeasant);
|
||||
TEST_METHOD(CreatePeasantWithNew);
|
||||
TEST_METHOD(AddPeasants);
|
||||
TEST_METHOD(GetPeasantsByID);
|
||||
TEST_METHOD(AddPeasantsToNewMonarch);
|
||||
TEST_METHOD(RemovePeasantFromMonarchWhenFreed);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _killPeasant(const com_ptr<Remoting::implementation::Monarch>& m,
|
||||
const uint64_t peasantID);
|
||||
};
|
||||
|
||||
void RemotingTests::_killPeasant(const com_ptr<Remoting::implementation::Monarch>& m,
|
||||
const uint64_t peasantID)
|
||||
{
|
||||
if (peasantID <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
com_ptr<DeadPeasant> tombstone;
|
||||
tombstone.attach(new DeadPeasant());
|
||||
m->_peasants[peasantID] = *tombstone;
|
||||
}
|
||||
|
||||
void RemotingTests::CreateMonarch()
|
||||
{
|
||||
auto m1 = winrt::make_self<Remoting::implementation::Monarch>();
|
||||
@@ -52,4 +102,194 @@ namespace RemotingUnitTests
|
||||
L"A Monarch with an explicit PID should use the one we provided");
|
||||
}
|
||||
|
||||
void RemotingTests::CreatePeasant()
|
||||
{
|
||||
auto p1 = winrt::make_self<Remoting::implementation::Peasant>();
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_ARE_EQUAL(GetCurrentProcessId(),
|
||||
p1->GetPID(),
|
||||
L"A Peasant without an explicit PID should use the current PID");
|
||||
|
||||
Log::Comment(L"That's what we need for window process management, but for tests, it'll be more useful to fake the PIDs.");
|
||||
|
||||
auto expectedFakePID = 2345u;
|
||||
MAKE_PEASANT(p2, expectedFakePID);
|
||||
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
VERIFY_ARE_EQUAL(expectedFakePID,
|
||||
p2->GetPID(),
|
||||
L"A Peasant with an explicit PID should use the one we provided");
|
||||
}
|
||||
|
||||
void RemotingTests::CreatePeasantWithNew()
|
||||
{
|
||||
Log::Comment(L"The same thing as the above test, but with `new` instead of insanity on the stack");
|
||||
|
||||
auto p1 = winrt::make_self<Remoting::implementation::Peasant>();
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_ARE_EQUAL(GetCurrentProcessId(),
|
||||
p1->GetPID(),
|
||||
L"A Peasant without an explicit PID should use the current PID");
|
||||
|
||||
auto expectedFakePID = 2345u;
|
||||
|
||||
com_ptr<Remoting::implementation::Peasant> p2;
|
||||
VERIFY_IS_NULL(p2);
|
||||
p2.attach(new Remoting::implementation::Peasant(expectedFakePID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
VERIFY_ARE_EQUAL(expectedFakePID,
|
||||
p2->GetPID(),
|
||||
L"A Peasant with an explicit PID should use the one we provided");
|
||||
}
|
||||
|
||||
void RemotingTests::AddPeasants()
|
||||
{
|
||||
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);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void RemotingTests::GetPeasantsByID()
|
||||
{
|
||||
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);
|
||||
|
||||
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());
|
||||
|
||||
auto maybeP1 = m0->_getPeasant(1);
|
||||
VERIFY_IS_NOT_NULL(maybeP1);
|
||||
VERIFY_ARE_EQUAL(peasant1PID, maybeP1.GetPID());
|
||||
|
||||
auto maybeP2 = m0->_getPeasant(2);
|
||||
VERIFY_IS_NOT_NULL(maybeP2);
|
||||
VERIFY_ARE_EQUAL(peasant2PID, maybeP2.GetPID());
|
||||
}
|
||||
|
||||
void RemotingTests::AddPeasantsToNewMonarch()
|
||||
{
|
||||
const auto monarch0PID = 12345u;
|
||||
const auto peasant1PID = 23456u;
|
||||
const auto peasant2PID = 34567u;
|
||||
const auto monarch3PID = 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::Monarch> m3;
|
||||
m3.attach(new Remoting::implementation::Monarch(monarch3PID));
|
||||
|
||||
VERIFY_IS_NOT_NULL(m0);
|
||||
VERIFY_IS_NOT_NULL(p1);
|
||||
VERIFY_IS_NOT_NULL(p2);
|
||||
VERIFY_IS_NOT_NULL(m3);
|
||||
|
||||
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());
|
||||
|
||||
m3->AddPeasant(*p1);
|
||||
m3->AddPeasant(*p2);
|
||||
|
||||
VERIFY_ARE_EQUAL(1, p1->GetID());
|
||||
VERIFY_ARE_EQUAL(2, p2->GetID());
|
||||
}
|
||||
|
||||
void RemotingTests::RemovePeasantFromMonarchWhenFreed()
|
||||
{
|
||||
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);
|
||||
|
||||
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());
|
||||
|
||||
Log::Comment(L"Kill peasant 1. Make sure that it gets removed from the monarch.");
|
||||
RemotingTests::_killPeasant(m0, p1->GetID());
|
||||
|
||||
auto maybeP2 = m0->_getPeasant(2);
|
||||
VERIFY_IS_NOT_NULL(maybeP2);
|
||||
VERIFY_ARE_EQUAL(peasant2PID, maybeP2.GetPID());
|
||||
|
||||
auto maybeP1 = m0->_getPeasant(1);
|
||||
VERIFY_IS_NULL(maybeP1);
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "AppHost.h"
|
||||
// #include "MonarchFactory.h"
|
||||
#include "../types/inc/Viewport.hpp"
|
||||
#include "../types/inc/utils.hpp"
|
||||
#include "../types/inc/User32Utils.hpp"
|
||||
@@ -14,6 +13,7 @@ using namespace winrt::Windows::UI::Composition;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Hosting;
|
||||
using namespace winrt::Windows::Foundation::Numerics;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace ::Microsoft::Console;
|
||||
using namespace ::Microsoft::Console::Types;
|
||||
@@ -30,50 +30,16 @@ AppHost::AppHost() noexcept :
|
||||
{
|
||||
_logic = _app.Logic(); // get a ref to app's logic
|
||||
|
||||
{
|
||||
std::vector<winrt::hstring> args;
|
||||
if (auto commandline{ GetCommandLineW() })
|
||||
{
|
||||
int argc = 0;
|
||||
|
||||
// Get the argv, and turn them into a hstring array to pass to the app.
|
||||
wil::unique_any<LPWSTR*, decltype(&::LocalFree), ::LocalFree> argv{ CommandLineToArgvW(commandline, &argc) };
|
||||
if (argv)
|
||||
{
|
||||
for (auto& elem : wil::make_range(argv.get(), argc))
|
||||
{
|
||||
args.emplace_back(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (args.empty())
|
||||
{
|
||||
args.emplace_back(L"wt.exe");
|
||||
}
|
||||
|
||||
_windowManager.ProposeCommandline({ args }, L"placeholder/cwd");
|
||||
// _RegisterAsMonarch();
|
||||
// _CreateMonarch();
|
||||
_shouldCreateWindow = _windowManager.ShouldCreateWindow();
|
||||
if (!_shouldCreateWindow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (auto peasant{ _windowManager.CurrentWindow() })
|
||||
{
|
||||
peasant.ExecuteCommandlineRequested({ this, &AppHost::_DispatchCommandline });
|
||||
}
|
||||
|
||||
// TODO:MG if we end up not creating a new window, we crash. I'm
|
||||
// thinking this is because the XAML host is not happy about being torn
|
||||
// down before it has a chance to do really anything. Is there some way
|
||||
// to get the app logic without instantiating the entire app? or at
|
||||
// least the parts we'll need for remoting?
|
||||
}
|
||||
|
||||
// If there were commandline args to our process, try and process them here.
|
||||
// Do this before AppLogic::Create, otherwise this will have no effect
|
||||
_HandleCommandlineArgs(); // TODO:MG <-- This probably needs to move into _ProposeCommandlineToMonarch
|
||||
// Do this before AppLogic::Create, otherwise this will have no effect.
|
||||
//
|
||||
// This will send our commandline to the Monarch, to ask if we should make a
|
||||
// new window or not. If not, exit immediately.
|
||||
_HandleCommandlineArgs();
|
||||
if (!_shouldCreateWindow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_useNonClientArea = _logic.GetShowTabsInTitlebar();
|
||||
if (_useNonClientArea)
|
||||
@@ -137,9 +103,35 @@ void AppHost::SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable&
|
||||
}
|
||||
}
|
||||
|
||||
void _buildArgsFromCommandline(std::vector<winrt::hstring>& args)
|
||||
{
|
||||
if (auto commandline{ GetCommandLineW() })
|
||||
{
|
||||
int argc = 0;
|
||||
|
||||
// Get the argv, and turn them into a hstring array to pass to the app.
|
||||
wil::unique_any<LPWSTR*, decltype(&::LocalFree), ::LocalFree> argv{ CommandLineToArgvW(commandline, &argc) };
|
||||
if (argv)
|
||||
{
|
||||
for (auto& elem : wil::make_range(argv.get(), argc))
|
||||
{
|
||||
args.emplace_back(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (args.empty())
|
||||
{
|
||||
args.emplace_back(L"wt.exe");
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Retrieve any commandline args passed on the commandline, and pass them to
|
||||
// the app logic for processing.
|
||||
// the WindowManager, to ask if we should become a window process.
|
||||
// - If we should create a window, then pass the arguments to the app logic for
|
||||
// processing.
|
||||
// - If we shouldn't become a window, set _shouldCreateWindow to false and exit
|
||||
// immediately.
|
||||
// - If the logic determined there's an error while processing that commandline,
|
||||
// display a message box to the user with the text of the error, and exit.
|
||||
// * We display a message box because we're a Win32 application (not a
|
||||
@@ -152,6 +144,19 @@ void AppHost::SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable&
|
||||
// - <none>
|
||||
void AppHost::_HandleCommandlineArgs()
|
||||
{
|
||||
std::vector<winrt::hstring> args;
|
||||
_buildArgsFromCommandline(args);
|
||||
std::wstring cwd{ wil::GetCurrentDirectoryW<std::wstring>() };
|
||||
|
||||
Remoting::CommandlineArgs eventArgs{ { args }, { cwd } };
|
||||
_windowManager.ProposeCommandline(eventArgs);
|
||||
|
||||
_shouldCreateWindow = _windowManager.ShouldCreateWindow();
|
||||
if (!_shouldCreateWindow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto peasant{ _windowManager.CurrentWindow() })
|
||||
{
|
||||
if (auto args{ peasant.InitialArgs() })
|
||||
@@ -176,42 +181,19 @@ void AppHost::_HandleCommandlineArgs()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After handling the initial args, hookup the callback for handling
|
||||
// future commandline invocations. When our peasant is told to execute a
|
||||
// commandline (in the future), it'll trigger this callback, that we'll
|
||||
// use to send the actions to the app.
|
||||
peasant.ExecuteCommandlineRequested({ this, &AppHost::_DispatchCommandline });
|
||||
}
|
||||
// if (auto commandline{ GetCommandLineW() })
|
||||
// {
|
||||
// int argc = 0;
|
||||
|
||||
// // Get the argv, and turn them into a hstring array to pass to the app.
|
||||
// wil::unique_any<LPWSTR*, decltype(&::LocalFree), ::LocalFree> argv{ CommandLineToArgvW(commandline, &argc) };
|
||||
// if (argv)
|
||||
// {
|
||||
// std::vector<winrt::hstring> args;
|
||||
// for (auto& elem : wil::make_range(argv.get(), argc))
|
||||
// {
|
||||
// args.emplace_back(elem);
|
||||
// }
|
||||
|
||||
// const auto result = _logic.SetStartupCommandline({ args });
|
||||
// const auto message = _logic.ParseCommandlineMessage();
|
||||
// if (!message.empty())
|
||||
// {
|
||||
// const auto displayHelp = result == 0;
|
||||
// const auto messageTitle = displayHelp ? IDS_HELP_DIALOG_TITLE : IDS_ERROR_DIALOG_TITLE;
|
||||
// const auto messageIcon = displayHelp ? MB_ICONWARNING : MB_ICONERROR;
|
||||
// // TODO:GH#4134: polish this dialog more, to make the text more
|
||||
// // like msiexec /?
|
||||
// MessageBoxW(nullptr,
|
||||
// message.data(),
|
||||
// GetStringResource(messageTitle).data(),
|
||||
// MB_OK | messageIcon);
|
||||
|
||||
// if (_logic.ShouldExitEarly())
|
||||
// {
|
||||
// ExitProcess(result);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// TODO:projects/5 if we end up not creating a new window, we crash. I'm
|
||||
// thinking this is because the XAML host is not happy about being torn
|
||||
// down before it has a chance to do really anything. Is there some way
|
||||
// to get the app logic without instantiating the entire app? or at
|
||||
// least the parts we'll need for remoting?
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -534,26 +516,7 @@ bool AppHost::HasWindow()
|
||||
return _shouldCreateWindow;
|
||||
}
|
||||
|
||||
// void AppHost::_RegisterAsMonarch()
|
||||
// {
|
||||
// winrt::check_hresult(CoRegisterClassObject(Monarch_clsid,
|
||||
// winrt::make<::MonarchFactory>().get(),
|
||||
// CLSCTX_LOCAL_SERVER,
|
||||
// REGCLS_MULTIPLEUSE,
|
||||
// &_registrationHostClass));
|
||||
// }
|
||||
|
||||
// void AppHost::_CreateMonarch()
|
||||
// {
|
||||
// }
|
||||
|
||||
// bool AppHost::_ProposeCommandlineToMonarch()
|
||||
// {
|
||||
// // returns true if we should create a new window
|
||||
// return true;
|
||||
// }
|
||||
|
||||
void AppHost::_DispatchCommandline(winrt::Windows::Foundation::IInspectable sender,
|
||||
void AppHost::_DispatchCommandline(winrt::Windows::Foundation::IInspectable /*sender*/,
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs args)
|
||||
{
|
||||
_logic.ExecuteCommandline(args.Args());
|
||||
|
||||
@@ -26,7 +26,6 @@ private:
|
||||
winrt::TerminalApp::App _app;
|
||||
winrt::TerminalApp::AppLogic _logic;
|
||||
bool _shouldCreateWindow{ false };
|
||||
// DWORD _registrationHostClass{ 0 };
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager _windowManager{ nullptr };
|
||||
|
||||
void _HandleCommandlineArgs();
|
||||
@@ -46,10 +45,6 @@ private:
|
||||
const winrt::Windows::Foundation::IInspectable& arg);
|
||||
void _WindowMouseWheeled(const til::point coord, const int32_t delta);
|
||||
|
||||
// void _RegisterAsMonarch();
|
||||
// void _CreateMonarch();
|
||||
// bool _ProposeCommandlineToMonarch();
|
||||
|
||||
void _DispatchCommandline(winrt::Windows::Foundation::IInspectable sender,
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs args);
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<test name="terminalApp" type="unit" binary="UnitTests_TerminalApp\Terminal.App.Unit.Tests.dll" />
|
||||
<test name="localTerminalApp" type="unit" runInHostApp="true" binary="TerminalApp.LocalTests.dll" />
|
||||
<test name="localSettingsModel" type="unit" runInHostApp="true" binary="SettingsModel.LocalTests.dll" />
|
||||
<test name="unitRemoting" type="unit" runInHostApp="true" binary="Remoting.UnitTests.dll" />
|
||||
<test name="unitRemoting" type="unit" binary="Remoting.UnitTests.dll" />
|
||||
<test name="interactivityWin32" type="unit" binary="Conhost.Interactivity.Win32.Unit.Tests.dll" />
|
||||
<test name="terminal" type="unit" binary="ConParser.Unit.Tests.dll" />
|
||||
<test name="adapter" type="unit" binary="ConAdapter.Unit.Tests.dll" />
|
||||
|
||||
Reference in New Issue
Block a user