mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-20 13:57:43 +00:00
Compare commits
116 Commits
dev/cazamo
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c04f089953 | ||
|
|
310fa770d6 | ||
|
|
2649256931 | ||
|
|
842e70743f | ||
|
|
0980e47187 | ||
|
|
d88b426059 | ||
|
|
7fc9f9e189 | ||
|
|
3b02296c64 | ||
|
|
0672af9f15 | ||
|
|
0a30739670 | ||
|
|
754b5c0ae1 | ||
|
|
6f30689fbf | ||
|
|
915fa3f6db | ||
|
|
4b11bacea8 | ||
|
|
a0eb76322c | ||
|
|
e77bfa4392 | ||
|
|
0bb66c8880 | ||
|
|
58be7a46f7 | ||
|
|
4153896df5 | ||
|
|
73933910e2 | ||
|
|
cd2f1ab48f | ||
|
|
9d4e2f4b20 | ||
|
|
1010fd81ce | ||
|
|
41a443ab38 | ||
|
|
62fb815842 | ||
|
|
68e6608110 | ||
|
|
a88cf47994 | ||
|
|
8a22d3529f | ||
|
|
297018dd08 | ||
|
|
35f4bf2de2 | ||
|
|
176d546f2c | ||
|
|
5e49cb37e9 | ||
|
|
14675bb4f6 | ||
|
|
352aab12dc | ||
|
|
31b8f938ed | ||
|
|
cc6739520a | ||
|
|
7ba80e6ccb | ||
|
|
e866f3d28b | ||
|
|
199446e5e5 | ||
|
|
d3ba2fc3f5 | ||
|
|
36278a9199 | ||
|
|
059467d4ba | ||
|
|
51ec42661f | ||
|
|
ae356758b6 | ||
|
|
5343d560b0 | ||
|
|
978fd6e2ba | ||
|
|
35651bc92c | ||
|
|
a3fbc64384 | ||
|
|
b6254f8294 | ||
|
|
3f17a38db7 | ||
|
|
fc9e871794 | ||
|
|
fe57d5ca73 | ||
|
|
a9d6b30baf | ||
|
|
26b287c4ca | ||
|
|
9fff54faef | ||
|
|
0102ce9ac2 | ||
|
|
4d47cd5866 | ||
|
|
0a11643f1d | ||
|
|
17075d6744 | ||
|
|
25a8851986 | ||
|
|
de5f7af25d | ||
|
|
092b3558f3 | ||
|
|
c2446334e6 | ||
|
|
3982358188 | ||
|
|
0d528f84f2 | ||
|
|
6bc711de06 | ||
|
|
f622d80004 | ||
|
|
4cec7e9b4b | ||
|
|
cf920e7d58 | ||
|
|
389ba20a98 | ||
|
|
dd8606ff9b | ||
|
|
7bc1457d42 | ||
|
|
e9e04d4e70 | ||
|
|
58e8f3c11c | ||
|
|
8df9523a77 | ||
|
|
fd0640997d | ||
|
|
fb74fc8c6a | ||
|
|
5f4087ff00 | ||
|
|
81889a685c | ||
|
|
e82c627ebe | ||
|
|
d726165330 | ||
|
|
57e1f26d14 | ||
|
|
b49997b4b4 | ||
|
|
2086e0f3af | ||
|
|
6107c3e551 | ||
|
|
46469aa5e3 | ||
|
|
c869b47e13 | ||
|
|
9531069538 | ||
|
|
521e301541 | ||
|
|
842326daa5 | ||
|
|
fb7c80938b | ||
|
|
29d0d57656 | ||
|
|
cbd61b0a7d | ||
|
|
1cc9835454 | ||
|
|
86914bdfc1 | ||
|
|
e0b003ad4d | ||
|
|
f89368c19b | ||
|
|
5582e1bcc8 | ||
|
|
a23c1a24dc | ||
|
|
5f9add4000 | ||
|
|
11126f9b37 | ||
|
|
e31202b0b8 | ||
|
|
e6dc314c17 | ||
|
|
2d4030683a | ||
|
|
262d95aae5 | ||
|
|
63ba8e19fd | ||
|
|
1b39db7ab0 | ||
|
|
2dd8f409b2 | ||
|
|
049c043279 | ||
|
|
a1da6c117e | ||
|
|
7c9ffb0e02 | ||
|
|
84df8197d4 | ||
|
|
5b3aa54b56 | ||
|
|
ef6bb8a73c | ||
|
|
4e144425f0 | ||
|
|
f353323a23 |
34
Scratch.sln
34
Scratch.sln
@@ -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
6492
oss/md4c/md4c.c
Normal file
File diff suppressed because it is too large
Load Diff
407
oss/md4c/md4c.h
Normal file
407
oss/md4c/md4c.h
Normal 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.
|
||||
* (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. Ӓ
|
||||
* (c) Hexadecimal entity, e.g. ካ
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 
|
||||
*
|
||||
* The image alt text is propagated as a normal text via the MD_PARSER::text()
|
||||
* callback. However, the image title ('foo " 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]: """ (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 */
|
||||
78
scratch/ScratchIslandApp/SampleApp/CodeBlock.cpp
Normal file
78
scratch/ScratchIslandApp/SampleApp/CodeBlock.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
47
scratch/ScratchIslandApp/SampleApp/CodeBlock.h
Normal file
47
scratch/ScratchIslandApp/SampleApp/CodeBlock.h
Normal 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);
|
||||
}
|
||||
22
scratch/ScratchIslandApp/SampleApp/CodeBlock.idl
Normal file
22
scratch/ScratchIslandApp/SampleApp/CodeBlock.idl
Normal 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;
|
||||
};
|
||||
|
||||
}
|
||||
163
scratch/ScratchIslandApp/SampleApp/CodeBlock.xaml
Normal file
163
scratch/ScratchIslandApp/SampleApp/CodeBlock.xaml
Normal 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=""
|
||||
Visibility="Collapsed" />
|
||||
<FontIcon x:Name="ButtonOutlineIcon"
|
||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
Foreground="{ThemeResource PlayButtonNormalColor}"
|
||||
Glyph="" />
|
||||
<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="" />
|
||||
<Setter Target="ButtonOutlineIcon.Glyph" Value="" />
|
||||
<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="" />
|
||||
<Setter Target="ButtonOutlineIcon.Glyph" Value="" />
|
||||
<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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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="" />
|
||||
</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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
21
scratch/ScratchIslandApp/SampleApp/formatting-test.md
Normal file
21
scratch/ScratchIslandApp/SampleApp/formatting-test.md
Normal 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
|
||||
@@ -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>
|
||||
|
||||
61
scratch/ScratchIslandApp/SampleApp/simple-test.md
Normal file
61
scratch/ScratchIslandApp/SampleApp/simple-test.md
Normal 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
|
||||
```
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
56
src/cascadia/TerminalApp/IPaneContent.idl
Normal file
56
src/cascadia/TerminalApp/IPaneContent.idl
Normal 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; };
|
||||
};
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
6
src/cascadia/TerminalApp/PaneArgs.cpp
Normal file
6
src/cascadia/TerminalApp/PaneArgs.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "PaneArgs.h"
|
||||
#include "BellEventArgs.g.cpp"
|
||||
18
src/cascadia/TerminalApp/PaneArgs.h
Normal file
18
src/cascadia/TerminalApp/PaneArgs.h
Normal 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;
|
||||
};
|
||||
};
|
||||
68
src/cascadia/TerminalApp/ScratchpadContent.cpp
Normal file
68
src/cascadia/TerminalApp/ScratchpadContent.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
43
src/cascadia/TerminalApp/ScratchpadContent.h
Normal file
43
src/cascadia/TerminalApp/ScratchpadContent.h
Normal 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 };
|
||||
};
|
||||
}
|
||||
86
src/cascadia/TerminalApp/SettingsPaneContent.cpp
Normal file
86
src/cascadia/TerminalApp/SettingsPaneContent.cpp
Normal 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>();
|
||||
}
|
||||
}
|
||||
50
src/cascadia/TerminalApp/SettingsPaneContent.h
Normal file
50
src/cascadia/TerminalApp/SettingsPaneContent.h
Normal 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);
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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" });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
355
src/cascadia/TerminalApp/TerminalPaneContent.cpp
Normal file
355
src/cascadia/TerminalApp/TerminalPaneContent.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
97
src/cascadia/TerminalApp/TerminalPaneContent.h
Normal file
97
src/cascadia/TerminalApp/TerminalPaneContent.h
Normal 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*/);
|
||||
};
|
||||
}
|
||||
30
src/cascadia/TerminalApp/TerminalPaneContent.idl
Normal file
30
src/cascadia/TerminalApp/TerminalPaneContent.idl
Normal 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);
|
||||
}
|
||||
}
|
||||
57
src/cascadia/TerminalApp/TerminalSettingsCache.cpp
Normal file
57
src/cascadia/TerminalApp/TerminalSettingsCache.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
37
src/cascadia/TerminalApp/TerminalSettingsCache.h
Normal file
37
src/cascadia/TerminalApp/TerminalSettingsCache.h
Normal 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);
|
||||
}
|
||||
12
src/cascadia/TerminalApp/TerminalSettingsCache.idl
Normal file
12
src/cascadia/TerminalApp/TerminalSettingsCache.idl
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
<ClInclude Include="../TabRowControl.h" />
|
||||
<ClInclude Include="../App.h" />
|
||||
<ClInclude Include="../TerminalTab.h" />
|
||||
<ClInclude Include="../SettingsTab.h" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -37,5 +37,6 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalConnectionProvider);
|
||||
#include <telemetry/ProjectTelemetry.h>
|
||||
|
||||
#include "til.h"
|
||||
#include <til/winrt.h>
|
||||
|
||||
#include <cppwinrt_utils.h>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
178
src/cascadia/TerminalControl/Notebook.cpp
Normal file
178
src/cascadia/TerminalControl/Notebook.cpp
Normal 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());
|
||||
}
|
||||
|
||||
}
|
||||
69
src/cascadia/TerminalControl/Notebook.h
Normal file
69
src/cascadia/TerminalControl/Notebook.h
Normal 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);
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user