Compare commits

...

116 Commits

Author SHA1 Message Date
Mike Griese
c04f089953 I guess I'm stashing this for now. I've got other plans 2024-03-14 14:07:57 -05:00
Mike Griese
310fa770d6 Revert "Trying something: Is til::event broken?"
This reverts commit d88b426059.
2024-03-14 09:21:45 -05:00
Mike Griese
2649256931 LMAO I was instantiating one ConptyOutputThread PER BLOCK 2024-03-14 09:21:28 -05:00
Mike Griese
842e70743f Trying again to fix scrolling (it got a little better?) 2024-03-14 09:21:00 -05:00
Mike Griese
0980e47187 fix conhost build 2024-03-14 09:20:10 -05:00
Mike Griese
d88b426059 Trying something: Is til::event broken? 2024-03-14 09:19:38 -05:00
Mike Griese
7fc9f9e189 small amount of cleanup 2024-03-13 15:35:58 -05:00
Mike Griese
3b02296c64 add support for loading files at runtime 2024-03-13 15:33:31 -05:00
Mike Griese
0672af9f15 load-bearing: don't scroll the scroll viewer if you scrolled the termcontrol 2024-03-13 14:11:42 -05:00
Mike Griese
0a30739670 I think the progress states work now so that's cool 2024-03-13 13:40:29 -05:00
Mike Griese
754b5c0ae1 Start adding more states for more visual fun
I know it's folly to fuck around with XAML during a hackathon, but this is really fun.
2024-03-13 11:26:36 -05:00
Mike Griese
6f30689fbf cool hover-y play buttons 2024-03-13 11:08:03 -05:00
Mike Griese
915fa3f6db hoo-ah, it works 2024-03-13 07:07:23 -05:00
Mike Griese
4b11bacea8 the formatting for easy stuff is almost done 2024-03-13 07:04:15 -05:00
Mike Griese
a0eb76322c some niceties to format headers 2024-03-13 06:00:30 -05:00
Mike Griese
e77bfa4392 we're generating XAML from MD. off to the races 2024-03-12 16:47:22 -05:00
Mike Griese
0bb66c8880 get md4c compiling 2024-03-12 16:29:17 -05:00
Mike Griese
58be7a46f7 maybe better locking? better window sizing for sure 2024-03-12 15:39:51 -05:00
Mike Griese
4153896df5 Fix scrolling by having BRD do LITERALLY THE SAME THING as terminal 2024-03-12 15:17:24 -05:00
Mike Griese
73933910e2 this _seems_ to lock the creation of controls better, s.t. they explode less often 2024-03-12 14:51:16 -05:00
Mike Griese
cd2f1ab48f terminal blocks get moved into code blocks on the play button press. This is pretty effective 2024-03-12 14:37:20 -05:00
Mike Griese
9d4e2f4b20 wire up play button to send input to the notebook 2024-03-12 11:47:33 -05:00
Mike Griese
1010fd81ce minor refactor s.t. NotebookBlock is a winrt type 2024-03-12 11:26:42 -05:00
Mike Griese
41a443ab38 Add a simple CodeBlock class to assist in wrapping up code blocks and their output 2024-03-12 10:53:51 -05:00
Mike Griese
62fb815842 some code cleanup, and the beginning of experimenting with some formattitng 2024-03-12 10:08:01 -05:00
Mike Griese
68e6608110 scroll each block independently. Now, let's add some markdown. 2024-03-11 16:50:28 -05:00
Mike Griese
a88cf47994 Very nearly allow scrollbars to be sized for the block.
Problem is, they're all kinda using the same VisibleViewport as defined by the
Terminal itself. Each individual renderdata needs to own their own, separately.
2024-03-11 16:05:11 -05:00
Mike Griese
8a22d3529f better sizing for these controls, cause I should actually set the bottom before attempting to use it 2024-03-11 14:59:16 -05:00
Mike Griese
297018dd08 these don't need to be there 2024-03-11 14:22:06 -05:00
Mike Griese
35f4bf2de2 this is pretty close. Sizes are at least in the realm of real 2024-03-11 14:21:24 -05:00
Mike Griese
176d546f2c this does shrink the control down, but now to get the _right_ size 2024-03-11 13:43:23 -05:00
Mike Griese
5e49cb37e9 don't just add a empty block at the start 2024-03-11 12:24:00 -05:00
Mike Griese
14675bb4f6 Amazing. Just render the section of the veiwport between the marks. It's pretty easy tbh.
Obviously, scrollbars are weird, and heights are wrong. And sometimes theres duplicated output. But it's actually progressing!
2024-03-11 12:16:01 -05:00
Mike Griese
352aab12dc Initialize a separate BlockRenderData for each control. This works, but does nothing new. 2024-03-11 11:46:55 -05:00
Mike Griese
31b8f938ed clean up comments 2024-03-11 11:23:51 -05:00
Mike Griese
cc6739520a Auto-focus new blocks. This is super dumb, because...
As you might expect, the new TermControl doesn't have an offset within the
ScrollViewer, until _after it's added to the UI tree AND a layout pass happens.
So you literally need to just wait a hot millisecond before you can scroll to
the thing.
2024-03-11 11:13:22 -05:00
Mike Griese
7ba80e6ccb Tricky: don't recreate the Terminal each time. Also, change the renderer always
This works because for the first control, we'll initialize the buffer, then set
the renderer of the `Terminal` to our renderer (a no-op). Subsequent blocks
won't re-initialize the buffer, but they will move the active renderer to their
own. Nice.
2024-03-11 10:14:00 -05:00
Mike Griese
e866f3d28b Start auto-creating blocks on each prompt. None really seem to render right.
Because each TermControl has it's own renderer, storing the invalid map itself,
none of them know to keep drawing
2024-03-11 09:52:13 -05:00
Mike Griese
199446e5e5 refactor for easier forking. The middle one got activated? That's unexpected, for sure. I suppose it all depends on the order of the controls getting to Terminal::Initialize to see who wins the battle to be the renderer 2024-03-08 15:59:44 -06:00
Mike Griese
d3ba2fc3f5 dedupe output by clearing out the connection when we make a new control 2024-03-08 15:51:28 -06:00
Mike Griese
36278a9199 WOWOW I just stuck two blocks into one notebook and it more or less just worked.
Notebook is just making two controls just to test. And it's got duplicated output. But it _works_
2024-03-08 15:37:02 -06:00
Mike Griese
059467d4ba Change the ControlCore ctor to accept a ControlData
That `ControlData` contains a possibly bundled `Terminal` and `RenderData` for the controlcore to use.

We're gonna have the notebook generate those
2024-03-08 12:22:48 -06:00
Mike Griese
51ec42661f Checkpoint: Add a BlockRenderData that's basically just a TerminalRenderData wrapper 2024-03-08 11:35:09 -06:00
Mike Griese
ae356758b6 Change the Renderer to a pointer instead of a reference.
This is so we can change it out at a later time. Hopefully.
2024-03-08 11:10:21 -06:00
Mike Griese
5343d560b0 Merge remote-tracking branch 'origin/dev/migrie/til-events-for-all' into dev/migrie/fhl/2024-spring-merge-base 2024-03-08 10:52:08 -06:00
Mike Griese
978fd6e2ba Merge branch 'dev/migrie/fhl/scratchpad-pane' into dev/migrie/f/sui-panes 2024-03-08 10:36:17 -06:00
Mike Griese
35651bc92c Merge branch 'dev/migrie/fhl/non-terminal-panes-2023' into dev/migrie/fhl/scratchpad-pane 2024-03-08 10:33:31 -06:00
Mike Griese
a3fbc64384 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2024-03-08 10:33:00 -06:00
Mike Griese
b6254f8294 GREAT-GRANDPARENT: This fixes a crash in parent pane selection
(cherry picked from commit 91a0d0e26d)
2024-03-07 16:51:02 -06:00
Leonard Hecker
3f17a38db7 Restore bad line endings on a bunch more files 2024-03-07 22:23:45 +01:00
Dustin Howett
fc9e871794 Restore bad line endings on a bunch of files
src/cascadia/TerminalApp/AboutDialog.h
src/cascadia/TerminalApp/CommandPalette.cpp
src/cascadia/TerminalApp/CommandPalette.h
src/cascadia/TerminalApp/FilteredCommand.h
src/cascadia/TerminalApp/HighlightedText.h
src/cascadia/TerminalApp/SuggestionsControl.cpp
src/cascadia/TerminalApp/SuggestionsControl.h
src/cascadia/TerminalApp/TabHeaderControl.cpp
src/cascadia/TerminalApp/TabHeaderControl.h
src/cascadia/TerminalApp/TabRowControl.h
src/cascadia/TerminalApp/TerminalPage.cpp
src/cascadia/TerminalApp/TerminalPage.h
src/cascadia/TerminalApp/TerminalTabStatus.h
src/cascadia/TerminalConnection/ConptyConnection.cpp
src/cascadia/TerminalConnection/ConptyConnection.h
src/cascadia/TerminalConnection/EchoConnection.cpp
src/cascadia/TerminalConnection/EchoConnection.h
src/cascadia/TerminalSettingsEditor/Appearances.cpp
src/cascadia/TerminalSettingsEditor/Appearances.h
src/cascadia/TerminalSettingsEditor/ColorSchemes.h
src/cascadia/TerminalSettingsEditor/EditColorScheme.h
src/cascadia/TerminalSettingsEditor/EnumEntry.h
src/cascadia/TerminalSettingsEditor/MainPage.h
src/cascadia/TerminalSettingsEditor/Profiles_Advanced.h
src/cascadia/TerminalSettingsEditor/Profiles_Appearance.h
src/cascadia/TerminalSettingsEditor/Profiles_Base.h
src/cascadia/TerminalSettingsEditor/ViewModelHelpers.h
src/cascadia/WindowsTerminal/IslandWindow.h
2024-03-07 09:50:28 -06:00
Mike Griese
fe57d5ca73 gutteral screaming at xaml 2024-03-07 06:51:53 -06:00
Mike Griese
a9d6b30baf whoops renamed that 2024-03-07 06:46:24 -06:00
Mike Griese
26b287c4ca format 2024-03-07 06:13:59 -06:00
Mike Griese
9fff54faef excise TYPED_EVENT 2024-03-07 06:13:21 -06:00
Mike Griese
0102ce9ac2 fix propertychanged 2024-03-06 11:26:16 -06:00
Mike Griese
4d47cd5866 cleanup 2024-03-04 16:34:36 -06:00
Mike Griese
0a11643f1d sanely pass around a cache instead of... whatever that was. 2024-03-04 16:30:16 -06:00
Mike Griese
17075d6744 Merge branch 'dev/migrie/fhl/scratchpad-pane' into dev/migrie/f/sui-panes 2024-02-28 11:50:29 -06:00
Mike Griese
25a8851986 Merge branch 'dev/migrie/fhl/non-terminal-panes-2023' into dev/migrie/fhl/scratchpad-pane 2024-02-28 11:36:02 -06:00
Mike Griese
de5f7af25d Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2024-02-28 11:32:40 -06:00
Mike Griese
092b3558f3 Merge branch 'dev/migrie/fhl/scratchpad-pane' into dev/migrie/f/sui-panes 2024-02-08 09:47:33 -06:00
Mike Griese
c2446334e6 Merge branch 'dev/migrie/fhl/non-terminal-panes-2023' into dev/migrie/fhl/scratchpad-pane 2024-02-08 09:46:46 -06:00
Mike Griese
3982358188 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2024-02-08 09:40:19 -06:00
Mike Griese
0d528f84f2 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2024-01-19 16:25:31 -06:00
Mike Griese
6bc711de06 maybe I'm not that good at coding 2023-11-08 11:10:58 -06:00
Mike Griese
f622d80004 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2023-11-08 05:55:27 -06:00
Mike Griese
4cec7e9b4b try to remove a few of these but ultimately, eh 2023-11-06 06:01:55 -06:00
Mike Griese
cf920e7d58 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2023-11-02 06:13:22 -05:00
Mike Griese
389ba20a98 spel 2023-10-25 14:41:57 -05:00
Mike Griese
dd8606ff9b Merge branch 'dev/migrie/fhl/scratchpad-pane' into dev/migrie/f/sui-panes 2023-10-25 11:04:43 -05:00
Mike Griese
7bc1457d42 nits and such 2023-10-25 11:03:41 -05:00
Mike Griese
e9e04d4e70 Merge branch 'dev/migrie/fhl/non-terminal-panes-2023' into dev/migrie/fhl/scratchpad-pane 2023-10-25 09:37:37 -05:00
Mike Griese
58e8f3c11c mostly nits 2023-10-25 09:37:23 -05:00
Mike Griese
8df9523a77 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2023-10-25 09:04:35 -05:00
Mike Griese
fd0640997d annoying build break 2023-10-13 15:17:38 -05:00
Mike Griese
fb74fc8c6a dead code 2023-10-13 14:58:19 -05:00
Mike Griese
5f4087ff00 finish exorcising SettingsTab 2023-10-13 14:56:50 -05:00
Mike Griese
81889a685c derp 2023-10-13 14:08:49 -05:00
Mike Griese
e82c627ebe dead code removal 2023-10-13 12:09:08 -05:00
Mike Griese
d726165330 terrible, but it works 2023-10-13 12:06:59 -05:00
Mike Griese
57e1f26d14 Merge branch 'dev/migrie/fhl/scratchpad-pane' into dev/migrie/f/sui-panes 2023-10-13 11:36:27 -05:00
Mike Griese
b49997b4b4 Merge branch 'dev/migrie/fhl/non-terminal-panes-2023' into dev/migrie/fhl/scratchpad-pane 2023-10-13 11:12:24 -05:00
Mike Griese
2086e0f3af Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2023-10-13 10:39:02 -05:00
Mike Griese
6107c3e551 Merge branch 'dev/migrie/fhl/scratchpad-pane' into dev/migrie/f/sui-panes 2023-09-11 05:43:06 -05:00
Mike Griese
46469aa5e3 Merge branch 'dev/migrie/fhl/non-terminal-panes-2023' into dev/migrie/fhl/scratchpad-pane 2023-09-11 05:24:30 -05:00
Mike Griese
c869b47e13 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2023-09-11 05:22:43 -05:00
Mike Griese
9531069538 background brush, done 2023-08-07 15:17:09 -05:00
Mike Griese
521e301541 update settings should work now 2023-08-03 13:50:11 -05:00
Mike Griese
842326daa5 icons for non-terminal pane content 2023-08-03 11:31:57 -05:00
Mike Griese
fb7c80938b derp 2023-08-01 11:37:10 -05:00
Mike Griese
29d0d57656 this works better than it has any right to 2023-07-27 16:29:26 -05:00
Mike Griese
cbd61b0a7d POC: yea, this works 2023-07-27 15:55:05 -05:00
Mike Griese
1cc9835454 feature flags too 2023-07-27 13:58:44 -05:00
Mike Griese
86914bdfc1 Merge branch 'dev/migrie/fhl/non-terminal-panes-2023' into dev/migrie/fhl/scratchpad-pane 2023-07-25 13:28:25 -05:00
Mike Griese
e0b003ad4d Merge branch 'main' into dev/migrie/fhl/non-terminal-panes-2023 2023-07-24 14:10:40 -05:00
Mike Griese
f89368c19b [PARENT] try to use GetActiveTerminalControl less in TerminalTab
(cherry picked from commit 262d95aae5)
2023-07-20 10:59:41 -05:00
Mike Griese
5582e1bcc8 [PARENT] You know what, I just went for it.
(cherry picked from commit 63ba8e19fd)
2023-07-20 10:59:28 -05:00
Mike Griese
a23c1a24dc keybindings too 2023-07-20 07:39:02 -05:00
Mike Griese
5f9add4000 Merge branch 'dev/migrie/fhl/non-terminal-panes-2023' into dev/migrie/fhl/scratchpad-pane 2023-07-20 07:04:10 -05:00
Mike Griese
11126f9b37 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2023-07-20 07:02:16 -05:00
Mike Griese
e31202b0b8 Merge commit '6a10ea5' into dev/migrie/fhl/non-terminal-panes-2023 2023-07-20 07:02:04 -05:00
Mike Griese
e6dc314c17 Merge commit 'b4042ea' into dev/migrie/fhl/non-terminal-panes-2023 2023-07-19 16:22:03 -05:00
Mike Griese
2d4030683a Let's just make it experimental 2023-07-18 13:47:58 -05:00
Mike Griese
262d95aae5 [PARENT] try to use GetActiveTerminalControl less in TerminalTab 2023-07-18 13:47:38 -05:00
Mike Griese
63ba8e19fd [PARENT] You know what, I just went for it. 2023-07-18 13:21:18 -05:00
Mike Griese
1b39db7ab0 Single commit that adds the whole scratchpad and action 2023-07-18 12:58:55 -05:00
Mike Griese
2dd8f409b2 [TO PARENT] dead code 2023-07-18 11:48:33 -05:00
Mike Griese
049c043279 some last cleanups 2023-07-18 10:26:32 -05:00
Mike Griese
a1da6c117e huge shuffling so that pane content can raise events instead of relying on termcontrol 2023-07-18 10:13:44 -05:00
Mike Griese
7c9ffb0e02 snapping now uses an interface, so that it's not TermControl-specific 2023-07-18 06:06:07 -05:00
Mike Griese
84df8197d4 close event 2023-07-17 14:22:12 -05:00
Mike Griese
5b3aa54b56 move GetNewTerminalArgs into IPaneContent 2023-07-17 12:42:43 -05:00
Mike Griese
ef6bb8a73c hey look, it builds now 2023-07-17 12:35:27 -05:00
Mike Griese
4e144425f0 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-terminal-panes-2023 2023-07-17 10:53:56 -05:00
Mike Griese
f353323a23 I wanted to do this in one shot but _zelda_ 2023-05-12 13:32:12 -05:00
167 changed files with 10926 additions and 1633 deletions

View File

@@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Package", "scratch\ScratchIslandApp\Package\Package.wapproj", "{CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleAppLib", "scratch\ScratchIslandApp\SampleApp\SampleAppLib.vcxproj", "{A4394404-37F7-41C1-802B-49788D3720E3}"
ProjectSection(ProjectDependencies) = postProject
{7CAE5851-50D5-4934-8D5E-30361A8A40F3} = {7CAE5851-50D5-4934-8D5E-30361A8A40F3}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleApp", "scratch\ScratchIslandApp\SampleApp\dll\SampleApp.vcxproj", "{26C51792-41A3-4FE0-AB5E-8B69D557BF91}"
ProjectSection(ProjectDependencies) = postProject
@@ -31,6 +34,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common Props", "Common Prop
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "src\dep\fmt\fmt.vcxproj", "{6BAE5851-50D5-4934-8D5E-30361A8A40F3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "md4c", "src\dep\md4c\md4c.vcxproj", "{7CAE5851-50D5-4934-8D5E-30361A8A40F3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types", "src\types\lib\types.vcxproj", "{18D09A24-8240-42D6-8CB6-236EEE820263}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}"
@@ -183,6 +188,34 @@ Global
{6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64
{6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32
{6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.ActiveCfg = AuditMode|x64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.Build.0 = AuditMode|x64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.ActiveCfg = AuditMode|Win32
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.Build.0 = AuditMode|Win32
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.ActiveCfg = Debug|ARM64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.Build.0 = Debug|ARM64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.ActiveCfg = Debug|x64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.Build.0 = Debug|x64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.ActiveCfg = Debug|Win32
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.Build.0 = Debug|Win32
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.Build.0 = Fuzzing|x64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.Build.0 = Fuzzing|Win32
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.ActiveCfg = Release|ARM64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.Build.0 = Release|ARM64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.ActiveCfg = Release|x64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32
{18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
{18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|x64.ActiveCfg = AuditMode|x64
@@ -213,6 +246,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}
{7CAE5851-50D5-4934-8D5E-30361A8A40F3} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}
{18D09A24-8240-42D6-8CB6-236EEE820263} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution

6492
oss/md4c/md4c.c Normal file

File diff suppressed because it is too large Load Diff

407
oss/md4c/md4c.h Normal file
View File

@@ -0,0 +1,407 @@
/*
* MD4C: Markdown parser for C
* (http://github.com/mity/md4c)
*
* Copyright (c) 2016-2024 Martin Mitáš
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef MD4C_H
#define MD4C_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined MD4C_USE_UTF16
/* Magic to support UTF-16. Note that in order to use it, you have to define
* the macro MD4C_USE_UTF16 both when building MD4C as well as when
* including this header in your code. */
#ifdef _WIN32
#include <windows.h>
typedef WCHAR MD_CHAR;
#else
#error MD4C_USE_UTF16 is only supported on Windows.
#endif
#else
typedef char MD_CHAR;
#endif
typedef unsigned MD_SIZE;
typedef unsigned MD_OFFSET;
/* Block represents a part of document hierarchy structure like a paragraph
* or list item.
*/
typedef enum MD_BLOCKTYPE {
/* <body>...</body> */
MD_BLOCK_DOC = 0,
/* <blockquote>...</blockquote> */
MD_BLOCK_QUOTE,
/* <ul>...</ul>
* Detail: Structure MD_BLOCK_UL_DETAIL. */
MD_BLOCK_UL,
/* <ol>...</ol>
* Detail: Structure MD_BLOCK_OL_DETAIL. */
MD_BLOCK_OL,
/* <li>...</li>
* Detail: Structure MD_BLOCK_LI_DETAIL. */
MD_BLOCK_LI,
/* <hr> */
MD_BLOCK_HR,
/* <h1>...</h1> (for levels up to 6)
* Detail: Structure MD_BLOCK_H_DETAIL. */
MD_BLOCK_H,
/* <pre><code>...</code></pre>
* Note the text lines within code blocks are terminated with '\n'
* instead of explicit MD_TEXT_BR. */
MD_BLOCK_CODE,
/* Raw HTML block. This itself does not correspond to any particular HTML
* tag. The contents of it _is_ raw HTML source intended to be put
* in verbatim form to the HTML output. */
MD_BLOCK_HTML,
/* <p>...</p> */
MD_BLOCK_P,
/* <table>...</table> and its contents.
* Detail: Structure MD_BLOCK_TABLE_DETAIL (for MD_BLOCK_TABLE),
* structure MD_BLOCK_TD_DETAIL (for MD_BLOCK_TH and MD_BLOCK_TD)
* Note all of these are used only if extension MD_FLAG_TABLES is enabled. */
MD_BLOCK_TABLE,
MD_BLOCK_THEAD,
MD_BLOCK_TBODY,
MD_BLOCK_TR,
MD_BLOCK_TH,
MD_BLOCK_TD
} MD_BLOCKTYPE;
/* Span represents an in-line piece of a document which should be rendered with
* the same font, color and other attributes. A sequence of spans forms a block
* like paragraph or list item. */
typedef enum MD_SPANTYPE {
/* <em>...</em> */
MD_SPAN_EM,
/* <strong>...</strong> */
MD_SPAN_STRONG,
/* <a href="xxx">...</a>
* Detail: Structure MD_SPAN_A_DETAIL. */
MD_SPAN_A,
/* <img src="xxx">...</a>
* Detail: Structure MD_SPAN_IMG_DETAIL.
* Note: Image text can contain nested spans and even nested images.
* If rendered into ALT attribute of HTML <IMG> tag, it's responsibility
* of the parser to deal with it.
*/
MD_SPAN_IMG,
/* <code>...</code> */
MD_SPAN_CODE,
/* <del>...</del>
* Note: Recognized only when MD_FLAG_STRIKETHROUGH is enabled.
*/
MD_SPAN_DEL,
/* For recognizing inline ($) and display ($$) equations
* Note: Recognized only when MD_FLAG_LATEXMATHSPANS is enabled.
*/
MD_SPAN_LATEXMATH,
MD_SPAN_LATEXMATH_DISPLAY,
/* Wiki links
* Note: Recognized only when MD_FLAG_WIKILINKS is enabled.
*/
MD_SPAN_WIKILINK,
/* <u>...</u>
* Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */
MD_SPAN_U
} MD_SPANTYPE;
/* Text is the actual textual contents of span. */
typedef enum MD_TEXTTYPE {
/* Normal text. */
MD_TEXT_NORMAL = 0,
/* NULL character. CommonMark requires replacing NULL character with
* the replacement char U+FFFD, so this allows caller to do that easily. */
MD_TEXT_NULLCHAR,
/* Line breaks.
* Note these are not sent from blocks with verbatim output (MD_BLOCK_CODE
* or MD_BLOCK_HTML). In such cases, '\n' is part of the text itself. */
MD_TEXT_BR, /* <br> (hard break) */
MD_TEXT_SOFTBR, /* '\n' in source text where it is not semantically meaningful (soft break) */
/* Entity.
* (a) Named entity, e.g. &nbsp;
* (Note MD4C does not have a list of known entities.
* Anything matching the regexp /&[A-Za-z][A-Za-z0-9]{1,47};/ is
* treated as a named entity.)
* (b) Numerical entity, e.g. &#1234;
* (c) Hexadecimal entity, e.g. &#x12AB;
*
* As MD4C is mostly encoding agnostic, application gets the verbatim
* entity text into the MD_PARSER::text_callback(). */
MD_TEXT_ENTITY,
/* Text in a code block (inside MD_BLOCK_CODE) or inlined code (`code`).
* If it is inside MD_BLOCK_CODE, it includes spaces for indentation and
* '\n' for new lines. MD_TEXT_BR and MD_TEXT_SOFTBR are not sent for this
* kind of text. */
MD_TEXT_CODE,
/* Text is a raw HTML. If it is contents of a raw HTML block (i.e. not
* an inline raw HTML), then MD_TEXT_BR and MD_TEXT_SOFTBR are not used.
* The text contains verbatim '\n' for the new lines. */
MD_TEXT_HTML,
/* Text is inside an equation. This is processed the same way as inlined code
* spans (`code`). */
MD_TEXT_LATEXMATH
} MD_TEXTTYPE;
/* Alignment enumeration. */
typedef enum MD_ALIGN {
MD_ALIGN_DEFAULT = 0, /* When unspecified. */
MD_ALIGN_LEFT,
MD_ALIGN_CENTER,
MD_ALIGN_RIGHT
} MD_ALIGN;
/* String attribute.
*
* This wraps strings which are outside of a normal text flow and which are
* propagated within various detailed structures, but which still may contain
* string portions of different types like e.g. entities.
*
* So, for example, lets consider this image:
*
* ![image alt text](http://example.org/image.png 'foo &quot; bar')
*
* The image alt text is propagated as a normal text via the MD_PARSER::text()
* callback. However, the image title ('foo &quot; bar') is propagated as
* MD_ATTRIBUTE in MD_SPAN_IMG_DETAIL::title.
*
* Then the attribute MD_SPAN_IMG_DETAIL::title shall provide the following:
* -- [0]: "foo " (substr_types[0] == MD_TEXT_NORMAL; substr_offsets[0] == 0)
* -- [1]: "&quot;" (substr_types[1] == MD_TEXT_ENTITY; substr_offsets[1] == 4)
* -- [2]: " bar" (substr_types[2] == MD_TEXT_NORMAL; substr_offsets[2] == 10)
* -- [3]: (n/a) (n/a ; substr_offsets[3] == 14)
*
* Note that these invariants are always guaranteed:
* -- substr_offsets[0] == 0
* -- substr_offsets[LAST+1] == size
* -- Currently, only MD_TEXT_NORMAL, MD_TEXT_ENTITY, MD_TEXT_NULLCHAR
* substrings can appear. This could change only of the specification
* changes.
*/
typedef struct MD_ATTRIBUTE {
const MD_CHAR* text;
MD_SIZE size;
const MD_TEXTTYPE* substr_types;
const MD_OFFSET* substr_offsets;
} MD_ATTRIBUTE;
/* Detailed info for MD_BLOCK_UL. */
typedef struct MD_BLOCK_UL_DETAIL {
int is_tight; /* Non-zero if tight list, zero if loose. */
MD_CHAR mark; /* Item bullet character in MarkDown source of the list, e.g. '-', '+', '*'. */
} MD_BLOCK_UL_DETAIL;
/* Detailed info for MD_BLOCK_OL. */
typedef struct MD_BLOCK_OL_DETAIL {
unsigned start; /* Start index of the ordered list. */
int is_tight; /* Non-zero if tight list, zero if loose. */
MD_CHAR mark_delimiter; /* Character delimiting the item marks in MarkDown source, e.g. '.' or ')' */
} MD_BLOCK_OL_DETAIL;
/* Detailed info for MD_BLOCK_LI. */
typedef struct MD_BLOCK_LI_DETAIL {
int is_task; /* Can be non-zero only with MD_FLAG_TASKLISTS */
MD_CHAR task_mark; /* If is_task, then one of 'x', 'X' or ' '. Undefined otherwise. */
MD_OFFSET task_mark_offset; /* If is_task, then offset in the input of the char between '[' and ']'. */
} MD_BLOCK_LI_DETAIL;
/* Detailed info for MD_BLOCK_H. */
typedef struct MD_BLOCK_H_DETAIL {
unsigned level; /* Header level (1 - 6) */
} MD_BLOCK_H_DETAIL;
/* Detailed info for MD_BLOCK_CODE. */
typedef struct MD_BLOCK_CODE_DETAIL {
MD_ATTRIBUTE info;
MD_ATTRIBUTE lang;
MD_CHAR fence_char; /* The character used for fenced code block; or zero for indented code block. */
} MD_BLOCK_CODE_DETAIL;
/* Detailed info for MD_BLOCK_TABLE. */
typedef struct MD_BLOCK_TABLE_DETAIL {
unsigned col_count; /* Count of columns in the table. */
unsigned head_row_count; /* Count of rows in the table header (currently always 1) */
unsigned body_row_count; /* Count of rows in the table body */
} MD_BLOCK_TABLE_DETAIL;
/* Detailed info for MD_BLOCK_TH and MD_BLOCK_TD. */
typedef struct MD_BLOCK_TD_DETAIL {
MD_ALIGN align;
} MD_BLOCK_TD_DETAIL;
/* Detailed info for MD_SPAN_A. */
typedef struct MD_SPAN_A_DETAIL {
MD_ATTRIBUTE href;
MD_ATTRIBUTE title;
int is_autolink; /* nonzero if this is an autolink */
} MD_SPAN_A_DETAIL;
/* Detailed info for MD_SPAN_IMG. */
typedef struct MD_SPAN_IMG_DETAIL {
MD_ATTRIBUTE src;
MD_ATTRIBUTE title;
} MD_SPAN_IMG_DETAIL;
/* Detailed info for MD_SPAN_WIKILINK. */
typedef struct MD_SPAN_WIKILINK {
MD_ATTRIBUTE target;
} MD_SPAN_WIKILINK_DETAIL;
/* Flags specifying extensions/deviations from CommonMark specification.
*
* By default (when MD_PARSER::flags == 0), we follow CommonMark specification.
* The following flags may allow some extensions or deviations from it.
*/
#define MD_FLAG_COLLAPSEWHITESPACE 0x0001 /* In MD_TEXT_NORMAL, collapse non-trivial whitespace into single ' ' */
#define MD_FLAG_PERMISSIVEATXHEADERS 0x0002 /* Do not require space in ATX headers ( ###header ) */
#define MD_FLAG_PERMISSIVEURLAUTOLINKS 0x0004 /* Recognize URLs as autolinks even without '<', '>' */
#define MD_FLAG_PERMISSIVEEMAILAUTOLINKS 0x0008 /* Recognize e-mails as autolinks even without '<', '>' and 'mailto:' */
#define MD_FLAG_NOINDENTEDCODEBLOCKS 0x0010 /* Disable indented code blocks. (Only fenced code works.) */
#define MD_FLAG_NOHTMLBLOCKS 0x0020 /* Disable raw HTML blocks. */
#define MD_FLAG_NOHTMLSPANS 0x0040 /* Disable raw HTML (inline). */
#define MD_FLAG_TABLES 0x0100 /* Enable tables extension. */
#define MD_FLAG_STRIKETHROUGH 0x0200 /* Enable strikethrough extension. */
#define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x0400 /* Enable WWW autolinks (even without any scheme prefix, if they begin with 'www.') */
#define MD_FLAG_TASKLISTS 0x0800 /* Enable task list extension. */
#define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */
#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */
#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */
#define MD_FLAG_HARD_SOFT_BREAKS 0x8000 /* Force all soft breaks to act as hard breaks. */
#define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS)
#define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS)
/* Convenient sets of flags corresponding to well-known Markdown dialects.
*
* Note we may only support subset of features of the referred dialect.
* The constant just enables those extensions which bring us as close as
* possible given what features we implement.
*
* ABI compatibility note: Meaning of these can change in time as new
* extensions, bringing the dialect closer to the original, are implemented.
*/
#define MD_DIALECT_COMMONMARK 0
#define MD_DIALECT_GITHUB (MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_TABLES | MD_FLAG_STRIKETHROUGH | MD_FLAG_TASKLISTS)
/* Parser structure.
*/
typedef struct MD_PARSER {
/* Reserved. Set to zero.
*/
unsigned abi_version;
/* Dialect options. Bitmask of MD_FLAG_xxxx values.
*/
unsigned flags;
/* Caller-provided rendering callbacks.
*
* For some block/span types, more detailed information is provided in a
* type-specific structure pointed by the argument 'detail'.
*
* The last argument of all callbacks, 'userdata', is just propagated from
* md_parse() and is available for any use by the application.
*
* Note any strings provided to the callbacks as their arguments or as
* members of any detail structure are generally not zero-terminated.
* Application has to take the respective size information into account.
*
* Any rendering callback may abort further parsing of the document by
* returning non-zero.
*/
int (*enter_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
int (*leave_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
int (*enter_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
int (*leave_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
int (*text)(MD_TEXTTYPE /*type*/, const MD_CHAR* /*text*/, MD_SIZE /*size*/, void* /*userdata*/);
/* Debug callback. Optional (may be NULL).
*
* If provided and something goes wrong, this function gets called.
* This is intended for debugging and problem diagnosis for developers;
* it is not intended to provide any errors suitable for displaying to an
* end user.
*/
void (*debug_log)(const char* /*msg*/, void* /*userdata*/);
/* Reserved. Set to NULL.
*/
void (*syntax)(void);
} MD_PARSER;
/* For backward compatibility. Do not use in new code.
*/
typedef MD_PARSER MD_RENDERER;
/* Parse the Markdown document stored in the string 'text' of size 'size'.
* The parser provides callbacks to be called during the parsing so the
* caller can render the document on the screen or convert the Markdown
* to another format.
*
* Zero is returned on success. If a runtime error occurs (e.g. a memory
* fails), -1 is returned. If the processing is aborted due any callback
* returning non-zero, the return value of the callback is returned.
*/
int md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata);
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* MD4C_H */

View File

@@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "CodeBlock.h"
#include <LibraryResources.h>
#include "CodeBlock.g.cpp"
#include "RequestRunCommandsArgs.g.cpp"
namespace winrt
{
namespace MUX = Microsoft::UI::Xaml;
namespace WUX = Windows::UI::Xaml;
using IInspectable = Windows::Foundation::IInspectable;
}
namespace winrt::SampleApp::implementation
{
CodeBlock::CodeBlock(const winrt::hstring& initialCommandlines) :
_providedCommandlines{ initialCommandlines }
{
InitializeComponent();
if (!_providedCommandlines.empty())
{
WUX::Controls::TextBlock b{};
b.Text(_providedCommandlines);
b.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); // TODO! get the Style from the control's resources
CommandLines().Children().Append(b);
}
}
void CodeBlock::_playPressed(const Windows::Foundation::IInspectable&,
const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
{
_block = nullptr;
OutputBlockContainer().Children().Clear();
auto args = winrt::make_self<RequestRunCommandsArgs>(Commandlines());
RequestRunCommands.raise(*this, *args);
}
winrt::Microsoft::Terminal::Control::NotebookBlock CodeBlock::OutputBlock()
{
return _block;
}
void CodeBlock::OutputBlock(const winrt::Microsoft::Terminal::Control::NotebookBlock& block)
{
_block = block;
_block.StateChanged({ get_weak(), &CodeBlock::_blockStateChanged });
OutputBlockContainer().Children().Append(_block.Control());
OutputBlockContainer().Visibility(WUX::Visibility::Visible);
}
void CodeBlock::_blockStateChanged(const winrt::Microsoft::Terminal::Control::NotebookBlock& sender,
const Windows::Foundation::IInspectable&)
{
switch (sender.State())
{
case winrt::Microsoft::Terminal::Control::BlockState::Default:
{
WUX::VisualStateManager::GoToState(RunButton(), L"Ready", false);
break;
}
case winrt::Microsoft::Terminal::Control::BlockState::Running:
{
WUX::VisualStateManager::GoToState(RunButton(), L"Running", false);
break;
}
case winrt::Microsoft::Terminal::Control::BlockState::Finished:
{
WUX::VisualStateManager::GoToState(RunButton(), L"AlreadyRan", false);
break;
}
}
}
}

View File

@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "CodeBlock.g.h"
#include "RequestRunCommandsArgs.g.h"
#include "../../../src/cascadia/inc/cppwinrt_utils.h"
#include <til/hash.h>
namespace winrt::SampleApp::implementation
{
struct CodeBlock : CodeBlockT<CodeBlock>
{
CodeBlock(const winrt::hstring& initialCommandlines);
til::property<winrt::hstring> Commandlines;
winrt::Microsoft::Terminal::Control::NotebookBlock OutputBlock();
void OutputBlock(const winrt::Microsoft::Terminal::Control::NotebookBlock& block);
til::property_changed_event PropertyChanged;
til::typed_event<SampleApp::CodeBlock, RequestRunCommandsArgs> RequestRunCommands;
private:
friend struct CodeBlockT<CodeBlock>; // for Xaml to bind events
winrt::hstring _providedCommandlines{};
winrt::Microsoft::Terminal::Control::NotebookBlock _block{ nullptr };
void _playPressed(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
void _blockStateChanged(const winrt::Microsoft::Terminal::Control::NotebookBlock& sender, const Windows::Foundation::IInspectable& e);
};
struct RequestRunCommandsArgs : RequestRunCommandsArgsT<RequestRunCommandsArgs>
{
RequestRunCommandsArgs(const winrt::hstring& commandlines) :
Commandlines{ commandlines } {};
til::property<winrt::hstring> Commandlines;
};
}
namespace winrt::SampleApp::factory_implementation
{
BASIC_FACTORY(CodeBlock);
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace SampleApp
{
runtimeclass RequestRunCommandsArgs
{
String Commandlines { get;};
}
[default_interface] runtimeclass CodeBlock : Windows.UI.Xaml.Controls.UserControl,
Windows.UI.Xaml.Data.INotifyPropertyChanged
{
CodeBlock(String initialCommandlines);
String Commandlines { get; set; };
Microsoft.Terminal.Control.NotebookBlock OutputBlock;
event Windows.Foundation.TypedEventHandler<CodeBlock, RequestRunCommandsArgs> RequestRunCommands;
};
}

View File

@@ -0,0 +1,163 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<UserControl x:Class="SampleApp.CodeBlock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)"
xmlns:contract7Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:SampleApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
d:DesignHeight="256"
d:DesignWidth="1024"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<Color x:Key="PlayButtonHoveredColor">#257f01</Color>
<Color x:Key="PlayButtonNormalColor">#88222222</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<Color x:Key="PlayButtonHoveredColor">#257f01</Color>
<Color x:Key="PlayButtonNormalColor">#88dddddd</Color>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<Style x:Key="PlayButtonTemplate"
TargetType="Button">
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="4" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="ButtonBaseElement"
Padding="{TemplateBinding Padding}"
AutomationProperties.AccessibilityView="Raw"
Background="{TemplateBinding Background}"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Viewbox Width="20"
Height="20">
<Grid>
<FontIcon x:Name="ButtonBackgroundIcon"
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
Foreground="{ThemeResource PlayButtonHoveredColor}"
Glyph="&#xF5b0;"
Visibility="Collapsed" />
<FontIcon x:Name="ButtonOutlineIcon"
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
Foreground="{ThemeResource PlayButtonNormalColor}"
Glyph="&#xE768;" />
<muxc:ProgressRing x:Name="StatusProgress"
IsActive="False" />
</Grid>
<!-- TODO! FontFamily="{ThemeResource SymbolThemeFontFamily}" -->
</Viewbox>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Target="ButtonBackgroundIcon.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="ButtonBackgroundIcon.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled" />
</VisualStateGroup>
<VisualStateGroup x:Name="PlayButtonStates">
<VisualState x:Name="Ready">
<VisualState.Setters>
<Setter Target="ButtonBackgroundIcon.Glyph" Value="&#xF5b0;" />
<Setter Target="ButtonOutlineIcon.Glyph" Value="&#xE768;" />
<Setter Target="StatusProgress.IsActive" Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Running">
<VisualState.Setters>
<Setter Target="ButtonBackgroundIcon.Glyph" Value=" " />
<Setter Target="ButtonOutlineIcon.Glyph" Value=" " />
<Setter Target="StatusProgress.IsActive" Value="True" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="AlreadyRan">
<VisualState.Setters>
<Setter Target="ButtonBackgroundIcon.Glyph" Value="&#xe72c;" />
<Setter Target="ButtonOutlineIcon.Glyph" Value="&#xe72c;" />
<Setter Target="StatusProgress.IsActive" Value="False" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CodeBlockLineTemplate"
TargetType="TextBlock">
<Setter Property="FontFamily" Value="Cascadia Code" />
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="RunButton"
Grid.Column="0"
Margin="0,9,0,0"
Padding="0"
VerticalAlignment="Top"
Style="{StaticResource PlayButtonTemplate}"
Tapped="_playPressed" />
<Border Grid.Column="1"
HorizontalAlignment="Stretch"
Background="#f6f8fa"
BorderBrush="#dbdbdb"
BorderThickness="1"
CornerRadius="4">
<StackPanel x:Name="CommandsAndOutput">
<StackPanel x:Name="CommandLines"
Padding="8">
<TextBlock FontFamily="Cascadia Code"
Text="{x:Bind Commandlines}" />
</StackPanel>
<StackPanel x:Name="OutputBlockContainer"
Visibility="Collapsed">
<!-- Put the TermControl here. -->
</StackPanel>
</StackPanel>
</Border>
</Grid>
</UserControl>

View File

@@ -6,6 +6,9 @@
#include <LibraryResources.h>
#include "MyPage.g.cpp"
#include "MySettings.h"
#include "CodeBlock.h"
#define MD4C_USE_UTF16
#include "..\..\..\oss\md4c\md4c.h"
using namespace std::chrono_literals;
using namespace winrt::Microsoft::Terminal;
@@ -19,6 +22,248 @@ namespace winrt
namespace winrt::SampleApp::implementation
{
struct MyMarkdownData
{
WUX::Controls::StackPanel root{};
implementation::MyPage* page{ nullptr };
WUX::Controls::TextBlock current{ nullptr };
WUX::Documents::Run currentRun{ nullptr };
SampleApp::CodeBlock currentCodeBlock{ nullptr };
};
int md_parser_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata)
{
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
switch (type)
{
case MD_BLOCK_UL:
{
break;
}
case MD_BLOCK_H:
{
MD_BLOCK_H_DETAIL* headerDetail = reinterpret_cast<MD_BLOCK_H_DETAIL*>(detail);
data->current = WUX::Controls::TextBlock{};
const auto fontSize = std::max(16u, 36u - ((headerDetail->level - 1) * 6u));
data->current.FontSize(fontSize);
data->current.FontWeight(Windows::UI::Text::FontWeights::Bold());
WUX::Documents::Run run{};
// run.Text(winrtL'#');
// Immediately add the header block
data->root.Children().Append(data->current);
if (headerDetail->level == 1)
{
// <Border Height="1" BorderThickness="1" BorderBrush="Red" HorizontalAlignment="Stretch"></Border>
WUX::Controls::Border b;
b.Height(1);
b.BorderThickness(WUX::ThicknessHelper::FromLengths(1, 1, 1, 1));
b.BorderBrush(WUX::Media::SolidColorBrush(Windows::UI::Colors::Gray()));
b.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
data->root.Children().Append(b);
}
break;
}
case MD_BLOCK_CODE:
{
MD_BLOCK_CODE_DETAIL* codeDetail = reinterpret_cast<MD_BLOCK_CODE_DETAIL*>(detail);
codeDetail;
data->currentCodeBlock = winrt::make<implementation::CodeBlock>(L"");
data->currentCodeBlock.Margin(WUX::ThicknessHelper::FromLengths(8, 8, 8, 8));
data->currentCodeBlock.RequestRunCommands({ data->page, &MyPage::_handleRunCommandRequest });
data->root.Children().Append(data->currentCodeBlock);
}
default:
{
break;
}
}
return 0;
}
int md_parser_leave_block(MD_BLOCKTYPE type, void* /*detail*/, void* userdata)
{
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
data;
switch (type)
{
case MD_BLOCK_UL:
{
break;
}
case MD_BLOCK_H:
{
// data->root.Children().Append(data->current);
data->current = nullptr;
break;
}
case MD_BLOCK_CODE:
{
// data->root.Children().Append(data->current);
data->current = nullptr;
break;
}
default:
{
break;
}
}
return 0;
}
int md_parser_enter_span(MD_SPANTYPE type, void* /*detail*/, void* userdata)
{
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
data;
if (data->current == nullptr)
{
data->current = WUX::Controls::TextBlock();
data->root.Children().Append(data->current);
}
if (data->currentRun == nullptr)
{
data->currentRun = WUX::Documents::Run();
}
auto currentRun = data->currentRun;
switch (type)
{
case MD_SPAN_STRONG:
{
currentRun.FontWeight(Windows::UI::Text::FontWeights::Bold());
break;
}
case MD_SPAN_EM:
{
currentRun.FontStyle(Windows::UI::Text::FontStyle::Italic);
break;
}
case MD_SPAN_CODE:
{
currentRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" });
break;
}
default:
{
break;
}
}
return 0;
}
int md_parser_leave_span(MD_SPANTYPE type, void* /*detail*/, void* userdata)
{
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
switch (type)
{
case MD_SPAN_EM:
case MD_SPAN_STRONG:
// {
// break;
// }
case MD_SPAN_CODE:
{
if (const auto& currentRun{ data->currentRun })
{
// data->current.Inlines().Append(currentRun);
// data->currentRun = nullptr;
}
break;
}
default:
{
break;
}
}
return 0;
}
int md_parser_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata)
{
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
winrt::hstring str{ text, size };
switch (type)
{
case MD_TEXT_BR:
case MD_TEXT_SOFTBR:
{
if (const auto& curr{ data->current })
{
data->current = WUX::Controls::TextBlock();
data->root.Children().Append(data->current);
}
break;
}
case MD_TEXT_CODE:
{
if (str == L"\n")
{
break;
}
if (const auto& codeBlock{ data->currentCodeBlock })
{
// code in a fenced block
auto currentText = codeBlock.Commandlines();
auto newText = currentText.empty() ? str :
currentText + winrt::hstring{ L"\r\n" } + str;
codeBlock.Commandlines(newText);
break;
}
else
{
// just normal `code` inline
// data->currentRun.Text(str);
[[fallthrough]];
}
}
case MD_TEXT_NORMAL:
default:
{
auto run = data->currentRun ? data->currentRun : WUX::Documents::Run{};
run.Text(str);
if (data->current)
{
data->current.Inlines().Append(run);
}
else
{
WUX::Controls::TextBlock block{};
block.Inlines().Append(run);
data->root.Children().Append(block);
data->current = block;
}
// data->root.Children().Append(block);
data->currentRun = nullptr;
break;
}
}
return 0;
}
int parseMarkdown(const winrt::hstring& markdown, MyMarkdownData& data)
{
MD_PARSER parser{
.abi_version = 0,
.flags = 0,
.enter_block = &md_parser_enter_block,
.leave_block = &md_parser_leave_block,
.enter_span = &md_parser_enter_span,
.leave_span = &md_parser_leave_span,
.text = &md_parser_text,
};
const auto result = md_parse(
markdown.c_str(),
(unsigned)markdown.size(),
&parser,
&data // user data
);
return result;
}
MyPage::MyPage()
{
InitializeComponent();
@@ -26,27 +271,77 @@ namespace winrt::SampleApp::implementation
void MyPage::Create()
{
auto settings = winrt::make_self<implementation::MySettings>();
_filePath = FilePathInput().Text();
_createNotebook();
_loadMarkdown();
}
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This TermControl is hosted in-proc...",
winrt::hstring{},
L"",
false,
L"",
nullptr,
32,
80,
winrt::guid(),
winrt::guid()) };
void MyPage::_clearOldNotebook()
{
RenderedMarkdown().Children().Clear();
_notebook = nullptr;
}
void MyPage::_loadMarkdown()
{
// Read _filePath, then parse as markdown.
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"
winrt::hstring myClass{ winrt::name_of<TerminalConnection::ConptyConnection>() };
TerminalConnection::ConnectionInformation connectInfo{ myClass, connectionSettings };
const wil::unique_handle file{ CreateFileW(_filePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) };
if (!file)
{
return;
}
TerminalConnection::ITerminalConnection conn{ TerminalConnection::ConnectionInformation::CreateConnection(connectInfo) };
Control::TermControl control{ *settings, *settings, conn };
char buffer[32 * 1024];
DWORD read = 0;
for (;;)
{
if (!ReadFile(file.get(), &buffer[0], sizeof(buffer), &read, nullptr))
{
break;
}
if (read < sizeof(buffer))
{
break;
}
}
// BLINDLY TREATING TEXT AS utf-8 (I THINK)
std::string markdownContents{ buffer, read };
winrt::hstring c = winrt::to_hstring(markdownContents);
MyMarkdownData data;
data.page = this;
InProcContent().Children().Append(control);
const auto parseResult = parseMarkdown(c, data);
if (0 == parseResult)
{
RenderedMarkdown().Children().Append(data.root);
}
}
void MyPage::_loadTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
{
auto p = FilePathInput().Text();
if (p != _filePath)
{
_filePath = p;
// Does the file exist? if not, bail
const wil::unique_handle file{ CreateFileW(_filePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) };
if (!file)
{
return;
}
// It does. Clear the old one
_clearOldNotebook();
_createNotebook();
_loadMarkdown();
}
}
void MyPage::_reloadTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
{
// Clear the old one
_clearOldNotebook();
_createNotebook();
_loadMarkdown();
}
// Method Description:
@@ -58,7 +353,113 @@ namespace winrt::SampleApp::implementation
// - the title of the focused control if there is one, else "Windows Terminal"
hstring MyPage::Title()
{
return { L"Sample Application" };
if (const auto& active{ _notebook.ActiveBlock() })
{
return active.Control().Title();
}
return { L"Terminal Notebook test" };
}
void MyPage::_createNotebook()
{
auto settings = winrt::make_self<implementation::MySettings>();
settings->DefaultBackground(til::color{ 0x25, 0x25, 0x25 });
settings->AutoMarkPrompts(true);
settings->StartingTitle(L"Terminal Notebook test");
auto envMap = winrt::single_threaded_map<winrt::hstring, winrt::hstring>();
envMap.Insert(L"PROMPT", L"$e]133;D$e\\$e]133;A$e\\$e]9;9;$P$e\\$P$G$e]133;B$e\\");
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This a notebook connection.",
winrt::hstring{},
L"",
false,
L"",
envMap.GetView(),
32,
80,
winrt::guid(),
winrt::guid()) };
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"
winrt::hstring myClass{ winrt::name_of<TerminalConnection::ConptyConnection>() };
TerminalConnection::ConnectionInformation connectInfo{ myClass, connectionSettings };
TerminalConnection::ITerminalConnection conn{ TerminalConnection::ConnectionInformation::CreateConnection(connectInfo) };
_notebook = Control::Notebook(*settings, *settings, conn);
}
void MyPage::_newBlockHandler(const Control::Notebook& /*sender*/,
const Control::NotebookBlock& block)
{
_addControl(block.Control());
}
void MyPage::_handleRunCommandRequest(const SampleApp::CodeBlock& sender,
const SampleApp::RequestRunCommandsArgs& request)
{
auto text = request.Commandlines();
auto targetControl = _notebook.ActiveBlock().Control();
sender.OutputBlock(_notebook.ActiveBlock());
targetControl.Height(256);
targetControl.VerticalAlignment(WUX::VerticalAlignment::Top);
targetControl.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
targetControl.Initialized([this, text](const auto&, auto&&) {
_notebook.SendCommands(text + L"\r");
});
}
void MyPage::_scrollToElement(const WUX::UIElement& element,
bool isVerticalScrolling,
bool smoothScrolling)
{
const auto scrollViewer = _scrollViewer();
const auto origin = winrt::Windows::Foundation::Point{ 0, 0 };
const auto transform_scrollContent = element.TransformToVisual(scrollViewer.Content().try_as<WUX::UIElement>());
const auto position_scrollContent = transform_scrollContent.TransformPoint(origin);
if (isVerticalScrolling)
{
scrollViewer.ChangeView(nullptr, position_scrollContent.Y, nullptr, !smoothScrolling);
}
else
{
scrollViewer.ChangeView(position_scrollContent.X, nullptr, nullptr, !smoothScrolling);
}
}
void MyPage::_addControl(const Control::TermControl& control)
{
control.Height(256);
control.VerticalAlignment(WUX::VerticalAlignment::Top);
control.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
WUX::Controls::Grid wrapper{};
wrapper.VerticalAlignment(WUX::VerticalAlignment::Top);
wrapper.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
wrapper.CornerRadius(WUX::CornerRadiusHelper::FromRadii(6, 6, 6, 6));
wrapper.Margin(WUX::ThicknessHelper::FromLengths(0, 5, 0, 7));
wrapper.Children().Append(control);
RenderedMarkdown().Children().Append(wrapper);
control.Focus(WUX::FocusState::Programmatic);
// Incredibly dumb: move off UI thread, then back on, then scroll to the
// new control.
_stupid(wrapper);
}
winrt::fire_and_forget MyPage::_stupid(WUX::UIElement elem)
{
co_await winrt::resume_after(2ms); // no, resume_background is not enough to make this work.
co_await winrt::resume_foreground(this->Dispatcher(), winrt::Windows::UI::Core::CoreDispatcherPriority::Low);
_scrollToElement(elem);
}
}

View File

@@ -17,8 +17,31 @@ namespace winrt::SampleApp::implementation
hstring Title();
void _handleRunCommandRequest(const SampleApp::CodeBlock& sender,
const SampleApp::RequestRunCommandsArgs& control);
private:
friend struct MyPageT<MyPage>; // for Xaml to bind events
void _createNotebook();
void _clearOldNotebook();
void _loadMarkdown();
winrt::Microsoft::Terminal::Control::Notebook _notebook{ nullptr };
winrt::hstring _filePath{};
void _loadTapped(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
void _reloadTapped(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
void _newBlockHandler(const winrt::Microsoft::Terminal::Control::Notebook& sender,
const winrt::Microsoft::Terminal::Control::NotebookBlock& control);
void _addControl(const winrt::Microsoft::Terminal::Control::TermControl& control);
void _scrollToElement(const Windows::UI::Xaml::UIElement& element,
bool isVerticalScrolling = true,
bool smoothScrolling = true);
winrt::fire_and_forget _stupid(Windows::UI::Xaml::UIElement elem);
};
}

View File

@@ -19,15 +19,26 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="GuidInput"
Width="400"
PlaceholderText="{}{guid here}" />
<Button Grid.Row="0">
Create
</Button>
</StackPanel>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="FilePathInput"
Grid.Column="0"
PlaceholderText="Enter a path to a markdown file..."
Text="Z:\dev\public\OpenConsole\scratch\ScratchIslandApp\SampleApp\simple-test.md" />
<StackPanel Grid.Column="1"
Orientation="Horizontal">
<Button Tapped="_loadTapped">
Load
</Button>
<Button Tapped="_reloadTapped">
<FontIcon FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
Glyph="&#xe72c;" />
</Button>
</StackPanel>
</Grid>
<Grid x:Name="TabContent"
Grid.Row="1"
@@ -35,7 +46,7 @@
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="1" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
@@ -46,14 +57,22 @@
VerticalAlignment="Stretch"
Background="#ff0000" />
<Grid x:Name="OutOfProcContent"
Grid.Column="1"
Padding="16"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#0000ff" />
<ScrollViewer x:Name="_scrollViewer"
Grid.Column="1"
Padding="3"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#eeeeee"
BringIntoViewOnFocusChange="True"
IsVerticalScrollChainingEnabled="True">
<StackPanel x:Name="RenderedMarkdown"
Grid.Column="1"
Padding="16"
HorizontalAlignment="Stretch"
Background="#fff"
Orientation="Vertical"
RequestedTheme="Light" />
</ScrollViewer>
</Grid>

View File

@@ -40,11 +40,18 @@
<Page Include="MyPage.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="CodeBlock.xaml">
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="App.base.h" />
<ClInclude Include="MySettings.h" />
<ClInclude Include="CodeBlock.h">
<DependentUpon>CodeBlock.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="MyPage.h">
<DependentUpon>MyPage.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -64,6 +71,10 @@
<DependentUpon>MyPage.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="CodeBlock.cpp">
<DependentUpon>CodeBlock.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
@@ -75,6 +86,8 @@
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<!-- <ClCompile Include="$(OpenConsoleDir)oss\md4c\md4c.c" /> -->
</ItemGroup>
<!-- ========================= idl Files ======================== -->
<ItemGroup>
@@ -89,6 +102,10 @@
<DependentUpon>MyPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="CodeBlock.idl">
<DependentUpon>CodeBlock.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
</ItemGroup>
<!-- ========================= Misc Files ======================== -->
<ItemGroup>
@@ -103,6 +120,14 @@
just has a bug in it.-->
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>Warning</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
<ItemGroup>
<!-- subsume fmt, one of our dependencies, into contypes. -->
<ProjectReference Include="$(OpenConsoleDir)src\dep\md4c\md4c.vcxproj">
<Project>{7cae5851-50d5-4934-8d5e-30361a8a40f3}</Project>
</ProjectReference>
</ItemGroup>
<!-- ========================== Other References ========================= -->
<ItemGroup>
<!-- Manually add references to each of our dependent winmds. Mark them as

View File

@@ -0,0 +1,21 @@
# Formatting test
## h2
### h3
#### h4
##### h5
**bold**
_italic_
_**BOTH**_
`code`
text before `code` and after
```
a fenced block of code
```
> quoted text
code that's indented

View File

@@ -39,6 +39,7 @@
#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.Documents.h>
#include <winrt/Windows.ui.xaml.media.h>
#include <winrt/Windows.UI.Xaml.Media.Animation.h>
#include <winrt/Windows.ui.xaml.input.h>
@@ -68,3 +69,4 @@ TRACELOGGING_DECLARE_PROVIDER(g_hSampleAppProvider);
// Manually include til after we include Windows.Foundation to give it winrt superpowers
#include "til.h"
#include <til/winrt.h>

View File

@@ -0,0 +1,61 @@
# Readme
This is my cool project. It's got lots of commands.
#### Useful directories
Click these to `cd` the notebook to relevant locations.
```
cd /d %~%
```
```
cd /d z:\dev\public\OpenConsole
```
## build
### Setup
Dependencies!
```
winget search "I most certainly don't exist"
```
### Actual build
To build the thing, run the following command:
```cmd
build the_thing
```
## test
```cmd
pwsh -c gci
ping 8.8.8.8
```
That _should_ run the tests
## Other helpful commmands
```
git status
```
```
git --no-pager diff dev/migrie/fhl/2024-spring-merge-base --stat -- . ":!oss/md4c"
```
```
ping 8.8.8.8
```
```
set FOO=%FOO%+1 & echo FOO set to %FOO%
```
```
echo This has been a test of the new code block objects
```

View File

@@ -57,8 +57,8 @@ void SampleIslandWindow::MakeWindow() noexcept
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
1024, //CW_USEDEFAULT, // Initial width
1024, // CW_USEDEFAULT, // Initial height
nullptr,
nullptr,
wc.hInstance,

View File

@@ -48,7 +48,7 @@ TextBuffer::TextBuffer(til::size screenBufferSize,
const TextAttribute defaultAttributes,
const UINT cursorSize,
const bool isActiveBuffer,
Microsoft::Console::Render::Renderer& renderer) :
Microsoft::Console::Render::Renderer* renderer) :
_renderer{ renderer },
_currentAttributes{ defaultAttributes },
// This way every TextBuffer will start with a ""unique"" _lastMutationId
@@ -860,7 +860,7 @@ void TextBuffer::IncrementCircularBuffer(const TextAttribute& fillAttributes)
// to the logical position 0 in the window (cursor coordinates and all other coordinates).
if (_isActiveBuffer)
{
_renderer.TriggerFlush(true);
_renderer->TriggerFlush(true);
}
// Prune hyperlinks to delete obsolete references
@@ -1235,7 +1235,7 @@ bool TextBuffer::IsActiveBuffer() const noexcept
return _isActiveBuffer;
}
Microsoft::Console::Render::Renderer& TextBuffer::GetRenderer() noexcept
Microsoft::Console::Render::Renderer* TextBuffer::GetRenderer() noexcept
{
return _renderer;
}
@@ -1244,7 +1244,7 @@ void TextBuffer::TriggerRedraw(const Viewport& viewport)
{
if (_isActiveBuffer)
{
_renderer.TriggerRedraw(viewport);
_renderer->TriggerRedraw(viewport);
}
}
@@ -1252,7 +1252,7 @@ void TextBuffer::TriggerRedrawCursor(const til::point position)
{
if (_isActiveBuffer)
{
_renderer.TriggerRedrawCursor(&position);
_renderer->TriggerRedrawCursor(&position);
}
}
@@ -1260,7 +1260,7 @@ void TextBuffer::TriggerRedrawAll()
{
if (_isActiveBuffer)
{
_renderer.TriggerRedrawAll();
_renderer->TriggerRedrawAll();
}
}
@@ -1268,7 +1268,7 @@ void TextBuffer::TriggerScroll()
{
if (_isActiveBuffer)
{
_renderer.TriggerScroll();
_renderer->TriggerScroll();
}
}
@@ -1276,7 +1276,7 @@ void TextBuffer::TriggerScroll(const til::point delta)
{
if (_isActiveBuffer)
{
_renderer.TriggerScroll(&delta);
_renderer->TriggerScroll(&delta);
}
}
@@ -1284,7 +1284,7 @@ void TextBuffer::TriggerNewTextNotification(const std::wstring_view newText)
{
if (_isActiveBuffer)
{
_renderer.TriggerNewTextNotification(newText);
_renderer->TriggerNewTextNotification(newText);
}
}

View File

@@ -108,7 +108,7 @@ public:
const TextAttribute defaultAttributes,
const UINT cursorSize,
const bool isActiveBuffer,
Microsoft::Console::Render::Renderer& renderer);
Microsoft::Console::Render::Renderer* renderer);
TextBuffer(const TextBuffer&) = delete;
TextBuffer(TextBuffer&&) = delete;
@@ -201,7 +201,8 @@ public:
void SetAsActiveBuffer(const bool isActiveBuffer) noexcept;
bool IsActiveBuffer() const noexcept;
Microsoft::Console::Render::Renderer& GetRenderer() noexcept;
Microsoft::Console::Render::Renderer* GetRenderer() noexcept;
void ChangeRenderer(Microsoft::Console::Render::Renderer* newRenderer) { _renderer = newRenderer; };
void TriggerRedraw(const Microsoft::Console::Types::Viewport& viewport);
void TriggerRedrawCursor(const til::point position);
@@ -369,7 +370,7 @@ private:
static void _AppendRTFText(std::string& contentBuilder, const std::wstring_view& text);
Microsoft::Console::Render::Renderer& _renderer;
Microsoft::Console::Render::Renderer* _renderer;
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;

View File

@@ -1326,7 +1326,7 @@ namespace TerminalAppLocalTests
const auto& controlSettings = activeControl.Settings();
VERIFY_IS_NOT_NULL(controlSettings);
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() });
});
TestOnUIThread([&page]() {
@@ -1344,7 +1344,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(controlSettings);
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() });
// And we should have stored a function to revert the change.
VERIFY_ARE_EQUAL(1u, page->_restorePreviewFuncs.size());
@@ -1366,7 +1366,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(controlSettings);
Log::Comment(L"Color should be changed");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() });
// After preview there should be no more restore functions to execute.
VERIFY_ARE_EQUAL(0u, page->_restorePreviewFuncs.size());
@@ -1394,7 +1394,7 @@ namespace TerminalAppLocalTests
const auto& controlSettings = activeControl.Settings();
VERIFY_IS_NOT_NULL(controlSettings);
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() });
});
TestOnUIThread([&page]() {
@@ -1412,7 +1412,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(controlSettings);
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() });
});
TestOnUIThread([&page]() {
@@ -1428,7 +1428,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(controlSettings);
Log::Comment(L"Color should be the same as it originally was");
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() });
});
Log::Comment(L"Sleep to let events propagate");
Sleep(250);
@@ -1450,7 +1450,7 @@ namespace TerminalAppLocalTests
const auto& controlSettings = activeControl.Settings();
VERIFY_IS_NOT_NULL(controlSettings);
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() });
});
TestOnUIThread([&page]() {
@@ -1467,7 +1467,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(controlSettings);
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() });
});
TestOnUIThread([&page]() {
@@ -1484,7 +1484,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(controlSettings);
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, til::color{ controlSettings.DefaultBackground() });
});
TestOnUIThread([&page]() {
@@ -1503,7 +1503,7 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(controlSettings);
Log::Comment(L"Color should be changed");
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, til::color{ controlSettings.DefaultBackground() });
});
Log::Comment(L"Sleep to let events propagate");
Sleep(250);

View File

@@ -56,6 +56,8 @@ Author(s):
#include <winrt/windows.applicationmodel.core.h>
#include <winrt/Microsoft.Terminal.TerminalConnection.h>
#include <winrt/Microsoft.Terminal.Core.h>
#include <winrt/Microsoft.Terminal.Control.h>
#include <winrt/Microsoft.Terminal.Settings.Model.h>
#include <winrt/Microsoft.UI.Xaml.Controls.h>

View File

@@ -95,8 +95,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows });
peasant.RenameRequested({ this, &Monarch::_renameRequested });
peasant.ShowNotificationIconRequested([this](auto&&, auto&&) { _ShowNotificationIconRequestedHandlers(*this, nullptr); });
peasant.HideNotificationIconRequested([this](auto&&, auto&&) { _HideNotificationIconRequestedHandlers(*this, nullptr); });
peasant.ShowNotificationIconRequested([this](auto&&, auto&&) { ShowNotificationIconRequested.raise(*this, nullptr); });
peasant.HideNotificationIconRequested([this](auto&&, auto&&) { HideNotificationIconRequested.raise(*this, nullptr); });
peasant.QuitAllRequested({ this, &Monarch::_handleQuitAll });
{
@@ -111,7 +111,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_WindowCreatedHandlers(nullptr, nullptr);
WindowCreated.raise(nullptr, nullptr);
return newPeasantsId;
}
catch (...)
@@ -141,7 +141,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// Let the process hosting the monarch run any needed logic before
// closing all windows.
auto args = winrt::make_self<implementation::QuitAllRequestedArgs>();
_QuitAllRequestedHandlers(*this, *args);
QuitAllRequested.raise(*this, *args);
if (const auto action = args->BeforeQuitAllAction())
{
@@ -207,7 +207,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
std::unique_lock lock{ _peasantsMutex };
_peasants.erase(peasantId);
}
_WindowClosedHandlers(nullptr, nullptr);
WindowClosed.raise(nullptr, nullptr);
}
// Method Description:
@@ -650,7 +650,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
auto findWindowArgs{ winrt::make_self<Remoting::implementation::FindTargetWindowArgs>(args) };
// This is handled by some handler in-proc
_FindTargetWindowRequestedHandlers(*this, *findWindowArgs);
FindTargetWindowRequested.raise(*this, *findWindowArgs);
// After the event was handled, ResultTargetWindow() will be filled with
// the parsed result.
@@ -741,7 +741,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
result->WindowName(targetWindowName);
result->ShouldCreateWindow(true);
_RequestNewWindowHandlers(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
RequestNewWindow.raise(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
// If this fails, it'll be logged in the following
// TraceLoggingWrite statement, with succeeded=false
@@ -779,7 +779,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
result->Id(windowID);
result->WindowName(targetWindowName);
_RequestNewWindowHandlers(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
RequestNewWindow.raise(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
return *result;
}
@@ -796,7 +796,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
auto result = winrt::make_self<Remoting::implementation::ProposeCommandlineResult>(true);
result->WindowName(targetWindowName);
_RequestNewWindowHandlers(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
RequestNewWindow.raise(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
return *result;
}
@@ -1115,7 +1115,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
auto request = winrt::make_self<implementation::WindowRequestedArgs>(nameIsReserved ? L"" : window,
content,
windowBounds);
_RequestNewWindowHandlers(*this, *request);
RequestNewWindow.raise(*this, *request);
}
}

View File

@@ -101,14 +101,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex, const Windows::Foundation::IReference<Windows::Foundation::Rect>& windowBounds);
void RequestSendContent(const Remoting::RequestReceiveContentArgs& args);
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs> FindTargetWindowRequested;
til::typed_event<> ShowNotificationIconRequested;
til::typed_event<> HideNotificationIconRequested;
til::typed_event<> WindowCreated;
til::typed_event<> WindowClosed;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs> QuitAllRequested;
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs);
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs> RequestNewWindow;
private:
uint64_t _ourPID;
@@ -223,7 +223,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// A peasant died, let the app host know that the number of
// windows has changed.
_WindowClosedHandlers(nullptr, nullptr);
WindowClosed.raise(nullptr, nullptr);
}
}

View File

@@ -67,7 +67,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// 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);
ExecuteCommandlineRequested.raise(*this, args);
return true;
}
@@ -97,7 +97,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// 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.
_WindowActivatedHandlers(*this, args);
WindowActivated.raise(*this, args);
successfullyNotified = true;
}
catch (...)
@@ -146,7 +146,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_SummonRequestedHandlers(*this, localCopy);
SummonRequested.raise(*this, localCopy);
}
// Method Description:
@@ -161,7 +161,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
{
// Not worried about try/catching this. The handler is in AppHost, which
// is in-proc for us.
_DisplayWindowIdRequestedHandlers(*this, nullptr);
DisplayWindowIdRequested.raise(*this, nullptr);
}
// Method Description:
@@ -182,7 +182,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// 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.
_IdentifyWindowsRequestedHandlers(*this, nullptr);
IdentifyWindowsRequested.raise(*this, nullptr);
successfullyNotified = true;
}
catch (...)
@@ -207,7 +207,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// 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);
RenameRequested.raise(*this, args);
if (args.Succeeded())
{
_WindowName = args.NewName();
@@ -233,7 +233,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
{
try
{
_ShowNotificationIconRequestedHandlers(*this, nullptr);
ShowNotificationIconRequested.raise(*this, nullptr);
}
catch (...)
{
@@ -249,7 +249,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
{
try
{
_HideNotificationIconRequestedHandlers(*this, nullptr);
HideNotificationIconRequested.raise(*this, nullptr);
}
catch (...)
{
@@ -265,7 +265,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
{
try
{
_QuitAllRequestedHandlers(*this, nullptr);
QuitAllRequested.raise(*this, nullptr);
}
catch (...)
{
@@ -281,7 +281,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
{
try
{
_AttachRequestedHandlers(*this, request);
AttachRequested.raise(*this, request);
}
catch (...)
{
@@ -297,7 +297,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
{
try
{
_QuitRequestedHandlers(*this, nullptr);
QuitRequested.raise(*this, nullptr);
}
catch (...)
{
@@ -318,7 +318,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
hstring Peasant::GetWindowLayout()
{
auto args = winrt::make_self<implementation::GetWindowLayoutArgs>();
_GetWindowLayoutRequestedHandlers(nullptr, *args);
GetWindowLayoutRequested.raise(nullptr, *args);
if (const auto op = args->WindowLayoutJsonAsync())
{
// This will fail if called on the UI thread, so the monarch should
@@ -331,6 +331,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void Peasant::SendContent(const Remoting::RequestReceiveContentArgs& args)
{
_SendContentRequestedHandlers(*this, args);
SendContentRequested.raise(*this, args);
}
}

View File

@@ -68,25 +68,25 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
winrt::hstring GetWindowLayout();
void SendContent(const winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs& args);
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs> WindowActivated;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs> ExecuteCommandlineRequested;
til::typed_event<> IdentifyWindowsRequested;
til::typed_event<> DisplayWindowIdRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs> RenameRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior> SummonRequested;
til::typed_event<> ShowNotificationIconRequested;
til::typed_event<> HideNotificationIconRequested;
til::typed_event<> QuitAllRequested;
til::typed_event<> QuitRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs> GetWindowLayoutRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest> AttachRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs> SendContentRequested;
WINRT_PROPERTY(winrt::hstring, WindowName);
WINRT_PROPERTY(winrt::hstring, ActiveTabTitle);
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs);
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);
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior);
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
TYPED_EVENT(SendContentRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs);
private:
Peasant(const uint64_t testPID);
uint64_t _ourPID;

View File

@@ -89,10 +89,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// done when we become the king. This will be called both for the first
// window, and when the current monarch dies.
_monarch.WindowCreated({ get_weak(), &WindowManager::_WindowCreatedHandlers });
_monarch.WindowClosed({ get_weak(), &WindowManager::_WindowClosedHandlers });
_monarch.WindowCreated({ get_weak(), &WindowManager::_bubbleWindowCreated });
_monarch.WindowClosed({ get_weak(), &WindowManager::_bubbleWindowClosed });
_monarch.FindTargetWindowRequested({ this, &WindowManager::_raiseFindTargetWindowRequested });
_monarch.QuitAllRequested({ get_weak(), &WindowManager::_QuitAllRequestedHandlers });
_monarch.QuitAllRequested({ get_weak(), &WindowManager::_bubbleQuitAllRequested });
_monarch.RequestNewWindow({ get_weak(), &WindowManager::_raiseRequestNewWindow });
}
@@ -109,12 +109,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void WindowManager::_raiseFindTargetWindowRequested(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args)
{
_FindTargetWindowRequestedHandlers(sender, args);
FindTargetWindowRequested.raise(sender, args);
}
void WindowManager::_raiseRequestNewWindow(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args)
{
_RequestNewWindowHandlers(sender, args);
RequestNewWindow.raise(sender, args);
}
Remoting::ProposeCommandlineResult WindowManager::ProposeCommandline(const Remoting::CommandlineArgs& args, const bool isolatedMode)
@@ -162,7 +162,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
auto findWindowArgs{ winrt::make_self<Remoting::implementation::FindTargetWindowArgs>(args) };
// This is handled by some handler in-proc
_FindTargetWindowRequestedHandlers(*this, *findWindowArgs);
FindTargetWindowRequested.raise(*this, *findWindowArgs);
// After the event was handled, ResultTargetWindow() will be filled with
// the parsed result.
@@ -356,7 +356,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
_monarch.AddPeasant(*p);
p->GetWindowLayoutRequested({ get_weak(), &WindowManager::_GetWindowLayoutRequestedHandlers });
p->GetWindowLayoutRequested({ get_weak(), &WindowManager::_bubbleGetWindowLayoutRequested });
TraceLoggingWrite(g_hRemotingProvider,
"WindowManager_CreateOurPeasant",
@@ -367,6 +367,23 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
return *p;
}
void WindowManager::_bubbleGetWindowLayoutRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs& e)
{
GetWindowLayoutRequested.raise(s, e);
}
void WindowManager::_bubbleWindowCreated(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e)
{
WindowCreated.raise(s, e);
}
void WindowManager::_bubbleWindowClosed(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e)
{
WindowClosed.raise(s, e);
}
void WindowManager::_bubbleQuitAllRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& e)
{
QuitAllRequested.raise(s, e);
}
void WindowManager::SignalClose(const Remoting::Peasant& peasant)
{
if (_monarch)

View File

@@ -47,14 +47,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
winrt::fire_and_forget RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex, Windows::Foundation::IReference<Windows::Foundation::Rect> windowBounds);
winrt::fire_and_forget RequestSendContent(Remoting::RequestReceiveContentArgs args);
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs> FindTargetWindowRequested;
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs);
til::typed_event<> WindowCreated;
til::typed_event<> WindowClosed;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs> QuitAllRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs> GetWindowLayoutRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs> RequestNewWindow;
private:
DWORD _registrationHostClass{ 0 };
@@ -70,6 +69,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);
void _raiseRequestNewWindow(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args);
void _bubbleWindowCreated(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e);
void _bubbleWindowClosed(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e);
void _bubbleQuitAllRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& e);
void _bubbleGetWindowLayoutRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs& e);
};
}

View File

@@ -15,9 +15,9 @@ namespace winrt::TerminalApp::implementation
winrt::hstring ApplicationDisplayName();
winrt::hstring ApplicationVersion();
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(bool, UpdatesAvailable, _PropertyChangedHandlers, false);
WINRT_OBSERVABLE_PROPERTY(bool, CheckingForUpdates, _PropertyChangedHandlers, false);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(bool, UpdatesAvailable, PropertyChanged.raise, false);
WINRT_OBSERVABLE_PROPERTY(bool, CheckingForUpdates, PropertyChanged.raise, false);
private:
friend struct AboutDialogT<AboutDialog>; // for Xaml to bind events

View File

@@ -5,6 +5,7 @@
#include "App.h"
#include "TerminalPage.h"
#include "ScratchpadContent.h"
#include "../WinRTUtils/inc/WtExeUtils.h"
#include "../../types/inc/utils.hpp"
#include "Utils.h"
@@ -117,7 +118,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleCloseWindow(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_CloseRequestedHandlers(nullptr, nullptr);
CloseRequested.raise(nullptr, nullptr);
args.Handled(true);
}
@@ -948,7 +949,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleIdentifyWindows(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_IdentifyWindowsRequestedHandlers(*this, nullptr);
IdentifyWindowsRequested.raise(*this, nullptr);
args.Handled(true);
}
@@ -977,7 +978,7 @@ namespace winrt::TerminalApp::implementation
{
const auto newName = realArgs.Name();
const auto request = winrt::make_self<implementation::RenameWindowRequestedArgs>(newName);
_RenameWindowRequestedHandlers(*this, *request);
RenameWindowRequested.raise(*this, *request);
args.Handled(true);
}
}
@@ -1147,7 +1148,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleOpenSystemMenu(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_OpenSystemMenuHandlers(*this, nullptr);
OpenSystemMenu.raise(*this, nullptr);
args.Handled(true);
}
@@ -1401,7 +1402,7 @@ namespace winrt::TerminalApp::implementation
{
if (const auto activePane{ activeTab->GetActivePane() })
{
_restartPaneConnection(activePane);
_restartPaneConnection(activePane->GetContent().try_as<TerminalApp::TerminalPaneContent>(), nullptr);
}
}
args.Handled(true);
@@ -1416,6 +1417,25 @@ namespace winrt::TerminalApp::implementation
}
args.Handled(true);
}
void TerminalPage::_HandleOpenScratchpad(const IInspectable& sender,
const ActionEventArgs& args)
{
if (Feature_ScratchpadPane::IsEnabled())
{
const auto& scratchPane{ winrt::make_self<ScratchpadContent>() };
// This is maybe a little wacky - add our key event handler to the pane
// we made. So that we can get actions for keys that the content didn't
// handle.
scratchPane->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler });
const auto resultPane = std::make_shared<Pane>(*scratchPane);
_SplitPane(_senderOrFocusedTab(sender), SplitDirection::Automatic, 0.5f, resultPane);
args.Handled(true);
}
}
void TerminalPage::_HandleOpenAbout(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{

View File

@@ -423,7 +423,7 @@ namespace winrt::TerminalApp::implementation
_settingsLoadExceptionText,
warnings,
_settings);
_SettingsChangedHandlers(*this, *ev);
SettingsChanged.raise(*this, *ev);
return;
}
}
@@ -452,7 +452,7 @@ namespace winrt::TerminalApp::implementation
_settingsLoadExceptionText,
warnings,
_settings);
_SettingsChangedHandlers(*this, *ev);
SettingsChanged.raise(*this, *ev);
}
// This is a continuation of AppLogic::Create() and includes the more expensive parts.

View File

@@ -74,7 +74,7 @@ namespace winrt::TerminalApp::implementation
TerminalApp::ParseCommandlineResult GetParseCommandlineMessage(array_view<const winrt::hstring> args);
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SettingsLoadEventArgs);
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SettingsLoadEventArgs> SettingsChanged;
private:
bool _isElevated{ false };

View File

@@ -32,7 +32,7 @@ namespace winrt::TerminalApp::implementation
{
auto button{ sender.as<Windows::UI::Xaml::Controls::Button>() };
auto rectClr{ button.Background().as<Windows::UI::Xaml::Media::SolidColorBrush>() };
_ColorSelectedHandlers(rectClr.Color());
ColorSelected.raise(rectClr.Color());
Hide();
}
@@ -45,7 +45,7 @@ namespace winrt::TerminalApp::implementation
// - <none>
void ColorPickupFlyout::ClearColorButton_Click(const IInspectable&, const Windows::UI::Xaml::RoutedEventArgs&)
{
_ColorClearedHandlers();
ColorCleared.raise();
Hide();
}
@@ -80,12 +80,12 @@ namespace winrt::TerminalApp::implementation
void ColorPickupFlyout::CustomColorButton_Click(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::RoutedEventArgs&)
{
auto color = customColorPicker().Color();
_ColorSelectedHandlers(color);
ColorSelected.raise(color);
Hide();
}
void ColorPickupFlyout::ColorPicker_ColorChanged(const Microsoft::UI::Xaml::Controls::ColorPicker&, const Microsoft::UI::Xaml::Controls::ColorChangedEventArgs& args)
{
_ColorSelectedHandlers(args.NewColor());
ColorSelected.raise(args.NewColor());
}
}

View File

@@ -13,8 +13,8 @@ namespace winrt::TerminalApp::implementation
void ClearColorButton_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
void ColorPicker_ColorChanged(const Microsoft::UI::Xaml::Controls::ColorPicker&, const Microsoft::UI::Xaml::Controls::ColorChangedEventArgs& args);
WINRT_CALLBACK(ColorCleared, TerminalApp::ColorClearedArgs);
WINRT_CALLBACK(ColorSelected, TerminalApp::ColorSelectedArgs);
til::event<TerminalApp::ColorClearedArgs> ColorCleared;
til::event<TerminalApp::ColorSelectedArgs> ColorSelected;
};
}

View File

@@ -235,7 +235,7 @@ namespace winrt::TerminalApp::implementation
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
{
_PreviewActionHandlers(*this, actionPaletteItem.Command());
PreviewAction.raise(*this, actionPaletteItem.Command());
}
}
else if (_currentMode == CommandPaletteMode::CommandlineMode)
@@ -569,7 +569,7 @@ namespace winrt::TerminalApp::implementation
void CommandPalette::_moveBackButtonClicked(const Windows::Foundation::IInspectable& /*sender*/,
const Windows::UI::Xaml::RoutedEventArgs&)
{
_PreviewActionHandlers(*this, nullptr);
PreviewAction.raise(*this, nullptr);
_searchBox().Focus(FocusState::Programmatic);
const auto previousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
@@ -714,7 +714,7 @@ namespace winrt::TerminalApp::implementation
// All other actions can just be dispatched.
if (actionPaletteItem.Command().ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
{
_DispatchCommandRequestedHandlers(*this, actionPaletteItem.Command());
DispatchCommandRequested.raise(*this, actionPaletteItem.Command());
}
TraceLoggingWrite(
@@ -768,7 +768,7 @@ namespace winrt::TerminalApp::implementation
{
if (const auto tab{ tabPaletteItem.Tab() })
{
_SwitchToTabRequestedHandlers(*this, tab);
SwitchToTabRequested.raise(*this, tab);
}
}
}
@@ -796,7 +796,7 @@ namespace winrt::TerminalApp::implementation
if (const auto commandLinePaletteItem{ filteredCommand.value().Item().try_as<winrt::TerminalApp::CommandLinePaletteItem>() })
{
_CommandLineExecutionRequestedHandlers(*this, commandLinePaletteItem.CommandLine());
CommandLineExecutionRequested.raise(*this, commandLinePaletteItem.CommandLine());
_close();
}
}
@@ -1187,7 +1187,7 @@ namespace winrt::TerminalApp::implementation
{
Visibility(Visibility::Collapsed);
_PreviewActionHandlers(*this, nullptr);
PreviewAction.raise(*this, nullptr);
// Reset visibility in case anchor mode tab switcher just finished.
_searchBox().Visibility(Visibility::Visible);

View File

@@ -48,18 +48,18 @@ namespace winrt::TerminalApp::implementation
void EnableTabSwitcherMode(const uint32_t startIdx, Microsoft::Terminal::Settings::Model::TabSwitcherMode tabSwitcherMode);
void EnableTabSearchMode();
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, PrefixCharacter, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, _PropertyChangedHandlers);
til::property_changed_event PropertyChanged;
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::TerminalApp::TabBase> SwitchToTabRequested;
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::hstring> CommandLineExecutionRequested;
til::typed_event<winrt::TerminalApp::CommandPalette, Microsoft::Terminal::Settings::Model::Command> DispatchCommandRequested;
til::typed_event<Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command> PreviewAction;
TYPED_EVENT(SwitchToTabRequested, winrt::TerminalApp::CommandPalette, winrt::TerminalApp::TabBase);
TYPED_EVENT(CommandLineExecutionRequested, winrt::TerminalApp::CommandPalette, winrt::hstring);
TYPED_EVENT(DispatchCommandRequested, winrt::TerminalApp::CommandPalette, Microsoft::Terminal::Settings::Model::Command);
TYPED_EVENT(PreviewAction, Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, PrefixCharacter, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, PropertyChanged.raise);
private:
struct winrt_object_hash

View File

@@ -62,7 +62,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
{
_outputRevoker = wrappedConnection.TerminalOutput(winrt::auto_revoke, { this, &DebugTapConnection::_OutputHandler });
_stateChangedRevoker = wrappedConnection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*e*/) {
_StateChangedHandlers(*this, nullptr);
StateChanged.raise(*this, nullptr);
});
_wrappedConnection = wrappedConnection;
}
@@ -127,7 +127,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
{
output.insert(++lfPos, L"\r\n");
}
_TerminalOutputHandlers(output);
TerminalOutput.raise(output);
}
// Called by the DebugInputTapConnection to print user input
@@ -135,7 +135,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
{
auto clean{ til::visualize_control_codes(str) };
auto formatted{ wil::str_printf<std::wstring>(L"\x1b[91m%ls\x1b[m", clean.data()) };
_TerminalOutputHandlers(formatted);
TerminalOutput.raise(formatted);
}
// Wire us up so that we can forward input through

View File

@@ -25,9 +25,9 @@ namespace winrt::Microsoft::TerminalApp::implementation
void SetInputTap(const Microsoft::Terminal::TerminalConnection::ITerminalConnection& inputTap);
WINRT_CALLBACK(TerminalOutput, winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler);
til::event<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler> TerminalOutput;
TYPED_EVENT(StateChanged, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection, winrt::Windows::Foundation::IInspectable);
til::typed_event<winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection, winrt::Windows::Foundation::IInspectable> StateChanged;
private:
void _PrintInput(const hstring& data);

View File

@@ -23,11 +23,11 @@ namespace winrt::TerminalApp::implementation
static int Compare(const winrt::TerminalApp::FilteredCommand& first, const winrt::TerminalApp::FilteredCommand& second);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::PaletteItem, Item, _PropertyChangedHandlers, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Filter, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::HighlightedText, HighlightedName, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(int, Weight, _PropertyChangedHandlers);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::PaletteItem, Item, PropertyChanged.raise, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Filter, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::HighlightedText, HighlightedName, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(int, Weight, PropertyChanged.raise);
private:
winrt::TerminalApp::HighlightedText _computeHighlightedName();

View File

@@ -13,9 +13,9 @@ namespace winrt::TerminalApp::implementation
HighlightedTextSegment() = default;
HighlightedTextSegment(const winrt::hstring& text, bool isHighlighted);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, TextSegment, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, IsHighlighted, _PropertyChangedHandlers);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, TextSegment, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsHighlighted, PropertyChanged.raise);
};
struct HighlightedText : HighlightedTextT<HighlightedText>
@@ -23,8 +23,8 @@ namespace winrt::TerminalApp::implementation
HighlightedText() = default;
HighlightedText(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>& segments);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>, Segments, _PropertyChangedHandlers);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>, Segments, PropertyChanged.raise);
};
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
runtimeclass BellEventArgs
{
Boolean FlashTaskbar { get; };
};
interface IPaneContent
{
Windows.UI.Xaml.FrameworkElement GetRoot();
void UpdateSettings(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
Windows.Foundation.Size MinSize { get; };
String Title { get; };
UInt64 TaskbarState { get; };
UInt64 TaskbarProgress { get; };
Boolean ReadOnly { get; };
String Icon { get; };
Windows.Foundation.IReference<Windows.UI.Color> TabColor { get; };
Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
Microsoft.Terminal.Settings.Model.NewTerminalArgs GetNewTerminalArgs(Boolean asContent);
void Focus(Windows.UI.Xaml.FocusState reason);
void Close();
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
event Windows.Foundation.TypedEventHandler<Object, BellEventArgs> BellRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> ConnectionStateChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> ReadOnlyChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FocusRequested;
};
enum PaneSnapDirection
{
Width,
Height
};
interface ISnappable
{
Single SnapDownToGrid(PaneSnapDirection direction, Single sizeToSnap);
Windows.Foundation.Size GridSize { get; };
};
}

View File

@@ -69,18 +69,18 @@ namespace winrt::TerminalApp::implementation
void MinMaxCloseControl::_MinimizeClick(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const RoutedEventArgs& e)
{
_MinimizeClickHandlers(*this, e);
MinimizeClick.raise(*this, e);
}
void MinMaxCloseControl::_MaximizeClick(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const RoutedEventArgs& e)
{
_MaximizeClickHandlers(*this, e);
MaximizeClick.raise(*this, e);
}
void MinMaxCloseControl::_CloseClick(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const RoutedEventArgs& e)
{
_CloseClickHandlers(*this, e);
CloseClick.raise(*this, e);
}
void MinMaxCloseControl::SetWindowVisualState(WindowVisualState visualState)

View File

@@ -28,9 +28,9 @@ namespace winrt::TerminalApp::implementation
void _CloseClick(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
TYPED_EVENT(MinimizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
TYPED_EVENT(MaximizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> MinimizeClick;
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> MaximizeClick;
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> CloseClick;
std::shared_ptr<ThrottledFuncTrailing<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
std::optional<CaptionButton> _lastPressedButton{ std::nullopt };

View File

@@ -11,10 +11,10 @@ namespace winrt::TerminalApp::implementation
public:
Windows::UI::Xaml::Controls::IconElement ResolvedIcon();
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Name, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, KeyChordText, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Name, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, KeyChordText, PropertyChanged.raise);
};
}

View File

@@ -33,19 +33,21 @@ static const int CombinedPaneBorderSize = 2 * PaneBorderSize;
static const int AnimationDurationInMilliseconds = 200;
static const Duration AnimationDuration = DurationHelper::FromTimeSpan(winrt::Windows::Foundation::TimeSpan(std::chrono::milliseconds(AnimationDurationInMilliseconds)));
Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFocused) :
_control{ control },
_lastActive{ lastFocused },
_profile{ profile }
Pane::Pane(const IPaneContent& content, const bool lastFocused) :
_content{ content },
_lastActive{ lastFocused }
{
_root.Children().Append(_borderFirst);
_borderFirst.Child(_control);
_setupControlEvents();
const auto& control{ _content.GetRoot() };
_borderFirst.Child(control);
// Register an event with the control to have it inform us when it gains focus.
_gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler });
_lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler });
if (control)
{
_gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ContentGotFocusHandler });
_lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ContentLostFocusHandler });
}
// When our border is tapped, make sure to transfer focus to our control.
// LOAD-BEARING: This will NOT work if the border's BorderBrush is set to
@@ -102,19 +104,6 @@ Pane::Pane(std::shared_ptr<Pane> first,
});
}
void Pane::_setupControlEvents()
{
_controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &Pane::_ControlConnectionStateChangedHandler });
_controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { this, &Pane::_ControlWarningBellHandler });
_controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { this, &Pane::_CloseTerminalRequestedHandler });
_controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { this, &Pane::_RestartTerminalRequestedHandler });
_controlEvents._ReadOnlyChanged = _control.ReadOnlyChanged(winrt::auto_revoke, { this, &Pane::_ControlReadOnlyChangedHandler });
}
void Pane::_removeControlEvents()
{
_controlEvents = {};
}
// Method Description:
// - Extract the terminal settings from the current (leaf) pane's control
// to be used to create an equivalent control
@@ -129,55 +118,7 @@ NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
// Leaves are the only things that have controls
assert(_IsLeaf());
NewTerminalArgs args{};
auto controlSettings = _control.Settings();
args.Profile(controlSettings.ProfileName());
// If we know the user's working directory use it instead of the profile.
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
{
args.StartingDirectory(dir);
}
else
{
args.StartingDirectory(controlSettings.StartingDirectory());
}
args.TabTitle(controlSettings.StartingTitle());
args.Commandline(controlSettings.Commandline());
args.SuppressApplicationTitle(controlSettings.SuppressApplicationTitle());
if (controlSettings.TabColor() || controlSettings.StartingTabColor())
{
til::color c;
// StartingTabColor is prioritized over other colors
if (const auto color = controlSettings.StartingTabColor())
{
c = til::color(color.Value());
}
else
{
c = til::color(controlSettings.TabColor().Value());
}
args.TabColor(winrt::Windows::Foundation::IReference<winrt::Windows::UI::Color>{ static_cast<winrt::Windows::UI::Color>(c) });
}
// TODO:GH#9800 - we used to be able to persist the color scheme that a
// TermControl was initialized with, by name. With the change to having the
// control own its own copy of its settings, this isn't possible anymore.
//
// We may be able to get around this by storing the Name in the Core::Scheme
// object. That would work for schemes set by the Terminal, but not ones set
// by VT, but that seems good enough.
// Only fill in the ContentId if absolutely needed. If you fill in a number
// here (even 0), we'll serialize that number, AND treat that action as an
// "attach existing" rather than a "create"
if (asContent)
{
args.ContentId(_control.ContentId());
}
return args;
return _content.GetNewTerminalArgs(asContent);
}
// Method Description:
@@ -1022,181 +963,18 @@ Pane::PaneNeighborSearch Pane::_FindPaneAndNeighbor(const std::shared_ptr<Pane>
}
// Method Description:
// - Called when our attached control is closed. Triggers listeners to our close
// event, if we're a leaf pane.
// - If this was called, and we became a parent pane (due to work on another
// thread), this function will do nothing (allowing the control's new parent
// to handle the event instead).
// - Returns true if the connection state of this pane is closed.
// Arguments:
// - <none>
// Return Value:
// - <none>
winrt::fire_and_forget Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& /*args*/)
// - true if the connection state of this Pane is closed.
bool Pane::IsConnectionClosed() const
{
auto newConnectionState = ConnectionState::Closed;
if (const auto coreState = sender.try_as<ICoreState>())
if (const auto& control{ GetTerminalControl() })
{
newConnectionState = coreState.ConnectionState();
}
const auto previousConnectionState = std::exchange(_connectionState, newConnectionState);
if (newConnectionState < ConnectionState::Closed)
{
// Pane doesn't care if the connection isn't entering a terminal state.
co_return;
}
const auto weakThis = weak_from_this();
co_await wil::resume_foreground(_root.Dispatcher());
const auto strongThis = weakThis.lock();
if (!strongThis)
{
co_return;
}
// It's possible that this event handler started being executed, scheduled
// on the UI thread, another child got created. So our control is
// actually no longer _our_ control, and instead could be a descendant.
//
// When the control's new Pane takes ownership of the control, the new
// parent will register its own event handler. That event handler will get
// fired after this handler returns, and will properly cleanup state.
if (!_IsLeaf())
{
co_return;
}
if (previousConnectionState < ConnectionState::Connected && newConnectionState >= ConnectionState::Failed)
{
// A failure to complete the connection (before it has _connected_) is not covered by "closeOnExit".
// This is to prevent a misconfiguration (closeOnExit: always, startingDirectory: garbage) resulting
// in Terminal flashing open and immediately closed.
co_return;
}
if (_profile)
{
if (_isDefTermSession && _profile.CloseOnExit() == CloseOnExitMode::Automatic)
{
// For 'automatic', we only care about the connection state if we were launched by Terminal
// Since we were launched via defterm, ignore the connection state (i.e. we treat the
// close on exit mode as 'always', see GH #13325 for discussion)
Close();
}
const auto mode = _profile.CloseOnExit();
if ((mode == CloseOnExitMode::Always) ||
((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed))
{
Close();
}
}
}
void Pane::_CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
// It's possible that this event handler started being executed, then before
// we got the lock, another thread created another child. So our control is
// actually no longer _our_ control, and instead could be a descendant.
//
// When the control's new Pane takes ownership of the control, the new
// parent will register its own event handler. That event handler will get
// fired after this handler returns, and will properly cleanup state.
if (!_IsLeaf())
{
return;
}
Close();
}
void Pane::_RestartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
if (!_IsLeaf())
{
return;
}
_RestartTerminalRequestedHandlers(shared_from_this());
}
winrt::fire_and_forget Pane::_playBellSound(winrt::Windows::Foundation::Uri uri)
{
auto weakThis{ weak_from_this() };
co_await wil::resume_foreground(_root.Dispatcher());
if (auto pane{ weakThis.lock() })
{
if (!_bellPlayerCreated)
{
// The MediaPlayer might not exist on Windows N SKU.
try
{
_bellPlayerCreated = true;
_bellPlayer = winrt::Windows::Media::Playback::MediaPlayer();
// GH#12258: The media keys (like play/pause) should have no effect on our bell sound.
_bellPlayer.CommandManager().IsEnabled(false);
}
CATCH_LOG();
}
if (_bellPlayer)
{
const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) };
const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) };
_bellPlayer.Source(item);
_bellPlayer.Play();
}
}
}
// Method Description:
// - Plays a warning note when triggered by the BEL control character,
// using the sound configured for the "Critical Stop" system event.`
// This matches the behavior of the Windows Console host.
// - Will also flash the taskbar if the bellStyle setting for this profile
// has the 'visual' flag set
// Arguments:
// - <unused>
void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
{
if (!_IsLeaf())
{
return;
}
if (_profile)
{
// We don't want to do anything if nothing is set, so check for that first
if (static_cast<int>(_profile.BellStyle()) != 0)
{
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible))
{
// Audible is set, play the sound
auto sounds{ _profile.BellSound() };
if (sounds && sounds.Size() > 0)
{
winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW<std::wstring>(sounds.GetAt(rand() % sounds.Size()).c_str()) };
winrt::Windows::Foundation::Uri uri{ soundPath };
_playBellSound(uri);
}
else
{
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
}
}
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
{
_control.BellLightOn();
}
// raise the event with the bool value corresponding to the taskbar flag
_PaneRaiseBellHandlers(nullptr, WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Taskbar));
}
return control.ConnectionState() >= ConnectionState::Closed;
}
return false;
}
// Event Description:
@@ -1207,7 +985,7 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
// - <unused>
// Return Value:
// - <none>
void Pane::_ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
void Pane::_ContentGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
const RoutedEventArgs& /* args */)
{
auto f = FocusState::Programmatic;
@@ -1215,17 +993,17 @@ void Pane::_ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectabl
{
f = o.FocusState();
}
_GotFocusHandlers(shared_from_this(), f);
GotFocus.raise(shared_from_this(), f);
}
// Event Description:
// - Called when our control loses focus. We'll use this to trigger our LostFocus
// callback. The tab that's hosting us should have registered a callback which
// can be used to update its own internal focus state
void Pane::_ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectable& /* sender */,
void Pane::_ContentLostFocusHandler(const winrt::Windows::Foundation::IInspectable& /* sender */,
const RoutedEventArgs& /* args */)
{
_LostFocusHandlers(shared_from_this());
LostFocus.raise(shared_from_this());
}
// Method Description:
@@ -1237,7 +1015,7 @@ void Pane::_ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectab
void Pane::Close()
{
// Fire our Closed event to tell our parent that we should be removed.
_ClosedHandlers(nullptr, nullptr);
Closed.raise(nullptr, nullptr);
}
// Method Description:
@@ -1245,21 +1023,9 @@ void Pane::Close()
// and connections beneath it.
void Pane::Shutdown()
{
// Clear out our media player callbacks, and stop any playing media. This
// will prevent the callback from being triggered after we've closed, and
// also make sure that our sound stops when we're closed.
if (_bellPlayer)
{
_bellPlayer.Pause();
_bellPlayer.Source(nullptr);
_bellPlayer.Close();
_bellPlayer = nullptr;
_bellPlayerCreated = false;
}
if (_IsLeaf())
{
_control.Close();
_content.Close();
}
else
{
@@ -1314,7 +1080,14 @@ TermControl Pane::GetLastFocusedTerminalControl()
{
if (p->_IsLeaf())
{
return p->_control;
if (const auto& terminalPane{ p->_content.try_as<TerminalPaneContent>() })
{
return terminalPane.GetTerminal();
}
else
{
return nullptr;
}
}
pane = p;
}
@@ -1322,7 +1095,38 @@ TermControl Pane::GetLastFocusedTerminalControl()
}
return _firstChild->GetLastFocusedTerminalControl();
}
return _control;
if (const auto& terminalPane{ _content.try_as<TerminalPaneContent>() })
{
return terminalPane.GetTerminal();
}
else
{
return nullptr;
}
}
IPaneContent Pane::GetLastFocusedContent()
{
if (!_IsLeaf())
{
if (_lastActive)
{
auto pane = shared_from_this();
while (const auto p = pane->_parentChildPath.lock())
{
if (p->_IsLeaf())
{
return p->_content;
}
pane = p;
}
// We didn't find our child somehow, they might have closed under us.
}
return _firstChild->GetLastFocusedContent();
}
return _content;
}
// Method Description:
@@ -1332,9 +1136,16 @@ TermControl Pane::GetLastFocusedTerminalControl()
// - <none>
// Return Value:
// - nullptr if this Pane is a parent, otherwise the TermControl of this Pane.
TermControl Pane::GetTerminalControl()
TermControl Pane::GetTerminalControl() const
{
return _IsLeaf() ? _control : nullptr;
if (const auto& terminalPane{ _getTerminalContent() })
{
return terminalPane.GetTerminal();
}
else
{
return nullptr;
}
}
// Method Description:
@@ -1381,19 +1192,11 @@ void Pane::SetActive()
Profile Pane::GetFocusedProfile()
{
auto lastFocused = GetActivePane();
return lastFocused ? lastFocused->_profile : nullptr;
}
// Method Description:
// - Returns true if the connection state of this pane is closed. If this Pane is not a leaf this will
// return false.
// Arguments:
// - <none>
// Return Value:
// - true if the connection state of this Pane is closed.
bool Pane::IsConnectionClosed() const
{
return _control && _control.ConnectionState() >= ConnectionState::Closed;
if (const auto& terminalPane{ lastFocused->_getTerminalContent() })
{
return terminalPane.GetProfile();
}
return nullptr;
}
// Method Description:
@@ -1465,10 +1268,10 @@ void Pane::UpdateVisuals()
// - <none>
void Pane::_Focus()
{
_GotFocusHandlers(shared_from_this(), FocusState::Programmatic);
if (const auto& control = GetLastFocusedTerminalControl())
GotFocus.raise(shared_from_this(), FocusState::Programmatic);
if (const auto& lastContent{ GetLastFocusedContent() })
{
control.Focus(FocusState::Programmatic);
lastContent.Focus(FocusState::Programmatic);
}
}
@@ -1508,20 +1311,22 @@ void Pane::_FocusFirstChild()
}
}
// Method Description:
// - Updates the settings of this pane, presuming that it is a leaf.
// Arguments:
// - settings: The new TerminalSettings to apply to any matching controls
// - profile: The profile from which these settings originated.
// Return Value:
// - <none>
void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Profile& profile)
void Pane::UpdateSettings(const CascadiaSettings& settings, const winrt::TerminalApp::TerminalSettingsCache& cache)
{
assert(_IsLeaf());
_profile = profile;
_control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings());
if (_content)
{
// We need to do a bit more work here for terminal
// panes. They need to know about the profile that was used for
// them, and about the focused/unfocused settings.
if (const auto& terminalPaneContent{ _content.try_as<TerminalPaneContent>() })
{
terminalPaneContent.UpdateTerminalSettings(cache);
}
else
{
_content.UpdateSettings(settings);
}
}
}
// Method Description:
@@ -1573,7 +1378,7 @@ std::shared_ptr<Pane> Pane::DetachPane(std::shared_ptr<Pane> pane)
auto detached = isFirstChild ? _firstChild : _secondChild;
// Remove the child from the tree, replace the current node with the
// other child.
_CloseChild(isFirstChild, true);
_CloseChild(isFirstChild);
// Update the borders on this pane and any children to match if we have
// no parent.
@@ -1582,7 +1387,7 @@ std::shared_ptr<Pane> Pane::DetachPane(std::shared_ptr<Pane> pane)
// Trigger the detached event on each child
detached->WalkTree([](auto pane) {
pane->_DetachedHandlers(pane);
pane->Detached.raise(pane);
});
return detached;
@@ -1602,12 +1407,9 @@ std::shared_ptr<Pane> Pane::DetachPane(std::shared_ptr<Pane> pane)
// Arguments:
// - closeFirst: if true, the first child should be closed, and the second
// should be preserved, and vice-versa for false.
// - isDetaching: if true, then the pane event handlers for the closed child
// should be kept, this way they don't have to be recreated when it is later
// reattached to a tree somewhere as the control moves with the pane.
// Return Value:
// - <none>
void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
void Pane::_CloseChild(const bool closeFirst)
{
// If we're a leaf, then chances are both our children closed in close
// succession. We waited on the lock while the other child was closed, so
@@ -1643,35 +1445,16 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
_borders = _GetCommonBorders();
// take the control, profile, id and isDefTermSession of the pane that _wasn't_ closed.
_control = remainingChild->_control;
_connectionState = remainingChild->_connectionState;
_profile = remainingChild->_profile;
_content = remainingChild->_content;
_id = remainingChild->Id();
_isDefTermSession = remainingChild->_isDefTermSession;
// Add our new event handler before revoking the old one.
_setupControlEvents();
// Revoke the old event handlers. Remove both the handlers for the panes
// themselves closing, and remove their handlers for their controls
// closing. At this point, if the remaining child's control is closed,
// they'll trigger only our event handler for the control's close.
// However, if we are detaching the pane we want to keep its control
// handlers since it is just getting moved.
if (!isDetaching)
{
closedChild->WalkTree([](auto p) {
if (p->_IsLeaf())
{
p->_removeControlEvents();
}
});
}
closedChild->Closed(closedChildClosedToken);
remainingChild->Closed(remainingChildClosedToken);
remainingChild->_removeControlEvents();
// If we or either of our children was focused, we want to take that
// focus from them.
@@ -1691,7 +1474,8 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
// Reattach the TermControl to our grid.
_root.Children().Append(_borderFirst);
_borderFirst.Child(_control);
const auto& control{ _content.GetRoot() };
_borderFirst.Child(control);
// Make sure to set our _splitState before focusing the control. If you
// fail to do this, when the tab handles the GotFocus event and asks us
@@ -1700,14 +1484,17 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
_splitState = SplitState::None;
// re-attach our handler for the control's GotFocus event.
_gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler });
_lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler });
if (control)
{
_gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ContentGotFocusHandler });
_lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ContentLostFocusHandler });
}
// If we're inheriting the "last active" state from one of our children,
// focus our control now. This should trigger our own GotFocus event.
if (usedToFocusClosedChildsTerminal || _lastActive)
{
_control.Focus(FocusState::Programmatic);
_content.Focus(FocusState::Programmatic);
// See GH#7252
// Manually fire off the GotFocus event. Typically, this is done
@@ -1717,7 +1504,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
// the control. Because Tab is relying on GotFocus to know who the
// active pane in the tree is, without this call, _no one_ will be
// the active pane any longer.
_GotFocusHandlers(shared_from_this(), FocusState::Programmatic);
GotFocus.raise(shared_from_this(), FocusState::Programmatic);
}
_UpdateBorders();
@@ -1746,15 +1533,6 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
// Remove the event handlers on the old children
remainingChild->Closed(remainingChildClosedToken);
closedChild->Closed(closedChildClosedToken);
if (!isDetaching)
{
closedChild->WalkTree([](auto p) {
if (p->_IsLeaf())
{
p->_removeControlEvents();
}
});
}
// Reset our UI:
_root.Children().Clear();
@@ -1828,7 +1606,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
}
// Notify the discarded child that it was closed by its parent
closedChild->_ClosedByParentHandlers();
closedChild->ClosedByParent.raise();
}
void Pane::_CloseChildRoutine(const bool closeFirst)
@@ -1847,7 +1625,7 @@ void Pane::_CloseChildRoutine(const bool closeFirst)
// this one doesn't seem to.
if (!animationsEnabledInOS || !animationsEnabledInApp || eitherChildZoomed)
{
_CloseChild(closeFirst, false);
_CloseChild(closeFirst);
return;
}
@@ -1950,7 +1728,7 @@ void Pane::_CloseChildRoutine(const bool closeFirst)
{
// We don't need to manually undo any of the above trickiness.
// We're going to re-parent the child's content into us anyways
pane->_CloseChild(closeFirst, false);
pane->_CloseChild(closeFirst);
}
});
}
@@ -2173,7 +1951,7 @@ void Pane::_SetupEntranceAnimation()
auto child = isFirstChild ? _firstChild : _secondChild;
auto childGrid = child->_root;
// If we are splitting a parent pane this may be null
auto control = child->_control;
auto control = child->_content ? child->_content.GetRoot() : nullptr;
// Build up our animation:
// * it'll take as long as our duration (200ms)
// * it'll change the value of our property from 0 to secondSize
@@ -2494,9 +2272,6 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
if (_IsLeaf())
{
// revoke our handler - the child will take care of the control now.
_removeControlEvents();
// Remove our old GotFocus handler from the control. We don't want the
// control telling us that it's now focused, we want it telling its new
// parent.
@@ -2525,11 +2300,8 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
else
{
// Move our control, guid, isDefTermSession into the first one.
_firstChild = std::make_shared<Pane>(_profile, _control);
_firstChild->_connectionState = std::exchange(_connectionState, ConnectionState::NotConnected);
_profile = nullptr;
_control = { nullptr };
_firstChild->_isDefTermSession = _isDefTermSession;
_firstChild = std::make_shared<Pane>(_content);
_content = nullptr;
_firstChild->_broadcastEnabled = _broadcastEnabled;
}
@@ -2852,8 +2624,16 @@ float Pane::CalcSnappedDimension(const bool widthOrHeight, const float dimension
// If requested size is already snapped, then both returned values equal this value.
Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
{
const auto direction{ widthOrHeight ? PaneSnapDirection::Width : PaneSnapDirection::Height };
if (_IsLeaf())
{
const auto& snappable{ _content.try_as<ISnappable>() };
if (!snappable)
{
return { dimension, dimension };
}
// If we're a leaf pane, align to the grid of controlling terminal
const auto minSize = _GetMinSize();
@@ -2864,8 +2644,10 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
return { minDimension, minDimension };
}
auto lower = _control.SnapDimensionToGrid(widthOrHeight, dimension);
if (widthOrHeight)
auto lower = snappable.SnapDownToGrid(widthOrHeight ? PaneSnapDirection::Width : PaneSnapDirection::Height,
dimension);
if (direction == PaneSnapDirection::Width)
{
lower += WI_IsFlagSet(_borders, Borders::Left) ? PaneBorderSize : 0;
lower += WI_IsFlagSet(_borders, Borders::Right) ? PaneBorderSize : 0;
@@ -2884,8 +2666,10 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
}
else
{
const auto cellSize = _control.CharacterDimensions();
const auto higher = lower + (widthOrHeight ? cellSize.Width : cellSize.Height);
const auto cellSize = snappable.GridSize();
const auto higher = lower + (direction == PaneSnapDirection::Width ?
cellSize.Width :
cellSize.Height);
return { lower, higher };
}
}
@@ -2931,21 +2715,36 @@ void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& si
{
if (_IsLeaf())
{
// We're a leaf pane, so just add one more row or column (unless isMinimumSize
// is true, see below).
if (sizeNode.isMinimumSize)
const auto& snappable{ _content.try_as<ISnappable>() };
if (snappable)
{
// If the node is of its minimum size, this size might not be snapped (it might
// be, say, half a character, or fixed 10 pixels), so snap it upward. It might
// however be already snapped, so add 1 to make sure it really increases
// (not strictly necessary but to avoid surprises).
sizeNode.size = _CalcSnappedDimension(widthOrHeight, sizeNode.size + 1).higher;
// We're a leaf pane, so just add one more row or column (unless isMinimumSize
// is true, see below).
if (sizeNode.isMinimumSize)
{
// If the node is of its minimum size, this size might not be snapped (it might
// be, say, half a character, or fixed 10 pixels), so snap it upward. It might
// however be already snapped, so add 1 to make sure it really increases
// (not strictly necessary but to avoid surprises).
sizeNode.size = _CalcSnappedDimension(widthOrHeight,
sizeNode.size + 1)
.higher;
}
else
{
const auto cellSize = snappable.GridSize();
sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height;
}
}
else
{
const auto cellSize = _control.CharacterDimensions();
sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height;
// If we're a leaf that didn't have a TermControl, then just increment
// by one. We have to increment by _some_ value, because this is used in
// a while() loop to find the next bigger size we can snap to. But since
// a non-terminal control doesn't really care what size it's snapped to,
// we can just say "one pixel larger is the next snap point"
sizeNode.size += 1;
}
}
else
@@ -3050,7 +2849,7 @@ Size Pane::_GetMinSize() const
{
if (_IsLeaf())
{
auto controlSize = _control.MinimumSize();
auto controlSize = _content.MinSize();
auto newWidth = controlSize.Width;
auto newHeight = controlSize.Height;
@@ -3148,14 +2947,17 @@ int Pane::GetLeafPaneCount() const noexcept
// created via default handoff
void Pane::FinalizeConfigurationGivenDefault()
{
_isDefTermSession = true;
if (const auto& terminalPane{ _content.try_as<TerminalPaneContent>() })
{
terminalPane.MarkAsDefterm();
}
}
// Method Description:
// - Returns true if the pane or one of its descendants is read-only
bool Pane::ContainsReadOnly() const
{
return _IsLeaf() ? _control.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
return _IsLeaf() ? _content.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
}
// Method Description:
@@ -3170,8 +2972,8 @@ void Pane::CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& s
{
if (_IsLeaf())
{
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(_control.TaskbarState(),
_control.TaskbarProgress()) };
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(_content.TaskbarState(),
_content.TaskbarProgress()) };
states.push_back(tbState);
}
else
@@ -3186,9 +2988,12 @@ void Pane::EnableBroadcast(bool enabled)
if (_IsLeaf())
{
_broadcastEnabled = enabled;
_control.CursorVisibility(enabled ?
CursorDisplayState::Shown :
CursorDisplayState::Default);
if (const auto& termControl{ GetTerminalControl() })
{
termControl.CursorVisibility(enabled ?
CursorDisplayState::Shown :
CursorDisplayState::Default);
}
UpdateVisuals();
}
else
@@ -3205,9 +3010,12 @@ void Pane::BroadcastKey(const winrt::Microsoft::Terminal::Control::TermControl&
const bool keyDown)
{
WalkTree([&](const auto& pane) {
if (pane->_IsLeaf() && pane->_control != sourceControl && !pane->_control.ReadOnly())
if (const auto& termControl{ pane->GetTerminalControl() })
{
pane->_control.RawWriteKeyEvent(vkey, scanCode, modifiers, keyDown);
if (termControl != sourceControl && !termControl.ReadOnly())
{
termControl.RawWriteKeyEvent(vkey, scanCode, modifiers, keyDown);
}
}
});
}
@@ -3218,9 +3026,12 @@ void Pane::BroadcastChar(const winrt::Microsoft::Terminal::Control::TermControl&
const winrt::Microsoft::Terminal::Core::ControlKeyStates modifiers)
{
WalkTree([&](const auto& pane) {
if (pane->_IsLeaf() && pane->_control != sourceControl && !pane->_control.ReadOnly())
if (const auto& termControl{ pane->GetTerminalControl() })
{
pane->_control.RawWriteChar(character, scanCode, modifiers);
if (termControl != sourceControl && !termControl.ReadOnly())
{
termControl.RawWriteChar(character, scanCode, modifiers);
}
}
});
}
@@ -3229,19 +3040,16 @@ void Pane::BroadcastString(const winrt::Microsoft::Terminal::Control::TermContro
const winrt::hstring& text)
{
WalkTree([&](const auto& pane) {
if (pane->_IsLeaf() && pane->_control != sourceControl && !pane->_control.ReadOnly())
if (const auto& termControl{ pane->GetTerminalControl() })
{
pane->_control.RawWriteString(text);
if (termControl != sourceControl && !termControl.ReadOnly())
{
termControl.RawWriteString(text);
}
}
});
}
void Pane::_ControlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*e*/)
{
UpdateVisuals();
}
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::_ComputeBorderColor()
{
if (_lastActive)
@@ -3249,7 +3057,7 @@ winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::_ComputeBorderColor()
return _themeResources.focusedBorderBrush;
}
if (_broadcastEnabled && (_IsLeaf() && !_control.ReadOnly()))
if (_broadcastEnabled && (_IsLeaf() && !_content.ReadOnly()))
{
return _themeResources.broadcastBorderBrush;
}

View File

@@ -21,6 +21,7 @@
#pragma once
#include "TaskbarState.h"
#include "TerminalPaneContent.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
@@ -61,8 +62,7 @@ struct PaneResources
class Pane : public std::enable_shared_from_this<Pane>
{
public:
Pane(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const winrt::Microsoft::Terminal::Control::TermControl& control,
Pane(const winrt::TerminalApp::IPaneContent& content,
const bool lastFocused = false);
Pane(std::shared_ptr<Pane> first,
@@ -73,7 +73,8 @@ public:
std::shared_ptr<Pane> GetActivePane();
winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl();
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl();
winrt::TerminalApp::IPaneContent GetLastFocusedContent();
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl() const;
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
bool IsConnectionClosed() const;
@@ -82,10 +83,15 @@ public:
// - If this is a branch/root pane, return nullptr.
winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const
{
return _profile;
if (const auto& c{ _content.try_as<winrt::TerminalApp::TerminalPaneContent>() })
{
return c.GetProfile();
}
return nullptr;
}
winrt::Windows::UI::Xaml::Controls::Grid GetRootElement();
winrt::TerminalApp::IPaneContent GetContent() const noexcept { return _IsLeaf() ? _content : nullptr; }
bool WasLastFocused() const noexcept;
void UpdateVisuals();
@@ -102,8 +108,7 @@ public:
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent = false, const bool asMovePane = false);
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(const bool asContent = false) const;
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const winrt::TerminalApp::TerminalSettingsCache& cache);
bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
std::shared_ptr<Pane> NavigateDirection(const std::shared_ptr<Pane> sourcePane,
const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction,
@@ -210,16 +215,15 @@ public:
void CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states);
WINRT_CALLBACK(ClosedByParent, winrt::delegate<>);
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
til::event<winrt::delegate<>> ClosedByParent;
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> Closed;
using gotFocusArgs = winrt::delegate<std::shared_ptr<Pane>, winrt::Windows::UI::Xaml::FocusState>;
WINRT_CALLBACK(GotFocus, gotFocusArgs);
WINRT_CALLBACK(LostFocus, winrt::delegate<std::shared_ptr<Pane>>);
WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler<bool>);
WINRT_CALLBACK(Detached, winrt::delegate<std::shared_ptr<Pane>>);
WINRT_CALLBACK(RestartTerminalRequested, winrt::delegate<std::shared_ptr<Pane>>);
til::event<gotFocusArgs> GotFocus;
til::event<winrt::delegate<std::shared_ptr<Pane>>> LostFocus;
til::event<winrt::Windows::Foundation::EventHandler<bool>> PaneRaiseBell;
til::event<winrt::delegate<std::shared_ptr<Pane>>> Detached;
private:
struct PanePoint;
@@ -239,10 +243,8 @@ private:
std::shared_ptr<Pane> _secondChild{ nullptr };
SplitState _splitState{ SplitState::None };
float _desiredSplitPosition;
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
bool _isDefTermSession{ false };
winrt::TerminalApp::IPaneContent _content{ nullptr };
#pragma endregion
std::optional<uint32_t> _id;
@@ -252,17 +254,6 @@ private:
winrt::event_token _firstClosedToken{ 0 };
winrt::event_token _secondClosedToken{ 0 };
struct ControlEventTokens
{
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
winrt::Microsoft::Terminal::Control::TermControl::WarningBell_revoker _WarningBell;
winrt::Microsoft::Terminal::Control::TermControl::CloseTerminalRequested_revoker _CloseTerminalRequested;
winrt::Microsoft::Terminal::Control::TermControl::RestartTerminalRequested_revoker _RestartTerminalRequested;
winrt::Microsoft::Terminal::Control::TermControl::ReadOnlyChanged_revoker _ReadOnlyChanged;
} _controlEvents;
void _setupControlEvents();
void _removeControlEvents();
winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker;
winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker;
@@ -271,13 +262,14 @@ private:
bool _zoomed{ false };
bool _broadcastEnabled{ false };
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
bool _bellPlayerCreated{ false };
bool _IsLeaf() const noexcept;
bool _HasFocusedChild() const noexcept;
void _SetupChildCloseHandlers();
bool _HasChild(const std::shared_ptr<Pane> child);
winrt::TerminalApp::TerminalPaneContent _getTerminalContent() const
{
return _IsLeaf() ? _content.try_as<winrt::TerminalApp::TerminalPaneContent>() : nullptr;
}
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> _Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
@@ -303,24 +295,16 @@ private:
const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction,
const PanePoint offset);
void _CloseChild(const bool closeFirst, const bool isDetaching);
void _CloseChild(const bool closeFirst);
void _CloseChildRoutine(const bool closeFirst);
void _Focus();
void _FocusFirstChild();
winrt::fire_and_forget _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& e);
void _ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
void _ContentGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
void _ContentLostFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _ControlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e);
void _CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _RestartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
std::pair<float, float> _CalcChildrenSizes(const float fullSize) const;
SnapChildrenSizeResult _CalcSnappedChildrenSizes(const bool widthOrHeight, const float fullSize) const;
SnapSizeResult _CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
@@ -331,8 +315,6 @@ private:
SplitState _convertAutomaticOrDirectionalSplitState(const winrt::Microsoft::Terminal::Settings::Model::SplitDirection& splitType) const;
winrt::fire_and_forget _playBellSound(winrt::Windows::Foundation::Uri uri);
// Function Description:
// - Returns true if the given direction can be used with the given split
// type.

View File

@@ -0,0 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "PaneArgs.h"
#include "BellEventArgs.g.cpp"

View File

@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "BellEventArgs.g.h"
namespace winrt::TerminalApp::implementation
{
struct BellEventArgs : public BellEventArgsT<BellEventArgs>
{
public:
BellEventArgs(bool flashTaskbar) :
FlashTaskbar(flashTaskbar) {}
til::property<bool> FlashTaskbar;
};
};

View File

@@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ScratchpadContent.h"
#include "PaneArgs.h"
#include "ScratchpadContent.g.cpp"
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
ScratchpadContent::ScratchpadContent()
{
_root = winrt::Windows::UI::Xaml::Controls::Grid{};
// Vertical and HorizontalAlignment are Stretch by default
auto res = Windows::UI::Xaml::Application::Current().Resources();
auto bg = res.Lookup(winrt::box_value(L"UnfocusedBorderBrush"));
_root.Background(bg.try_as<Media::Brush>());
_box = winrt::Windows::UI::Xaml::Controls::TextBox{};
_box.Margin({ 10, 10, 10, 10 });
_box.AcceptsReturn(true);
_box.TextWrapping(TextWrapping::Wrap);
_root.Children().Append(_box);
}
void ScratchpadContent::UpdateSettings(const CascadiaSettings& /*settings*/)
{
// Nothing to do.
}
winrt::Windows::UI::Xaml::FrameworkElement ScratchpadContent::GetRoot()
{
return _root;
}
winrt::Windows::Foundation::Size ScratchpadContent::MinSize()
{
return { 1, 1 };
}
void ScratchpadContent::Focus(winrt::Windows::UI::Xaml::FocusState reason)
{
_box.Focus(reason);
}
void ScratchpadContent::Close()
{
CloseRequested.raise(*this, nullptr);
}
NewTerminalArgs ScratchpadContent::GetNewTerminalArgs(const bool /* asContent */) const
{
return nullptr;
}
winrt::hstring ScratchpadContent::Icon() const
{
static constexpr std::wstring_view glyph{ L"\xe70b" }; // QuickNote
return winrt::hstring{ glyph };
}
winrt::Windows::UI::Xaml::Media::Brush ScratchpadContent::BackgroundBrush()
{
return _root.Background();
}
}

View File

@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "ScratchpadContent.g.h"
namespace winrt::TerminalApp::implementation
{
struct ScratchpadContent : ScratchpadContentT<ScratchpadContent>
{
ScratchpadContent();
winrt::Windows::UI::Xaml::FrameworkElement GetRoot();
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
winrt::Windows::Foundation::Size MinSize();
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
void Close();
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const;
winrt::hstring Title() { return L"Scratchpad"; }
uint64_t TaskbarState() { return 0; }
uint64_t TaskbarProgress() { return 0; }
bool ReadOnly() { return false; }
winrt::hstring Icon() const;
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept { return nullptr; }
winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush();
til::typed_event<> CloseRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::BellEventArgs> BellRequested;
til::typed_event<> TitleChanged;
til::typed_event<> TabColorChanged;
til::typed_event<> TaskbarProgressChanged;
til::typed_event<> ConnectionStateChanged;
til::typed_event<> ReadOnlyChanged;
til::typed_event<> FocusRequested;
private:
winrt::Windows::UI::Xaml::Controls::Grid _root{ nullptr };
winrt::Windows::UI::Xaml::Controls::TextBox _box{ nullptr };
};
}

View File

@@ -0,0 +1,86 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "SettingsPaneContent.h"
#include "PaneArgs.h"
#include "SettingsPaneContent.g.cpp"
#include "Utils.h"
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Microsoft::Terminal::Settings::Model;
#define ASSERT_UI_THREAD() assert(_sui.Dispatcher().HasThreadAccess())
namespace winrt::TerminalApp::implementation
{
SettingsPaneContent::SettingsPaneContent(CascadiaSettings settings)
{
_sui = winrt::Microsoft::Terminal::Settings::Editor::MainPage{ settings };
// Stash away the current requested theme of the app. We'll need that in
// _BackgroundBrush() to do a theme-aware resource lookup
_requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme();
}
void SettingsPaneContent::UpdateSettings(const CascadiaSettings& settings)
{
ASSERT_UI_THREAD();
_sui.UpdateSettings(settings);
_requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme();
}
winrt::Windows::UI::Xaml::FrameworkElement SettingsPaneContent::GetRoot()
{
return _sui;
}
winrt::Windows::Foundation::Size SettingsPaneContent::MinSize()
{
return { 1, 1 };
}
void SettingsPaneContent::Focus(winrt::Windows::UI::Xaml::FocusState reason)
{
if (reason != FocusState::Unfocused)
{
_sui.as<Controls::Page>().Focus(reason);
}
}
void SettingsPaneContent::Close()
{
CloseRequested.raise(*this, nullptr);
}
NewTerminalArgs SettingsPaneContent::GetNewTerminalArgs(const bool /* asContent */) const
{
// For now, we're doing a terrible thing in TerminalTab itself to
// generate an OpenSettings action manually, without asking for the pane
// structure.
return nullptr;
}
winrt::hstring SettingsPaneContent::Icon() const
{
// This is the Setting icon (looks like a gear)
static constexpr std::wstring_view glyph{ L"\xE713" };
return winrt::hstring{ glyph };
}
Windows::Foundation::IReference<winrt::Windows::UI::Color> SettingsPaneContent::TabColor() const noexcept
{
return nullptr;
}
winrt::Windows::UI::Xaml::Media::Brush SettingsPaneContent::BackgroundBrush()
{
// Look up the color we should use for the settings tab item from our
// resources. This should only be used for when "terminalBackground" is
// requested.
static const auto key = winrt::box_value(L"SettingsUiTabBrush");
// You can't just do a Application::Current().Resources().TryLookup
// lookup, cause the app theme never changes! Do the hacky version
// instead.
return ThemeLookup(Application::Current().Resources(), _requestedTheme, key).try_as<winrt::Windows::UI::Xaml::Media::Brush>();
}
}

View File

@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "SettingsPaneContent.g.h"
#include <LibraryResources.h>
namespace winrt::TerminalApp::implementation
{
struct SettingsPaneContent : SettingsPaneContentT<SettingsPaneContent>
{
SettingsPaneContent(winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
winrt::Windows::UI::Xaml::FrameworkElement GetRoot();
winrt::Microsoft::Terminal::Settings::Editor::MainPage SettingsUI() { return _sui; }
winrt::Windows::Foundation::Size MinSize();
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
void Close();
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const;
winrt::hstring Title() { return RS_(L"SettingsTab"); }
uint64_t TaskbarState() { return 0; }
uint64_t TaskbarProgress() { return 0; }
bool ReadOnly() { return false; }
winrt::hstring Icon() const;
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept;
winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush();
til::typed_event<> CloseRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::BellEventArgs> BellRequested;
til::typed_event<> TitleChanged;
til::typed_event<> TabColorChanged;
til::typed_event<> TaskbarProgressChanged;
til::typed_event<> ConnectionStateChanged;
til::typed_event<> ReadOnlyChanged;
til::typed_event<> FocusRequested;
private:
winrt::Microsoft::Terminal::Settings::Editor::MainPage _sui{ nullptr };
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(SettingsPaneContent);
}

View File

@@ -1,131 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include <LibraryResources.h>
#include "SettingsTab.h"
#include "SettingsTab.g.cpp"
#include "Utils.h"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Settings::Editor;
using namespace winrt::Windows::System;
namespace winrt
{
namespace MUX = Microsoft::UI::Xaml;
namespace WUX = Windows::UI::Xaml;
}
#define ASSERT_UI_THREAD() assert(TabViewItem().Dispatcher().HasThreadAccess())
namespace winrt::TerminalApp::implementation
{
SettingsTab::SettingsTab(MainPage settingsUI,
winrt::Windows::UI::Xaml::ElementTheme requestedTheme)
{
Content(settingsUI);
_requestedTheme = requestedTheme;
_MakeTabViewItem();
_CreateContextMenu();
_CreateIcon();
}
void SettingsTab::UpdateSettings(CascadiaSettings settings)
{
ASSERT_UI_THREAD();
auto settingsUI{ Content().as<MainPage>() };
settingsUI.UpdateSettings(settings);
// Stash away the current requested theme of the app. We'll need that in
// _BackgroundBrush() to do a theme-aware resource lookup
_requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme();
}
// Method Description:
// - Creates a list of actions that can be run to recreate the state of this tab
// Arguments:
// - asContent: unused. There's nothing different we need to do when
// serializing the settings tab for moving to another window. If we ever
// really want to support opening the SUI to a specific page, we can
// re-evaluate including that arg in this action then.
// Return Value:
// - The list of actions.
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions(const bool /*asContent*/) const
{
ASSERT_UI_THREAD();
ActionAndArgs action;
action.Action(ShortcutAction::OpenSettings);
OpenSettingsArgs args{ SettingsTarget::SettingsUI };
action.Args(args);
return std::vector{ std::move(action) };
}
// Method Description:
// - Focus the settings UI
// Arguments:
// - focusState: The FocusState mode by which focus is to be obtained.
// Return Value:
// - <none>
void SettingsTab::Focus(WUX::FocusState focusState)
{
ASSERT_UI_THREAD();
_focusState = focusState;
if (_focusState != FocusState::Unfocused)
{
Content().as<WUX::Controls::Page>().Focus(focusState);
}
}
// Method Description:
// - Initializes a TabViewItem for this Tab instance.
// Arguments:
// - <none>
// Return Value:
// - <none>
void SettingsTab::_MakeTabViewItem()
{
TabBase::_MakeTabViewItem();
Title(RS_(L"SettingsTab"));
TabViewItem().Header(winrt::box_value(Title()));
}
// Method Description:
// - Set the icon on the TabViewItem for this tab.
// Arguments:
// - <none>
// Return Value:
// - <none>
void SettingsTab::_CreateIcon()
{
// This is the Setting icon (looks like a gear)
static constexpr std::wstring_view glyph{ L"\xE713" };
// The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
Icon(winrt::hstring{ glyph });
TabViewItem().IconSource(Microsoft::Terminal::UI::IconPathConverter::IconSourceMUX(glyph, false));
}
winrt::Windows::UI::Xaml::Media::Brush SettingsTab::_BackgroundBrush()
{
// Look up the color we should use for the settings tab item from our
// resources. This should only be used for when "terminalBackground" is
// requested.
static const auto key = winrt::box_value(L"SettingsUiTabBrush");
// You can't just do a Application::Current().Resources().TryLookup
// lookup, cause the app theme never changes! Do the hacky version
// instead.
return ThemeLookup(Application::Current().Resources(), _requestedTheme, key).try_as<winrt::Windows::UI::Xaml::Media::Brush>();
}
}

View File

@@ -1,43 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- SettingsTab.h
Abstract:
- The SettingsTab is a tab whose content is a Settings UI control. They can
coexist in a TabView with all other types of tabs, like the TerminalTab.
There should only be at most one SettingsTab open at any given time.
Author(s):
- Leon Liang - October 2020
--*/
#pragma once
#include "TabBase.h"
#include "SettingsTab.g.h"
namespace winrt::TerminalApp::implementation
{
struct SettingsTab : SettingsTabT<SettingsTab, TabBase>
{
public:
SettingsTab(winrt::Microsoft::Terminal::Settings::Editor::MainPage settingsUI,
winrt::Windows::UI::Xaml::ElementTheme requestedTheme);
void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
private:
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;
void _MakeTabViewItem() override;
void _CreateIcon();
virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override;
};
}

View File

@@ -1,12 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TabBase.idl";
namespace TerminalApp
{
[default_interface] runtimeclass SettingsTab : TabBase
{
void UpdateSettings(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
}
}

View File

@@ -268,7 +268,7 @@ namespace winrt::TerminalApp::implementation
const auto selectedCommand = _filteredActionsView().SelectedItem();
const auto filteredCommand{ selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>() };
_PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"SelectedItem" });
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"SelectedItem" });
// Make sure to not send the preview if we're collapsed. This can
// sometimes fire after we've been closed, which can trigger us to

View File

@@ -50,12 +50,12 @@ namespace winrt::TerminalApp::implementation
til::typed_event<winrt::TerminalApp::SuggestionsControl, Microsoft::Terminal::Settings::Model::Command> DispatchCommandRequested;
til::typed_event<Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command> PreviewAction;
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, _PropertyChangedHandlers);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, PropertyChanged.raise);
private:
struct winrt_object_hash

View File

@@ -53,7 +53,7 @@ namespace winrt::TerminalApp::implementation
contextMenuFlyout.Closed([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_RequestFocusActiveControlHandlers();
tab->RequestFocusActiveControl.raise();
}
});
_AppendCloseMenuItems(contextMenuFlyout);
@@ -106,7 +106,7 @@ namespace winrt::TerminalApp::implementation
closeTabMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_CloseRequestedHandlers(nullptr, nullptr);
tab->CloseRequested.raise(nullptr, nullptr);
}
});
closeTabMenuItem.Text(RS_(L"TabClose"));
@@ -260,7 +260,7 @@ namespace winrt::TerminalApp::implementation
TabViewItem().Tapped([weakThis{ get_weak() }](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_RequestFocusActiveControlHandlers();
tab->RequestFocusActiveControl.raise();
}
});

View File

@@ -32,23 +32,23 @@ namespace winrt::TerminalApp::implementation
Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility CloseButtonVisibility();
void CloseButtonVisibility(Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility visible);
WINRT_CALLBACK(RequestFocusActiveControl, winrt::delegate<void()>);
til::event<winrt::delegate<void()>> RequestFocusActiveControl;
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
WINRT_CALLBACK(CloseRequested, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> Closed;
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> CloseRequested;
til::property_changed_event PropertyChanged;
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
WINRT_PROPERTY(uint32_t, TabViewIndex, 0);
// The TabViewNumTabs is the number of Tab objects in TerminalPage's _tabs vector.
WINRT_PROPERTY(uint32_t, TabViewNumTabs, 0);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, ReadOnly, _PropertyChangedHandlers, false);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, ReadOnly, PropertyChanged.raise, false);
WINRT_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewItem, TabViewItem, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::FrameworkElement, Content, _PropertyChangedHandlers, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::FrameworkElement, Content, PropertyChanged.raise, nullptr);
protected:
winrt::Windows::UI::Xaml::FocusState _focusState{ winrt::Windows::UI::Xaml::FocusState::Unfocused };

View File

@@ -120,7 +120,7 @@ namespace winrt::TerminalApp::implementation
_CloseRenameBox();
if (!_renameCancelled)
{
_TitleChangeRequestedHandlers(HeaderRenamerTextBox().Text());
TitleChangeRequested.raise(HeaderRenamerTextBox().Text());
}
}
@@ -132,7 +132,7 @@ namespace winrt::TerminalApp::implementation
{
HeaderRenamerTextBox().Visibility(Windows::UI::Xaml::Visibility::Collapsed);
HeaderTextBlock().Visibility(Windows::UI::Xaml::Visibility::Visible);
_RenameEndedHandlers(*this, nullptr);
RenameEnded.raise(*this, nullptr);
}
}
}

View File

@@ -19,14 +19,13 @@ namespace winrt::TerminalApp::implementation
bool InRename();
WINRT_CALLBACK(TitleChangeRequested, TerminalApp::TitleChangeRequestedArgs);
til::event<TerminalApp::TitleChangeRequestedArgs> TitleChangeRequested;
til::typed_event<> RenameEnded;
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(double, RenamerMaxWidth, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, _PropertyChangedHandlers);
TYPED_EVENT(RenameEnded, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(double, RenamerMaxWidth, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, PropertyChanged.raise);
private:
bool _receivedKeyDown{ false };

View File

@@ -19,7 +19,6 @@
#include "TabRowControl.h"
#include "ColorHelper.h"
#include "DebugTapConnection.h"
#include "SettingsTab.h"
#include "..\TerminalSettingsModel\FileUtils.h"
#include <shlobj.h>
@@ -63,7 +62,7 @@ namespace winrt::TerminalApp::implementation
// - existingConnection: An optional connection that is already established to a PTY
// for this tab to host instead of creating one.
// If not defined, the tab will create the connection.
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection)
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs)
try
{
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
@@ -86,7 +85,7 @@ namespace winrt::TerminalApp::implementation
//
// This call to _MakePane won't return nullptr, we already checked that
// case above with the _maybeElevate call.
_CreateNewTabFromPane(_MakePane(newTerminalArgs, nullptr, existingConnection));
_CreateNewTabFromPane(_MakePane(newTerminalArgs, nullptr));
return S_OK;
}
CATCH_RETURN();
@@ -148,7 +147,7 @@ namespace winrt::TerminalApp::implementation
// Update the taskbar progress as well. We'll raise our own
// SetTaskbarProgress event here, to get tell the hosting
// application to re-query this value from us.
page->_SetTaskbarProgressHandlers(*page, nullptr);
page->SetTaskbarProgress.raise(*page, nullptr);
auto profile = tab->GetFocusedProfile();
page->_UpdateBackground(profile);
@@ -164,24 +163,15 @@ namespace winrt::TerminalApp::implementation
if (page && tab)
{
page->_RaiseVisualBellHandlers(nullptr, nullptr);
page->RaiseVisualBell.raise(nullptr, nullptr);
}
});
auto tabViewItem = newTabImpl->TabViewItem();
_tabView.TabItems().InsertAt(insertPosition, tabViewItem);
// Set this tab's icon to the icon from the user's profile
if (const auto profile{ newTabImpl->GetFocusedProfile() })
{
const auto& icon = profile.EvaluatedIcon();
if (!icon.empty())
{
const auto theme = _settings.GlobalSettings().CurrentTheme();
const auto iconStyle = (theme && theme.Tab()) ? theme.Tab().IconStyle() : IconStyle::Default;
newTabImpl->UpdateIcon(icon, iconStyle);
}
}
// Set this tab's icon to the icon from the content
_UpdateTabIcon(*newTabImpl);
tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabClick });
@@ -226,13 +216,15 @@ namespace winrt::TerminalApp::implementation
// Arguments:
// - pane: The pane to use as the root.
// - insertPosition: Optional parameter to indicate the position of tab.
void TerminalPage::_CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition)
TerminalApp::TerminalTab TerminalPage::_CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition)
{
if (pane)
{
auto newTabImpl = winrt::make_self<TerminalTab>(pane);
_InitializeTab(newTabImpl, insertPosition);
return *newTabImpl;
}
return nullptr;
}
// Method Description:
@@ -242,11 +234,13 @@ namespace winrt::TerminalApp::implementation
// - tab: the Tab to update the title for.
void TerminalPage::_UpdateTabIcon(TerminalTab& tab)
{
if (const auto profile = tab.GetFocusedProfile())
if (const auto content{ tab.GetActiveContent() })
{
const auto& icon{ content.Icon() };
const auto theme = _settings.GlobalSettings().CurrentTheme();
const auto iconStyle = (theme && theme.Tab()) ? theme.Tab().IconStyle() : IconStyle::Default;
tab.UpdateIcon(profile.EvaluatedIcon(), iconStyle);
tab.UpdateIcon(icon, iconStyle);
}
}
@@ -486,7 +480,7 @@ namespace winrt::TerminalApp::implementation
// if the user manually closed all tabs.
// Do this only if we are the last window; the monarch will notice
// we are missing and remove us that way otherwise.
_LastTabClosedHandlers(*this, winrt::make<LastTabClosedEventArgs>(!_maintainStateOnTabClose));
LastTabClosed.raise(*this, winrt::make<LastTabClosedEventArgs>(!_maintainStateOnTabClose));
}
else if (focusedTabIndex.has_value() && focusedTabIndex.value() == gsl::narrow_cast<uint32_t>(tabIndex))
{
@@ -800,14 +794,6 @@ namespace winrt::TerminalApp::implementation
}
}
}
else if (auto index{ _GetFocusedTabIndex() })
{
const auto tab{ _tabs.GetAt(*index) };
if (tab.try_as<TerminalApp::SettingsTab>())
{
_HandleCloseTabRequested(tab);
}
}
}
// Method Description:
@@ -954,7 +940,7 @@ namespace winrt::TerminalApp::implementation
// Raise an event that our title changed
if (_settings.GlobalSettings().ShowTitleInTitlebar())
{
_TitleChangedHandlers(*this, tab.Title());
TitleChanged.raise(*this, tab.Title());
}
_updateThemeColors();

View File

@@ -52,7 +52,7 @@ namespace winrt::TerminalApp::implementation
// Sometimes nested bindings do not get updated,
// thus let's notify property changed on TabStatus when one of its properties changes
auto item{ weakThis.get() };
item->_PropertyChangedHandlers(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
item->PropertyChanged.raise(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
});
}
}

View File

@@ -18,7 +18,7 @@ namespace winrt::TerminalApp::implementation
return _tab.get();
}
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, PropertyChanged.raise);
private:
winrt::weak_ref<winrt::TerminalApp::TabBase> _tab;

View File

@@ -17,8 +17,8 @@ namespace winrt::TerminalApp::implementation
void OnNewTabButtonDrop(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::DragEventArgs& e);
void OnNewTabButtonDragOver(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::DragEventArgs& e);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(bool, ShowElevationShield, _PropertyChangedHandlers, false);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(bool, ShowElevationShield, PropertyChanged.raise, false);
};
}

View File

@@ -88,9 +88,6 @@
<DependentUpon>PaletteItemTemplateSelector.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="SettingsTab.h">
<DependentUpon>SettingsTab.idl</DependentUpon>
</ClInclude>
<ClInclude Include="PaletteItem.h" />
<ClInclude Include="TabBase.h">
<DependentUpon>TabBase.idl</DependentUpon>
@@ -131,6 +128,9 @@
</ClInclude>
<ClInclude Include="FilteredCommand.h" />
<ClInclude Include="Pane.h" />
<ClInclude Include="PaneArgs.h">
<DependentUpon>IPaneContent.idl</DependentUpon>
</ClInclude>
<ClInclude Include="ColorHelper.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="ShortcutActionDispatch.h">
@@ -158,7 +158,19 @@
<ClInclude Include="SettingsLoadEventArgs.h">
<DependentUpon>TerminalWindow.idl</DependentUpon>
</ClInclude>
<ClInclude Include="TerminalPaneContent.h">
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClInclude>
<ClInclude Include="ScratchpadContent.h">
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClInclude>
<ClInclude Include="SettingsPaneContent.h">
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClInclude>
<ClInclude Include="Toast.h" />
<ClInclude Include="TerminalSettingsCache.h">
<DependentUpon>TerminalSettingsCache.idl</DependentUpon>
</ClInclude>
<ClInclude Include="SuggestionsControl.h">
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
</ClInclude>
@@ -179,9 +191,6 @@
<DependentUpon>PaletteItemTemplateSelector.idl</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="SettingsTab.cpp">
<DependentUpon>SettingsTab.idl</DependentUpon>
</ClCompile>
<ClCompile Include="PaletteItem.cpp" />
<ClCompile Include="TabBase.cpp">
<DependentUpon>TabBase.idl</DependentUpon>
@@ -230,6 +239,9 @@
</ClCompile>
<ClCompile Include="FilteredCommand.cpp" />
<ClCompile Include="Pane.cpp" />
<ClCompile Include="PaneArgs.cpp">
<DependentUpon>IPaneContent.idl</DependentUpon>
</ClCompile>
<ClCompile Include="Pane.LayoutSizeNode.cpp" />
<ClCompile Include="ColorHelper.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
@@ -262,8 +274,20 @@
<ClCompile Include="TerminalWindow.cpp">
<DependentUpon>TerminalWindow.idl</DependentUpon>
</ClCompile>
<ClCompile Include="TerminalPaneContent.cpp">
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClCompile>
<ClCompile Include="ScratchpadContent.cpp">
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClCompile>
<ClCompile Include="SettingsPaneContent.cpp">
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="Toast.cpp" />
<ClCompile Include="TerminalSettingsCache.cpp">
<DependentUpon>TerminalSettingsCache.idl</DependentUpon>
</ClCompile>
<ClCompile Include="SuggestionsControl.cpp">
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
</ClCompile>
@@ -283,7 +307,6 @@
<Midl Include="PaletteItemTemplateSelector.idl">
<SubType>Designer</SubType>
</Midl>
<Midl Include="SettingsTab.idl" />
<Midl Include="PaletteItem.idl" />
<Midl Include="ShortcutActionDispatch.idl" />
<Midl Include="AppKeyBindings.idl" />
@@ -334,6 +357,9 @@
<SubType>Code</SubType>
</Midl>
<Midl Include="FilteredCommand.idl" />
<Midl Include="IPaneContent.idl" />
<Midl Include="TerminalPaneContent.idl" />
<Midl Include="TerminalSettingsCache.idl" />
</ItemGroup>
<!-- ========================= Misc Files ======================== -->
<ItemGroup>

View File

@@ -24,9 +24,6 @@
<ClCompile Include="Tab.cpp">
<Filter>tab</Filter>
</ClCompile>
<ClCompile Include="SettingsTab.cpp">
<Filter>tab</Filter>
</ClCompile>
<ClCompile Include="FilteredCommand.cpp">
<Filter>commandPalette</Filter>
</ClCompile>
@@ -64,9 +61,6 @@
<ClInclude Include="Tab.h">
<Filter>tab</Filter>
</ClInclude>
<ClInclude Include="SettingsTab.h">
<Filter>tab</Filter>
</ClInclude>
<ClInclude Include="FilteredCommand.h">
<Filter>commandPalette</Filter>
</ClInclude>
@@ -98,6 +92,7 @@
<Midl Include="ShortcutActionDispatch.idl">
<Filter>settings</Filter>
</Midl>
<Midl Include="IDirectKeyListener.idl" />
<Midl Include="SettingsTab.idl">
<Filter>tab</Filter>
</Midl>

View File

@@ -21,7 +21,7 @@
#include "App.h"
#include "ColorHelper.h"
#include "DebugTapConnection.h"
#include "SettingsTab.h"
#include "SettingsPaneContent.h"
#include "TabRowControl.h"
#include "Utils.h"
@@ -187,7 +187,7 @@ namespace winrt::TerminalApp::implementation
}
// Inform the host that our titlebar content has changed.
_SetTitleBarContentHandlers(*this, _tabRow);
SetTitleBarContent.raise(*this, _tabRow);
// GH#13143 Manually set the tab row's background to transparent here.
//
@@ -658,7 +658,7 @@ namespace winrt::TerminalApp::implementation
// have a tab yet, but will once we're initialized.
if (_tabs.Size() == 0 && !(_shouldStartInboundListener || _isEmbeddingInboundListener))
{
_LastTabClosedHandlers(*this, winrt::make<LastTabClosedEventArgs>(false));
LastTabClosed.raise(*this, winrt::make<LastTabClosedEventArgs>(false));
co_return;
}
else
@@ -689,7 +689,7 @@ namespace winrt::TerminalApp::implementation
Dispatcher().RunAsync(CoreDispatcherPriority::Low, [weak = get_weak()]() {
if (auto self{ weak.get() })
{
self->_InitializedHandlers(*self, nullptr);
self->Initialized.raise(*self, nullptr);
}
});
}
@@ -1299,15 +1299,20 @@ namespace winrt::TerminalApp::implementation
return connection;
}
TerminalConnection::ITerminalConnection TerminalPage::_duplicateConnectionForRestart(std::shared_ptr<Pane> pane)
TerminalConnection::ITerminalConnection TerminalPage::_duplicateConnectionForRestart(const TerminalApp::TerminalPaneContent& paneContent)
{
const auto& control{ pane->GetTerminalControl() };
if (paneContent == nullptr)
{
return nullptr;
}
const auto& control{ paneContent.GetTerminal() };
if (control == nullptr)
{
return nullptr;
}
const auto& connection = control.Connection();
auto profile{ pane->GetProfile() };
auto profile{ paneContent.GetProfile() };
TerminalSettingsCreateResult controlSettings{ nullptr };
@@ -1623,7 +1628,7 @@ namespace winrt::TerminalApp::implementation
if (tab == _GetFocusedTab())
{
_TitleChangedHandlers(*this, newTabTitle);
TitleChanged.raise(*this, newTabTitle);
}
}
@@ -1728,9 +1733,9 @@ namespace winrt::TerminalApp::implementation
hostingTab.TaskbarProgressChanged({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
}
void TerminalPage::_RegisterPaneEvents(std::shared_ptr<Pane>& pane)
void TerminalPage::_RegisterPaneEvents(const TerminalApp::TerminalPaneContent& paneContent)
{
pane->RestartTerminalRequested({ get_weak(), &TerminalPage::_restartPaneConnection });
paneContent.RestartTerminalRequested({ get_weak(), &TerminalPage::_restartPaneConnection });
}
// Method Description:
@@ -1892,7 +1897,7 @@ namespace winrt::TerminalApp::implementation
co_return;
}
_QuitRequestedHandlers(nullptr, nullptr);
QuitRequested.raise(nullptr, nullptr);
}
}
@@ -2180,7 +2185,7 @@ namespace winrt::TerminalApp::implementation
{
request->WindowPosition(dragPoint->to_winrt_point());
}
_RequestMoveContentHandlers(*this, *request);
RequestMoveContent.raise(*this, *request);
}
bool TerminalPage::_MoveTab(winrt::com_ptr<TerminalTab> tab, MoveTabArgs args)
@@ -2358,6 +2363,12 @@ namespace winrt::TerminalApp::implementation
}
}
// For now, prevent splitting the _settingsTab. We can always revisit this later.
if (*activeTab == _settingsTab)
{
return;
}
// If the caller is calling us with the return value of _MakePane
// directly, it's possible that nullptr was returned, if the connections
// was supposed to be launched in an elevated window. In that case, do
@@ -2384,7 +2395,10 @@ namespace winrt::TerminalApp::implementation
// re-add our event handler to that newly created pane.
//
// _MakePane will already call this for the newly created pane.
_RegisterPaneEvents(original);
if (const auto& paneContent{ original->GetContent().try_as<TerminalPaneContent>() })
{
_RegisterPaneEvents(*paneContent);
}
// After GH#6586, the control will no longer focus itself
// automatically when it's finished being laid out. Manually focus
@@ -2946,7 +2960,7 @@ namespace winrt::TerminalApp::implementation
winrt::fire_and_forget TerminalPage::_SetTaskbarProgressHandler(const IInspectable /*sender*/, const IInspectable /*eventArgs*/)
{
co_await wil::resume_foreground(Dispatcher());
_SetTaskbarProgressHandlers(*this, nullptr);
SetTaskbarProgress.raise(*this, nullptr);
}
// Method Description:
@@ -2956,7 +2970,7 @@ namespace winrt::TerminalApp::implementation
// - args: the arguments specifying how to set the display status to ShowWindow for our window handle
void TerminalPage::_ShowWindowChangedHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::ShowWindowArgs args)
{
_ShowWindowChangedHandlers(*this, args);
ShowWindowChanged.raise(*this, args);
}
// Method Description:
@@ -3116,10 +3130,9 @@ namespace winrt::TerminalApp::implementation
// Don't need to worry about duplicating or anything - we'll
// serialize the actual profile's GUID along with the content guid.
const auto& profile = _settings.GetProfileForArgs(newTerminalArgs);
const auto control = _AttachControlToContent(newTerminalArgs.ContentId());
return std::make_shared<Pane>(profile, control);
auto terminalPane{ winrt::make<TerminalPaneContent>(profile, control) };
return std::make_shared<Pane>(terminalPane);
}
TerminalSettingsCreateResult controlSettings{ nullptr };
@@ -3175,13 +3188,15 @@ namespace winrt::TerminalApp::implementation
const auto control = _CreateNewControlAndContent(controlSettings, connection);
auto resultPane = std::make_shared<Pane>(profile, control);
auto terminalPane{ winrt::make<TerminalPaneContent>(profile, control) };
auto resultPane = std::make_shared<Pane>(terminalPane);
if (debugConnection) // this will only be set if global debugging is on and tap is active
{
auto newControl = _CreateNewControlAndContent(controlSettings, debugConnection);
// Split (auto) with the debug tap.
auto debugPane = std::make_shared<Pane>(profile, newControl);
auto debugTerminalPane{ winrt::make<TerminalPaneContent>(profile, newControl) };
auto debugPane = std::make_shared<Pane>(debugTerminalPane);
// Since we're doing this split directly on the pane (instead of going through TerminalTab,
// we need to handle the panes 'active' states
@@ -3195,16 +3210,22 @@ namespace winrt::TerminalApp::implementation
original->SetActive();
}
_RegisterPaneEvents(resultPane);
_RegisterPaneEvents(terminalPane);
return resultPane;
}
void TerminalPage::_restartPaneConnection(const std::shared_ptr<Pane>& pane)
void TerminalPage::_restartPaneConnection(
const TerminalApp::TerminalPaneContent& paneContent,
const winrt::Windows::Foundation::IInspectable&)
{
if (const auto& connection{ _duplicateConnectionForRestart(pane) })
// Note: callers are likely passing in `nullptr` as the args here, as
// the TermControl.RestartTerminalRequested event doesn't actually pass
// any args upwards itself. If we ever change this, make sure you check
// for nulls
if (const auto& connection{ _duplicateConnectionForRestart(paneContent) })
{
pane->GetTerminalControl().Connection(connection);
paneContent.GetTerminal().Connection(connection);
connection.Start();
}
}
@@ -3285,50 +3306,18 @@ namespace winrt::TerminalApp::implementation
// Refresh UI elements
// Mapping by GUID isn't _excellent_ because the defaults profile doesn't have a stable GUID; however,
// when we stabilize its guid this will become fully safe.
std::unordered_map<winrt::guid, std::pair<Profile, TerminalSettingsCreateResult>> profileGuidSettingsMap;
const auto profileDefaults{ _settings.ProfileDefaults() };
const auto allProfiles{ _settings.AllProfiles() };
profileGuidSettingsMap.reserve(allProfiles.Size() + 1);
// Include the Defaults profile for consideration
profileGuidSettingsMap.insert_or_assign(profileDefaults.Guid(), std::pair{ profileDefaults, nullptr });
for (const auto& newProfile : allProfiles)
{
// Avoid creating a TerminalSettings right now. They're not totally cheap, and we suspect that users with many
// panes may not be using all of their profiles at the same time. Lazy evaluation is king!
profileGuidSettingsMap.insert_or_assign(newProfile.Guid(), std::pair{ newProfile, nullptr });
}
// Recreate the TerminalSettings cache here. We'll use that as we're
// updating terminal panes, so that we don't have to build a _new_
// TerminalSettings for every profile we update - we can just look them
// up the previous ones we built.
_terminalSettingsCache = TerminalApp::TerminalSettingsCache{ _settings, *_bindings };
for (const auto& tab : _tabs)
{
if (auto terminalTab{ _GetTerminalTabImpl(tab) })
{
terminalTab->UpdateSettings();
// Manually enumerate the panes in each tab; this will let us recycle TerminalSettings
// objects but only have to iterate one time.
terminalTab->GetRootPane()->WalkTree([&](auto&& pane) {
if (const auto profile{ pane->GetProfile() })
{
const auto found{ profileGuidSettingsMap.find(profile.Guid()) };
// GH#2455: If there are any panes with controls that had been
// initialized with a Profile that no longer exists in our list of
// profiles, we'll leave it unmodified. The profile doesn't exist
// anymore, so we can't possibly update its settings.
if (found != profileGuidSettingsMap.cend())
{
auto& pair{ found->second };
if (!pair.second)
{
pair.second = TerminalSettings::CreateWithProfile(_settings, pair.first, *_bindings);
}
pane->UpdateSettings(pair.second, pair.first);
}
}
});
// Let the tab know that there are new settings. It's up to each content to decide what to do with them.
terminalTab->UpdateSettings(_settings, _terminalSettingsCache);
// Update the icon of the tab for the currently focused profile in that tab.
// Only do this for TerminalTabs. Other types of tabs won't have multiple panes
@@ -3338,10 +3327,6 @@ namespace winrt::TerminalApp::implementation
// Force the TerminalTab to re-grab its currently active control's title.
terminalTab->UpdateTitle();
}
else if (auto settingsTab = tab.try_as<TerminalApp::SettingsTab>())
{
settingsTab.UpdateSettings(_settings);
}
auto tabImpl{ winrt::get_self<TabBase>(tab) };
tabImpl->SetActionMap(_settings.ActionMap());
@@ -3364,7 +3349,7 @@ namespace winrt::TerminalApp::implementation
// will let the user hot-reload this setting, but any runtime changes to
// the alwaysOnTop setting will be lost.
_isAlwaysOnTop = _settings.GlobalSettings().AlwaysOnTop();
_AlwaysOnTopChangedHandlers(*this, nullptr);
AlwaysOnTopChanged.raise(*this, nullptr);
// Settings AllowDependentAnimations will affect whether animations are
// enabled application-wide, so we don't need to check it each time we
@@ -3572,7 +3557,7 @@ namespace winrt::TerminalApp::implementation
{
_isInFocusMode = newInFocusMode;
_UpdateTabView();
_FocusModeChangedHandlers(*this, nullptr);
FocusModeChanged.raise(*this, nullptr);
}
}
@@ -3597,7 +3582,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::ToggleAlwaysOnTop()
{
_isAlwaysOnTop = !_isAlwaysOnTop;
_AlwaysOnTopChangedHandlers(*this, nullptr);
AlwaysOnTopChanged.raise(*this, nullptr);
}
// Method Description:
@@ -3798,7 +3783,7 @@ namespace winrt::TerminalApp::implementation
}
_isFullscreen = newFullscreen;
_UpdateTabView();
_FullscreenChangedHandlers(*this, nullptr);
FullscreenChanged.raise(*this, nullptr);
}
// Method Description:
@@ -3817,7 +3802,7 @@ namespace winrt::TerminalApp::implementation
return;
}
_isMaximized = newMaximized;
_ChangeMaximizeRequestedHandlers(*this, nullptr);
ChangeMaximizeRequested.raise(*this, nullptr);
}
HRESULT TerminalPage::_OnNewConnection(const ConptyConnection& connection)
@@ -3860,7 +3845,7 @@ namespace winrt::TerminalApp::implementation
_CreateNewTabFromPane(newPane);
// Request a summon of this window to the foreground
_SummonWindowRequestedHandlers(*this, nullptr);
SummonWindowRequested.raise(*this, nullptr);
const IInspectable unused{ nullptr };
_SetAsDefaultDismissHandler(unused, unused);
@@ -3906,7 +3891,10 @@ namespace winrt::TerminalApp::implementation
}
}
winrt::Microsoft::Terminal::Settings::Editor::MainPage sui{ _settings };
// Create the SUI pane content
auto settingsContent{ winrt::make_self<SettingsPaneContent>(_settings) };
auto sui = settingsContent->SettingsUI();
if (_hostingHwnd)
{
sui.SetHostingWindow(reinterpret_cast<uint64_t>(*_hostingHwnd));
@@ -3922,54 +3910,9 @@ namespace winrt::TerminalApp::implementation
}
});
auto newTabImpl = winrt::make_self<SettingsTab>(sui, _settings.GlobalSettings().CurrentTheme().RequestedTheme());
// Add the new tab to the list of our tabs.
_tabs.Append(*newTabImpl);
_mruTabs.Append(*newTabImpl);
newTabImpl->SetDispatch(*_actionDispatch);
newTabImpl->SetActionMap(_settings.ActionMap());
// Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command.
_UpdateTabIndices();
// Don't capture a strong ref to the tab. If the tab is removed as this
// is called, we don't really care anymore about handling the event.
auto weakTab = make_weak(newTabImpl);
auto tabViewItem = newTabImpl->TabViewItem();
_tabView.TabItems().Append(tabViewItem);
tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabClick });
// When the tab requests close, try to close it (prompt for approval, if required)
newTabImpl->CloseRequested([weakTab, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) {
auto page{ weakThis.get() };
auto tab{ weakTab.get() };
if (page && tab)
{
page->_HandleCloseTabRequested(*tab);
}
});
// When the tab is closed, remove it from our list of tabs.
newTabImpl->Closed([weakTab, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) {
const auto page = weakThis.get();
const auto tab = weakTab.get();
if (page && tab)
{
page->_RemoveTab(*tab);
}
});
_settingsTab = *newTabImpl;
// This kicks off TabView::SelectionChanged, in response to which
// we'll attach the terminal's Xaml control to the Xaml root.
_tabView.SelectedItem(tabViewItem);
// Create the tab
auto resultPane = std::make_shared<Pane>(*settingsContent);
_settingsTab = _CreateNewTabFromPane(resultPane);
}
else
{
@@ -4315,7 +4258,7 @@ namespace winrt::TerminalApp::implementation
{
WindowRenamer().IsOpen(false);
}
_RenameWindowRequestedHandlers(*this, request);
RenameWindowRequested.raise(*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
@@ -4651,13 +4594,15 @@ namespace winrt::TerminalApp::implementation
til::color bgColor = backgroundSolidBrush.Color();
Media::Brush terminalBrush{ nullptr };
if (const auto& control{ _GetActiveControl() })
if (const auto tab{ _GetFocusedTabImpl() })
{
terminalBrush = control.BackgroundBrush();
}
else if (const auto& settingsTab{ _GetFocusedTab().try_as<TerminalApp::SettingsTab>() })
{
terminalBrush = settingsTab.Content().try_as<Settings::Editor::MainPage>().BackgroundBrush();
if (const auto& pane{ tab->GetActivePane() })
{
if (const auto& lastContent{ pane->GetLastFocusedContent() })
{
terminalBrush = lastContent.BackgroundBrush();
}
}
}
if (_settings.GlobalSettings().UseAcrylicInTabRow())
@@ -5122,7 +5067,7 @@ namespace winrt::TerminalApp::implementation
// This will go up to the monarch, who will then dispatch the request
// back down to the source TerminalPage, who will then perform a
// RequestMoveContent to move their tab to us.
_RequestReceiveContentHandlers(*this, *request);
RequestReceiveContent.raise(*this, *request);
}
}

View File

@@ -172,33 +172,33 @@ namespace winrt::TerminalApp::implementation
uint32_t NumberOfTabs() const;
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
til::property_changed_event PropertyChanged;
// -------------------------------- WinRT Events ---------------------------------
TYPED_EVENT(TitleChanged, IInspectable, winrt::hstring);
TYPED_EVENT(LastTabClosed, IInspectable, winrt::TerminalApp::LastTabClosedEventArgs);
TYPED_EVENT(SetTitleBarContent, IInspectable, winrt::Windows::UI::Xaml::UIElement);
TYPED_EVENT(FocusModeChanged, IInspectable, IInspectable);
TYPED_EVENT(FullscreenChanged, IInspectable, IInspectable);
TYPED_EVENT(ChangeMaximizeRequested, IInspectable, IInspectable);
TYPED_EVENT(AlwaysOnTopChanged, IInspectable, IInspectable);
TYPED_EVENT(RaiseVisualBell, IInspectable, IInspectable);
TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable);
TYPED_EVENT(Initialized, IInspectable, IInspectable);
TYPED_EVENT(IdentifyWindowsRequested, IInspectable, IInspectable);
TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs);
TYPED_EVENT(SummonWindowRequested, IInspectable, IInspectable);
til::typed_event<IInspectable, winrt::hstring> TitleChanged;
til::typed_event<IInspectable, winrt::TerminalApp::LastTabClosedEventArgs> LastTabClosed;
til::typed_event<IInspectable, winrt::Windows::UI::Xaml::UIElement> SetTitleBarContent;
til::typed_event<IInspectable, IInspectable> FocusModeChanged;
til::typed_event<IInspectable, IInspectable> FullscreenChanged;
til::typed_event<IInspectable, IInspectable> ChangeMaximizeRequested;
til::typed_event<IInspectable, IInspectable> AlwaysOnTopChanged;
til::typed_event<IInspectable, IInspectable> RaiseVisualBell;
til::typed_event<IInspectable, IInspectable> SetTaskbarProgress;
til::typed_event<IInspectable, IInspectable> Initialized;
til::typed_event<IInspectable, IInspectable> IdentifyWindowsRequested;
til::typed_event<Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs> RenameWindowRequested;
til::typed_event<IInspectable, IInspectable> SummonWindowRequested;
TYPED_EVENT(CloseRequested, IInspectable, IInspectable);
TYPED_EVENT(OpenSystemMenu, IInspectable, IInspectable);
TYPED_EVENT(QuitRequested, IInspectable, IInspectable);
TYPED_EVENT(ShowWindowChanged, IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs)
til::typed_event<IInspectable, IInspectable> CloseRequested;
til::typed_event<IInspectable, IInspectable> OpenSystemMenu;
til::typed_event<IInspectable, IInspectable> QuitRequested;
til::typed_event<IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs> ShowWindowChanged;
TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs);
TYPED_EVENT(RequestReceiveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs);
til::typed_event<Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs> RequestMoveContent;
til::typed_event<Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs> RequestReceiveContent;
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, _PropertyChangedHandlers, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, FrameBrush, _PropertyChangedHandlers, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, PropertyChanged.raise, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, FrameBrush, PropertyChanged.raise, nullptr);
private:
friend struct TerminalPageT<TerminalPage>; // for Xaml to bind events
@@ -224,7 +224,7 @@ namespace winrt::TerminalApp::implementation
void _UpdateTabIndices();
TerminalApp::SettingsTab _settingsTab{ nullptr };
TerminalApp::TerminalTab _settingsTab{ nullptr };
bool _isInFocusMode{ false };
bool _isFullscreen{ false };
@@ -272,6 +272,8 @@ namespace winrt::TerminalApp::implementation
TerminalApp::ContentManager _manager{ nullptr };
TerminalApp::TerminalSettingsCache _terminalSettingsCache{ nullptr };
struct StashedDragData
{
winrt::com_ptr<winrt::TerminalApp::implementation::TabBase> draggedTab{ nullptr };
@@ -302,14 +304,14 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _CreateNewTabFlyoutProfile(const Microsoft::Terminal::Settings::Model::Profile profile, int profileIndex);
void _OpenNewTabDropdown();
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
void _CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition = -1);
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs);
TerminalApp::TerminalTab _CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition = -1);
std::wstring _evaluatePathForCwd(std::wstring_view path);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings, const bool inheritCursor);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _duplicateConnectionForRestart(std::shared_ptr<Pane> pane);
void _restartPaneConnection(const std::shared_ptr<Pane>& pane);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _duplicateConnectionForRestart(const TerminalApp::TerminalPaneContent& paneContent);
void _restartPaneConnection(const TerminalApp::TerminalPaneContent&, const winrt::Windows::Foundation::IInspectable&);
winrt::fire_and_forget _OpenNewWindow(const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
@@ -345,7 +347,7 @@ namespace winrt::TerminalApp::implementation
void _InitializeTab(winrt::com_ptr<TerminalTab> newTabImpl, uint32_t insertPosition = -1);
void _RegisterTerminalEvents(Microsoft::Terminal::Control::TermControl term);
void _RegisterTabEvents(TerminalTab& hostingTab);
void _RegisterPaneEvents(std::shared_ptr<Pane>& pane);
void _RegisterPaneEvents(const TerminalApp::TerminalPaneContent& paneContent);
void _DismissTabContextMenus();
void _FocusCurrentTab(const bool focusAlways);

View File

@@ -0,0 +1,355 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "TerminalPaneContent.h"
#include "PaneArgs.h"
#include "TerminalPaneContent.g.cpp"
#include <Mmsystem.h>
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::TerminalConnection;
namespace winrt::TerminalApp::implementation
{
TerminalPaneContent::TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const winrt::Microsoft::Terminal::Control::TermControl& control) :
_control{ control },
_profile{ profile }
{
_setupControlEvents();
}
void TerminalPaneContent::_setupControlEvents()
{
_controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &TerminalPaneContent::_controlConnectionStateChangedHandler });
_controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlWarningBellHandler });
_controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_closeTerminalRequestedHandler });
_controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_restartTerminalRequestedHandler });
_controlEvents._TitleChanged = _control.TitleChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlTitleChanged });
_controlEvents._TabColorChanged = _control.TabColorChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlTabColorChanged });
_controlEvents._SetTaskbarProgress = _control.SetTaskbarProgress(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlSetTaskbarProgress });
_controlEvents._ReadOnlyChanged = _control.ReadOnlyChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlReadOnlyChanged });
_controlEvents._FocusFollowMouseRequested = _control.FocusFollowMouseRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlFocusFollowMouseRequested });
}
void TerminalPaneContent::_removeControlEvents()
{
_controlEvents = {};
}
winrt::Windows::UI::Xaml::FrameworkElement TerminalPaneContent::GetRoot()
{
return _control;
}
winrt::Microsoft::Terminal::Control::TermControl TerminalPaneContent::GetTerminal()
{
return _control;
}
winrt::Windows::Foundation::Size TerminalPaneContent::MinSize()
{
return _control.MinimumSize();
}
void TerminalPaneContent::Focus(winrt::Windows::UI::Xaml::FocusState reason)
{
_control.Focus(reason);
}
void TerminalPaneContent::Close()
{
_removeControlEvents();
// Clear out our media player callbacks, and stop any playing media. This
// will prevent the callback from being triggered after we've closed, and
// also make sure that our sound stops when we're closed.
if (_bellPlayer)
{
_bellPlayer.Pause();
_bellPlayer.Source(nullptr);
_bellPlayer.Close();
_bellPlayer = nullptr;
_bellPlayerCreated = false;
}
CloseRequested.raise(*this, nullptr);
}
winrt::hstring TerminalPaneContent::Icon() const
{
return _profile.EvaluatedIcon();
}
Windows::Foundation::IReference<winrt::Windows::UI::Color> TerminalPaneContent::TabColor() const noexcept
{
return _control.TabColor();
}
NewTerminalArgs TerminalPaneContent::GetNewTerminalArgs(const bool asContent) const
{
NewTerminalArgs args{};
const auto& controlSettings = _control.Settings();
args.Profile(controlSettings.ProfileName());
// If we know the user's working directory use it instead of the profile.
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
{
args.StartingDirectory(dir);
}
else
{
args.StartingDirectory(controlSettings.StartingDirectory());
}
args.TabTitle(controlSettings.StartingTitle());
args.Commandline(controlSettings.Commandline());
args.SuppressApplicationTitle(controlSettings.SuppressApplicationTitle());
if (controlSettings.TabColor() || controlSettings.StartingTabColor())
{
til::color c;
// StartingTabColor is prioritized over other colors
if (const auto color = controlSettings.StartingTabColor())
{
c = til::color(color.Value());
}
else
{
c = til::color(controlSettings.TabColor().Value());
}
args.TabColor(winrt::Windows::Foundation::IReference<winrt::Windows::UI::Color>{ static_cast<winrt::Windows::UI::Color>(c) });
}
// TODO:GH#9800 - we used to be able to persist the color scheme that a
// TermControl was initialized with, by name. With the change to having the
// control own its own copy of its settings, this isn't possible anymore.
//
// We may be able to get around this by storing the Name in the Core::Scheme
// object. That would work for schemes set by the Terminal, but not ones set
// by VT, but that seems good enough.
// Only fill in the ContentId if absolutely needed. If you fill in a number
// here (even 0), we'll serialize that number, AND treat that action as an
// "attach existing" rather than a "create"
if (asContent)
{
args.ContentId(_control.ContentId());
}
return args;
}
void TerminalPaneContent::_controlTitleChanged(const IInspectable&, const IInspectable&)
{
TitleChanged.raise(*this, nullptr);
}
void TerminalPaneContent::_controlTabColorChanged(const IInspectable&, const IInspectable&)
{
TabColorChanged.raise(*this, nullptr);
}
void TerminalPaneContent::_controlSetTaskbarProgress(const IInspectable&, const IInspectable&)
{
TaskbarProgressChanged.raise(*this, nullptr);
}
void TerminalPaneContent::_controlReadOnlyChanged(const IInspectable&, const IInspectable&)
{
ReadOnlyChanged.raise(*this, nullptr);
}
void TerminalPaneContent::_controlFocusFollowMouseRequested(const IInspectable&, const IInspectable&)
{
FocusRequested.raise(*this, nullptr);
}
// Method Description:
// - Called when our attached control is closed. Triggers listeners to our close
// event, if we're a leaf pane.
// - If this was called, and we became a parent pane (due to work on another
// thread), this function will do nothing (allowing the control's new parent
// to handle the event instead).
// Arguments:
// - <none>
// Return Value:
// - <none>
winrt::fire_and_forget TerminalPaneContent::_controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& args)
{
ConnectionStateChanged.raise(sender, args);
auto newConnectionState = ConnectionState::Closed;
if (const auto coreState = sender.try_as<ICoreState>())
{
newConnectionState = coreState.ConnectionState();
}
const auto previousConnectionState = std::exchange(_connectionState, newConnectionState);
if (newConnectionState < ConnectionState::Closed)
{
// Pane doesn't care if the connection isn't entering a terminal state.
co_return;
}
const auto weakThis = get_weak();
co_await wil::resume_foreground(_control.Dispatcher());
const auto strongThis = weakThis.get();
if (!strongThis)
{
co_return;
}
// It's possible that this event handler started being executed, scheduled
// on the UI thread, another child got created. So our control is
// actually no longer _our_ control, and instead could be a descendant.
//
// When the control's new Pane takes ownership of the control, the new
// parent will register its own event handler. That event handler will get
// fired after this handler returns, and will properly cleanup state.
if (previousConnectionState < ConnectionState::Connected && newConnectionState >= ConnectionState::Failed)
{
// A failure to complete the connection (before it has _connected_) is not covered by "closeOnExit".
// This is to prevent a misconfiguration (closeOnExit: always, startingDirectory: garbage) resulting
// in Terminal flashing open and immediately closed.
co_return;
}
if (_profile)
{
if (_isDefTermSession && _profile.CloseOnExit() == CloseOnExitMode::Automatic)
{
// For 'automatic', we only care about the connection state if we were launched by Terminal
// Since we were launched via defterm, ignore the connection state (i.e. we treat the
// close on exit mode as 'always', see GH #13325 for discussion)
Close();
}
const auto mode = _profile.CloseOnExit();
if ((mode == CloseOnExitMode::Always) ||
((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed))
{
Close();
}
}
}
// Method Description:
// - Plays a warning note when triggered by the BEL control character,
// using the sound configured for the "Critical Stop" system event.`
// This matches the behavior of the Windows Console host.
// - Will also flash the taskbar if the bellStyle setting for this profile
// has the 'visual' flag set
// Arguments:
// - <unused>
void TerminalPaneContent::_controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
{
if (_profile)
{
// We don't want to do anything if nothing is set, so check for that first
if (static_cast<int>(_profile.BellStyle()) != 0)
{
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible))
{
// Audible is set, play the sound
auto sounds{ _profile.BellSound() };
if (sounds && sounds.Size() > 0)
{
winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW<std::wstring>(sounds.GetAt(rand() % sounds.Size()).c_str()) };
winrt::Windows::Foundation::Uri uri{ soundPath };
_playBellSound(uri);
}
else
{
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
}
}
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
{
_control.BellLightOn();
}
// raise the event with the bool value corresponding to the taskbar flag
BellRequested.raise(*this,
*winrt::make_self<TerminalApp::implementation::BellEventArgs>(WI_IsFlagSet(_profile.BellStyle(), BellStyle::Taskbar)));
}
}
}
winrt::fire_and_forget TerminalPaneContent::_playBellSound(winrt::Windows::Foundation::Uri uri)
{
auto weakThis{ get_weak() };
co_await wil::resume_foreground(_control.Dispatcher());
if (auto pane{ weakThis.get() })
{
if (!_bellPlayerCreated)
{
// The MediaPlayer might not exist on Windows N SKU.
try
{
_bellPlayerCreated = true;
_bellPlayer = winrt::Windows::Media::Playback::MediaPlayer();
// GH#12258: The media keys (like play/pause) should have no effect on our bell sound.
_bellPlayer.CommandManager().IsEnabled(false);
}
CATCH_LOG();
}
if (_bellPlayer)
{
const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) };
const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) };
_bellPlayer.Source(item);
_bellPlayer.Play();
}
}
}
void TerminalPaneContent::_closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
Close();
}
void TerminalPaneContent::_restartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
RestartTerminalRequested.raise(*this, nullptr);
}
void TerminalPaneContent::UpdateSettings(const CascadiaSettings& /*settings*/)
{
// Do nothing. We'll later be updated manually by
// UpdateTerminalSettings, which we need for profile and
// focused/unfocused settings.
assert(false); // If you hit this, you done goofed.
}
void TerminalPaneContent::UpdateTerminalSettings(const TerminalApp::TerminalSettingsCache& cache)
{
if (const auto& settings{ cache.TryLookup(_profile) })
{
_control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings());
}
}
// Method Description:
// - Should be called when this pane is created via a default terminal handoff
// - Finalizes our configuration given the information that we have been
// created via default handoff
void TerminalPaneContent::MarkAsDefterm()
{
_isDefTermSession = true;
}
winrt::Windows::UI::Xaml::Media::Brush TerminalPaneContent::BackgroundBrush()
{
return _control.BackgroundBrush();
}
float TerminalPaneContent::SnapDownToGrid(const TerminalApp::PaneSnapDirection direction, const float sizeToSnap)
{
return _control.SnapDimensionToGrid(direction == PaneSnapDirection::Width, sizeToSnap);
}
Windows::Foundation::Size TerminalPaneContent::GridSize()
{
return _control.CharacterDimensions();
}
}

View File

@@ -0,0 +1,97 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "TerminalPaneContent.g.h"
#include "../../cascadia/inc/cppwinrt_utils.h"
#include <til/winrt.h>
namespace winrt::TerminalApp::implementation
{
struct TerminalPaneContent : TerminalPaneContentT<TerminalPaneContent>
{
TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const winrt::Microsoft::Terminal::Control::TermControl& control);
winrt::Windows::UI::Xaml::FrameworkElement GetRoot();
winrt::Microsoft::Terminal::Control::TermControl GetTerminal();
winrt::Windows::Foundation::Size MinSize();
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
void Close();
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const;
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
void UpdateTerminalSettings(const TerminalApp::TerminalSettingsCache& cache);
void MarkAsDefterm();
winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const
{
return _profile;
};
winrt::hstring Title() { return _control.Title(); }
uint64_t TaskbarState() { return _control.TaskbarState(); }
uint64_t TaskbarProgress() { return _control.TaskbarProgress(); }
bool ReadOnly() { return _control.ReadOnly(); }
winrt::hstring Icon() const;
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept;
winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush();
float SnapDownToGrid(const TerminalApp::PaneSnapDirection direction, const float sizeToSnap);
Windows::Foundation::Size GridSize();
til::typed_event<TerminalApp::TerminalPaneContent, winrt::Windows::Foundation::IInspectable> RestartTerminalRequested;
til::typed_event<> CloseRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::BellEventArgs> BellRequested;
til::typed_event<> TitleChanged;
til::typed_event<> TabColorChanged;
til::typed_event<> TaskbarProgressChanged;
til::typed_event<> ConnectionStateChanged;
til::typed_event<> ReadOnlyChanged;
til::typed_event<> FocusRequested;
private:
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
bool _isDefTermSession{ false };
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
bool _bellPlayerCreated{ false };
struct ControlEventTokens
{
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
winrt::Microsoft::Terminal::Control::TermControl::WarningBell_revoker _WarningBell;
winrt::Microsoft::Terminal::Control::TermControl::CloseTerminalRequested_revoker _CloseTerminalRequested;
winrt::Microsoft::Terminal::Control::TermControl::RestartTerminalRequested_revoker _RestartTerminalRequested;
winrt::Microsoft::Terminal::Control::TermControl::TitleChanged_revoker _TitleChanged;
winrt::Microsoft::Terminal::Control::TermControl::TabColorChanged_revoker _TabColorChanged;
winrt::Microsoft::Terminal::Control::TermControl::SetTaskbarProgress_revoker _SetTaskbarProgress;
winrt::Microsoft::Terminal::Control::TermControl::ReadOnlyChanged_revoker _ReadOnlyChanged;
winrt::Microsoft::Terminal::Control::TermControl::FocusFollowMouseRequested_revoker _FocusFollowMouseRequested;
} _controlEvents;
void _setupControlEvents();
void _removeControlEvents();
winrt::fire_and_forget _playBellSound(winrt::Windows::Foundation::Uri uri);
winrt::fire_and_forget _controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& e);
void _controlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e);
void _controlTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
void _controlTabColorChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
void _controlSetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
void _controlReadOnlyChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
void _controlFocusFollowMouseRequested(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
void _closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _restartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
};
}

View File

@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "IPaneContent.idl";
import "TerminalSettingsCache.idl";
namespace TerminalApp
{
[default_interface] runtimeclass TerminalPaneContent : IPaneContent, ISnappable
{
Microsoft.Terminal.Control.TermControl GetTerminal();
void UpdateTerminalSettings(TerminalSettingsCache cache);
void MarkAsDefterm();
Microsoft.Terminal.Settings.Model.Profile GetProfile();
event Windows.Foundation.TypedEventHandler<TerminalPaneContent, Object> RestartTerminalRequested;
}
[default_interface] runtimeclass ScratchpadContent : IPaneContent
{
}
[default_interface] runtimeclass SettingsPaneContent : IPaneContent
{
SettingsPaneContent(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
}
}

View File

@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "TerminalSettingsCache.h"
#include "TerminalSettingsCache.g.cpp"
namespace winrt
{
namespace MUX = Microsoft::UI::Xaml;
namespace WUX = Windows::UI::Xaml;
namespace MTSM = Microsoft::Terminal::Settings::Model;
}
namespace winrt::TerminalApp::implementation
{
TerminalSettingsCache::TerminalSettingsCache(const MTSM::CascadiaSettings& settings, const TerminalApp::AppKeyBindings& bindings) :
_settings{ settings },
_bindings{ bindings }
{
// Mapping by GUID isn't _excellent_ because the defaults profile doesn't have a stable GUID; however,
// when we stabilize its guid this will become fully safe.
const auto profileDefaults{ _settings.ProfileDefaults() };
const auto allProfiles{ _settings.AllProfiles() };
profileGuidSettingsMap.reserve(allProfiles.Size() + 1);
// Include the Defaults profile for consideration
profileGuidSettingsMap.insert_or_assign(profileDefaults.Guid(), std::pair{ profileDefaults, nullptr });
for (const auto& newProfile : allProfiles)
{
// Avoid creating a TerminalSettings right now. They're not totally cheap, and we suspect that users with many
// panes may not be using all of their profiles at the same time. Lazy evaluation is king!
profileGuidSettingsMap.insert_or_assign(newProfile.Guid(), std::pair{ newProfile, nullptr });
}
}
MTSM::TerminalSettingsCreateResult TerminalSettingsCache::TryLookup(const MTSM::Profile& profile)
{
const auto found{ profileGuidSettingsMap.find(profile.Guid()) };
// GH#2455: If there are any panes with controls that had been
// initialized with a Profile that no longer exists in our list of
// profiles, we'll leave it unmodified. The profile doesn't exist
// anymore, so we can't possibly update its settings.
if (found != profileGuidSettingsMap.cend())
{
auto& pair{ found->second };
if (!pair.second)
{
pair.second = MTSM::TerminalSettings::CreateWithProfile(_settings, pair.first, _bindings);
}
return pair.second;
}
return nullptr;
}
}

View File

@@ -0,0 +1,37 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Class Name:
- TerminalSettingsCache.h
Abstract:
- This is a helper class used as we update the settings for panes. This class
contains a single map of guid -> TerminalSettings, so that as we update all
the panes during a settings reload, we only need to create a TerminalSettings
once per profile.
--*/
#pragma once
#include "TerminalSettingsCache.g.h"
#include <inc/cppwinrt_utils.h>
namespace winrt::TerminalApp::implementation
{
class TerminalSettingsCache : public TerminalSettingsCacheT<TerminalSettingsCache>
{
public:
TerminalSettingsCache(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const TerminalApp::AppKeyBindings& bindings);
Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult TryLookup(const Microsoft::Terminal::Settings::Model::Profile& profile);
private:
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
TerminalApp::AppKeyBindings _bindings{ nullptr };
std::unordered_map<winrt::guid, std::pair<Microsoft::Terminal::Settings::Model::Profile, Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult>> profileGuidSettingsMap;
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(TerminalSettingsCache);
}

View File

@@ -0,0 +1,12 @@
import "AppKeyBindings.idl";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
[default_interface] runtimeclass TerminalSettingsCache
{
TerminalSettingsCache(Microsoft.Terminal.Settings.Model.CascadiaSettings settings, AppKeyBindings bindings);
Microsoft.Terminal.Settings.Model.TerminalSettingsCreateResult TryLookup(Microsoft.Terminal.Settings.Model.Profile profile);
}
}

View File

@@ -80,7 +80,7 @@ namespace winrt::TerminalApp::implementation
void TerminalTab::_Setup()
{
_rootClosedToken = _rootPane->Closed([=](auto&& /*s*/, auto&& /*e*/) {
_ClosedHandlers(nullptr, nullptr);
Closed.raise(nullptr, nullptr);
});
Content(_rootPane->GetRootElement());
@@ -103,7 +103,7 @@ namespace winrt::TerminalApp::implementation
_headerControl.RenameEnded([weakThis = get_weak()](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_RequestFocusActiveControlHandlers();
tab->RequestFocusActiveControl.raise();
}
});
@@ -186,6 +186,11 @@ namespace winrt::TerminalApp::implementation
return nullptr;
}
IPaneContent TerminalTab::GetActiveContent() const
{
return _activePane ? _activePane->GetContent() : nullptr;
}
// Method Description:
// - Called after construction of a Tab object to bind event handlers to its
// associated Pane and TermControl objects
@@ -200,9 +205,9 @@ namespace winrt::TerminalApp::implementation
_rootPane->WalkTree([&](std::shared_ptr<Pane> pane) {
// Attach event handlers to each new pane
_AttachEventHandlersToPane(pane);
if (auto control = pane->GetTerminalControl())
if (auto content = pane->GetContent())
{
_AttachEventHandlersToControl(pane->Id().value(), control);
_AttachEventHandlersToContent(pane->Id().value(), content);
}
});
}
@@ -261,12 +266,18 @@ namespace winrt::TerminalApp::implementation
// of the settings that apply to all tabs.
// Return Value:
// - <none>
void TerminalTab::UpdateSettings()
void TerminalTab::UpdateSettings(const CascadiaSettings& settings, const TerminalApp::TerminalSettingsCache& cache)
{
ASSERT_UI_THREAD();
// The tabWidthMode may have changed, update the header control accordingly
_UpdateHeaderControlMaxWidth();
// Update the settings on all our panes.
_rootPane->WalkTree([&](auto pane) {
pane->UpdateSettings(settings, cache);
return false;
});
}
// Method Description:
@@ -275,7 +286,7 @@ namespace winrt::TerminalApp::implementation
// - iconPath: The new path string to use as the IconPath for our TabViewItem
// Return Value:
// - <none>
void TerminalTab::UpdateIcon(const winrt::hstring iconPath, const winrt::Microsoft::Terminal::Settings::Model::IconStyle iconStyle)
void TerminalTab::UpdateIcon(const winrt::hstring& iconPath, const winrt::Microsoft::Terminal::Settings::Model::IconStyle iconStyle)
{
ASSERT_UI_THREAD();
@@ -377,8 +388,8 @@ namespace winrt::TerminalApp::implementation
{
return RS_(L"MultiplePanes");
}
const auto lastFocusedControl = GetActiveTerminalControl();
return lastFocusedControl ? lastFocusedControl.Title() : L"";
const auto activeContent = GetActiveContent();
return activeContent ? activeContent.Title() : winrt::hstring{ L"" };
}
// Method Description:
@@ -433,9 +444,32 @@ namespace winrt::TerminalApp::implementation
// Give initial ids (0 for the child created with this tab,
// 1 for the child after the first split.
auto state = _rootPane->BuildStartupActions(0, 1, asContent);
Pane::BuildStartupState state;
// HORRIBLE
//
// Workaround till we know how we actually want to handle state
// restoring other kinda of panes. If this is a settings tab, just
// restore it as a settings tab. Don't bother recreating terminal args
// for every pane.
//
// In the future, we'll want to definitely get rid of
// Pane::GetTerminalArgsForPane, and somehow instead find a better way
// of re-creating the pane state. Probably through a combo of ResizePane
// actions and SetPaneOrientation actions.
if (const auto& settings{ _rootPane->GetContent().try_as<SettingsPaneContent>() })
{
ActionAndArgs action;
action.Action(ShortcutAction::OpenSettings);
OpenSettingsArgs args{ SettingsTarget::SettingsUI };
action.Args(args);
state.args = std::vector{ std::move(action) };
}
else
{
state = _rootPane->BuildStartupActions(0, 1, asContent);
ActionAndArgs newTabAction{};
newTabAction.Action(ShortcutAction::NewTab);
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane(asContent) };
@@ -513,7 +547,10 @@ namespace winrt::TerminalApp::implementation
if (p->_IsLeaf())
{
p->Id(_nextPaneId);
_AttachEventHandlersToControl(p->Id().value(), p->_control);
if (const auto& content{ p->GetContent() })
{
_AttachEventHandlersToContent(p->Id().value(), content);
}
_nextPaneId++;
}
return false;
@@ -596,14 +633,14 @@ namespace winrt::TerminalApp::implementation
_rootPane->Closed(_rootClosedToken);
auto p = _rootPane;
p->WalkTree([](auto pane) {
pane->_DetachedHandlers(pane);
pane->Detached.raise(pane);
});
// Clean up references and close the tab
_rootPane = nullptr;
_activePane = nullptr;
Content(nullptr);
_ClosedHandlers(nullptr, nullptr);
Closed.raise(nullptr, nullptr);
return p;
}
@@ -626,7 +663,11 @@ namespace winrt::TerminalApp::implementation
if (p->_IsLeaf())
{
p->Id(_nextPaneId);
_AttachEventHandlersToControl(p->Id().value(), p->_control);
if (const auto& content{ p->GetContent() })
{
_AttachEventHandlersToContent(p->Id().value(), content);
}
_nextPaneId++;
}
});
@@ -883,29 +924,18 @@ namespace winrt::TerminalApp::implementation
// the control itself doesn't have a particular ID and its pointer is
// unstable since it is moved when panes split.
// Arguments:
// - paneId: The ID of the pane that contains the given control.
// - control: the control to remove events from.
// - paneId: The ID of the pane that contains the given content.
// Return Value:
// - <none>
void TerminalTab::_DetachEventHandlersFromControl(const uint32_t paneId, const TermControl& control)
void TerminalTab::_DetachEventHandlersFromContent(const uint32_t paneId)
{
auto it = _controlEvents.find(paneId);
if (it != _controlEvents.end())
auto it = _contentEvents.find(paneId);
if (it != _contentEvents.end())
{
auto& events = it->second;
control.TitleChanged(events.titleToken);
control.TabColorChanged(events.colorToken);
control.SetTaskbarProgress(events.taskbarToken);
control.ConnectionStateChanged(events.stateToken);
control.ReadOnlyChanged(events.readOnlyToken);
control.FocusFollowMouseRequested(events.focusToken);
events.KeySent.revoke();
events.CharSent.revoke();
events.StringSent.revoke();
_controlEvents.erase(paneId);
// revoke the event handlers by resetting the event struct
it->second = {};
// and remove it from the map
_contentEvents.erase(paneId);
}
}
@@ -920,87 +950,104 @@ namespace winrt::TerminalApp::implementation
// - control: the TermControl to add events to.
// Return Value:
// - <none>
void TerminalTab::_AttachEventHandlersToControl(const uint32_t paneId, const TermControl& control)
void TerminalTab::_AttachEventHandlersToContent(const uint32_t paneId, const TerminalApp::IPaneContent& content)
{
auto weakThis{ get_weak() };
auto dispatcher = TabViewItem().Dispatcher();
ControlEventTokens events{};
ContentEventTokens events{};
events.titleToken = control.TitleChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
// The lambda lives in the `std::function`-style container owned by `control`. That is, when the
// `control` gets destroyed the lambda struct also gets destroyed. In other words, we need to
// copy `weakThis` onto the stack, because that's the only thing that gets captured in coroutines.
// See: https://devblogs.microsoft.com/oldnewthing/20211103-00/?p=105870
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThisCopy.get() })
{
// The title of the control changed, but not necessarily the title of the tab.
// Set the tab's text to the active panes' text.
tab->UpdateTitle();
}
});
events.colorToken = control.TabColorChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThisCopy.get() })
{
// The control's tabColor changed, but it is not necessarily the
// active control in this tab. We'll just recalculate the
// current color anyways.
tab->_RecalculateAndApplyTabColor();
}
});
events.taskbarToken = control.SetTaskbarProgress([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThisCopy.get() })
{
tab->_UpdateProgressState();
}
});
events.stateToken = control.ConnectionStateChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThisCopy.get() })
{
tab->_UpdateConnectionClosedState();
}
});
events.readOnlyToken = control.ReadOnlyChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThisCopy.get() })
{
tab->_RecalculateAndApplyReadOnly();
}
});
events.focusToken = control.FocusFollowMouseRequested([dispatcher, weakThis](auto sender, auto) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (const auto tab{ weakThisCopy.get() })
{
if (tab->_focused())
events.TitleChanged = content.TitleChanged(
winrt::auto_revoke,
[dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
// The lambda lives in the `std::function`-style container owned by `control`. That is, when the
// `control` gets destroyed the lambda struct also gets destroyed. In other words, we need to
// copy `weakThis` onto the stack, because that's the only thing that gets captured in coroutines.
// See: https://devblogs.microsoft.com/oldnewthing/20211103-00/?p=105870
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
// Check if Tab's lifetime has expired
if (auto tab{ weakThisCopy.get() })
{
if (const auto termControl{ sender.try_as<winrt::Microsoft::Terminal::Control::TermControl>() })
// The title of the control changed, but not necessarily the title of the tab.
// Set the tab's text to the active panes' text.
tab->UpdateTitle();
}
});
events.TabColorChanged = content.TabColorChanged(
winrt::auto_revoke,
[dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThisCopy.get() })
{
// The control's tabColor changed, but it is not necessarily the
// active control in this tab. We'll just recalculate the
// current color anyways.
tab->_RecalculateAndApplyTabColor();
}
});
events.TaskbarProgressChanged = content.TaskbarProgressChanged(
winrt::auto_revoke,
[dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
// Check if Tab's lifetime has expired
if (auto tab{ weakThisCopy.get() })
{
tab->_UpdateProgressState();
}
});
events.ConnectionStateChanged = content.ConnectionStateChanged(
winrt::auto_revoke,
[dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThisCopy.get() })
{
tab->_UpdateConnectionClosedState();
}
});
events.ReadOnlyChanged = content.ReadOnlyChanged(
winrt::auto_revoke,
[dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThis.get() })
{
tab->_RecalculateAndApplyReadOnly();
}
});
events.FocusRequested = content.FocusRequested(
winrt::auto_revoke,
[dispatcher, weakThis](auto sender, auto) -> winrt::fire_and_forget {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (const auto tab{ weakThisCopy.get() })
{
if (tab->_focused())
{
termControl.Focus(FocusState::Pointer);
if (const auto content{ sender.try_as<TerminalApp::IPaneContent>() })
{
content.Focus(FocusState::Pointer);
}
}
}
}
});
});
if (_tabStatus.IsInputBroadcastActive())
{
_addBroadcastHandlers(control, events);
if (const auto& termContent{ content.try_as<TerminalApp::TerminalPaneContent>() })
{
_addBroadcastHandlers(termContent.GetTerminal(), events);
}
}
_controlEvents[paneId] = std::move(events);
_contentEvents[paneId] = std::move(events);
}
// Method Description:
@@ -1075,7 +1122,7 @@ namespace winrt::TerminalApp::implementation
}
// fire an event signaling that our taskbar progress changed.
_TaskbarProgressChangedHandlers(nullptr, nullptr);
TaskbarProgressChanged.raise(nullptr, nullptr);
}
// Method Description:
@@ -1155,7 +1202,7 @@ namespace winrt::TerminalApp::implementation
_RecalculateAndApplyReadOnly();
// Raise our own ActivePaneChanged event.
_ActivePaneChangedHandlers();
ActivePaneChanged.raise();
}
// Method Description:
@@ -1250,36 +1297,12 @@ namespace winrt::TerminalApp::implementation
}
});
// Add a PaneRaiseBell event handler to the Pane
auto bellToken = pane->PaneRaiseBell([weakThis](auto&& /*s*/, auto&& visual) {
if (auto tab{ weakThis.get() })
{
if (visual)
{
// If visual is set, we need to bubble this event all the way to app host to flash the taskbar
// In this part of the chain we bubble it from the hosting tab to the page
tab->_TabRaiseVisualBellHandlers();
}
// Show the bell indicator in the tab header
tab->ShowBellIndicator(true);
// If this tab is focused, activate the bell indicator timer, which will
// remove the bell indicator once it fires
// (otherwise, the indicator is removed when the tab gets focus)
if (tab->_focusState != WUX::FocusState::Unfocused)
{
tab->ActivateBellIndicatorTimer();
}
}
});
// box the event token so that we can give a reference to it in the
// event handler.
auto detachedToken = std::make_shared<winrt::event_token>();
// Add a Detached event handler to the Pane to clean up tab state
// and other event handlers when a pane is removed from this tab.
*detachedToken = pane->Detached([weakThis, weakPane, gotFocusToken, lostFocusToken, closedToken, bellToken, detachedToken](std::shared_ptr<Pane> /*sender*/) {
*detachedToken = pane->Detached([weakThis, weakPane, gotFocusToken, lostFocusToken, closedToken, detachedToken](std::shared_ptr<Pane> /*sender*/) {
// Make sure we do this at most once
if (auto pane{ weakPane.lock() })
{
@@ -1287,14 +1310,10 @@ namespace winrt::TerminalApp::implementation
pane->GotFocus(gotFocusToken);
pane->LostFocus(lostFocusToken);
pane->Closed(closedToken);
pane->PaneRaiseBell(bellToken);
if (auto tab{ weakThis.get() })
{
if (auto control = pane->GetTerminalControl())
{
tab->_DetachEventHandlersFromControl(pane->Id().value(), control);
}
tab->_DetachEventHandlersFromContent(pane->Id().value());
for (auto i = tab->_mruPanes.begin(); i != tab->_mruPanes.end(); ++i)
{
@@ -1495,9 +1514,14 @@ namespace winrt::TerminalApp::implementation
// GH#10112 - if we're opening the tab renamer, don't
// immediately toss focus to the control. We don't want to steal
// focus from the tab renamer.
if (!tab->_headerControl.InRename() && !tab->GetActiveTerminalControl().SearchBoxEditInFocus())
const auto& terminalControl{ tab->GetActiveTerminalControl() }; // maybe null
// If we're
// * NOT in a rename
// * AND (the content isn't a TermControl, OR the term control doesn't have focus in the search box)
if (!tab->_headerControl.InRename() &&
(terminalControl == nullptr || !terminalControl.SearchBoxEditInFocus()))
{
tab->_RequestFocusActiveControlHandlers();
tab->RequestFocusActiveControl.raise();
}
}
});
@@ -1517,12 +1541,12 @@ namespace winrt::TerminalApp::implementation
{
ASSERT_UI_THREAD();
std::optional<winrt::Windows::UI::Color> controlTabColor;
if (const auto& control = GetActiveTerminalControl())
std::optional<winrt::Windows::UI::Color> contentTabColor;
if (const auto& content{ GetActiveContent() })
{
if (const auto color = control.TabColor())
if (const auto color = content.TabColor())
{
controlTabColor = color.Value();
contentTabColor = color.Value();
}
}
@@ -1532,7 +1556,7 @@ namespace winrt::TerminalApp::implementation
// Color | | Set by
// -------------------- | -- | --
// Runtime Color | _optional_ | Color Picker / `setTabColor` action
// Control Tab Color | _optional_ | Profile's `tabColor`, or a color set by VT
// Content Tab Color | _optional_ | Profile's `tabColor`, or a color set by VT (whatever the tab's content wants)
// Theme Tab Background | _optional_ | `tab.backgroundColor` in the theme (handled in _RecalculateAndApplyTabColor)
// Tab Default Color | **default** | TabView in XAML
//
@@ -1541,7 +1565,7 @@ namespace winrt::TerminalApp::implementation
// tabview color" (and clear out any colors we've set).
return til::coalesce(_runtimeTabColor,
controlTabColor,
contentTabColor,
std::optional<Windows::UI::Color>(std::nullopt));
}
@@ -1580,7 +1604,7 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::UI::Xaml::Media::Brush TerminalTab::_BackgroundBrush()
{
Media::Brush terminalBrush{ nullptr };
if (const auto& c{ GetActiveTerminalControl() })
if (const auto& c{ GetActiveContent() })
{
terminalBrush = c.BackgroundBrush();
}
@@ -1695,6 +1719,18 @@ namespace winrt::TerminalApp::implementation
return _zoomedPane != nullptr;
}
TermControl _termControlFromPane(const auto& pane)
{
if (const auto content{ pane->GetContent() })
{
if (const auto termContent{ content.try_as<winrt::TerminalApp::TerminalPaneContent>() })
{
return termContent.GetTerminal();
}
}
return nullptr;
}
// Method Description:
// - Toggle read-only mode on the active pane
// - If a parent pane is selected, this will ensure that all children have
@@ -1706,14 +1742,14 @@ namespace winrt::TerminalApp::implementation
auto hasReadOnly = false;
auto allReadOnly = true;
_activePane->WalkTree([&](const auto& p) {
if (const auto& control{ p->GetTerminalControl() })
if (const auto& control{ _termControlFromPane(p) })
{
hasReadOnly |= control.ReadOnly();
allReadOnly &= control.ReadOnly();
}
});
_activePane->WalkTree([&](const auto& p) {
if (const auto& control{ p->GetTerminalControl() })
if (const auto& control{ _termControlFromPane(p) })
{
// If all controls have the same read only state then just toggle
if (allReadOnly || !hasReadOnly)
@@ -1738,14 +1774,14 @@ namespace winrt::TerminalApp::implementation
auto hasReadOnly = false;
auto allReadOnly = true;
_activePane->WalkTree([&](const auto& p) {
if (const auto& control{ p->GetTerminalControl() })
if (const auto& control{ _termControlFromPane(p) })
{
hasReadOnly |= control.ReadOnly();
allReadOnly &= control.ReadOnly();
}
});
_activePane->WalkTree([&](const auto& p) {
if (const auto& control{ p->GetTerminalControl() })
if (const auto& control{ _termControlFromPane(p) })
{
// If all controls have the same read only state then just disable
if (allReadOnly || !hasReadOnly)
@@ -1776,6 +1812,10 @@ namespace winrt::TerminalApp::implementation
ReadOnly(_rootPane->ContainsReadOnly());
_updateIsClosable();
// Update all the visuals on all our panes, so they can update their
// border colors accordingly.
_rootPane->WalkTree([](const auto& p) { p->UpdateVisuals(); });
}
std::shared_ptr<Pane> TerminalTab::GetActivePane() const
@@ -1826,10 +1866,10 @@ namespace winrt::TerminalApp::implementation
{
return;
}
if (const auto& control{ p->GetTerminalControl() })
if (const auto& control{ _termControlFromPane(p) })
{
auto it = _controlEvents.find(*paneId);
if (it != _controlEvents.end())
auto it = _contentEvents.find(*paneId);
if (it != _contentEvents.end())
{
auto& events = it->second;
@@ -1847,7 +1887,7 @@ namespace winrt::TerminalApp::implementation
});
}
void TerminalTab::_addBroadcastHandlers(const TermControl& termControl, ControlEventTokens& events)
void TerminalTab::_addBroadcastHandlers(const TermControl& termControl, ContentEventTokens& events)
{
auto weakThis{ get_weak() };
// ADD EVENT HANDLERS HERE

View File

@@ -25,6 +25,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Control::TermControl GetActiveTerminalControl() const;
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile() const noexcept;
winrt::TerminalApp::IPaneContent GetActiveContent() const;
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
@@ -41,7 +42,7 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<Pane> newPane);
void ToggleSplitOrientation();
void UpdateIcon(const winrt::hstring iconPath, const winrt::Microsoft::Terminal::Settings::Model::IconStyle iconStyle);
void UpdateIcon(const winrt::hstring& iconPath, const winrt::Microsoft::Terminal::Settings::Model::IconStyle iconStyle);
void HideIcon(const bool hide);
void ShowBellIndicator(const bool show);
@@ -57,7 +58,7 @@ namespace winrt::TerminalApp::implementation
bool SwapPane(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool FocusPane(const uint32_t id);
void UpdateSettings();
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const TerminalApp::TerminalSettingsCache& cache);
void UpdateTitle();
void Shutdown() override;
@@ -96,9 +97,9 @@ namespace winrt::TerminalApp::implementation
return _tabStatus;
}
WINRT_CALLBACK(ActivePaneChanged, winrt::delegate<>);
WINRT_CALLBACK(TabRaiseVisualBell, winrt::delegate<>);
TYPED_EVENT(TaskbarProgressChanged, IInspectable, IInspectable);
til::event<winrt::delegate<>> ActivePaneChanged;
til::event<winrt::delegate<>> TabRaiseVisualBell;
til::typed_event<IInspectable, IInspectable> TaskbarProgressChanged;
private:
static constexpr double HeaderRenameBoxWidthDefault{ 165 };
@@ -122,20 +123,22 @@ namespace winrt::TerminalApp::implementation
winrt::event_token _colorClearedToken;
winrt::event_token _pickerClosedToken;
struct ControlEventTokens
struct ContentEventTokens
{
winrt::event_token titleToken;
winrt::event_token colorToken;
winrt::event_token taskbarToken;
winrt::event_token stateToken;
winrt::event_token readOnlyToken;
winrt::event_token focusToken;
winrt::TerminalApp::IPaneContent::BellRequested_revoker BellRequested;
winrt::TerminalApp::IPaneContent::TitleChanged_revoker TitleChanged;
winrt::TerminalApp::IPaneContent::TabColorChanged_revoker TabColorChanged;
winrt::TerminalApp::IPaneContent::TaskbarProgressChanged_revoker TaskbarProgressChanged;
winrt::TerminalApp::IPaneContent::ConnectionStateChanged_revoker ConnectionStateChanged;
winrt::TerminalApp::IPaneContent::ReadOnlyChanged_revoker ReadOnlyChanged;
winrt::TerminalApp::IPaneContent::FocusRequested_revoker FocusRequested;
// These events literally only apply if the content is a TermControl.
winrt::Microsoft::Terminal::Control::TermControl::KeySent_revoker KeySent;
winrt::Microsoft::Terminal::Control::TermControl::CharSent_revoker CharSent;
winrt::Microsoft::Terminal::Control::TermControl::StringSent_revoker StringSent;
};
std::unordered_map<uint32_t, ControlEventTokens> _controlEvents;
std::unordered_map<uint32_t, ContentEventTokens> _contentEvents;
winrt::event_token _rootClosedToken{};
@@ -162,8 +165,8 @@ namespace winrt::TerminalApp::implementation
void _CreateContextMenu() override;
virtual winrt::hstring _CreateToolTipTitle() override;
void _DetachEventHandlersFromControl(const uint32_t paneId, const winrt::Microsoft::Terminal::Control::TermControl& control);
void _AttachEventHandlersToControl(const uint32_t paneId, const winrt::Microsoft::Terminal::Control::TermControl& control);
void _DetachEventHandlersFromContent(const uint32_t paneId);
void _AttachEventHandlersToContent(const uint32_t paneId, const winrt::TerminalApp::IPaneContent& content);
void _AttachEventHandlersToPane(std::shared_ptr<Pane> pane);
void _UpdateActivePane(std::shared_ptr<Pane> pane);
@@ -181,7 +184,7 @@ namespace winrt::TerminalApp::implementation
virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override;
void _addBroadcastHandlers(const winrt::Microsoft::Terminal::Control::TermControl& control, ControlEventTokens& events);
void _addBroadcastHandlers(const winrt::Microsoft::Terminal::Control::TermControl& control, ContentEventTokens& events);
void _chooseColorClicked(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _renameTabClicked(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e);

View File

@@ -11,15 +11,15 @@ namespace winrt::TerminalApp::implementation
{
TerminalTabStatus() = default;
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(bool, IsConnectionClosed, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, IsPaneZoomed, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingActive, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingIndeterminate, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, BellIndicator, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, IsReadOnlyActive, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(uint32_t, ProgressValue, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, IsInputBroadcastActive, _PropertyChangedHandlers);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(bool, IsConnectionClosed, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsPaneZoomed, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingActive, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingIndeterminate, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, BellIndicator, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsReadOnlyActive, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(uint32_t, ProgressValue, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsInputBroadcastActive, PropertyChanged.raise);
};
}

View File

@@ -226,7 +226,7 @@ namespace winrt::TerminalApp::implementation
auto args = winrt::make_self<SystemMenuChangeArgs>(RS_(L"SettingsMenuItem"),
SystemMenuChangeAction::Add,
SystemMenuItemHandler(this, &TerminalWindow::_OpenSettingsUI));
_SystemMenuChangeRequestedHandlers(*this, *args);
SystemMenuChangeRequested.raise(*this, *args);
TraceLoggingWrite(
g_hTerminalAppProvider,
@@ -748,7 +748,7 @@ namespace winrt::TerminalApp::implementation
void TerminalWindow::_RefreshThemeRoutine()
{
// Propagate the event to the host layer, so it can update its own UI
_RequestedThemeChangedHandlers(*this, Theme());
RequestedThemeChanged.raise(*this, Theme());
}
// This may be called on a background thread, or the main thread, but almost
@@ -767,7 +767,7 @@ namespace winrt::TerminalApp::implementation
_root->SetSettings(_settings, true);
// Bubble the notification up to the AppHost, now that we've updated our _settings.
_SettingsChangedHandlers(*this, args);
SettingsChanged.raise(*this, args);
if (FAILED(args.Result()))
{
@@ -1239,7 +1239,7 @@ namespace winrt::TerminalApp::implementation
// If we're entering Quake Mode from Focus Mode, then this will do nothing
// If we're leaving Quake Mode (we're already in Focus Mode), then this will do nothing
_root->SetFocusMode(true);
_IsQuakeWindowChangedHandlers(*this, nullptr);
IsQuakeWindowChanged.raise(*this, nullptr);
}
}
void TerminalWindow::WindowId(const uint64_t& id)
@@ -1359,8 +1359,8 @@ namespace winrt::TerminalApp::implementation
// PropertyChangedEventArgs will throw.
try
{
_PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"WindowName" });
_PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"WindowNameForDisplay" });
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"WindowName" });
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"WindowNameForDisplay" });
}
CATCH_LOG();
}

View File

@@ -48,9 +48,9 @@ namespace winrt::TerminalApp::implementation
winrt::hstring WindowNameForDisplay() const noexcept;
bool IsQuakeWindow() const noexcept;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, VirtualWorkingDirectory, _PropertyChangedHandlers, L"");
til::property_changed_event PropertyChanged;
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, VirtualWorkingDirectory, PropertyChanged.raise, L"");
public:
// Used for setting the initial CWD, before we have XAML set up for property change notifications.
@@ -156,14 +156,17 @@ namespace winrt::TerminalApp::implementation
// -------------------------------- WinRT Events ---------------------------------
// PropertyChanged is surprisingly not a typed event, so we'll define that one manually.
// Usually we'd just do
// WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
// til::property_changed_event PropertyChanged;
//
// But what we're doing here is exposing the Page's PropertyChanged _as
// our own event_. It's a FORWARDED_CALLBACK, essentially.
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return _root->PropertyChanged(handler); }
void PropertyChanged(winrt::event_token const& token) { _root->PropertyChanged(token); }
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Settings::Model::Theme);
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Settings::Model::Theme> RequestedThemeChanged;
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IInspectable> IsQuakeWindowChanged;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs> SystemMenuChangeRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SettingsLoadEventArgs> SettingsChanged;
private:
// If you add controls here, but forget to null them either here or in
@@ -230,12 +233,6 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested);
FORWARDED_TYPED_EVENT(ShowWindowChanged, Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs, _root, ShowWindowChanged);
TYPED_EVENT(IsQuakeWindowChanged, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable);
TYPED_EVENT(SystemMenuChangeRequested, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs);
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SettingsLoadEventArgs);
FORWARDED_TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs, _root, RequestMoveContent);
FORWARDED_TYPED_EVENT(RequestReceiveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs, _root, RequestReceiveContent);

View File

@@ -36,7 +36,6 @@
<ClInclude Include="../TabRowControl.h" />
<ClInclude Include="../App.h" />
<ClInclude Include="../TerminalTab.h" />
<ClInclude Include="../SettingsTab.h" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>

View File

@@ -40,6 +40,7 @@
#include <winrt/Windows.UI.Xaml.Automation.Peers.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.Documents.h>
#include <winrt/Windows.UI.Xaml.Input.h>
#include <winrt/Windows.UI.Xaml.Markup.h>
@@ -83,6 +84,7 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider);
// Manually include til after we include Windows.Foundation to give it winrt superpowers
#include "til.h"
#include <til/winrt.h>
#include <SafeDispatcherTimer.h>

View File

@@ -94,7 +94,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// - str: the string to write.
void AzureConnection::_WriteStringWithNewline(const std::wstring_view str)
{
_TerminalOutputHandlers(str + L"\r\n");
TerminalOutput.raise(str + L"\r\n");
}
// Method description:
@@ -110,7 +110,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
catch (const std::exception& runtimeException)
{
// This also catches the AzureException, which has a .what()
_TerminalOutputHandlers(_colorize(91, til::u8u16(std::string{ runtimeException.what() })));
TerminalOutput.raise(_colorize(91, til::u8u16(std::string{ runtimeException.what() })));
}
catch (...)
{
@@ -160,13 +160,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
_currentInputMode = mode;
_TerminalOutputHandlers(L"> \x1b[92m"); // Make prompted user input green
TerminalOutput.raise(L"> \x1b[92m"); // Make prompted user input green
_inputEvent.wait(inputLock, [this, mode]() {
return _currentInputMode != mode || _isStateAtOrBeyond(ConnectionState::Closing);
});
_TerminalOutputHandlers(L"\x1b[m");
TerminalOutput.raise(L"\x1b[m");
if (_isStateAtOrBeyond(ConnectionState::Closing))
{
@@ -204,19 +204,19 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
if (_userInput.size() > 0)
{
_userInput.pop_back();
_TerminalOutputHandlers(L"\x08 \x08"); // overstrike the character with a space
TerminalOutput.raise(L"\x08 \x08"); // overstrike the character with a space
}
}
else
{
_TerminalOutputHandlers(data); // echo back
TerminalOutput.raise(data); // echo back
switch (_currentInputMode)
{
case InputMode::Line:
if (data.size() > 0 && gsl::at(data, 0) == UNICODE_CARRIAGERETURN)
{
_TerminalOutputHandlers(L"\r\n"); // we probably got a \r, so we need to advance to the next line.
TerminalOutput.raise(L"\r\n"); // we probably got a \r, so we need to advance to the next line.
_currentInputMode = InputMode::None; // toggling the mode indicates completion
_inputEvent.notify_one();
break;
@@ -279,7 +279,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
if (_hOutputThread)
{
// Waiting for the output thread to exit ensures that all pending _TerminalOutputHandlers()
// Waiting for the output thread to exit ensures that all pending TerminalOutput.raise()
// calls have returned and won't notify our caller (ControlCore) anymore. This ensures that
// we don't call a destroyed event handler asynchronously from a background thread (GH#13880).
WaitForSingleObject(_hOutputThread.get(), INFINITE);
@@ -422,7 +422,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
// Pass the output to our registered event handlers
_TerminalOutputHandlers(_u16Str);
TerminalOutput.raise(_u16Str);
break;
}
case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
@@ -765,7 +765,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
const auto shellType = _ParsePreferredShellType(settingsResponse);
_WriteStringWithNewline(RS_(L"AzureRequestingTerminal"));
const auto socketUri = _GetTerminal(shellType);
_TerminalOutputHandlers(L"\r\n");
TerminalOutput.raise(L"\r\n");
//// Step 8: connecting to said terminal
{

View File

@@ -26,7 +26,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
void Resize(uint32_t rows, uint32_t columns);
void Close();
WINRT_CALLBACK(TerminalOutput, TerminalOutputHandler);
til::event<TerminalOutputHandler> TerminalOutput;
private:
til::CoordType _initialRows{};

View File

@@ -17,7 +17,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
return _connectionState;
}
TYPED_EVENT(StateChanged, ITerminalConnection, winrt::Windows::Foundation::IInspectable);
til::typed_event<ITerminalConnection, winrt::Windows::Foundation::IInspectable> StateChanged;
protected:
template<typename U>
@@ -49,7 +49,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
// Dispatch the event outside of lock.
#pragma warning(suppress : 26491) // We can't avoid static_cast downcast because this is template magic.
_StateChangedHandlers(*static_cast<T*>(this), nullptr);
StateChanged.raise(*static_cast<T*>(this), nullptr);
return true;
}
CATCH_FAIL_FAST()

View File

@@ -415,15 +415,15 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") },
fmt::format(_errorFormat, static_cast<unsigned int>(hr)),
_commandline) };
_TerminalOutputHandlers(failureText);
TerminalOutput.raise(failureText);
// If the path was invalid, let's present an informative message to the user
if (hr == HRESULT_FROM_WIN32(ERROR_DIRECTORY))
{
winrt::hstring badPathText{ fmt::format(std::wstring_view{ RS_(L"BadPathText") },
_startingDirectory) };
_TerminalOutputHandlers(L"\r\n");
_TerminalOutputHandlers(badPathText);
TerminalOutput.raise(L"\r\n");
TerminalOutput.raise(badPathText);
}
_transitionToState(ConnectionState::Failed);
@@ -442,11 +442,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
// GH#11556 - make sure to format the error code to this string as an UNSIGNED int
winrt::hstring exitText{ fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, fmt::format(_errorFormat, status)) };
_TerminalOutputHandlers(L"\r\n");
_TerminalOutputHandlers(exitText);
_TerminalOutputHandlers(L"\r\n");
_TerminalOutputHandlers(RS_(L"CtrlDToClose"));
_TerminalOutputHandlers(L"\r\n");
TerminalOutput.raise(L"\r\n");
TerminalOutput.raise(exitText);
TerminalOutput.raise(L"\r\n");
TerminalOutput.raise(RS_(L"CtrlDToClose"));
TerminalOutput.raise(L"\r\n");
}
CATCH_LOG();
}
@@ -554,7 +554,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// thread exit as fast as possible by aborting any ongoing writes coming from OpenConsole.
CancelSynchronousIo(_hOutputThread.get());
// Waiting for the output thread to exit ensures that all pending _TerminalOutputHandlers()
// Waiting for the output thread to exit ensures that all pending TerminalOutput.raise()
// calls have returned and won't notify our caller (ControlCore) anymore. This ensures that
// we don't call a destroyed event handler asynchronously from a background thread (GH#13880).
const auto result = WaitForSingleObject(_hOutputThread.get(), 1000);
@@ -676,7 +676,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
// Pass the output to our registered event handlers
_TerminalOutputHandlers(_u16Str);
TerminalOutput.raise(_u16Str);
}
return 0;

View File

@@ -57,7 +57,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
const winrt::guid& guid,
const winrt::guid& profileGuid);
WINRT_CALLBACK(TerminalOutput, TerminalOutputHandler);
til::event<TerminalOutputHandler> TerminalOutput;
private:
static void closePseudoConsoleAsync(HPCON hPC) noexcept;

View File

@@ -33,7 +33,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
prettyPrint << wch;
}
}
_TerminalOutputHandlers(prettyPrint.str());
TerminalOutput.raise(prettyPrint.str());
}
void EchoConnection::Resize(uint32_t /*rows*/, uint32_t /*columns*/) noexcept

View File

@@ -21,8 +21,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
winrt::guid SessionId() const noexcept { return {}; }
ConnectionState State() const noexcept { return ConnectionState::Connected; }
WINRT_CALLBACK(TerminalOutput, TerminalOutputHandler);
TYPED_EVENT(StateChanged, ITerminalConnection, IInspectable);
til::event<TerminalOutputHandler> TerminalOutput;
til::typed_event<ITerminalConnection, IInspectable> StateChanged;
};
}

View File

@@ -37,5 +37,6 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalConnectionProvider);
#include <telemetry/ProjectTelemetry.h>
#include "til.h"
#include <til/winrt.h>
#include <cppwinrt_utils.h>

View File

@@ -77,25 +77,56 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
ControlCore::ControlCore(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection) :
ControlCore::ControlCore() :
_desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, DEFAULT_FONT_SIZE, CP_UTF8 },
_actualFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false }
{
}
ControlCore::ControlCore(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
ControlData& data) :
ControlCore()
{
// TODO! In this case, do we need to set a flag to make sure we don't
// end up clearing out the Terminal when we get initialized? Probably!
_construct(settings, unfocusedAppearance, data);
}
// The normal ctor that the Windows Terminal comes through
ControlCore::ControlCore(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection inboundConnection) :
ControlCore()
{
ControlData data{
.terminal = std::make_shared<::Microsoft::Terminal::Core::Terminal>(),
.connection = inboundConnection
};
// In the usual case, the Terminal instance itself is the RenderData
// (without any extra indirection);
data.renderData = data.terminal.get();
_construct(settings, unfocusedAppearance, data);
}
void ControlCore::_construct(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
ControlData& data)
{
_settings = winrt::make_self<implementation::ControlSettings>(settings, unfocusedAppearance);
_terminal = std::make_shared<::Microsoft::Terminal::Core::Terminal>();
_terminal = data.terminal; // std::make_shared<::Microsoft::Terminal::Core::Terminal>();
const auto lock = _terminal->LockForWriting();
_setupDispatcherAndCallbacks();
Connection(connection);
Connection(data.connection);
_terminal->SetWriteInputCallback([this](std::wstring_view wstr) {
_sendInputToConnection(wstr);
});
// GH#8969: pre-seed working directory to prevent potential races
// TODO! This will reset it for every new block, that's dumb.
_terminal->SetWorkingDirectory(_settings->StartingDirectory());
auto pfnCopyToClipboard = std::bind(&ControlCore::_terminalCopyToClipboard, this, std::placeholders::_1);
@@ -107,8 +138,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnTitleChanged = std::bind(&ControlCore::_terminalTitleChanged, this, std::placeholders::_1);
_terminal->SetTitleChangedCallback(pfnTitleChanged);
auto pfnScrollPositionChanged = std::bind(&ControlCore::_terminalScrollPositionChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
_terminal->SetScrollPositionChangedCallback(pfnScrollPositionChanged);
// auto pfnScrollPositionChanged = std::bind(&ControlCore::_terminalScrollPositionChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
// _terminal->SetScrollPositionChangedCallback(pfnScrollPositionChanged);
_scrollPosToken = _terminal->ScrollPositionChanged({ this, &ControlCore::_terminalScrollPositionChanged });
auto pfnTerminalCursorPositionChanged = std::bind(&ControlCore::_terminalCursorPositionChanged, this);
_terminal->SetCursorPositionChangedCallback(pfnTerminalCursorPositionChanged);
@@ -140,11 +172,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Now create the renderer and initialize the render thread.
const auto& renderSettings = _terminal->GetRenderSettings();
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(renderSettings, _terminal.get(), nullptr, 0, std::move(renderThread));
_renderData = data.renderData;
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(renderSettings, _renderData, nullptr, 0, std::move(renderThread));
_renderer->SetBackgroundColorChangedCallback([this]() { _rendererBackgroundColorChanged(); });
_renderer->SetFrameColorChangedCallback([this]() { _rendererTabColorChanged(); });
_renderer->SetRendererEnteredErrorStateCallback([this]() { _RendererEnteredErrorStateHandlers(nullptr, nullptr); });
_renderer->SetRendererEnteredErrorStateCallback([this]() { RendererEnteredErrorState.raise(nullptr, nullptr); });
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
}
@@ -186,7 +219,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
[weakThis = get_weak()]() {
if (auto core{ weakThis.get() }; !core->_IsClosing())
{
core->_CursorPositionChangedHandlers(*core, nullptr);
core->CursorPositionChanged.raise(*core, nullptr);
}
});
@@ -208,7 +241,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
[weakThis = get_weak()](const auto& update) {
if (auto core{ weakThis.get() }; !core->_IsClosing())
{
core->_ScrollPositionChangedHandlers(*core, update);
core->ScrollPositionChanged.raise(*core, update);
}
});
}
@@ -244,11 +277,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_setupDispatcherAndCallbacks();
const auto actualNewSize = _actualFont.GetSize();
// Bubble this up, so our new control knows how big we want the font.
_FontSizeChangedHandlers(*this, winrt::make<FontSizeChangedArgs>(actualNewSize.width, actualNewSize.height));
FontSizeChanged.raise(*this, winrt::make<FontSizeChangedArgs>(actualNewSize.width, actualNewSize.height));
// The renderer will be re-enabled in Initialize
_AttachedHandlers(*this, nullptr);
Attached.raise(*this, nullptr);
}
TerminalConnection::ITerminalConnection ControlCore::Connection()
@@ -276,7 +309,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// Subscribe to the connection's disconnected event and call our connection closed handlers.
_connectionStateChangedRevoker = newConnection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*v*/) {
_ConnectionStateChangedHandlers(*this, nullptr);
ConnectionStateChanged.raise(*this, nullptr);
});
// Get our current size in rows/cols, and hook them up to
@@ -298,13 +331,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// This event is explicitly revoked in the destructor: does not need weak_ref
_connectionOutputEventRevoker = _connection.TerminalOutput(winrt::auto_revoke, { this, &ControlCore::_connectionOutputHandler });
}
else
{
// HAX
_terminal->ScrollPositionChanged(_scrollPosToken);
}
// Fire off a connection state changed notification, to let our hosting
// app know that we're in a different state now.
if (oldState != ConnectionState())
{ // rely on the null handling again
// send the notification
_ConnectionStateChangedHandlers(*this, nullptr);
ConnectionStateChanged.raise(*this, nullptr);
}
}
@@ -356,7 +394,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
const auto width = vp.Width();
const auto height = vp.Height();
_connection.Resize(height, width);
if (_connection)
_connection.Resize(height, width);
if (_owningHwnd != 0)
{
@@ -370,7 +409,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_settings->InitialCols(width);
_settings->InitialRows(height);
_terminal->CreateFromSettings(*_settings, *_renderer);
_terminal->CreateFromSettings(*_settings, _renderer.get());
_terminal->ChangeRenderer(_renderer.get());
// IMPORTANT! Set this callback up sooner than later. If we do it
// after Enable, then it'll be possible to paint the frame once
@@ -403,7 +443,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Start the connection outside of lock, because it could
// start writing output immediately.
_connection.Start();
if (_connection &&
_connection.State() < TerminalConnection::ConnectionState::Connecting)
{
_connection.Start();
}
return true;
}
@@ -449,7 +493,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
else
{
_connection.WriteInput(wstr);
if (_connection)
_connection.WriteInput(wstr);
}
}
@@ -471,18 +516,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const wchar_t CtrlD = 0x4;
const wchar_t Enter = '\r';
if (_connection.State() >= winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::Closed)
if (_connection && _connection.State() >= winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::Closed)
{
if (ch == CtrlD)
{
_CloseTerminalRequestedHandlers(*this, nullptr);
CloseTerminalRequested.raise(*this, nullptr);
return true;
}
if (ch == Enter)
{
// Ask the hosting application to give us a new connection.
_RestartTerminalRequestedHandlers(*this, nullptr);
RestartTerminalRequested.raise(*this, nullptr);
return true;
}
}
@@ -561,13 +606,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (const auto uri = _terminal->GetHyperlinkAtBufferPosition(_terminal->GetSelectionAnchor()); !uri.empty())
{
lock.unlock();
_OpenHyperlinkHandlers(*this, winrt::make<OpenHyperlinkEventArgs>(winrt::hstring{ uri }));
OpenHyperlink.raise(*this, winrt::make<OpenHyperlinkEventArgs>(winrt::hstring{ uri }));
}
else
{
const auto selectedText = _terminal->GetTextBuffer().GetPlainText(_terminal->GetSelectionAnchor(), _terminal->GetSelectionEnd());
lock.unlock();
_OpenHyperlinkHandlers(*this, winrt::make<OpenHyperlinkEventArgs>(winrt::hstring{ selectedText }));
OpenHyperlink.raise(*this, winrt::make<OpenHyperlinkEventArgs>(winrt::hstring{ selectedText }));
}
return true;
}
@@ -688,7 +733,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// This is a scroll event that wasn't initiated by the terminal
// itself - it was initiated by the mouse wheel, or the scrollbar.
const auto lock = _terminal->LockForWriting();
_terminal->UserScrollViewport(viewTop);
_renderData->UserScrollViewport(viewTop);
// HAX we can check if we're running as a block because in that case
// we'll have different render data than just the Terminal itself.
// That's probably not a good way of doing this, but it is _A_ way.
if (_renderData != _terminal.get())
{
_renderer->TriggerScroll();
}
}
const auto shared = _shared.lock_shared();
@@ -746,7 +799,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
auto eventArgs = winrt::make_self<TransparencyChangedEventArgs>(newOpacity);
_TransparencyChangedHandlers(*this, *eventArgs);
TransparencyChanged.raise(*this, *eventArgs);
}
void ControlCore::ToggleShaderEffects()
@@ -824,7 +877,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderer->TriggerRedrawAll();
}
_HoveredHyperlinkChangedHandlers(*this, nullptr);
HoveredHyperlinkChanged.raise(*this, nullptr);
}
}
@@ -937,7 +990,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderer->NotifyPaintFrame();
auto eventArgs = winrt::make_self<TransparencyChangedEventArgs>(Opacity());
_TransparencyChangedHandlers(*this, *eventArgs);
TransparencyChanged.raise(*this, *eventArgs);
_renderer->TriggerRedrawAll(true, true);
}
@@ -1016,11 +1069,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_desiredFont.GetFaceName(),
_actualFont.GetFaceName()) };
auto noticeArgs = winrt::make<NoticeEventArgs>(NoticeLevel::Warning, message);
_RaiseNoticeHandlers(*this, std::move(noticeArgs));
RaiseNotice.raise(*this, std::move(noticeArgs));
}
const auto actualNewSize = _actualFont.GetSize();
_FontSizeChangedHandlers(*this, winrt::make<FontSizeChangedArgs>(actualNewSize.width, actualNewSize.height));
FontSizeChanged.raise(*this, winrt::make<FontSizeChangedArgs>(actualNewSize.width, actualNewSize.height));
}
// Method Description:
@@ -1121,7 +1174,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto hr = _terminal->UserResize({ vp.Width(), vp.Height() });
if (SUCCEEDED(hr) && hr != S_FALSE)
{
_connection.Resize(vp.Height(), vp.Width());
if (_connection)
{
_connection.Resize(vp.Height(), vp.Width());
}
}
}
@@ -1222,7 +1278,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// when an OSC 52 is emitted.
void ControlCore::_terminalCopyToClipboard(std::wstring_view wstr)
{
_CopyToClipboardHandlers(*this, winrt::make<implementation::CopyToClipboardEventArgs>(winrt::hstring{ wstr }));
CopyToClipboard.raise(*this, winrt::make<implementation::CopyToClipboardEventArgs>(winrt::hstring{ wstr }));
}
// Method Description:
@@ -1255,11 +1311,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto& [textData, htmlData, rtfData] = _terminal->RetrieveSelectedTextFromBuffer(singleLine, copyHtml, copyRtf);
// send data up for clipboard
_CopyToClipboardHandlers(*this,
winrt::make<CopyToClipboardEventArgs>(winrt::hstring{ textData },
winrt::to_hstring(htmlData),
winrt::to_hstring(rtfData),
copyFormats));
CopyToClipboard.raise(*this,
winrt::make<CopyToClipboardEventArgs>(winrt::hstring{ textData },
winrt::to_hstring(htmlData),
winrt::to_hstring(rtfData),
copyFormats));
return true;
}
@@ -1450,10 +1506,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _terminal->GetTaskbarProgress();
}
// This returns the top of the visible viewport.
int ControlCore::ScrollOffset()
{
const auto lock = _terminal->LockForReading();
return _terminal->GetScrollOffset();
// return _terminal->GetScrollOffset();
// const auto viewStart = _terminal->ViewStartIndex();
const auto visibleTop = _renderData->GetViewport().Top();
// return std::max(0, viewStart - visibleTop);
return visibleTop;
}
// Function Description:
@@ -1464,7 +1525,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
int ControlCore::ViewHeight() const
{
const auto lock = _terminal->LockForReading();
return _terminal->GetViewport().Height();
// return _terminal->GetViewport().Height();
return _renderData->GetViewport().Height();
}
// Function Description:
@@ -1475,7 +1537,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
int ControlCore::BufferHeight() const
{
const auto lock = _terminal->LockForReading();
return _terminal->GetBufferHeight();
// return _terminal->GetBufferHeight();
return _renderData->GetBufferHeight();
}
void ControlCore::_terminalWarningBell()
@@ -1483,7 +1546,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Since this can only ever be triggered by output from the connection,
// then the Terminal already has the write lock when calling this
// callback.
_WarningBellHandlers(*this, nullptr);
WarningBell.raise(*this, nullptr);
}
// Method Description:
@@ -1500,7 +1563,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Since this can only ever be triggered by output from the connection,
// then the Terminal already has the write lock when calling this
// callback.
_TitleChangedHandlers(*this, winrt::make<TitleChangedEventArgs>(winrt::hstring{ wstr }));
TitleChanged.raise(*this, winrt::make<TitleChangedEventArgs>(winrt::hstring{ wstr }));
}
// Method Description:
@@ -1513,9 +1576,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// of the buffer.
// - viewHeight: the height of the viewport in rows.
// - bufferSize: the length of the buffer, in rows
void ControlCore::_terminalScrollPositionChanged(const int viewTop,
const int viewHeight,
const int bufferSize)
void ControlCore::_terminalScrollPositionChanged(const int /*viewTop*/,
const int /*viewHeight*/,
const int /*bufferSize*/)
{
if (!_initializedTerminal.load(std::memory_order_relaxed))
{
@@ -1523,13 +1586,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
// Start the throttled update of our scrollbar.
// As raised in Terminal::_NotifyScrollEvent
// {
// const auto visible = _GetVisibleViewport();
// const auto top = visible.Top();
// const auto height = visible.Height();
// const auto bottom = this->GetBufferHeight();
// _pfnScrollPositionChanged(top, height, bottom);
// }
const auto viewport = _renderData->GetViewport();
const int viewTop = viewport.Top();
const int viewHeight = viewport.Height();
const int bufferSize = _renderData->GetBufferHeight();
auto update{ winrt::make<ScrollPositionChangedArgs>(viewTop,
viewHeight,
bufferSize) };
if (_inUnitTests) [[unlikely]]
{
_ScrollPositionChangedHandlers(*this, update);
ScrollPositionChanged.raise(*this, update);
}
else
{
@@ -1554,13 +1631,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ControlCore::_terminalTaskbarProgressChanged()
{
_TaskbarProgressChangedHandlers(*this, nullptr);
TaskbarProgressChanged.raise(*this, nullptr);
}
void ControlCore::_terminalShowWindowChanged(bool showOrHide)
{
auto showWindow = winrt::make_self<implementation::ShowWindowArgs>(showOrHide);
_ShowWindowChangedHandlers(*this, *showWindow);
ShowWindowChanged.raise(*this, *showWindow);
}
// Method Description:
@@ -1645,7 +1722,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// DO NOT call _updateSelectionUI() here.
// We don't want to show the markers so manually tell it to clear it.
_terminal->SetBlockSelection(false);
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
UpdateSelectionMarkers.raise(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
foundResults->TotalMatches(gsl::narrow<int32_t>(_searcher.Results().size()));
foundResults->CurrentMatch(gsl::narrow<int32_t>(_searcher.CurrentMatch()));
@@ -1656,7 +1733,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Raise a FoundMatch event, which the control will use to notify
// narrator if there was any results in the buffer
_FoundMatchHandlers(*this, *foundResults);
FoundMatch.raise(*this, *foundResults);
}
Windows::Foundation::Collections::IVector<int32_t> ControlCore::SearchResultRows()
@@ -1702,13 +1779,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Stop accepting new output and state changes before we disconnect everything.
_connectionOutputEventRevoker.revoke();
_connectionStateChangedRevoker.revoke();
_connection.Close();
if (_connection)
{
_connection.Close();
}
}
}
void ControlCore::_rendererWarning(const HRESULT hr)
{
_RendererWarningHandlers(*this, winrt::make<RendererWarningArgs>(hr));
RendererWarning.raise(*this, winrt::make<RendererWarningArgs>(hr));
}
winrt::fire_and_forget ControlCore::_renderEngineSwapChainChanged(const HANDLE sourceHandle)
@@ -1737,18 +1817,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_lastSwapChainHandle = std::move(duplicatedHandle);
// Now bubble the event up to the control.
_SwapChainChangedHandlers(*this, winrt::box_value<uint64_t>(reinterpret_cast<uint64_t>(_lastSwapChainHandle.get())));
SwapChainChanged.raise(*this, winrt::box_value<uint64_t>(reinterpret_cast<uint64_t>(_lastSwapChainHandle.get())));
}
}
void ControlCore::_rendererBackgroundColorChanged()
{
_BackgroundColorChangedHandlers(*this, nullptr);
BackgroundColorChanged.raise(*this, nullptr);
}
void ControlCore::_rendererTabColorChanged()
{
_TabColorChangedHandlers(*this, nullptr);
TabColorChanged.raise(*this, nullptr);
}
void ControlCore::BlinkAttributeTick()
@@ -1953,7 +2033,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderer->TriggerSelection();
// only show the markers if we're doing a keyboard selection or in mark mode
const bool showMarkers{ _terminal->SelectionMode() >= ::Microsoft::Terminal::Core::Terminal::SelectionInteractionMode::Keyboard };
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(!showMarkers));
UpdateSelectionMarkers.raise(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(!showMarkers));
}
void ControlCore::AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
@@ -1986,7 +2066,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ControlCore::_raiseReadOnlyWarning()
{
auto noticeArgs = winrt::make<NoticeEventArgs>(NoticeLevel::Info, RS_(L"TermControlReadOnly"));
_RaiseNoticeHandlers(*this, std::move(noticeArgs));
RaiseNotice.raise(*this, std::move(noticeArgs));
}
void ControlCore::_connectionOutputHandler(const hstring& hstr)
{
@@ -2290,7 +2370,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// _sendInputToConnection() asserts that we aren't in focus mode,
// but window focus events are always fine to send.
_connection.WriteInput(*out);
if (_connection)
_connection.WriteInput(*out);
}
}
@@ -2481,7 +2562,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
co_await winrt::resume_background();
_CompletionsChangedHandlers(*this, *args);
CompletionsChanged.raise(*this, *args);
}
void ControlCore::_selectSpan(til::point_span s)
{
@@ -2718,4 +2799,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _clickedOnMark(_contextMenuBufferPosition,
[](const ::ScrollMark& m) -> bool { return !m.HasOutput(); });
}
til::rect ControlCore::ViewInPixels(const til::rect& viewInCharacters)
{
auto v = Viewport::FromExclusive(viewInCharacters);
return _renderEngine->GetViewportInPixels(v).ToExclusive();
}
}

View File

@@ -65,12 +65,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
};
struct ControlData
{
std::shared_ptr<::Microsoft::Terminal::Core::Terminal> terminal;
::Microsoft::Console::Render::IRenderData* renderData;
TerminalConnection::ITerminalConnection connection;
};
struct ControlCore : ControlCoreT<ControlCore>
{
public:
// Projected
ControlCore(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection);
// not projected
ControlCore(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
ControlData& data);
~ControlCore();
bool Initialize(const float actualWidth,
@@ -252,36 +265,38 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// -------------------------------- WinRT Events ---------------------------------
// clang-format off
TYPED_EVENT(FontSizeChanged, IInspectable, Control::FontSizeChangedArgs);
til::typed_event<IInspectable, Control::FontSizeChangedArgs> FontSizeChanged;
TYPED_EVENT(CopyToClipboard, IInspectable, Control::CopyToClipboardEventArgs);
TYPED_EVENT(TitleChanged, IInspectable, Control::TitleChangedEventArgs);
TYPED_EVENT(WarningBell, IInspectable, IInspectable);
TYPED_EVENT(TabColorChanged, IInspectable, IInspectable);
TYPED_EVENT(BackgroundColorChanged, IInspectable, IInspectable);
TYPED_EVENT(ScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
TYPED_EVENT(CursorPositionChanged, IInspectable, IInspectable);
TYPED_EVENT(TaskbarProgressChanged, IInspectable, IInspectable);
TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable);
TYPED_EVENT(HoveredHyperlinkChanged, IInspectable, IInspectable);
TYPED_EVENT(RendererEnteredErrorState, IInspectable, IInspectable);
TYPED_EVENT(SwapChainChanged, IInspectable, IInspectable);
TYPED_EVENT(RendererWarning, IInspectable, Control::RendererWarningArgs);
TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs);
TYPED_EVENT(TransparencyChanged, IInspectable, Control::TransparencyChangedEventArgs);
TYPED_EVENT(ReceivedOutput, IInspectable, IInspectable);
TYPED_EVENT(FoundMatch, IInspectable, Control::FoundResultsArgs);
TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs);
TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
TYPED_EVENT(CompletionsChanged, IInspectable, Control::CompletionsChangedEventArgs);
til::typed_event<IInspectable, Control::CopyToClipboardEventArgs> CopyToClipboard;
til::typed_event<IInspectable, Control::TitleChangedEventArgs> TitleChanged;
til::typed_event<> WarningBell;
til::typed_event<> TabColorChanged;
til::typed_event<> BackgroundColorChanged;
til::typed_event<IInspectable, Control::ScrollPositionChangedArgs> ScrollPositionChanged;
til::typed_event<> CursorPositionChanged;
til::typed_event<> TaskbarProgressChanged;
til::typed_event<> ConnectionStateChanged;
til::typed_event<> HoveredHyperlinkChanged;
til::typed_event<IInspectable, IInspectable> RendererEnteredErrorState;
til::typed_event<> SwapChainChanged;
til::typed_event<IInspectable, Control::RendererWarningArgs> RendererWarning;
til::typed_event<IInspectable, Control::NoticeEventArgs> RaiseNotice;
til::typed_event<IInspectable, Control::TransparencyChangedEventArgs> TransparencyChanged;
til::typed_event<> ReceivedOutput;
til::typed_event<IInspectable, Control::FoundResultsArgs> FoundMatch;
til::typed_event<IInspectable, Control::ShowWindowArgs> ShowWindowChanged;
til::typed_event<IInspectable, Control::UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
til::typed_event<IInspectable, Control::OpenHyperlinkEventArgs> OpenHyperlink;
til::typed_event<IInspectable, Control::CompletionsChangedEventArgs> CompletionsChanged;
TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
TYPED_EVENT(RestartTerminalRequested, IInspectable, IInspectable);
til::typed_event<> CloseTerminalRequested;
til::typed_event<> RestartTerminalRequested;
TYPED_EVENT(Attached, IInspectable, IInspectable);
til::typed_event<> Attached;
// clang-format on
til::rect ViewInPixels(const til::rect& viewInCharacters);
private:
struct SharedState
{
@@ -309,6 +324,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::unique_ptr<::Microsoft::Console::Render::IRenderEngine> _renderEngine{ nullptr };
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr };
::Microsoft::Console::Render::IRenderData* _renderData{ nullptr };
winrt::event_token _scrollPosToken{};
::Search _searcher;
winrt::handle _lastSwapChainHandle{ nullptr };
@@ -346,6 +364,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Windows::Foundation::Collections::IVector<int32_t> _cachedSearchResultRows{ nullptr };
// not projected
ControlCore();
void _construct(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
ControlData& data);
void _setupDispatcherAndCallbacks();
bool _setFontSizeUnderLock(float fontSize);

View File

@@ -40,19 +40,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
ControlInteractivity::ControlInteractivity(IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection) :
ControlInteractivity{ settings,
unfocusedAppearance,
winrt::make_self<ControlCore>(settings, unfocusedAppearance, connection) }
{
}
ControlInteractivity::ControlInteractivity(IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
winrt::com_ptr<ControlCore> core) :
_touchAnchor{ std::nullopt },
_lastMouseClickTimestamp{},
_lastMouseClickPos{},
_selectionNeedsToBeCopied{ false }
_selectionNeedsToBeCopied{ false },
_core{ core }
{
_id = _nextId.fetch_add(1, std::memory_order_relaxed);
_core = winrt::make_self<ControlCore>(settings, unfocusedAppearance, connection);
_core->Attached([weakThis = get_weak()](auto&&, auto&&) {
if (auto self{ weakThis.get() })
{
self->_AttachedHandlers(*self, nullptr);
self->Attached.raise(*self, nullptr);
}
});
}
@@ -117,7 +125,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ControlInteractivity::Close()
{
_ClosedHandlers(*this, nullptr);
Closed.raise(*this, nullptr);
if (_core)
{
_core->Close();
@@ -230,7 +238,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core->BracketedPasteEnabled());
// send paste event up to TermApp
_PasteFromClipboardHandlers(*this, std::move(args));
PasteFromClipboard.raise(*this, std::move(args));
}
void ControlInteractivity::PointerPressed(Control::MouseButtonState buttonState,
@@ -307,7 +315,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core->AnchorContextMenu(terminalPosition);
auto contextArgs = winrt::make<ContextMenuRequestedEventArgs>(til::point{ pixelPosition }.to_winrt_point());
_ContextMenuRequestedHandlers(*this, contextArgs);
ContextMenuRequested.raise(*this, contextArgs);
}
else
{
@@ -611,21 +619,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// row, then actually update the scroll position in the core, and raise
// a ScrollPositionChanged to inform the control.
auto viewTop = ::base::saturated_cast<int>(::std::round(_internalScrollbarPosition));
if (viewTop != _core->ScrollOffset())
auto coreScrollOffset = _core->ScrollOffset();
if (viewTop != coreScrollOffset)
{
_core->UserScrollViewport(viewTop);
// _core->ScrollOffset() is now set to newValue
_ScrollPositionChangedHandlers(*this,
winrt::make<ScrollPositionChangedArgs>(_core->ScrollOffset(),
_core->ViewHeight(),
_core->BufferHeight()));
ScrollPositionChanged.raise(*this,
winrt::make<ScrollPositionChangedArgs>(_core->ScrollOffset(),
_core->ViewHeight(),
_core->BufferHeight()));
}
}
void ControlInteractivity::_hyperlinkHandler(const std::wstring_view uri)
{
_OpenHyperlinkHandlers(*this, winrt::make<OpenHyperlinkEventArgs>(winrt::hstring{ uri }));
OpenHyperlink.raise(*this, winrt::make<OpenHyperlinkEventArgs>(winrt::hstring{ uri }));
}
bool ControlInteractivity::_canSendVTMouseInput(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers)

View File

@@ -34,10 +34,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
struct ControlInteractivity : ControlInteractivityT<ControlInteractivity>
{
public:
// Projected
ControlInteractivity(IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection);
// Not projected
ControlInteractivity(IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
winrt::com_ptr<ControlCore> core);
void GotFocus();
void LostFocus();
void UpdateSettings();
@@ -91,13 +97,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
uint64_t Id();
void AttachToNewControl(const Microsoft::Terminal::Control::IKeyBindings& keyBindings);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
TYPED_EVENT(ScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
TYPED_EVENT(ContextMenuRequested, IInspectable, Control::ContextMenuRequestedEventArgs);
til::typed_event<IInspectable, Control::OpenHyperlinkEventArgs> OpenHyperlink;
til::typed_event<IInspectable, Control::PasteFromClipboardEventArgs> PasteFromClipboard;
til::typed_event<IInspectable, Control::ScrollPositionChangedArgs> ScrollPositionChanged;
til::typed_event<IInspectable, Control::ContextMenuRequestedEventArgs> ContextMenuRequested;
TYPED_EVENT(Attached, IInspectable, IInspectable);
TYPED_EVENT(Closed, IInspectable, IInspectable);
til::typed_event<IInspectable, IInspectable> Attached;
til::typed_event<IInspectable, IInspectable> Closed;
private:
// NOTE: _uiaEngine must be ordered before _core.

View File

@@ -233,7 +233,7 @@ HRESULT HwndTerminal::Initialize()
_renderEngine = std::move(engine);
_terminal->Create({ 80, 25 }, 9001, *_renderer);
_terminal->Create({ 80, 25 }, 9001, _renderer.get());
_terminal->SetWriteInputCallback([=](std::wstring_view input) noexcept { _WriteTextToConnection(input); });
localPointerToThread->EnablePainting();
@@ -275,7 +275,8 @@ void HwndTerminal::RegisterScrollCallback(std::function<void(int, int, int)> cal
{
return;
}
_terminal->SetScrollPositionChangedCallback(callback);
callback;
// _terminal->SetScrollPositionChangedCallback(callback);
}
void HwndTerminal::_WriteTextToConnection(const std::wstring_view input) noexcept

View File

@@ -60,7 +60,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void InteractivityAutomationPeer::SignalSelectionChanged()
{
_SelectionChangedHandlers(*this, nullptr);
SelectionChanged.raise(*this, nullptr);
}
// Method Description:
@@ -75,7 +75,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void InteractivityAutomationPeer::SignalTextChanged()
{
_TextChangedHandlers(*this, nullptr);
TextChanged.raise(*this, nullptr);
}
// Method Description:
@@ -90,12 +90,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void InteractivityAutomationPeer::SignalCursorChanged()
{
_CursorChangedHandlers(*this, nullptr);
CursorChanged.raise(*this, nullptr);
}
void InteractivityAutomationPeer::NotifyNewOutput(std::wstring_view newOutput)
{
_NewOutputHandlers(*this, hstring{ newOutput });
NewOutput.raise(*this, hstring{ newOutput });
}
#pragma region ITextProvider

View File

@@ -71,10 +71,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) override;
#pragma endregion
TYPED_EVENT(SelectionChanged, IInspectable, IInspectable);
TYPED_EVENT(TextChanged, IInspectable, IInspectable);
TYPED_EVENT(CursorChanged, IInspectable, IInspectable);
TYPED_EVENT(NewOutput, IInspectable, hstring);
til::typed_event<IInspectable, IInspectable> SelectionChanged;
til::typed_event<IInspectable, IInspectable> TextChanged;
til::typed_event<IInspectable, IInspectable> CursorChanged;
til::typed_event<IInspectable, hstring> NewOutput;
private:
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider _CreateXamlUiaTextRange(::ITextRangeProvider* returnVal) const;

View File

@@ -0,0 +1,178 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Notebook.h"
#include "TermControl.h"
#include "Notebook.g.cpp"
using namespace ::Microsoft::Console::Types;
using namespace ::Microsoft::Console::VirtualTerminal;
using namespace ::Microsoft::Terminal::Core;
using namespace winrt::Windows::Graphics::Display;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Input;
using namespace winrt::Windows::UI::Xaml::Automation::Peers;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::ViewManagement;
using namespace winrt::Windows::UI::Input;
using namespace winrt::Windows::System;
using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::Storage::Streams;
namespace winrt
{
namespace MUX = Microsoft::UI::Xaml;
namespace WUX = Windows::UI::Xaml;
using IInspectable = Windows::Foundation::IInspectable;
}
namespace winrt::Microsoft::Terminal::Control::implementation
{
Notebook::Notebook(Control::IControlSettings settings,
Control::IControlAppearance unfocusedAppearance,
TerminalConnection::ITerminalConnection connection) :
_settings{ settings },
_unfocusedAppearance{ unfocusedAppearance },
_connection{ connection }
{
_terminal = std::make_shared<::Microsoft::Terminal::Core::Terminal>();
_terminal->NewPrompt({ get_weak(), &Notebook::_handleNewPrompt });
_fork(0);
}
void Notebook::_handleNewPrompt(const ::ScrollMark& mark)
{
_expectedPrompts--;
if (_expectedPrompts > 0)
return;
if (_gotFirstMark)
{
_fork(mark.start.y);
}
else
{
_gotFirstMark = true;
}
}
Windows::Foundation::Collections::IVector<Microsoft::Terminal::Control::NotebookBlock> Notebook::Blocks() const
{
return nullptr;
}
Control::NotebookBlock Notebook::ActiveBlock() const
{
const auto active{ _activeBlock() };
return active ? *active : Control::NotebookBlock{ nullptr };
}
winrt::com_ptr<implementation::NotebookBlock> Notebook::_activeBlock() const
{
if (_blocks.empty())
{
return nullptr;
}
return *_blocks.rbegin();
}
void Notebook::SendCommands(const winrt::hstring& commands)
{
auto numCarriageReturns = std::count(commands.begin(), commands.end(), L'\r');
auto active = _activeBlock();
if (numCarriageReturns > 0)
{
_expectedPrompts = numCarriageReturns;
active->State(BlockState::Running);
// BAD just make it not a winrt property you donkey
active->StateChanged.raise(*active, nullptr);
}
active->Control().SendInput(commands);
}
winrt::fire_and_forget Notebook::_fork(const til::CoordType start)
{
if (_currentlyCreating.exchange(true))
{
co_return;
}
auto active = _activeBlock();
if (active && !active->Control().Dispatcher().HasThreadAccess())
{
co_await wil::resume_foreground(active->Control().Dispatcher());
}
_forkOnUIThread(start);
}
void Notebook::_forkOnUIThread(const til::CoordType start)
{
auto exit = wil::scope_exit([&] { _currentlyCreating.exchange(false); });
auto active = _activeBlock();
if (active)
{
active->State(BlockState::Finished);
// BAD just make it not a winrt property you donkey
active->StateChanged.raise(*active, nullptr);
auto core{ active->core };
auto* renderData{ active->renderData.get() };
auto activeControl = active->Control();
// Get how tall the viewport is with the new bottom, under lock.
renderData->LockConsole();
// First, important. Set the bottom, so it thinks it has ended. This has to be under lock
renderData->SetBottom(start - 1);
auto blockRenderViewport = renderData->GetViewport();
renderData->UnlockConsole();
const auto rows = blockRenderViewport.Height();
const auto fakePixelHeight = 16 + 16 * rows;
const auto pixels = core->ViewInPixels(blockRenderViewport.ToExclusive());
const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
const auto controlHeightDips = activeControl.ActualHeight();
const auto viewHeightDips = pixels.height() * scaleFactor;
const auto fakeHeightDips = fakePixelHeight * scaleFactor;
controlHeightDips;
viewHeightDips;
fakeHeightDips;
auto t{ WUX::ThicknessHelper::FromLengths(0 /*r.left*/,
0 /*r.top*/,
0 /*r.right*/,
-(controlHeightDips - viewHeightDips) /*r.bottom*/) };
activeControl.Margin(t);
// activeControl.Height(fakeHeightDips);
activeControl.Connection(nullptr);
}
_createNewBlock(start);
}
void Notebook::_createNewBlock(const til::CoordType start)
{
auto newBlock = winrt::make_self<implementation::NotebookBlock>();
newBlock->renderData = std::make_unique<::Microsoft::Terminal::Core::BlockRenderData>(*_terminal, start);
ControlData data{
.terminal = _terminal,
.renderData = newBlock->renderData.get(),
.connection = _connection,
};
newBlock->core = winrt::make_self<implementation::ControlCore>(_settings, _unfocusedAppearance, data);
auto interactivityOne = winrt::make_self<implementation::ControlInteractivity>(_settings, _unfocusedAppearance, newBlock->core);
newBlock->Control(winrt::make<implementation::TermControl>(*interactivityOne));
_blocks.push_back(std::move(newBlock));
// NewBlock.raise(*this, ActiveBlock());
}
}

View File

@@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "Notebook.g.h"
#include "NotebookBlock.g.h"
#include "EventArgs.h"
#include "../../renderer/base/Renderer.hpp"
#include "../../renderer/uia/UiaRenderer.hpp"
#include "../../cascadia/TerminalCore/Terminal.hpp"
#include "../../cascadia/TerminalCore/BlockRenderData.hpp"
#include "../buffer/out/search.h"
#include "ControlInteractivity.h"
#include "ControlSettings.h"
namespace winrt::Microsoft::Terminal::Control::implementation
{
struct NotebookBlock : NotebookBlockT<NotebookBlock>
{
til::property<Microsoft::Terminal::Control::TermControl> Control{ nullptr };
til::property<Microsoft::Terminal::Control::BlockState> State{ BlockState::Default };
til::typed_event<Control::NotebookBlock, Windows::Foundation::IInspectable> StateChanged;
std::unique_ptr<::Microsoft::Terminal::Core::BlockRenderData> renderData{ nullptr };
winrt::com_ptr<Microsoft::Terminal::Control::implementation::ControlCore> core{ nullptr };
};
struct Notebook : NotebookT<Notebook>
{
public:
Notebook(Control::IControlSettings settings, Control::IControlAppearance unfocusedAppearance, TerminalConnection::ITerminalConnection connection);
Windows::Foundation::Collections::IVector<Microsoft::Terminal::Control::NotebookBlock> Blocks() const;
Microsoft::Terminal::Control::NotebookBlock ActiveBlock() const;
void SendCommands(const winrt::hstring& commands);
til::typed_event<Control::Notebook, Control::NotebookBlock> NewBlock;
private:
std::shared_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
TerminalConnection::ITerminalConnection _connection{ nullptr };
Control::IControlSettings _settings{ nullptr };
Control::IControlAppearance _unfocusedAppearance{ nullptr };
// I tried this with true, but then _everything was off by one? Sorta? It was weird.
// This should probalby be false if we want to do a "fresh" notebook, or to see any output before the first prompt
bool _gotFirstMark{ false };
std::vector<winrt::com_ptr<NotebookBlock>> _blocks{};
std::atomic<bool> _currentlyCreating{ false };
std::map<til::CoordType, bool> _rowsWithMarks{};
int64_t _expectedPrompts{ 0 };
winrt::fire_and_forget _fork(const til::CoordType start);
void _forkOnUIThread(const til::CoordType start);
void _createNewBlock(const til::CoordType start);
winrt::com_ptr<NotebookBlock> _activeBlock() const;
void _handleNewPrompt(const ::ScrollMark& mark);
};
}
namespace winrt::Microsoft::Terminal::Control::factory_implementation
{
BASIC_FACTORY(Notebook);
}

View File

@@ -28,7 +28,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// to immediately perform the search with the value appearing in the box.
if (Visibility() == Visibility::Visible)
{
_SearchChangedHandlers(TextBox().Text(), _GoForward(), _CaseSensitive());
SearchChanged.raise(TextBox().Text(), _GoForward(), _CaseSensitive());
}
});
@@ -86,11 +86,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto state = CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift);
if (WI_IsFlagSet(state, CoreVirtualKeyStates::Down))
{
_SearchHandlers(TextBox().Text(), !_GoForward(), _CaseSensitive());
Search.raise(TextBox().Text(), !_GoForward(), _CaseSensitive());
}
else
{
_SearchHandlers(TextBox().Text(), _GoForward(), _CaseSensitive());
Search.raise(TextBox().Text(), _GoForward(), _CaseSensitive());
}
e.Handled(true);
}
@@ -110,7 +110,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Escape)
{
_ClosedHandlers(*this, e);
Closed.raise(*this, e);
e.Handled(true);
}
}
@@ -181,7 +181,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
// kick off search
_SearchHandlers(TextBox().Text(), _GoForward(), _CaseSensitive());
Search.raise(TextBox().Text(), _GoForward(), _CaseSensitive());
}
// Method Description:
@@ -202,7 +202,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
// kick off search
_SearchHandlers(TextBox().Text(), _GoForward(), _CaseSensitive());
Search.raise(TextBox().Text(), _GoForward(), _CaseSensitive());
}
// Method Description:
@@ -215,7 +215,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void SearchBoxControl::CloseClick(const winrt::Windows::Foundation::IInspectable& /*sender*/, const RoutedEventArgs& e)
{
_ClosedHandlers(*this, e);
Closed.raise(*this, e);
}
// Method Description:
@@ -240,7 +240,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void SearchBoxControl::TextBoxTextChanged(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
{
_SearchChangedHandlers(TextBox().Text(), _GoForward(), _CaseSensitive());
SearchChanged.raise(TextBox().Text(), _GoForward(), _CaseSensitive());
}
// Method Description:
@@ -252,7 +252,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void SearchBoxControl::CaseSensitivityButtonClicked(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
{
_SearchChangedHandlers(TextBox().Text(), _GoForward(), _CaseSensitive());
SearchChanged.raise(TextBox().Text(), _GoForward(), _CaseSensitive());
}
// Method Description:

View File

@@ -44,9 +44,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void TextBoxTextChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void CaseSensitivityButtonClicked(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
WINRT_CALLBACK(Search, SearchHandler);
WINRT_CALLBACK(SearchChanged, SearchHandler);
TYPED_EVENT(Closed, Control::SearchBoxControl, Windows::UI::Xaml::RoutedEventArgs);
til::event<SearchHandler> Search;
til::event<SearchHandler> SearchChanged;
til::typed_event<Control::SearchBoxControl, Windows::UI::Xaml::RoutedEventArgs> Closed;
private:
std::unordered_set<winrt::Windows::Foundation::IInspectable> _focusableElements;

View File

@@ -124,7 +124,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Get the cursor position in text buffer position
auto cursorArgs = winrt::make_self<CursorPositionEventArgs>();
_CurrentCursorPositionHandlers(*this, *cursorArgs);
CurrentCursorPosition.raise(*this, *cursorArgs);
const til::point cursorPos{ til::math::flooring, cursorArgs->CurrentPosition() };
const auto actualCanvasWidth{ Canvas().ActualWidth() };
@@ -159,7 +159,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// Get Font Info as we use this is the pixel size for characters in the display
auto fontArgs = winrt::make_self<FontInfoEventArgs>();
_CurrentFontInfoHandlers(*this, *fontArgs);
CurrentFontInfo.raise(*this, *fontArgs);
const til::size fontSize{ til::math::flooring, fontArgs->FontSize() };
@@ -408,7 +408,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return;
}
_CompositionCompletedHandlers(text);
CompositionCompleted.raise(text);
_activeTextStart = _inputBuffer.size();

View File

@@ -43,9 +43,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void Close();
// -------------------------------- WinRT Events ---------------------------------
TYPED_EVENT(CurrentCursorPosition, Control::TSFInputControl, Control::CursorPositionEventArgs);
TYPED_EVENT(CurrentFontInfo, Control::TSFInputControl, Control::FontInfoEventArgs);
WINRT_CALLBACK(CompositionCompleted, Control::CompositionCompletedEventArgs);
til::typed_event<Control::TSFInputControl, Control::CursorPositionEventArgs> CurrentCursorPosition;
til::typed_event<Control::TSFInputControl, Control::FontInfoEventArgs> CurrentFontInfo;
til::event<Control::CompositionCompletedEventArgs> CompositionCompleted;
private:
void _layoutRequestedHandler(winrt::Windows::UI::Text::Core::CoreTextEditContext sender, const winrt::Windows::UI::Text::Core::CoreTextLayoutRequestedEventArgs& args);

Some files were not shown because too many files have changed in this diff Show More