-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a Monarch/Peasant sample app (#8171)
This PR adds a sample monarch/peasant application. This is a type of application where a single "Monarch" can coordinate the actions of multiple other "Peasant" processes, as described by the specs in #7240 and #8135. This project is intended to be a standalone sample of how the architecture would work, without involving the entirety of the Windows Terminal build. Eventually, this architecture will be incorporated into `wt.exe` itself, to enable scenarios like: * Run `wt` in the current window (#4472) * Single Instance Mode (#2227) For an example of this sample running, see the below GIF: ![monarch-peasant-sample-001](https://user-images.githubusercontent.com/18356694/98262202-f39b1500-1f4a-11eb-9220-4af4d922339f.gif) This sample operates largely by printing to the console, to help the reader understand how it's working through its logic. I'm doing this mostly so we can have a _committed_ sample of this type of application, kinda like how VtPipeTerm is a sample ConPTY application. It's a lot easier to understand (& build on) when there aren't any window shenanigans, settings loading, Island instantiation, or anything else that the whole of `WindowsTerminal.exe` needs * [x] I work here * [x] This is sample code, so I'm not shipping tests for it. * [x] Go see the doc over in #8135
- Loading branch information
1 parent
a7d7362
commit c33a979
Showing
30 changed files
with
1,556 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+2.87 KB
src/tools/MonarchPeasantPackage/Images/Square150x150Logo.scale-200.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+1.23 KB
...MonarchPeasantPackage/Images/Square44x44Logo.targetsize-24_altform-unplated.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 88 additions & 0 deletions
88
src/tools/MonarchPeasantPackage/MonarchPeasantPackage.wapproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '15.0'"> | ||
<VisualStudioVersion>15.0</VisualStudioVersion> | ||
</PropertyGroup> | ||
<ItemGroup Label="ProjectConfigurations"> | ||
<ProjectConfiguration Include="Debug|x86"> | ||
<Configuration>Debug</Configuration> | ||
<Platform>x86</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Release|x86"> | ||
<Configuration>Release</Configuration> | ||
<Platform>x86</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Debug|x64"> | ||
<Configuration>Debug</Configuration> | ||
<Platform>x64</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Release|x64"> | ||
<Configuration>Release</Configuration> | ||
<Platform>x64</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Debug|ARM"> | ||
<Configuration>Debug</Configuration> | ||
<Platform>ARM</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Release|ARM"> | ||
<Configuration>Release</Configuration> | ||
<Platform>ARM</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Debug|ARM64"> | ||
<Configuration>Debug</Configuration> | ||
<Platform>ARM64</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Release|ARM64"> | ||
<Configuration>Release</Configuration> | ||
<Platform>ARM64</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Debug|AnyCPU"> | ||
<Configuration>Debug</Configuration> | ||
<Platform>AnyCPU</Platform> | ||
</ProjectConfiguration> | ||
<ProjectConfiguration Include="Release|AnyCPU"> | ||
<Configuration>Release</Configuration> | ||
<Platform>AnyCPU</Platform> | ||
</ProjectConfiguration> | ||
</ItemGroup> | ||
<PropertyGroup> | ||
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath> | ||
</PropertyGroup> | ||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" /> | ||
<PropertyGroup> | ||
<ProjectGuid>f75e29d0-d288-478b-8d83-2c190f321a3f</ProjectGuid> | ||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion> | ||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion> | ||
<DefaultLanguage>en-US</DefaultLanguage> | ||
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled> | ||
<EntryPointProjectUniqueName>..\MonarchPeasantSample\MonarchPeasantSample.vcxproj</EntryPointProjectUniqueName> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<AppxManifest Include="Package.appxmanifest"> | ||
<SubType>Designer</SubType> | ||
</AppxManifest> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Content Include="Images\SplashScreen.scale-200.png" /> | ||
<Content Include="Images\LockScreenLogo.scale-200.png" /> | ||
<Content Include="Images\Square150x150Logo.scale-200.png" /> | ||
<Content Include="Images\Square44x44Logo.scale-200.png" /> | ||
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" /> | ||
<Content Include="Images\StoreLogo.png" /> | ||
<Content Include="Images\Wide310x150Logo.scale-200.png" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<ProjectReference Include="..\MonarchPeasantSample\MonarchPeasantSample.vcxproj" > | ||
<!-- | ||
THESE PROPERTIES ARE LOAD BEARING! | ||
We need them so the MonarchPeasantSample.winmd will be placed in the | ||
package root. If it's not there, then we won't be able to activate our | ||
WinRT classes! | ||
--> | ||
<Private>true</Private> | ||
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies> | ||
</ProjectReference> | ||
</ItemGroup> | ||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" /> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
|
||
<Package | ||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" | ||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" | ||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" | ||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" | ||
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" | ||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" | ||
IgnorableNamespaces="uap rescap"> | ||
|
||
<Identity | ||
Name="5d4b020d-14a7-4a1a-a359-3f468e23bae3" | ||
Publisher="CN=migrie" | ||
Version="1.0.0.0" /> | ||
|
||
<Properties> | ||
<DisplayName>MonarchPeasantPackage</DisplayName> | ||
<PublisherDisplayName>migrie</PublisherDisplayName> | ||
<Logo>Images\StoreLogo.png</Logo> | ||
</Properties> | ||
|
||
<Dependencies> | ||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" /> | ||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" /> | ||
</Dependencies> | ||
|
||
<Resources> | ||
<Resource Language="x-generate"/> | ||
</Resources> | ||
|
||
<Applications> | ||
<Application Id="App" | ||
Executable="$targetnametoken$.exe" | ||
EntryPoint="$targetentrypoint$"> | ||
<uap:VisualElements | ||
DisplayName="MonarchPeasantPackage" | ||
Description="MonarchPeasantPackage" | ||
BackgroundColor="transparent" | ||
Square150x150Logo="Images\Square150x150Logo.png" | ||
Square44x44Logo="Images\Square44x44Logo.png"> | ||
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" /> | ||
<uap:SplashScreen Image="Images\SplashScreen.png" /> | ||
</uap:VisualElements> | ||
|
||
<Extensions> | ||
<uap3:Extension Category="windows.appExecutionAlias" Executable="MonarchPeasantSample\MonarchPeasantSample.exe" EntryPoint="Windows.FullTrustApplication"> | ||
<uap3:AppExecutionAlias> | ||
<desktop:ExecutionAlias Alias="MonarchPeasantSample.exe" /> | ||
</uap3:AppExecutionAlias> | ||
</uap3:Extension> | ||
|
||
</Extensions> | ||
|
||
</Application> | ||
</Applications> | ||
|
||
<Capabilities> | ||
<Capability Name="internetClient" /> | ||
<rescap:Capability Name="runFullTrust" /> | ||
</Capabilities> | ||
</Package> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
#include "pch.h" | ||
#include "AppState.h" | ||
#include "../../types/inc/utils.hpp" | ||
|
||
using namespace winrt; | ||
using namespace winrt::Windows::Foundation; | ||
using namespace ::Microsoft::Console; | ||
|
||
void AppState::_setupConsole() | ||
{ | ||
hOutput = GetStdHandle(STD_OUTPUT_HANDLE); | ||
hInput = GetStdHandle(STD_INPUT_HANDLE); | ||
DWORD dwMode = 0; | ||
GetConsoleMode(hOutput, &dwMode); | ||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; | ||
SetConsoleMode(hOutput, dwMode); | ||
} | ||
|
||
void AppState::initializeState() | ||
{ | ||
// Initialize the console handles | ||
_setupConsole(); | ||
|
||
// Set up WinRT | ||
init_apartment(); | ||
} | ||
|
||
bool AppState::areWeTheKing(const bool logPIDs) | ||
{ | ||
auto kingPID = monarch.GetPID(); | ||
auto ourPID = GetCurrentProcessId(); | ||
if (logPIDs) | ||
{ | ||
if (ourPID == kingPID) | ||
{ | ||
printf(fmt::format("We're the\x1b[33m king\x1b[m - our PID is {}\n", ourPID).c_str()); | ||
} | ||
else | ||
{ | ||
printf(fmt::format("We're a lowly peasant - the king is {}\n", kingPID).c_str()); | ||
} | ||
} | ||
return (ourPID == kingPID); | ||
} | ||
|
||
void AppState::remindKingWhoTheyAre(const winrt::MonarchPeasantSample::IPeasant& iPeasant) | ||
{ | ||
winrt::com_ptr<MonarchPeasantSample::implementation::Monarch> monarchImpl; | ||
monarchImpl.copy_from(winrt::get_self<MonarchPeasantSample::implementation::Monarch>(monarch)); | ||
if (monarchImpl) | ||
{ | ||
auto ourID = iPeasant.GetID(); | ||
monarchImpl->SetSelfID(ourID); | ||
monarchImpl->AddPeasant(iPeasant); | ||
printf("The king is peasant #%lld\n", ourID); | ||
} | ||
else | ||
{ | ||
printf("Shoot, we wanted to be able to get the monarchImpl here but couldnt\n"); | ||
} | ||
} | ||
|
||
winrt::MonarchPeasantSample::Monarch AppState::instantiateMonarch() | ||
{ | ||
// Heads up! This only works because we're using | ||
// "metadata-based-marshalling" for our WinRT types. THat means the OS is | ||
// using the .winmd file we generate to figure out the proxy/stub | ||
// 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 packaged: the .winmd must be in the package root | ||
auto monarch = create_instance<winrt::MonarchPeasantSample::Monarch>(Monarch_clsid, | ||
CLSCTX_LOCAL_SERVER); | ||
return monarch; | ||
} | ||
|
||
MonarchPeasantSample::IPeasant AppState::_createOurPeasant() | ||
{ | ||
auto peasant = winrt::make_self<MonarchPeasantSample::implementation::Peasant>(); | ||
auto ourID = monarch.AddPeasant(*peasant); | ||
printf("The monarch assigned us the ID %llu\n", ourID); | ||
|
||
if (areWeTheKing()) | ||
{ | ||
remindKingWhoTheyAre(*peasant); | ||
} | ||
|
||
return *peasant; | ||
} | ||
|
||
void AppState::createMonarch() | ||
{ | ||
monarch = AppState::instantiateMonarch(); | ||
} | ||
|
||
// return true to exit early, false if we should continue into the main loop | ||
bool AppState::processCommandline() | ||
{ | ||
const bool isKing = areWeTheKing(false); | ||
// 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 }, { L"placeholder CWD" }); | ||
|
||
if (createNewWindow) | ||
{ | ||
peasant = _createOurPeasant(); | ||
peasant.ExecuteCommandline({ args }, { L"placeholder CWD" }); | ||
return false; | ||
} | ||
else | ||
{ | ||
printf("The Monarch instructed us to not create a new window. We'll be exiting now.\n"); | ||
} | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#pragma once | ||
#include "SampleMonarch.h" | ||
#include "SamplePeasant.h" | ||
#include "../../types/inc/utils.hpp" | ||
|
||
class AppState | ||
{ | ||
public: | ||
bool areWeTheKing(const bool logPIDs = false); | ||
void initializeState(); | ||
|
||
static winrt::MonarchPeasantSample::Monarch instantiateMonarch(); | ||
|
||
void createMonarch(); | ||
bool processCommandline(); | ||
void remindKingWhoTheyAre(const winrt::MonarchPeasantSample::IPeasant& peasant); | ||
|
||
HANDLE hInput{ INVALID_HANDLE_VALUE }; | ||
HANDLE hOutput{ INVALID_HANDLE_VALUE }; | ||
winrt::MonarchPeasantSample::IPeasant peasant{ nullptr }; | ||
winrt::MonarchPeasantSample::Monarch monarch{ nullptr }; | ||
std::vector<winrt::hstring> args; | ||
|
||
private: | ||
void _setupConsole(); | ||
int _appLoop(); | ||
|
||
winrt::MonarchPeasantSample::IPeasant _createOurPeasant(); | ||
}; | ||
|
||
bool monarchAppLoop(AppState& state); // Defined in MonarchMain.cpp | ||
bool peasantAppLoop(AppState& state); // Defined in PeasantMain.cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#include "pch.h" | ||
#include "AppState.h" | ||
#include "../../types/inc/utils.hpp" | ||
|
||
void printPeasants(const winrt::MonarchPeasantSample::Monarch& /*monarch*/) | ||
{ | ||
printf("This is unimplemented\n"); | ||
} | ||
|
||
bool monarchAppLoop(AppState& state) | ||
{ | ||
bool exitRequested = false; | ||
printf("Press `l` to list peasants, 'm' to change modes `q` to quit\n"); | ||
|
||
winrt::com_ptr<winrt::MonarchPeasantSample::implementation::Monarch> monarchImpl; | ||
monarchImpl.copy_from(winrt::get_self<winrt::MonarchPeasantSample::implementation::Monarch>(state.monarch)); | ||
|
||
while (!exitRequested) | ||
{ | ||
const auto ch = _getch(); | ||
if (ch == 'l') | ||
{ | ||
printPeasants(state.monarch); | ||
} | ||
else if (ch == 'q') | ||
{ | ||
exitRequested = true; | ||
} | ||
else if (ch == 'm') | ||
{ | ||
if (monarchImpl) | ||
{ | ||
monarchImpl->ToggleWindowingBehavior(); | ||
} | ||
} | ||
} | ||
return true; | ||
} |
Oops, something went wrong.