Merge remote-tracking branch 'origin/main' into dev/migrie/oop/ragnarok
This commit is contained in:
commit
1413d0145a
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -3,6 +3,8 @@
|
|||
###############################################################################
|
||||
* -text
|
||||
|
||||
*.inc linguist-language=cpp
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
|
|
1
.github/actions/spelling/allow/apis.txt
vendored
1
.github/actions/spelling/allow/apis.txt
vendored
|
@ -25,6 +25,7 @@ DERR
|
|||
dlldata
|
||||
DONTADDTORECENT
|
||||
DWORDLONG
|
||||
enumset
|
||||
environstrings
|
||||
EXPCMDFLAGS
|
||||
EXPCMDSTATE
|
||||
|
|
8
.github/actions/spelling/allow/math.txt
vendored
8
.github/actions/spelling/allow/math.txt
vendored
|
@ -1,3 +1,11 @@
|
|||
atan
|
||||
CPrime
|
||||
HBar
|
||||
HPrime
|
||||
isnan
|
||||
LPrime
|
||||
LStep
|
||||
powf
|
||||
RSub
|
||||
sqrtf
|
||||
ULP
|
||||
|
|
5
.github/actions/spelling/allow/microsoft.txt
vendored
5
.github/actions/spelling/allow/microsoft.txt
vendored
|
@ -1,5 +1,6 @@
|
|||
ACLs
|
||||
ADMINS
|
||||
advapi
|
||||
altform
|
||||
altforms
|
||||
appendwttlogging
|
||||
|
@ -15,6 +16,7 @@ CPLs
|
|||
cpptools
|
||||
cppvsdbg
|
||||
CPRs
|
||||
cryptbase
|
||||
DACL
|
||||
DACLs
|
||||
diffs
|
||||
|
@ -24,7 +26,9 @@ DTDs
|
|||
DWINRT
|
||||
enablewttlogging
|
||||
Intelli
|
||||
IVisual
|
||||
LKG
|
||||
LOCKFILE
|
||||
Lxss
|
||||
mfcribbon
|
||||
microsoft
|
||||
|
@ -44,6 +48,7 @@ powershell
|
|||
propkey
|
||||
pscustomobject
|
||||
QWORD
|
||||
regedit
|
||||
robocopy
|
||||
SACLs
|
||||
sdkddkver
|
||||
|
|
11
.github/actions/spelling/expect/expect.txt
vendored
11
.github/actions/spelling/expect/expect.txt
vendored
|
@ -189,13 +189,12 @@ cacafire
|
|||
callee
|
||||
capslock
|
||||
CARETBLINKINGENABLED
|
||||
carlos
|
||||
CARRIAGERETURN
|
||||
cascadia
|
||||
cassert
|
||||
castsi
|
||||
catid
|
||||
carlos
|
||||
zamora
|
||||
cazamor
|
||||
CBash
|
||||
cbegin
|
||||
|
@ -669,6 +668,7 @@ dwriteglyphrundescriptionclustermap
|
|||
dxgi
|
||||
dxgidwm
|
||||
dxinterop
|
||||
dxsm
|
||||
dxttbmp
|
||||
eachother
|
||||
eae
|
||||
|
@ -1232,6 +1232,7 @@ KLF
|
|||
KLMNO
|
||||
KLMNOPQRST
|
||||
KLMNOPQRSTQQQQQ
|
||||
KPRIORITY
|
||||
KVM
|
||||
langid
|
||||
LANGUAGELIST
|
||||
|
@ -1642,6 +1643,7 @@ onecoreuapuuid
|
|||
onecoreuuid
|
||||
ONECOREWINDOWS
|
||||
onehalf
|
||||
oneseq
|
||||
ONLCR
|
||||
openbash
|
||||
opencode
|
||||
|
@ -1708,6 +1710,7 @@ pcch
|
|||
PCCHAR
|
||||
PCCONSOLE
|
||||
PCD
|
||||
pcg
|
||||
pch
|
||||
PCHAR
|
||||
PCIDLIST
|
||||
|
@ -1803,6 +1806,7 @@ POSX
|
|||
POSXSCROLL
|
||||
POSYSCROLL
|
||||
ppci
|
||||
PPEB
|
||||
ppf
|
||||
ppguid
|
||||
ppidl
|
||||
|
@ -2022,6 +2026,7 @@ Rike
|
|||
RIPMSG
|
||||
RIS
|
||||
RMENU
|
||||
rng
|
||||
roadmap
|
||||
robomac
|
||||
roundtrip
|
||||
|
@ -2724,6 +2729,7 @@ wixproj
|
|||
wline
|
||||
wlinestream
|
||||
wmain
|
||||
wmemory
|
||||
WMSZ
|
||||
wnd
|
||||
WNDALLOC
|
||||
|
@ -2850,6 +2856,7 @@ YSize
|
|||
YSubstantial
|
||||
YVIRTUALSCREEN
|
||||
YWalk
|
||||
zamora
|
||||
ZCmd
|
||||
ZCtrl
|
||||
zsh
|
||||
|
|
2
.github/actions/spelling/expect/web.txt
vendored
2
.github/actions/spelling/expect/web.txt
vendored
|
@ -1,5 +1,7 @@
|
|||
http
|
||||
www
|
||||
easyrgb
|
||||
php
|
||||
ecma
|
||||
rapidtables
|
||||
WCAG
|
||||
|
|
|
@ -24,3 +24,4 @@ VERIFY_ARE_EQUAL\(L"[^"]+"
|
|||
std::memory_order_[\w]+
|
||||
D2DERR_SHADER_COMPILE_FAILED
|
||||
TIL_FEATURE_[0-9A-Z_]+
|
||||
vcvars\w*
|
||||
|
|
67
NOTICE.md
67
NOTICE.md
|
@ -117,7 +117,6 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
```
|
||||
|
||||
## dynamic_bitset
|
||||
|
@ -148,7 +147,6 @@ 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.
|
||||
|
||||
```
|
||||
|
||||
## \{fmt\}
|
||||
|
@ -215,7 +213,6 @@ 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.
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
@ -249,7 +246,71 @@ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
```
|
||||
|
||||
## PCG Random Number Generation
|
||||
|
||||
**Source**: [https://github.com/imneme/pcg-cpp](https://github.com/imneme/pcg-cpp)
|
||||
|
||||
### License
|
||||
|
||||
```
|
||||
Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
|
||||
|
||||
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.
|
||||
```
|
||||
|
||||
## ConEmu
|
||||
**Source**: [https://github.com/Maximus5/ConEmu](https://github.com/Maximus5/ConEmu)
|
||||
|
||||
### License
|
||||
|
||||
```
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2009-2017, Maximus5 <ConEmu.Maximus5@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
```
|
||||
|
||||
# Microsoft Open Source
|
||||
|
|
|
@ -15,7 +15,7 @@ Import-Module .\tools\OpenConsole.psm1
|
|||
Set-MsBuildDevEnvironment
|
||||
Get-Format
|
||||
```
|
||||
After, go to Tools > Options > Text Editor > C++ > Formatting and checking "Use custom clang-format.exe file" in Visual Studio and choose the clang-format.exe in the repository at /packages/clang-format.win-x86.10.0.0/tools/clang-format.exe by clicking "browse" right under the check box.
|
||||
After, go to Tools > Options > Text Editor > C++ > Formatting and check "Use custom clang-format.exe file" in Visual Studio and choose the clang-format.exe in the repository at /packages/clang-format.win-x86.10.0.0/tools/clang-format.exe by clicking "browse" right under the check box.
|
||||
|
||||
### Building in PowerShell
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
201
oss/pcg/LICENSE-APACHE.txt
Normal file
201
oss/pcg/LICENSE-APACHE.txt
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
19
oss/pcg/LICENSE-MIT.txt
Normal file
19
oss/pcg/LICENSE-MIT.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
|
||||
|
||||
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.
|
14
oss/pcg/cgmanifest.json
Normal file
14
oss/pcg/cgmanifest.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"Registrations": [
|
||||
{
|
||||
"component": {
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/imneme/pcg-cpp",
|
||||
"commitHash": "ffd522e7188bef30a00c74dc7eb9de5faff90092"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Version": 1
|
||||
}
|
82
oss/pcg/include/pcg_random.hpp
Normal file
82
oss/pcg/include/pcg_random.hpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
// PCG Random Number Generation for C++
|
||||
//
|
||||
// Copyright 2014-2019 Melissa O'Neill <oneill@pcg-random.org>,
|
||||
// and the PCG Project contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (provided in
|
||||
// LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)
|
||||
// or under the MIT license (provided in LICENSE-MIT.txt and at
|
||||
// http://opensource.org/licenses/MIT), at your option. This file may not
|
||||
// be copied, modified, or distributed except according to those terms.
|
||||
//
|
||||
// Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either
|
||||
// express or implied. See your chosen license for details.
|
||||
//
|
||||
// For additional information about the PCG random number generation scheme,
|
||||
// visit http://www.pcg-random.org/.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Leonard Hecker <lhecker@microsoft.com>:
|
||||
// The following contents are an extract of pcg_engines::oneseq_dxsm_64_32
|
||||
// reduced down to the bare essentials, while retaining base functionality.
|
||||
|
||||
namespace pcg_engines {
|
||||
class oneseq_dxsm_64_32 {
|
||||
using xtype = uint32_t;
|
||||
using itype = uint64_t;
|
||||
|
||||
itype state_;
|
||||
|
||||
static constexpr uint64_t multiplier() {
|
||||
return 6364136223846793005ULL;
|
||||
}
|
||||
|
||||
static constexpr uint64_t increment() {
|
||||
return 1442695040888963407ULL;
|
||||
}
|
||||
|
||||
static itype bump(itype state) {
|
||||
return state * multiplier() + increment();
|
||||
}
|
||||
|
||||
itype base_generate0() {
|
||||
itype old_state = state_;
|
||||
state_ = bump(state_);
|
||||
return old_state;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit oneseq_dxsm_64_32(itype state = 0xcafef00dd15ea5e5ULL) : state_(bump(state + increment())) {
|
||||
}
|
||||
|
||||
// Returns a value in the interval [0, UINT32_MAX].
|
||||
xtype operator()() {
|
||||
constexpr auto xtypebits = uint8_t(sizeof(xtype) * 8);
|
||||
constexpr auto itypebits = uint8_t(sizeof(itype) * 8);
|
||||
|
||||
auto internal = base_generate0();
|
||||
auto hi = xtype(internal >> (itypebits - xtypebits));
|
||||
auto lo = xtype(internal);
|
||||
|
||||
lo |= 1;
|
||||
hi ^= hi >> (xtypebits / 2);
|
||||
hi *= xtype(multiplier());
|
||||
hi ^= hi >> (3 * (xtypebits / 4));
|
||||
hi *= lo;
|
||||
return hi;
|
||||
}
|
||||
|
||||
// Returns a value in the interval [0, upper_bound).
|
||||
xtype operator()(xtype upper_bound) {
|
||||
uint32_t threshold = (UINT64_MAX + uint32_t(1) - upper_bound) % upper_bound;
|
||||
for (;;) {
|
||||
auto r = operator()();
|
||||
if (r >= threshold)
|
||||
return r % upper_bound;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
<EventProvider Id="EventProvider_TerminalWin32Host" Name="56c06166-2e2e-5f4d-7ff3-74f4b78c87d6" />
|
||||
<EventProvider Id="EventProvider_TerminalRemoting" Name="d6f04aad-629f-539a-77c1-73f5c3e4aa7b" />
|
||||
<EventProvider Id="EventProvider_TerminalDirectX" Name="c93e739e-ae50-5a14-78e7-f171e947535d" />
|
||||
<EventProvider Id="EventProvider_TerminalUIA" Name="e7ebce59-2161-572d-b263-2f16a6afb9e5"/>
|
||||
<Profile Id="Terminal.Verbose.File" Name="Terminal" Description="Terminal" LoggingMode="File" DetailLevel="Verbose">
|
||||
<Collectors>
|
||||
<EventCollectorId Value="EventCollector_Terminal">
|
||||
|
@ -23,6 +24,7 @@
|
|||
<EventProviderId Value="EventProvider_TerminalWin32Host" />
|
||||
<EventProviderId Value="EventProvider_TerminalRemoting" />
|
||||
<EventProviderId Value="EventProvider_TerminalDirectX" />
|
||||
<EventProviderId Value="EventProvider_TerminalUIA" />
|
||||
</EventProviders>
|
||||
</EventCollectorId>
|
||||
</Collectors>
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "precomp.h"
|
||||
#include "TextColor.h"
|
||||
|
||||
#include <til/bit.h>
|
||||
|
||||
// clang-format off
|
||||
|
||||
// A table mapping 8-bit RGB colors, in the form RRRGGGBB,
|
||||
|
@ -186,7 +188,7 @@ COLORREF TextColor::GetColor(const std::array<COLORREF, 256>& colorTable, const
|
|||
// the result will be something like 0b00100000.
|
||||
// 5. Use BitScanForward (bsf) to find the index of the most significant 1 bit.
|
||||
const auto haystack = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(colorTable.data())); // 1.
|
||||
const auto needle = _mm256_set1_epi32(__builtin_bit_cast(int, defaultColor)); // 2.
|
||||
const auto needle = _mm256_set1_epi32(til::bit_cast<int>(defaultColor)); // 2.
|
||||
const auto result = _mm256_cmpeq_epi32(haystack, needle); // 3.
|
||||
const auto mask = _mm256_movemask_ps(_mm256_castsi256_ps(result)); // 4.
|
||||
unsigned long index;
|
||||
|
@ -203,7 +205,7 @@ COLORREF TextColor::GetColor(const std::array<COLORREF, 256>& colorTable, const
|
|||
// --> the index returned by _BitScanForward must be divided by 2.
|
||||
const auto haystack1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(colorTable.data() + 0));
|
||||
const auto haystack2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(colorTable.data() + 4));
|
||||
const auto needle = _mm_set1_epi32(__builtin_bit_cast(int, defaultColor));
|
||||
const auto needle = _mm_set1_epi32(til::bit_cast<int>(defaultColor));
|
||||
const auto result1 = _mm_cmpeq_epi32(haystack1, needle);
|
||||
const auto result2 = _mm_cmpeq_epi32(haystack2, needle);
|
||||
const auto result = _mm_packs_epi32(result1, result2); // 3.5
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
Enabled="false"
|
||||
DisplayName="ms-resource:AppName" />
|
||||
</uap5:Extension>
|
||||
<!-- <uap3:Extension Category="windows.appExtension">
|
||||
<uap3:Extension Category="windows.appExtension">
|
||||
<uap3:AppExtension Name="com.microsoft.windows.console.host"
|
||||
Id="OpenConsole"
|
||||
DisplayName="OpenConsole"
|
||||
|
@ -102,15 +102,15 @@
|
|||
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
</com:ComInterface>
|
||||
</com:Extension> -->
|
||||
</com:Extension>
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<!-- <com:ExeServer DisplayName="OpenConsole" Executable="OpenConsole.exe">
|
||||
<com:ExeServer DisplayName="OpenConsole" Executable="OpenConsole.exe">
|
||||
<com:Class Id="2EACA947-7F5F-4CFA-BA87-8F7FBEEFBE69"/>
|
||||
</com:ExeServer>
|
||||
<com:ExeServer DisplayName="WindowsTerminal" Executable="WindowsTerminal.exe">
|
||||
<com:Class Id="E12CFF52-A866-4C77-9A90-F570A7AA2C6B"/>
|
||||
</com:ExeServer> -->
|
||||
</com:ExeServer>
|
||||
<com:SurrogateServer DisplayName="WindowsTerminalShellExt">
|
||||
<com:Class Id="9f156763-7844-4dc4-b2b1-901f640f5155" Path="WindowsTerminalShellExt.dll" ThreadingModel="STA"/>
|
||||
</com:SurrogateServer>
|
||||
|
|
|
@ -465,6 +465,10 @@ namespace SettingsModelLocalTests
|
|||
"name":"action7_startingDirectoryWithTrailingSlash",
|
||||
"command": { "action": "newWindow", "startingDirectory":"C:\\", "commandline": "bar.exe" }
|
||||
},
|
||||
{
|
||||
"name":"action8_tabTitleEscaping",
|
||||
"command": { "action": "newWindow", "tabTitle":"\\\";foo\\" }
|
||||
}
|
||||
])" };
|
||||
|
||||
const auto commands0Json = VerifyParseSucceeded(commands0String);
|
||||
|
@ -473,7 +477,7 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_EQUAL(0u, commands.Size());
|
||||
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
|
||||
VERIFY_ARE_EQUAL(0u, warnings.size());
|
||||
VERIFY_ARE_EQUAL(8u, commands.Size());
|
||||
VERIFY_ARE_EQUAL(9u, commands.Size());
|
||||
|
||||
{
|
||||
auto command = commands.Lookup(L"action0");
|
||||
|
@ -586,5 +590,20 @@ namespace SettingsModelLocalTests
|
|||
L"cmdline: \"%s\"", cmdline.c_str()));
|
||||
VERIFY_ARE_EQUAL(L"--startingDirectory \"C:\\\\\" -- \"bar.exe\"", terminalArgs.ToCommandline());
|
||||
}
|
||||
|
||||
{
|
||||
auto command = commands.Lookup(L"action8_tabTitleEscaping");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::NewWindow, command.ActionAndArgs().Action());
|
||||
const auto& realArgs = command.ActionAndArgs().Args().try_as<NewWindowArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
const auto& terminalArgs = realArgs.TerminalArgs();
|
||||
VERIFY_IS_NOT_NULL(terminalArgs);
|
||||
auto cmdline = terminalArgs.ToCommandline();
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"cmdline: \"%s\"", cmdline.c_str()));
|
||||
VERIFY_ARE_EQUAL(LR"-(--title "\\\"\;foo\\")-", terminalArgs.ToCommandline());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1092,7 +1092,7 @@ namespace SettingsModelLocalTests
|
|||
},
|
||||
{
|
||||
"name": "profile1",
|
||||
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
|
||||
"source": "Terminal.App.UnitTest.1",
|
||||
"historySize": 2222
|
||||
},
|
||||
|
|
|
@ -272,20 +272,30 @@ namespace SettingsModelLocalTests
|
|||
void ProfileTests::DuplicateProfileTest()
|
||||
{
|
||||
static constexpr std::string_view userProfiles{ R"({
|
||||
"profiles": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"backgroundImage": "file:///some/path",
|
||||
"hidden": false,
|
||||
}
|
||||
]
|
||||
"profiles": {
|
||||
"defaults": {
|
||||
"font": {
|
||||
"size": 123
|
||||
}
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"backgroundImage": "file:///some/path",
|
||||
"hidden": false,
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto duplicatedProfile = settings->DuplicateProfile(profile);
|
||||
|
||||
// GH#11392: Ensure duplicated profiles properly inherit the base layer, even for nested objects.
|
||||
VERIFY_ARE_EQUAL(123, duplicatedProfile.FontInfo().FontSize());
|
||||
|
||||
duplicatedProfile.Guid(profile.Guid());
|
||||
duplicatedProfile.Name(profile.Name());
|
||||
|
||||
|
@ -300,6 +310,17 @@ namespace SettingsModelLocalTests
|
|||
// the GUID generated for a dynamic profile (with a source) is different
|
||||
// than that of a profile without a source.
|
||||
|
||||
static constexpr std::string_view inboxSettings{ R"({
|
||||
"profiles": [
|
||||
{
|
||||
"name" : "profile0",
|
||||
"source": "Terminal.App.UnitTest.0"
|
||||
},
|
||||
{
|
||||
"name" : "profile1"
|
||||
}
|
||||
]
|
||||
})" };
|
||||
static constexpr std::string_view userSettings{ R"({
|
||||
"profiles": [
|
||||
{
|
||||
|
@ -312,9 +333,9 @@ namespace SettingsModelLocalTests
|
|||
]
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userSettings, DefaultJson);
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userSettings, inboxSettings);
|
||||
|
||||
VERIFY_ARE_EQUAL(4u, settings->AllProfiles().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings->AllProfiles().Size());
|
||||
|
||||
VERIFY_ARE_EQUAL(L"profile0", settings->AllProfiles().GetAt(0).Name());
|
||||
VERIFY_IS_TRUE(settings->AllProfiles().GetAt(0).HasGuid());
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace SettingsModelLocalTests
|
|||
// Return Value:
|
||||
// - the JsonObject representing this instance
|
||||
template<typename T>
|
||||
void RoundtripTest(const std::string& jsonString)
|
||||
void RoundtripTest(const std::string_view& jsonString)
|
||||
{
|
||||
const auto json{ VerifyParseSucceeded(jsonString) };
|
||||
const auto settings{ T::FromJson(json) };
|
||||
|
@ -69,7 +69,7 @@ namespace SettingsModelLocalTests
|
|||
|
||||
void SerializationTests::GlobalSettings()
|
||||
{
|
||||
const std::string globalsString{ R"(
|
||||
static constexpr std::string_view globalsString{ R"(
|
||||
{
|
||||
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
|
||||
|
||||
|
@ -105,7 +105,7 @@ namespace SettingsModelLocalTests
|
|||
"actions": []
|
||||
})" };
|
||||
|
||||
const std::string smallGlobalsString{ R"(
|
||||
static constexpr std::string_view smallGlobalsString{ R"(
|
||||
{
|
||||
"defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
|
||||
"actions": []
|
||||
|
@ -117,7 +117,7 @@ namespace SettingsModelLocalTests
|
|||
|
||||
void SerializationTests::Profile()
|
||||
{
|
||||
const std::string profileString{ R"(
|
||||
static constexpr std::string_view profileString{ R"(
|
||||
{
|
||||
"name": "Windows PowerShell",
|
||||
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
|
||||
|
@ -152,7 +152,7 @@ namespace SettingsModelLocalTests
|
|||
"selectionBackground": "#CCAABB",
|
||||
|
||||
"useAcrylic": false,
|
||||
"acrylicOpacity": 0.5,
|
||||
"opacity": 50,
|
||||
|
||||
"backgroundImage": "made_you_look.jpeg",
|
||||
"backgroundImageStretchMode": "uniformToFill",
|
||||
|
@ -167,7 +167,7 @@ namespace SettingsModelLocalTests
|
|||
"experimental.retroTerminalEffect": false
|
||||
})" };
|
||||
|
||||
const std::string smallProfileString{ R"(
|
||||
static constexpr std::string_view smallProfileString{ R"(
|
||||
{
|
||||
"name": "Custom Profile"
|
||||
})" };
|
||||
|
@ -175,7 +175,7 @@ namespace SettingsModelLocalTests
|
|||
// Setting "tabColor" to null tests two things:
|
||||
// - null should count as an explicit user-set value, not falling back to the parent's value
|
||||
// - null should be acceptable even though we're working with colors
|
||||
const std::string weirdProfileString{ R"(
|
||||
static constexpr std::string_view weirdProfileString{ R"(
|
||||
{
|
||||
"guid" : "{8b039d4d-77ca-5a83-88e1-dfc8e895a127}",
|
||||
"name": "Weird Profile",
|
||||
|
@ -192,7 +192,7 @@ namespace SettingsModelLocalTests
|
|||
|
||||
void SerializationTests::ColorScheme()
|
||||
{
|
||||
const std::string schemeString{ R"({
|
||||
static constexpr std::string_view schemeString{ R"({
|
||||
"name": "Campbell",
|
||||
|
||||
"cursorColor": "#FFFFFF",
|
||||
|
@ -225,56 +225,56 @@ namespace SettingsModelLocalTests
|
|||
void SerializationTests::Actions()
|
||||
{
|
||||
// simple command
|
||||
const std::string actionsString1{ R"([
|
||||
static constexpr std::string_view actionsString1{ R"([
|
||||
{ "command": "paste" }
|
||||
])" };
|
||||
|
||||
// complex command
|
||||
const std::string actionsString2A{ R"([
|
||||
static constexpr std::string_view actionsString2A{ R"([
|
||||
{ "command": { "action": "setTabColor" } }
|
||||
])" };
|
||||
const std::string actionsString2B{ R"([
|
||||
static constexpr std::string_view actionsString2B{ R"([
|
||||
{ "command": { "action": "setTabColor", "color": "#112233" } }
|
||||
])" };
|
||||
const std::string actionsString2C{ R"([
|
||||
static constexpr std::string_view actionsString2C{ R"([
|
||||
{ "command": { "action": "copy" } },
|
||||
{ "command": { "action": "copy", "singleLine": true, "copyFormatting": "html" } }
|
||||
])" };
|
||||
|
||||
// simple command with key chords
|
||||
const std::string actionsString3{ R"([
|
||||
static constexpr std::string_view actionsString3{ R"([
|
||||
{ "command": "toggleAlwaysOnTop", "keys": "ctrl+a" },
|
||||
{ "command": "toggleAlwaysOnTop", "keys": "ctrl+b" }
|
||||
])" };
|
||||
|
||||
// complex command with key chords
|
||||
const std::string actionsString4A{ R"([
|
||||
static constexpr std::string_view actionsString4A{ R"([
|
||||
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+c" },
|
||||
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+d" }
|
||||
])" };
|
||||
const std::string actionsString4B{ R"([
|
||||
static constexpr std::string_view actionsString4B{ R"([
|
||||
{ "command": { "action": "findMatch", "direction": "next" }, "keys": "ctrl+shift+s" },
|
||||
{ "command": { "action": "findMatch", "direction": "prev" }, "keys": "ctrl+shift+r" }
|
||||
])" };
|
||||
|
||||
// command with name and icon and multiple key chords
|
||||
const std::string actionsString5{ R"([
|
||||
static constexpr std::string_view actionsString5{ R"([
|
||||
{ "icon": "image.png", "name": "Scroll To Top Name", "command": "scrollToTop", "keys": "ctrl+e" },
|
||||
{ "command": "scrollToTop", "keys": "ctrl+f" }
|
||||
])" };
|
||||
|
||||
// complex command with new terminal args
|
||||
const std::string actionsString6{ R"([
|
||||
static constexpr std::string_view actionsString6{ R"([
|
||||
{ "command": { "action": "newTab", "index": 0 }, "keys": "ctrl+g" },
|
||||
])" };
|
||||
|
||||
// complex command with meaningful null arg
|
||||
const std::string actionsString7{ R"([
|
||||
static constexpr std::string_view actionsString7{ R"([
|
||||
{ "command": { "action": "renameWindow", "name": null }, "keys": "ctrl+h" }
|
||||
])" };
|
||||
|
||||
// nested command
|
||||
const std::string actionsString8{ R"([
|
||||
static constexpr std::string_view actionsString8{ R"([
|
||||
{
|
||||
"name": "Change font size...",
|
||||
"commands": [
|
||||
|
@ -286,7 +286,7 @@ namespace SettingsModelLocalTests
|
|||
])" };
|
||||
|
||||
// iterable command
|
||||
const std::string actionsString9A{ R"([
|
||||
static constexpr std::string_view actionsString9A{ R"([
|
||||
{
|
||||
"name": "New tab",
|
||||
"commands": [
|
||||
|
@ -299,7 +299,7 @@ namespace SettingsModelLocalTests
|
|||
]
|
||||
}
|
||||
])" };
|
||||
const std::string actionsString9B{ R"([
|
||||
static constexpr std::string_view actionsString9B{ R"([
|
||||
{
|
||||
"commands":
|
||||
[
|
||||
|
@ -315,7 +315,7 @@ namespace SettingsModelLocalTests
|
|||
"name": "Send Input ..."
|
||||
}
|
||||
])" };
|
||||
const std::string actionsString9C{ R""([
|
||||
static constexpr std::string_view actionsString9C{ R""([
|
||||
{
|
||||
"commands":
|
||||
[
|
||||
|
@ -338,7 +338,7 @@ namespace SettingsModelLocalTests
|
|||
"name": "Send Input (Evil) ..."
|
||||
}
|
||||
])"" };
|
||||
const std::string actionsString9D{ R""([
|
||||
static constexpr std::string_view actionsString9D{ R""([
|
||||
{
|
||||
"command":
|
||||
{
|
||||
|
@ -352,7 +352,7 @@ namespace SettingsModelLocalTests
|
|||
])"" };
|
||||
|
||||
// unbound command
|
||||
const std::string actionsString10{ R"([
|
||||
static constexpr std::string_view actionsString10{ R"([
|
||||
{ "command": "unbound", "keys": "ctrl+c" }
|
||||
])" };
|
||||
|
||||
|
@ -395,7 +395,7 @@ namespace SettingsModelLocalTests
|
|||
|
||||
void SerializationTests::CascadiaSettings()
|
||||
{
|
||||
const std::string settingsString{ R"({
|
||||
static constexpr std::string_view settingsString{ R"({
|
||||
"$help" : "https://aka.ms/terminal-documentation",
|
||||
"$schema" : "https://aka.ms/terminal-profiles-schema",
|
||||
"defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}",
|
||||
|
@ -465,7 +465,7 @@ namespace SettingsModelLocalTests
|
|||
|
||||
void SerializationTests::LegacyFontSettings()
|
||||
{
|
||||
const std::string profileString{ R"(
|
||||
static constexpr std::string_view profileString{ R"(
|
||||
{
|
||||
"name": "Profile with legacy font settings",
|
||||
|
||||
|
@ -474,7 +474,7 @@ namespace SettingsModelLocalTests
|
|||
"fontWeight": "normal"
|
||||
})" };
|
||||
|
||||
const std::string expectedOutput{ R"(
|
||||
static constexpr std::string_view expectedOutput{ R"(
|
||||
{
|
||||
"name": "Profile with legacy font settings",
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "pch.h"
|
||||
|
||||
#include <til/rand.h>
|
||||
|
||||
#include "../TerminalSettingsModel/CascadiaSettings.h"
|
||||
#include "../TerminalSettingsModel/TerminalSettings.h"
|
||||
#include "TestUtils.h"
|
||||
|
@ -34,14 +36,12 @@ namespace SettingsModelLocalTests
|
|||
END_TEST_CLASS()
|
||||
|
||||
TEST_METHOD(TryCreateWinRTType);
|
||||
|
||||
TEST_METHOD(TestTerminalArgsForBinding);
|
||||
|
||||
TEST_METHOD(CommandLineToArgvW);
|
||||
TEST_METHOD(GetProfileForArgsWithCommandline);
|
||||
TEST_METHOD(MakeSettingsForProfile);
|
||||
TEST_METHOD(MakeSettingsForDefaultProfileThatDoesntExist);
|
||||
|
||||
TEST_METHOD(TestLayerProfileOnColorScheme);
|
||||
|
||||
TEST_METHOD(TestCommandlineToTitlePromotion);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
|
@ -60,6 +60,139 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_ARE_NOT_EQUAL(oldFontSize, newFontSize);
|
||||
}
|
||||
|
||||
// CascadiaSettings::_normalizeCommandLine abuses some aspects from CommandLineToArgvW
|
||||
// to simplify the implementation. It assumes that all arguments returned by
|
||||
// CommandLineToArgvW are returned back to back in memory as "arg1\0arg2\0arg3\0...".
|
||||
// This test ensures CommandLineToArgvW doesn't change just to be sure.
|
||||
void TerminalSettingsTests::CommandLineToArgvW()
|
||||
{
|
||||
pcg_engines::oneseq_dxsm_64_32 rng{ til::gen_random<uint64_t>() };
|
||||
|
||||
const auto expectedArgc = static_cast<int>(rng(16) + 1);
|
||||
std::wstring expectedArgv;
|
||||
std::wstring input;
|
||||
|
||||
// We generate up to 16 arguments. Each argument is up to 64 chars long, is quoted
|
||||
// (2 chars, only applies to the input) and separated by a whitespace (1 char).
|
||||
expectedArgv.reserve(expectedArgc * 65);
|
||||
input.reserve(expectedArgc * 67);
|
||||
|
||||
for (int i = 0; i < expectedArgc; ++i)
|
||||
{
|
||||
const bool useQuotes = static_cast<bool>(rng(2));
|
||||
const auto count = static_cast<size_t>(rng(64));
|
||||
const auto ch = static_cast<wchar_t>(rng('z' - 'a' + 1) + 'a');
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
expectedArgv.push_back(L'\0');
|
||||
input.push_back(L' ');
|
||||
}
|
||||
|
||||
if (useQuotes)
|
||||
{
|
||||
input.push_back(L'"');
|
||||
}
|
||||
|
||||
expectedArgv.append(count, ch);
|
||||
input.append(count, ch);
|
||||
|
||||
if (useQuotes)
|
||||
{
|
||||
input.push_back(L'"');
|
||||
}
|
||||
}
|
||||
|
||||
int argc;
|
||||
wil::unique_hlocal_ptr<PWSTR[]> argv{ ::CommandLineToArgvW(input.c_str(), &argc) };
|
||||
VERIFY_ARE_EQUAL(expectedArgc, argc);
|
||||
VERIFY_IS_NOT_NULL(argv);
|
||||
|
||||
const auto lastArg = argv[argc - 1];
|
||||
const auto beg = argv[0];
|
||||
const auto end = lastArg + wcslen(lastArg);
|
||||
VERIFY_IS_GREATER_THAN(end, beg);
|
||||
VERIFY_ARE_EQUAL(expectedArgv.size(), static_cast<size_t>(end - beg));
|
||||
VERIFY_ARE_EQUAL(0, memcmp(beg, expectedArgv.data(), expectedArgv.size()));
|
||||
}
|
||||
|
||||
void TerminalSettingsTests::GetProfileForArgsWithCommandline()
|
||||
{
|
||||
// I'm exclusively using cmd.exe as I know exactly where it resides at.
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"defaults": {
|
||||
"historySize": 123
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"commandline": "%SystemRoot%\\System32\\cmd.exe"
|
||||
},
|
||||
{
|
||||
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
|
||||
"commandline": "cmd.exe /A"
|
||||
},
|
||||
{
|
||||
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
|
||||
"commandline": "cmd.exe /A /B"
|
||||
},
|
||||
{
|
||||
"guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
|
||||
"commandline": "cmd.exe /A /C",
|
||||
"connectionType": "{9a9977a7-1fe0-49c0-b6c0-13a0cd1c98a1}"
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
|
||||
struct TestCase
|
||||
{
|
||||
std::wstring_view input;
|
||||
int expected;
|
||||
};
|
||||
|
||||
static constexpr std::array testCases{
|
||||
// Base test.
|
||||
TestCase{ L"cmd.exe", 0 },
|
||||
// SearchPathW() normalization + case insensitive matching.
|
||||
TestCase{ L"cmd.exe /a", 1 },
|
||||
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A", 1 },
|
||||
// Test that we don't pick the equally long but different "/A /B" variant.
|
||||
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A /C", 1 },
|
||||
// Test that we don't pick the shorter "/A" variant,
|
||||
// but do pick the shorter "/A /B" variant for longer inputs.
|
||||
TestCase{ L"cmd.exe /A /B", 2 },
|
||||
TestCase{ L"cmd.exe /A /B /C", 2 },
|
||||
// Ignore profiles with a connection type, like the Azure cloud shell.
|
||||
// Instead it should pick any other prefix.
|
||||
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A /C", 1 },
|
||||
// Return base layer profile for missing profiles.
|
||||
TestCase{ L"C:\\Windows\\regedit.exe", -1 },
|
||||
};
|
||||
|
||||
for (const auto& testCase : testCases)
|
||||
{
|
||||
NewTerminalArgs args;
|
||||
args.Commandline(testCase.input);
|
||||
|
||||
const auto profile = settings->GetProfileForArgs(args);
|
||||
VERIFY_IS_NOT_NULL(profile);
|
||||
|
||||
if (testCase.expected < 0)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(123, profile.HistorySize());
|
||||
}
|
||||
else
|
||||
{
|
||||
GUID expectedGUID{ 0x6239a42c, static_cast<uint16_t>(0x1111 * testCase.expected), 0x49a3, { 0x80, 0xbd, 0xe8, 0xfd, 0xd0, 0x45, 0x18, 0x5c } };
|
||||
VERIFY_ARE_EQUAL(expectedGUID, static_cast<const GUID&>(profile.Guid()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalSettingsTests::TestTerminalArgsForBinding()
|
||||
{
|
||||
static constexpr std::string_view settingsJson{ R"(
|
||||
|
|
|
@ -1031,9 +1031,11 @@ namespace TerminalAppLocalTests
|
|||
// The first action is going to always be a new-tab action
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, appArgs._startupActions.at(0).Action());
|
||||
|
||||
auto actionAndArgs = appArgs._startupActions.at(1);
|
||||
const auto actionAndArgs = appArgs._startupActions.at(1);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::NextTab, actionAndArgs.Action());
|
||||
VERIFY_IS_NULL(actionAndArgs.Args());
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
|
||||
const auto myArgs = actionAndArgs.Args().as<NextTabArgs>();
|
||||
VERIFY_ARE_EQUAL(TabSwitcherMode::Disabled, myArgs.SwitcherMode().Value());
|
||||
}
|
||||
{
|
||||
AppCommandlineArgs appArgs{};
|
||||
|
@ -1047,7 +1049,9 @@ namespace TerminalAppLocalTests
|
|||
|
||||
auto actionAndArgs = appArgs._startupActions.at(1);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::PrevTab, actionAndArgs.Action());
|
||||
VERIFY_IS_NULL(actionAndArgs.Args());
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs.Args());
|
||||
const auto myArgs = actionAndArgs.Args().as<PrevTabArgs>();
|
||||
VERIFY_ARE_EQUAL(TabSwitcherMode::Disabled, myArgs.SwitcherMode().Value());
|
||||
}
|
||||
{
|
||||
AppCommandlineArgs appArgs{};
|
||||
|
|
|
@ -16,6 +16,31 @@ using namespace winrt::Microsoft::Terminal::Control;
|
|||
|
||||
namespace TerminalAppLocalTests
|
||||
{
|
||||
static constexpr std::wstring_view inboxSettings{ LR"({
|
||||
"schemes": [{
|
||||
"name": "Campbell",
|
||||
"foreground": "#CCCCCC",
|
||||
"background": "#0C0C0C",
|
||||
"cursorColor": "#FFFFFF",
|
||||
"black": "#0C0C0C",
|
||||
"red": "#C50F1F",
|
||||
"green": "#13A10E",
|
||||
"yellow": "#C19C00",
|
||||
"blue": "#0037DA",
|
||||
"purple": "#881798",
|
||||
"cyan": "#3A96DD",
|
||||
"white": "#CCCCCC",
|
||||
"brightBlack": "#767676",
|
||||
"brightRed": "#E74856",
|
||||
"brightGreen": "#16C60C",
|
||||
"brightYellow": "#F9F1A5",
|
||||
"brightBlue": "#3B78FF",
|
||||
"brightPurple": "#B4009E",
|
||||
"brightCyan": "#61D6D6",
|
||||
"brightWhite": "#F2F2F2"
|
||||
}]
|
||||
})" };
|
||||
|
||||
// TODO:microsoft/terminal#3838:
|
||||
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
|
||||
// an updated TAEF that will let us install framework packages when the test
|
||||
|
@ -107,11 +132,10 @@ namespace TerminalAppLocalTests
|
|||
"iterateOn": "profiles",
|
||||
"command": { "action": "splitPane", "profile": "${profile.name}" }
|
||||
},
|
||||
],
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ settingsJson, {} };
|
||||
CascadiaSettings settings{ settingsJson, inboxSettings };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
|
||||
|
@ -231,11 +255,10 @@ namespace TerminalAppLocalTests
|
|||
"iterateOn": "profiles",
|
||||
"command": { "action": "splitPane", "profile": "${profile.name}" }
|
||||
},
|
||||
],
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ settingsJson, {} };
|
||||
CascadiaSettings settings{ settingsJson, inboxSettings };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
|
||||
|
@ -357,11 +380,10 @@ namespace TerminalAppLocalTests
|
|||
"iterateOn": "profiles",
|
||||
"command": { "action": "splitPane", "profile": "${profile.name}" }
|
||||
},
|
||||
],
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ settingsJson, {} };
|
||||
CascadiaSettings settings{ settingsJson, inboxSettings };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
|
||||
|
@ -495,11 +517,10 @@ namespace TerminalAppLocalTests
|
|||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ settingsJson, {} };
|
||||
CascadiaSettings settings{ settingsJson, inboxSettings };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
@ -590,11 +611,10 @@ namespace TerminalAppLocalTests
|
|||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ settingsJson, {} };
|
||||
CascadiaSettings settings{ settingsJson, inboxSettings };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
@ -714,11 +734,10 @@ namespace TerminalAppLocalTests
|
|||
{ "command": { "action": "splitPane", "profile": "${profile.name}", "split": "down" } }
|
||||
]
|
||||
}
|
||||
],
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ settingsJson, {} };
|
||||
CascadiaSettings settings{ settingsJson, inboxSettings };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
@ -851,11 +870,10 @@ namespace TerminalAppLocalTests
|
|||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ settingsJson, {} };
|
||||
CascadiaSettings settings{ settingsJson, inboxSettings };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
@ -954,11 +972,10 @@ namespace TerminalAppLocalTests
|
|||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ settingsJson, {} };
|
||||
CascadiaSettings settings{ settingsJson, inboxSettings };
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
@ -1085,9 +1102,72 @@ namespace TerminalAppLocalTests
|
|||
}
|
||||
],
|
||||
"schemes": [
|
||||
{ "name": "scheme_0" },
|
||||
{ "name": "scheme_1" },
|
||||
{ "name": "scheme_2" },
|
||||
{
|
||||
"name": "Campbell",
|
||||
"foreground": "#CCCCCC",
|
||||
"background": "#0C0C0C",
|
||||
"cursorColor": "#FFFFFF",
|
||||
"black": "#0C0C0C",
|
||||
"red": "#C50F1F",
|
||||
"green": "#13A10E",
|
||||
"yellow": "#C19C00",
|
||||
"blue": "#0037DA",
|
||||
"purple": "#881798",
|
||||
"cyan": "#3A96DD",
|
||||
"white": "#CCCCCC",
|
||||
"brightBlack": "#767676",
|
||||
"brightRed": "#E74856",
|
||||
"brightGreen": "#16C60C",
|
||||
"brightYellow": "#F9F1A5",
|
||||
"brightBlue": "#3B78FF",
|
||||
"brightPurple": "#B4009E",
|
||||
"brightCyan": "#61D6D6",
|
||||
"brightWhite": "#F2F2F2"
|
||||
},
|
||||
{
|
||||
"name": "Campbell PowerShell",
|
||||
"foreground": "#CCCCCC",
|
||||
"background": "#012456",
|
||||
"cursorColor": "#FFFFFF",
|
||||
"black": "#0C0C0C",
|
||||
"red": "#C50F1F",
|
||||
"green": "#13A10E",
|
||||
"yellow": "#C19C00",
|
||||
"blue": "#0037DA",
|
||||
"purple": "#881798",
|
||||
"cyan": "#3A96DD",
|
||||
"white": "#CCCCCC",
|
||||
"brightBlack": "#767676",
|
||||
"brightRed": "#E74856",
|
||||
"brightGreen": "#16C60C",
|
||||
"brightYellow": "#F9F1A5",
|
||||
"brightBlue": "#3B78FF",
|
||||
"brightPurple": "#B4009E",
|
||||
"brightCyan": "#61D6D6",
|
||||
"brightWhite": "#F2F2F2"
|
||||
},
|
||||
{
|
||||
"name": "Vintage",
|
||||
"foreground": "#C0C0C0",
|
||||
"background": "#000000",
|
||||
"cursorColor": "#FFFFFF",
|
||||
"black": "#000000",
|
||||
"red": "#800000",
|
||||
"green": "#008000",
|
||||
"yellow": "#808000",
|
||||
"blue": "#000080",
|
||||
"purple": "#800080",
|
||||
"cyan": "#008080",
|
||||
"white": "#C0C0C0",
|
||||
"brightBlack": "#808080",
|
||||
"brightRed": "#FF0000",
|
||||
"brightGreen": "#00FF00",
|
||||
"brightYellow": "#FFFF00",
|
||||
"brightBlue": "#0000FF",
|
||||
"brightPurple": "#FF00FF",
|
||||
"brightCyan": "#00FFFF",
|
||||
"brightWhite": "#FFFFFF"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
|
@ -1100,10 +1180,6 @@ namespace TerminalAppLocalTests
|
|||
|
||||
CascadiaSettings settings{ settingsJson, {} };
|
||||
|
||||
// Since at least one profile does not reference a color scheme,
|
||||
// we add a warning saying "the color scheme is unknown"
|
||||
VERIFY_ARE_EQUAL(1u, settings.Warnings().Size());
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
auto nameMap{ settings.ActionMap().NameMap() };
|
||||
|
@ -1130,8 +1206,6 @@ namespace TerminalAppLocalTests
|
|||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
|
||||
// This is the same warning as above
|
||||
VERIFY_ARE_EQUAL(1u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
|
||||
// Yes, this test is testing splitPane with profiles named after each
|
||||
|
@ -1139,7 +1213,7 @@ namespace TerminalAppLocalTests
|
|||
// just easy tests to write.
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command scheme_0");
|
||||
auto command = expandedCommands.Lookup(L"iterable command Campbell");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
|
@ -1153,11 +1227,11 @@ namespace TerminalAppLocalTests
|
|||
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
|
||||
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
|
||||
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
|
||||
VERIFY_ARE_EQUAL(L"scheme_0", realArgs.TerminalArgs().Profile());
|
||||
VERIFY_ARE_EQUAL(L"Campbell", realArgs.TerminalArgs().Profile());
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command scheme_1");
|
||||
auto command = expandedCommands.Lookup(L"iterable command Campbell PowerShell");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
|
@ -1171,11 +1245,11 @@ namespace TerminalAppLocalTests
|
|||
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
|
||||
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
|
||||
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
|
||||
VERIFY_ARE_EQUAL(L"scheme_1", realArgs.TerminalArgs().Profile());
|
||||
VERIFY_ARE_EQUAL(L"Campbell PowerShell", realArgs.TerminalArgs().Profile());
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command scheme_2");
|
||||
auto command = expandedCommands.Lookup(L"iterable command Vintage");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
|
@ -1189,7 +1263,7 @@ namespace TerminalAppLocalTests
|
|||
VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty());
|
||||
VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty());
|
||||
VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty());
|
||||
VERIFY_ARE_EQUAL(L"scheme_2", realArgs.TerminalArgs().Profile());
|
||||
VERIFY_ARE_EQUAL(L"Vintage", realArgs.TerminalArgs().Profile());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -751,7 +751,7 @@ namespace TerminalAppLocalTests
|
|||
});
|
||||
VERIFY_SUCCEEDED(result);
|
||||
|
||||
Log::Comment(L"Move focus. This will cause us to un-zoom.");
|
||||
Log::Comment(L"Move focus. We should still be zoomed.");
|
||||
result = RunOnUIThread([&page]() {
|
||||
// Set up action
|
||||
MoveFocusArgs args{ FocusDirection::Left };
|
||||
|
@ -761,7 +761,7 @@ namespace TerminalAppLocalTests
|
|||
|
||||
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
|
||||
VERIFY_IS_FALSE(firstTab->IsZoomed());
|
||||
VERIFY_IS_TRUE(firstTab->IsZoomed());
|
||||
});
|
||||
VERIFY_SUCCEEDED(result);
|
||||
}
|
||||
|
@ -1357,7 +1357,8 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(L"Color should be changed to the preview");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
|
||||
// And we should have stored a function to revert the change.
|
||||
VERIFY_ARE_EQUAL(1u, page->_restorePreviewFuncs.size());
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
|
@ -1383,7 +1384,8 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(L"Color should be changed");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(nullptr, page->_originalSettings);
|
||||
// After preview there should be no more restore functions to execute.
|
||||
VERIFY_ARE_EQUAL(0u, page->_restorePreviewFuncs.size());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1428,7 +1430,6 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(L"Color should be changed to the preview");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
|
@ -1451,7 +1452,6 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(L"Color should be the same as it originally was");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(nullptr, page->_originalSettings);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1498,7 +1498,6 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(L"Color should be changed to the preview");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
|
@ -1522,7 +1521,6 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(L"Color should be changed to the preview");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
|
@ -1548,7 +1546,6 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(L"Color should be changed");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(nullptr, page->_originalSettings);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
5
src/cascadia/Remoting/GetWindowLayoutArgs.cpp
Normal file
5
src/cascadia/Remoting/GetWindowLayoutArgs.cpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
#include "pch.h"
|
||||
#include "GetWindowLayoutArgs.h"
|
||||
#include "GetWindowLayoutArgs.g.cpp"
|
32
src/cascadia/Remoting/GetWindowLayoutArgs.h
Normal file
32
src/cascadia/Remoting/GetWindowLayoutArgs.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Class Name:
|
||||
- GetWindowLayoutArgs.h
|
||||
|
||||
Abstract:
|
||||
- This is a helper class for getting the window layout from a peasant.
|
||||
Depending on if we are running on the monarch or on a peasant we might need
|
||||
to switch what thread we are executing on. This gives us the option of
|
||||
either returning the json result synchronously, or as a promise.
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GetWindowLayoutArgs.g.h"
|
||||
#include "../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct GetWindowLayoutArgs : public GetWindowLayoutArgsT<GetWindowLayoutArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, WindowLayoutJson, L"");
|
||||
WINRT_PROPERTY(winrt::Windows::Foundation::IAsyncOperation<winrt::hstring>, WindowLayoutJsonAsync, nullptr)
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(GetWindowLayoutArgs);
|
||||
}
|
|
@ -12,7 +12,6 @@
|
|||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Monarch.h">
|
||||
|
@ -36,6 +35,12 @@
|
|||
<ClInclude Include="WindowActivatedArgs.h">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GetWindowLayoutArgs.h">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="QuitAllRequestedArgs.h">
|
||||
<DependentUpon>Monarch.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="MonarchFactory.h" />
|
||||
<ClInclude Include="Peasant.h">
|
||||
|
@ -71,6 +76,12 @@
|
|||
<ClCompile Include="WindowActivatedArgs.cpp">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GetWindowLayoutArgs.cpp">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QuitAllRequestedArgs.cpp">
|
||||
<DependentUpon>Monarch.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
@ -128,6 +139,5 @@
|
|||
</ItemDefinitionGroup>
|
||||
<!-- ========================= Globals ======================== -->
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
</Project>
|
||||
</Project>
|
|
@ -6,6 +6,7 @@
|
|||
#include "Monarch.h"
|
||||
#include "CommandlineArgs.h"
|
||||
#include "FindTargetWindowArgs.h"
|
||||
#include "QuitAllRequestedArgs.h"
|
||||
#include "ProposeCommandlineResult.h"
|
||||
|
||||
#include "Monarch.g.cpp"
|
||||
|
@ -135,12 +136,18 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
// - <none> used
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Monarch::_handleQuitAll(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
winrt::fire_and_forget Monarch::_handleQuitAll(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
{
|
||||
// Let the process hosting the monarch run any needed logic before
|
||||
// closing all windows.
|
||||
_QuitAllRequestedHandlers(*this, nullptr);
|
||||
auto args = winrt::make_self<implementation::QuitAllRequestedArgs>();
|
||||
_QuitAllRequestedHandlers(*this, *args);
|
||||
|
||||
if (const auto action = args->BeforeQuitAllAction())
|
||||
{
|
||||
co_await action;
|
||||
}
|
||||
|
||||
_quitting.store(true);
|
||||
// Tell all peasants to exit.
|
||||
|
@ -994,4 +1001,28 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
|
||||
_forEachPeasant(func, onError);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Ask all peasants to return their window layout as json
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The collection of window layouts from each peasant.
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> Monarch::GetAllWindowLayouts()
|
||||
{
|
||||
std::vector<winrt::hstring> vec;
|
||||
auto callback = [&](const auto& /*id*/, const auto& p) {
|
||||
vec.emplace_back(p.GetWindowLayout());
|
||||
};
|
||||
auto onError = [](auto&& id) {
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_GetAllWindowLayouts_Failed",
|
||||
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not get a window layout from"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
};
|
||||
_forEachPeasant(callback, onError);
|
||||
|
||||
return winrt::single_threaded_vector(std::move(vec));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,13 +59,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
void SummonAllWindows();
|
||||
bool DoesQuakeWindowExist();
|
||||
Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo> GetPeasantInfos();
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
|
||||
|
||||
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::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
|
||||
|
||||
private:
|
||||
uint64_t _ourPID;
|
||||
|
@ -103,8 +104,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
void _renameRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
|
||||
|
||||
void _handleQuitAll(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
winrt::fire_and_forget _handleQuitAll(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
// Method Description:
|
||||
// - Helper for doing something on each and every peasant.
|
||||
|
@ -177,6 +178,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
}
|
||||
}
|
||||
_clearOldMruEntries(peasantsToErase);
|
||||
|
||||
// A peasant died, let the app host know that the number of
|
||||
// windows has changed.
|
||||
_WindowClosedHandlers(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,12 @@ namespace Microsoft.Terminal.Remoting
|
|||
Windows.Foundation.IReference<UInt64> WindowID;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass QuitAllRequestedArgs
|
||||
{
|
||||
QuitAllRequestedArgs();
|
||||
Windows.Foundation.IAsyncAction BeforeQuitAllAction;
|
||||
}
|
||||
|
||||
struct PeasantInfo
|
||||
{
|
||||
UInt64 Id;
|
||||
|
@ -52,12 +58,13 @@ namespace Microsoft.Terminal.Remoting
|
|||
void SummonAllWindows();
|
||||
Boolean DoesQuakeWindowExist();
|
||||
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos { get; };
|
||||
Windows.Foundation.Collections.IVector<String> GetAllWindowLayouts();
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WindowCreated;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WindowClosed;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitAllRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, QuitAllRequestedArgs> QuitAllRequested;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "Peasant.h"
|
||||
#include "CommandlineArgs.h"
|
||||
#include "SummonWindowBehavior.h"
|
||||
#include "GetWindowLayoutArgs.h"
|
||||
#include "Peasant.g.cpp"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
|
@ -289,4 +290,24 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Request and return the window layout from the current TerminalPage
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - the window layout as a json string
|
||||
hstring Peasant::GetWindowLayout()
|
||||
{
|
||||
auto args = winrt::make_self<implementation::GetWindowLayoutArgs>();
|
||||
_GetWindowLayoutRequestedHandlers(nullptr, *args);
|
||||
if (const auto op = args->WindowLayoutJsonAsync())
|
||||
{
|
||||
// This will fail if called on the UI thread, so the monarch should
|
||||
// never set WindowLayoutJsonAsync.
|
||||
auto str = op.get();
|
||||
return str;
|
||||
}
|
||||
return args->WindowLayoutJson();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs();
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
|
||||
|
||||
winrt::hstring GetWindowLayout();
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, WindowName);
|
||||
WINRT_PROPERTY(winrt::hstring, ActiveTabTitle);
|
||||
|
||||
|
@ -49,6 +52,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
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);
|
||||
|
||||
private:
|
||||
Peasant(const uint64_t testPID);
|
||||
|
|
|
@ -30,6 +30,11 @@ namespace Microsoft.Terminal.Remoting
|
|||
Windows.Foundation.DateTime ActivatedTime { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass GetWindowLayoutArgs {
|
||||
GetWindowLayoutArgs();
|
||||
String WindowLayoutJson;
|
||||
Windows.Foundation.IAsyncOperation<String> WindowLayoutJsonAsync;
|
||||
}
|
||||
|
||||
enum MonitorBehavior
|
||||
{
|
||||
|
@ -69,6 +74,7 @@ namespace Microsoft.Terminal.Remoting
|
|||
void RequestHideNotificationIcon();
|
||||
void RequestQuitAll();
|
||||
void Quit();
|
||||
String GetWindowLayout();
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, WindowActivatedArgs> WindowActivated;
|
||||
event Windows.Foundation.TypedEventHandler<Object, CommandlineArgs> ExecuteCommandlineRequested;
|
||||
|
@ -78,6 +84,7 @@ namespace Microsoft.Terminal.Remoting
|
|||
event Windows.Foundation.TypedEventHandler<Object, SummonWindowBehavior> SummonRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, GetWindowLayoutArgs> GetWindowLayoutRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitAllRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
|
||||
};
|
||||
|
|
5
src/cascadia/Remoting/QuitAllRequestedArgs.cpp
Normal file
5
src/cascadia/Remoting/QuitAllRequestedArgs.cpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
#include "pch.h"
|
||||
#include "QuitAllRequestedArgs.h"
|
||||
#include "QuitAllRequestedArgs.g.cpp"
|
30
src/cascadia/Remoting/QuitAllRequestedArgs.h
Normal file
30
src/cascadia/Remoting/QuitAllRequestedArgs.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Class Name:
|
||||
- QuitAllRequestedArgs.h
|
||||
|
||||
Abstract:
|
||||
- This is a helper class for allowing the monarch to run code before telling all
|
||||
peasants to quit. This way the monarch can raise an event and get back a future
|
||||
to wait for before continuing.
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "QuitAllRequestedArgs.g.h"
|
||||
#include "../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct QuitAllRequestedArgs : public QuitAllRequestedArgsT<QuitAllRequestedArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::Windows::Foundation::IAsyncAction, BeforeQuitAllAction, nullptr)
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(QuitAllRequestedArgs);
|
||||
}
|
|
@ -271,7 +271,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
_monarch.FindTargetWindowRequested({ this, &WindowManager::_raiseFindTargetWindowRequested });
|
||||
_monarch.ShowNotificationIconRequested([this](auto&&, auto&&) { _ShowNotificationIconRequestedHandlers(*this, nullptr); });
|
||||
_monarch.HideNotificationIconRequested([this](auto&&, auto&&) { _HideNotificationIconRequestedHandlers(*this, nullptr); });
|
||||
_monarch.QuitAllRequested([this](auto&&, auto&&) { _QuitAllRequestedHandlers(*this, nullptr); });
|
||||
_monarch.QuitAllRequested({ get_weak(), &WindowManager::_QuitAllRequestedHandlers });
|
||||
|
||||
_BecameMonarchHandlers(*this, nullptr);
|
||||
}
|
||||
|
@ -318,6 +318,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
}
|
||||
}
|
||||
|
||||
_peasant.GetWindowLayoutRequested({ get_weak(), &WindowManager::_GetWindowLayoutRequestedHandlers });
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_CreateOurPeasant",
|
||||
TraceLoggingUInt64(_peasant.GetID(), "peasantID", "The ID of our new peasant"),
|
||||
|
@ -610,4 +612,17 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
{
|
||||
winrt::get_self<implementation::Peasant>(_peasant)->ActiveTabTitle(title);
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> WindowManager::GetAllWindowLayouts()
|
||||
{
|
||||
if (_monarch)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _monarch.GetAllWindowLayouts();
|
||||
}
|
||||
CATCH_LOG()
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
winrt::fire_and_forget RequestQuitAll();
|
||||
bool DoesQuakeWindowExist();
|
||||
void UpdateActiveTabTitle(winrt::hstring title);
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
TYPED_EVENT(BecameMonarch, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
@ -57,7 +58,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
|||
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
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(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
|
||||
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
|
||||
|
||||
private:
|
||||
bool _shouldCreateWindow{ false };
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace Microsoft.Terminal.Remoting
|
|||
void SummonAllWindows();
|
||||
void RequestShowNotificationIcon();
|
||||
void RequestHideNotificationIcon();
|
||||
Windows.Foundation.Collections.IVector<String> GetAllWindowLayouts();
|
||||
|
||||
UInt64 GetNumberOfPeasants();
|
||||
void RequestQuitAll();
|
||||
void UpdateActiveTabTitle(String title);
|
||||
|
@ -25,8 +27,9 @@ namespace Microsoft.Terminal.Remoting
|
|||
event Windows.Foundation.TypedEventHandler<Object, Object> BecameMonarch;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WindowCreated;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WindowClosed;
|
||||
event Windows.Foundation.TypedEventHandler<Object, QuitAllRequestedArgs> QuitAllRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, GetWindowLayoutArgs> GetWindowLayoutRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitAllRequested;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -55,9 +55,7 @@ HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
|||
STARTUPINFOEX siEx{ 0 };
|
||||
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
||||
|
||||
// Append a "\." to the given path, so that this will work in "C:\"
|
||||
auto path{ wil::str_printf<std::wstring>(LR"-(%s\.)-", pszName.get()) };
|
||||
auto cmdline{ wil::str_printf<std::wstring>(LR"-("%s" -d "%s")-", GetWtExePath().c_str(), path.c_str()) };
|
||||
auto cmdline{ wil::str_printf<std::wstring>(LR"-("%s" -d %s)-", GetWtExePath().c_str(), QuoteAndEscapeCommandlineArg(pszName.get()).c_str()) };
|
||||
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
nullptr, // lpApplicationName
|
||||
cmdline.data(),
|
||||
|
@ -66,7 +64,7 @@ HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
|||
false, // bInheritHandles
|
||||
EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
|
||||
nullptr, // lpEnvironment
|
||||
path.data(),
|
||||
pszName.get(),
|
||||
&siEx.StartupInfo, // lpStartupInfo
|
||||
&_piClient // lpProcessInformation
|
||||
));
|
||||
|
|
|
@ -67,41 +67,17 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
void TerminalPage::_EndPreviewColorScheme()
|
||||
{
|
||||
// Get the focused control
|
||||
if (const auto& activeControl{ _GetActiveControl() })
|
||||
for (const auto& f : _restorePreviewFuncs)
|
||||
{
|
||||
// Get the runtime settings of the focused control
|
||||
const auto& controlSettings{ activeControl.Settings().as<TerminalSettings>() };
|
||||
|
||||
// Get the control's root settings, the ones that we actually
|
||||
// assigned to it.
|
||||
auto parentSettings{ controlSettings.GetParent() };
|
||||
while (parentSettings.GetParent() != nullptr)
|
||||
{
|
||||
parentSettings = parentSettings.GetParent();
|
||||
}
|
||||
|
||||
// If the root settings are the same as the ones we stashed,
|
||||
// then reset the parent of the runtime settings to the stashed
|
||||
// settings. This condition might be false if the settings
|
||||
// hot-reloaded while the palette was open. In that case, we
|
||||
// don't want to reset the settings to what they were _before_
|
||||
// the hot-reload.
|
||||
if (_originalSettings == parentSettings)
|
||||
{
|
||||
// Set the original settings as the parent of the control's settings
|
||||
activeControl.Settings().as<TerminalSettings>().SetParent(_originalSettings);
|
||||
}
|
||||
|
||||
activeControl.UpdateSettings();
|
||||
f();
|
||||
}
|
||||
_originalSettings = nullptr;
|
||||
_restorePreviewFuncs.clear();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Preview handler for the SetColorScheme action.
|
||||
// - This method will stash the settings of the current control in
|
||||
// _originalSettings. Then it will create a new TerminalSettings object
|
||||
// - This method will stash functions to reset the settings of the selected controls in
|
||||
// _restorePreviewFuncs. Then it will create a new TerminalSettings object
|
||||
// with only the properties from the ColorScheme set. It'll _insert_ a
|
||||
// TerminalSettings between the control's root settings (built from
|
||||
// CascadiaSettings) and the control's runtime settings. That'll cause the
|
||||
|
@ -112,33 +88,63 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
void TerminalPage::_PreviewColorScheme(const Settings::Model::SetColorSchemeArgs& args)
|
||||
{
|
||||
// Get the focused control
|
||||
if (const auto& activeControl{ _GetActiveControl() })
|
||||
if (const auto& scheme{ _settings.GlobalSettings().ColorSchemes().TryLookup(args.SchemeName()) })
|
||||
{
|
||||
if (const auto& scheme{ _settings.GlobalSettings().ColorSchemes().TryLookup(args.SchemeName()) })
|
||||
{
|
||||
// Clear the saved preview funcs because we don't need to add a restore each time
|
||||
// the preview color changes, we only need to be able to restore the last one.
|
||||
_restorePreviewFuncs.clear();
|
||||
|
||||
_ApplyToActiveControls([&](const auto& control) {
|
||||
// Get the settings of the focused control and stash them
|
||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
||||
const auto& controlSettings = control.Settings().as<TerminalSettings>();
|
||||
// Make sure to recurse up to the root - if you're doing
|
||||
// this while you're currently previewing a SetColorScheme
|
||||
// action, then the parent of the control's settings is _the
|
||||
// last preview TerminalSettings we inserted! We don't want
|
||||
// to save that one!
|
||||
_originalSettings = controlSettings.GetParent();
|
||||
while (_originalSettings.GetParent() != nullptr)
|
||||
auto originalSettings = controlSettings.GetParent();
|
||||
while (originalSettings.GetParent() != nullptr)
|
||||
{
|
||||
_originalSettings = _originalSettings.GetParent();
|
||||
originalSettings = originalSettings.GetParent();
|
||||
}
|
||||
// Create a new child for those settings
|
||||
TerminalSettingsCreateResult fake{ _originalSettings };
|
||||
TerminalSettingsCreateResult fake{ originalSettings };
|
||||
const auto& childStruct = TerminalSettings::CreateWithParent(fake);
|
||||
// Modify the child to have the applied color scheme
|
||||
childStruct.DefaultSettings().ApplyColorScheme(scheme);
|
||||
|
||||
// Insert that new child as the parent of the control's settings
|
||||
controlSettings.SetParent(childStruct.DefaultSettings());
|
||||
activeControl.UpdateSettings();
|
||||
}
|
||||
control.UpdateSettings();
|
||||
|
||||
// Take a copy of the inputs, since they are pointers anyways.
|
||||
_restorePreviewFuncs.emplace_back([=]() {
|
||||
// Get the runtime settings of the focused control
|
||||
const auto& controlSettings{ control.Settings().as<TerminalSettings>() };
|
||||
|
||||
// Get the control's root settings, the ones that we actually
|
||||
// assigned to it.
|
||||
auto parentSettings{ controlSettings.GetParent() };
|
||||
while (parentSettings.GetParent() != nullptr)
|
||||
{
|
||||
parentSettings = parentSettings.GetParent();
|
||||
}
|
||||
|
||||
// If the root settings are the same as the ones we stashed,
|
||||
// then reset the parent of the runtime settings to the stashed
|
||||
// settings. This condition might be false if the settings
|
||||
// hot-reloaded while the palette was open. In that case, we
|
||||
// don't want to reset the settings to what they were _before_
|
||||
// the hot-reload.
|
||||
if (originalSettings == parentSettings)
|
||||
{
|
||||
// Set the original settings as the parent of the control's settings
|
||||
control.Settings().as<TerminalSettings>().SetParent(originalSettings);
|
||||
}
|
||||
|
||||
control.UpdateSettings();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void TerminalPage::_HandleCloseWindow(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
CloseWindow(false);
|
||||
_CloseRequestedHandlers(nullptr, nullptr);
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
|
@ -377,11 +377,10 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<AdjustFontSizeArgs>())
|
||||
{
|
||||
if (const auto& termControl{ _GetActiveControl() })
|
||||
{
|
||||
termControl.AdjustFontSize(realArgs.Delta());
|
||||
args.Handled(true);
|
||||
}
|
||||
const auto res = _ApplyToActiveControls([&](auto& control) {
|
||||
control.AdjustFontSize(realArgs.Delta());
|
||||
});
|
||||
args.Handled(res);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,21 +394,19 @@ namespace winrt::TerminalApp::implementation
|
|||
void TerminalPage::_HandleResetFontSize(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (const auto& termControl{ _GetActiveControl() })
|
||||
{
|
||||
termControl.ResetFontSize();
|
||||
args.Handled(true);
|
||||
}
|
||||
const auto res = _ApplyToActiveControls([](auto& control) {
|
||||
control.ResetFontSize();
|
||||
});
|
||||
args.Handled(res);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleToggleShaderEffects(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (const auto& termControl{ _GetActiveControl() })
|
||||
{
|
||||
termControl.ToggleShaderEffects();
|
||||
args.Handled(true);
|
||||
}
|
||||
const auto res = _ApplyToActiveControls([](auto& control) {
|
||||
control.ToggleShaderEffects();
|
||||
});
|
||||
args.Handled(res);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleToggleFocusMode(const IInspectable& /*sender*/,
|
||||
|
@ -452,37 +449,33 @@ namespace winrt::TerminalApp::implementation
|
|||
args.Handled(false);
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<SetColorSchemeArgs>())
|
||||
{
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
if (const auto scheme = _settings.GlobalSettings().ColorSchemes().TryLookup(realArgs.SchemeName()))
|
||||
{
|
||||
if (auto activeControl = activeTab->GetActiveTerminalControl())
|
||||
{
|
||||
if (const auto scheme = _settings.GlobalSettings().ColorSchemes().TryLookup(realArgs.SchemeName()))
|
||||
const auto res = _ApplyToActiveControls([&](auto& control) {
|
||||
// Start by getting the current settings of the control
|
||||
auto controlSettings = control.Settings().as<TerminalSettings>();
|
||||
auto parentSettings = controlSettings;
|
||||
// Those are the _runtime_ settings however. What we
|
||||
// need to do is:
|
||||
//
|
||||
// 1. Blow away any colors set in the runtime settings.
|
||||
// 2. Apply the color scheme to the parent settings.
|
||||
//
|
||||
// 1 is important to make sure that the effects of
|
||||
// something like `colortool` are cleared when setting
|
||||
// the scheme.
|
||||
if (controlSettings.GetParent() != nullptr)
|
||||
{
|
||||
// Start by getting the current settings of the control
|
||||
auto controlSettings = activeControl.Settings().as<TerminalSettings>();
|
||||
auto parentSettings = controlSettings;
|
||||
// Those are the _runtime_ settings however. What we
|
||||
// need to do is:
|
||||
//
|
||||
// 1. Blow away any colors set in the runtime settings.
|
||||
// 2. Apply the color scheme to the parent settings.
|
||||
//
|
||||
// 1 is important to make sure that the effects of
|
||||
// something like `colortool` are cleared when setting
|
||||
// the scheme.
|
||||
if (controlSettings.GetParent() != nullptr)
|
||||
{
|
||||
parentSettings = controlSettings.GetParent();
|
||||
}
|
||||
|
||||
// ApplyColorScheme(nullptr) will clear the old color scheme.
|
||||
controlSettings.ApplyColorScheme(nullptr);
|
||||
parentSettings.ApplyColorScheme(scheme);
|
||||
|
||||
activeControl.UpdateSettings();
|
||||
args.Handled(true);
|
||||
parentSettings = controlSettings.GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyColorScheme(nullptr) will clear the old color scheme.
|
||||
controlSettings.ApplyColorScheme(nullptr);
|
||||
parentSettings.ApplyColorScheme(scheme);
|
||||
|
||||
control.UpdateSettings();
|
||||
});
|
||||
args.Handled(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -896,11 +889,10 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<ClearBufferArgs>())
|
||||
{
|
||||
if (const auto termControl{ _GetActiveControl() })
|
||||
{
|
||||
termControl.ClearBuffer(realArgs.Clear());
|
||||
args.Handled(true);
|
||||
}
|
||||
const auto res = _ApplyToActiveControls([&](auto& control) {
|
||||
control.ClearBuffer(realArgs.Clear());
|
||||
});
|
||||
args.Handled(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,6 +187,10 @@ void AppCommandlineArgs::_buildParser()
|
|||
_windowTarget,
|
||||
RS_A(L"CmdWindowTargetArgDesc"));
|
||||
|
||||
_app.add_option("-s,--saved",
|
||||
_loadPersistedLayoutIdx,
|
||||
RS_A(L"CmdSavedLayoutArgDesc"));
|
||||
|
||||
// Subcommands
|
||||
_buildNewTabParser();
|
||||
_buildSplitPaneParser();
|
||||
|
@ -700,6 +704,7 @@ void AppCommandlineArgs::_resetStateToDefault()
|
|||
_swapPaneDirection = FocusDirection::None;
|
||||
|
||||
_focusPaneTarget = -1;
|
||||
_loadPersistedLayoutIdx = -1;
|
||||
|
||||
// DON'T clear _launchMode here! This will get called once for every
|
||||
// subcommand, so we don't want `wt -F new-tab ; split-pane` clearing out
|
||||
|
@ -915,6 +920,12 @@ void AppCommandlineArgs::ValidateStartupCommands()
|
|||
}
|
||||
}
|
||||
}
|
||||
std::optional<uint32_t> AppCommandlineArgs::GetPersistedLayoutIdx() const noexcept
|
||||
{
|
||||
return _loadPersistedLayoutIdx >= 0 ?
|
||||
std::optional{ static_cast<uint32_t>(_loadPersistedLayoutIdx) } :
|
||||
std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> AppCommandlineArgs::GetLaunchMode() const noexcept
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
const std::string& GetExitMessage();
|
||||
bool ShouldExitEarly() const noexcept;
|
||||
|
||||
std::optional<uint32_t> GetPersistedLayoutIdx() const noexcept;
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> GetLaunchMode() const noexcept;
|
||||
|
||||
int ParseArgs(const winrt::Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
|
||||
|
@ -123,6 +124,7 @@ private:
|
|||
std::string _exitMessage;
|
||||
bool _shouldExitEarly{ false };
|
||||
|
||||
int _loadPersistedLayoutIdx{};
|
||||
std::string _windowTarget{};
|
||||
// Are you adding more args or attributes here? If they are not reset in _resetStateToDefault, make sure to reset them in FullResetState
|
||||
|
||||
|
|
|
@ -375,6 +375,8 @@ namespace winrt::TerminalApp::implementation
|
|||
co_return ContentDialogResult::None;
|
||||
}
|
||||
|
||||
_dialog = dialog;
|
||||
|
||||
// IMPORTANT: This is necessary as documented in the ContentDialog MSDN docs.
|
||||
// Since we're hosting the dialog in a Xaml island, we need to connect it to the
|
||||
// xaml tree somehow.
|
||||
|
@ -412,6 +414,16 @@ namespace winrt::TerminalApp::implementation
|
|||
// be released so another can be shown
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Dismiss the (only) visible ContentDialog
|
||||
void AppLogic::DismissDialog()
|
||||
{
|
||||
if (auto localDialog = std::exchange(_dialog, nullptr))
|
||||
{
|
||||
localDialog.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Displays a dialog for errors found while loading or validating the
|
||||
// settings. Uses the resources under the provided title and content keys
|
||||
|
@ -600,13 +612,11 @@ namespace winrt::TerminalApp::implementation
|
|||
winrt::Windows::Foundation::Size proposedSize{};
|
||||
|
||||
const float scale = static_cast<float>(dpi) / static_cast<float>(USER_DEFAULT_SCREEN_DPI);
|
||||
if (_root->ShouldUsePersistedLayout(_settings))
|
||||
if (const auto layout = _root->LoadPersistedLayout(_settings))
|
||||
{
|
||||
const auto layouts = ApplicationState::SharedInstance().PersistedWindowLayouts();
|
||||
|
||||
if (layouts && layouts.Size() > 0 && layouts.GetAt(0).InitialSize())
|
||||
if (layout.InitialSize())
|
||||
{
|
||||
proposedSize = layouts.GetAt(0).InitialSize().Value();
|
||||
proposedSize = layout.InitialSize().Value();
|
||||
// The size is saved as a non-scaled real pixel size,
|
||||
// so we need to scale it appropriately.
|
||||
proposedSize.Height = proposedSize.Height * scale;
|
||||
|
@ -704,13 +714,11 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
auto initialPosition{ _settings.GlobalSettings().InitialPosition() };
|
||||
|
||||
if (_root->ShouldUsePersistedLayout(_settings))
|
||||
if (const auto layout = _root->LoadPersistedLayout(_settings))
|
||||
{
|
||||
const auto layouts = ApplicationState::SharedInstance().PersistedWindowLayouts();
|
||||
|
||||
if (layouts && layouts.Size() > 0 && layouts.GetAt(0).InitialPosition())
|
||||
if (layout.InitialPosition())
|
||||
{
|
||||
initialPosition = layouts.GetAt(0).InitialPosition().Value();
|
||||
initialPosition = layout.InitialPosition().Value();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1151,10 +1159,22 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void AppLogic::WindowCloseButtonClicked()
|
||||
void AppLogic::CloseWindow(LaunchPosition pos)
|
||||
{
|
||||
if (_root)
|
||||
{
|
||||
// If persisted layout is enabled and we are the last window closing
|
||||
// we should save our state.
|
||||
if (_root->ShouldUsePersistedLayout(_settings) && _numOpenWindows == 1)
|
||||
{
|
||||
if (const auto layout = _root->GetWindowLayout())
|
||||
{
|
||||
layout.InitialPosition(pos);
|
||||
const auto state = ApplicationState::SharedInstance();
|
||||
state.PersistedWindowLayouts(winrt::single_threaded_vector<WindowLayout>({ layout }));
|
||||
}
|
||||
}
|
||||
|
||||
_root->CloseWindow(false);
|
||||
}
|
||||
}
|
||||
|
@ -1168,6 +1188,16 @@ namespace winrt::TerminalApp::implementation
|
|||
return {};
|
||||
}
|
||||
|
||||
bool AppLogic::HasCommandlineArguments() const noexcept
|
||||
{
|
||||
return _hasCommandLineArguments;
|
||||
}
|
||||
|
||||
bool AppLogic::HasSettingsStartupActions() const noexcept
|
||||
{
|
||||
return _hasSettingsStartupActions;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets the initial commandline to process on startup, and attempts to
|
||||
// parse it. Commands will be parsed into a list of ShortcutActions that
|
||||
|
@ -1191,6 +1221,10 @@ namespace winrt::TerminalApp::implementation
|
|||
// then it contains only the executable name and no other arguments.
|
||||
_hasCommandLineArguments = args.size() > 1;
|
||||
_appArgs.ValidateStartupCommands();
|
||||
if (const auto idx = _appArgs.GetPersistedLayoutIdx())
|
||||
{
|
||||
_root->SetPersistedLayoutIdx(idx.value());
|
||||
}
|
||||
_root->SetStartupActions(_appArgs.GetStartupActions());
|
||||
|
||||
// Check if we were started as a COM server for inbound connections of console sessions
|
||||
|
@ -1428,6 +1462,40 @@ namespace winrt::TerminalApp::implementation
|
|||
return _settings.GlobalSettings().ActionMap().GlobalHotkeys();
|
||||
}
|
||||
|
||||
bool AppLogic::ShouldUsePersistedLayout()
|
||||
{
|
||||
return _root != nullptr ? _root->ShouldUsePersistedLayout(_settings) : false;
|
||||
}
|
||||
|
||||
void AppLogic::SaveWindowLayoutJsons(const Windows::Foundation::Collections::IVector<hstring>& layouts)
|
||||
{
|
||||
std::vector<WindowLayout> converted;
|
||||
converted.reserve(layouts.Size());
|
||||
|
||||
for (const auto& json : layouts)
|
||||
{
|
||||
if (json != L"")
|
||||
{
|
||||
converted.emplace_back(WindowLayout::FromJson(json));
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationState::SharedInstance().PersistedWindowLayouts(winrt::single_threaded_vector(std::move(converted)));
|
||||
}
|
||||
|
||||
hstring AppLogic::GetWindowLayoutJson(LaunchPosition position)
|
||||
{
|
||||
if (_root != nullptr)
|
||||
{
|
||||
if (const auto layout = _root->GetWindowLayout())
|
||||
{
|
||||
layout.InitialPosition(position);
|
||||
return WindowLayout::ToJson(layout);
|
||||
}
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
void AppLogic::IdentifyWindow()
|
||||
{
|
||||
if (_root)
|
||||
|
@ -1459,8 +1527,17 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
void AppLogic::SetPersistedLayoutIdx(const uint32_t idx)
|
||||
{
|
||||
if (_root)
|
||||
{
|
||||
_root->SetPersistedLayoutIdx(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void AppLogic::SetNumberOfOpenWindows(const uint64_t num)
|
||||
{
|
||||
_numOpenWindows = num;
|
||||
if (_root)
|
||||
{
|
||||
_root->SetNumberOfOpenWindows(num);
|
||||
|
|
|
@ -55,6 +55,8 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
void Quit();
|
||||
|
||||
bool HasCommandlineArguments() const noexcept;
|
||||
bool HasSettingsStartupActions() const noexcept;
|
||||
int32_t SetStartupCommandline(array_view<const winrt::hstring> actions);
|
||||
int32_t ExecuteCommandline(array_view<const winrt::hstring> actions, const winrt::hstring& cwd);
|
||||
TerminalApp::FindTargetWindowResult FindTargetWindow(array_view<const winrt::hstring> actions);
|
||||
|
@ -65,12 +67,16 @@ namespace winrt::TerminalApp::implementation
|
|||
bool Fullscreen() const;
|
||||
bool AlwaysOnTop() const;
|
||||
|
||||
bool ShouldUsePersistedLayout();
|
||||
hstring GetWindowLayoutJson(Microsoft::Terminal::Settings::Model::LaunchPosition position);
|
||||
void SaveWindowLayoutJsons(const Windows::Foundation::Collections::IVector<hstring>& layouts);
|
||||
void IdentifyWindow();
|
||||
void RenameFailed();
|
||||
winrt::hstring WindowName();
|
||||
void WindowName(const winrt::hstring& name);
|
||||
uint64_t WindowId();
|
||||
void WindowId(const uint64_t& id);
|
||||
void SetPersistedLayoutIdx(const uint32_t idx);
|
||||
void SetNumberOfOpenWindows(const uint64_t num);
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
|
||||
|
@ -91,7 +97,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void TitlebarClicked();
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
void WindowCloseButtonClicked();
|
||||
void CloseWindow(Microsoft::Terminal::Settings::Model::LaunchPosition position);
|
||||
|
||||
winrt::TerminalApp::TaskbarState TaskbarState();
|
||||
|
||||
|
@ -100,6 +106,7 @@ namespace winrt::TerminalApp::implementation
|
|||
bool GetShowTitleInTitlebar();
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
|
||||
void DismissDialog();
|
||||
|
||||
Windows::Foundation::Collections::IMapView<Microsoft::Terminal::Control::KeyChord, Microsoft::Terminal::Settings::Model::Command> GlobalHotkeys();
|
||||
|
||||
|
@ -123,7 +130,10 @@ namespace winrt::TerminalApp::implementation
|
|||
HRESULT _settingsLoadedResult = S_OK;
|
||||
bool _loadedInitialSettings = false;
|
||||
|
||||
uint64_t _numOpenWindows{ 0 };
|
||||
|
||||
std::shared_mutex _dialogLock;
|
||||
winrt::Windows::UI::Xaml::Controls::ContentDialog _dialog;
|
||||
|
||||
::TerminalApp::AppCommandlineArgs _appArgs;
|
||||
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
|
||||
|
@ -175,6 +185,7 @@ namespace winrt::TerminalApp::implementation
|
|||
FORWARDED_TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs, _root, RenameWindowRequested);
|
||||
FORWARDED_TYPED_EVENT(IsQuakeWindowChanged, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IsQuakeWindowChanged);
|
||||
FORWARDED_TYPED_EVENT(SummonWindowRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, SummonWindowRequested);
|
||||
FORWARDED_TYPED_EVENT(CloseRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, CloseRequested);
|
||||
FORWARDED_TYPED_EVENT(OpenSystemMenu, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, OpenSystemMenu);
|
||||
FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested);
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ namespace TerminalApp
|
|||
void RunAsUwp();
|
||||
Boolean IsElevated();
|
||||
|
||||
Boolean HasCommandlineArguments();
|
||||
Boolean HasSettingsStartupActions();
|
||||
Int32 SetStartupCommandline(String[] commands);
|
||||
Int32 ExecuteCommandline(String[] commands, String cwd);
|
||||
String ParseCommandlineMessage { get; };
|
||||
|
@ -55,6 +57,7 @@ namespace TerminalApp
|
|||
void IdentifyWindow();
|
||||
String WindowName;
|
||||
UInt64 WindowId;
|
||||
void SetPersistedLayoutIdx(UInt32 idx);
|
||||
void SetNumberOfOpenWindows(UInt64 num);
|
||||
void RenameFailed();
|
||||
Boolean IsQuakeWindow();
|
||||
|
@ -69,10 +72,14 @@ namespace TerminalApp
|
|||
Boolean GetInitialAlwaysOnTop();
|
||||
Single CalcSnappedDimension(Boolean widthOrHeight, Single dimension);
|
||||
void TitlebarClicked();
|
||||
void WindowCloseButtonClicked();
|
||||
void CloseWindow(Microsoft.Terminal.Settings.Model.LaunchPosition position);
|
||||
|
||||
TaskbarState TaskbarState{ get; };
|
||||
|
||||
Boolean ShouldUsePersistedLayout();
|
||||
String GetWindowLayoutJson(Microsoft.Terminal.Settings.Model.LaunchPosition position);
|
||||
void SaveWindowLayoutJsons(Windows.Foundation.Collections.IVector<String> layouts);
|
||||
|
||||
Boolean GetMinimizeToNotificationArea();
|
||||
Boolean GetAlwaysShowNotificationIcon();
|
||||
Boolean GetShowTitleInTitlebar();
|
||||
|
@ -84,6 +91,7 @@ namespace TerminalApp
|
|||
// See IDialogPresenter and TerminalPage's DialogPresenter for more
|
||||
// information.
|
||||
Windows.Foundation.IAsyncOperation<Windows.UI.Xaml.Controls.ContentDialogResult> ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog);
|
||||
void DismissDialog();
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;
|
||||
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
|
||||
|
@ -99,6 +107,7 @@ namespace TerminalApp
|
|||
event Windows.Foundation.TypedEventHandler<Object, Object> SettingsChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IsQuakeWindowChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,22 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
|||
}
|
||||
void Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) {}
|
||||
~DebugInputTapConnection() = default;
|
||||
void Start()
|
||||
winrt::fire_and_forget Start()
|
||||
{
|
||||
// GH#11282: It's possible that we're about to be started, _before_
|
||||
// our paired connection is started. Both will get Start()'ed when
|
||||
// their owning TermControl is finally laid out. However, if we're
|
||||
// started first, then we'll immediately start printing to the other
|
||||
// control as well, which might not have initialized yet. If we do
|
||||
// that, we'll explode.
|
||||
//
|
||||
// Instead, wait here until the other connection is started too,
|
||||
// before actually starting the connection to the client app. This
|
||||
// will ensure both controls are initialized before the client app
|
||||
// is.
|
||||
co_await winrt::resume_background();
|
||||
_pairedTap->_start.wait();
|
||||
|
||||
_wrappedConnection.Start();
|
||||
}
|
||||
void WriteInput(hstring const& data)
|
||||
|
@ -59,6 +73,9 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
|||
void DebugTapConnection::Start()
|
||||
{
|
||||
// presume the wrapped connection is started.
|
||||
|
||||
// This is explained in the comment for GH#11282 above.
|
||||
_start.count_down();
|
||||
}
|
||||
|
||||
void DebugTapConnection::WriteInput(hstring const& data)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <winrt/Microsoft.Terminal.TerminalConnection.h>
|
||||
#include "../../inc/cppwinrt_utils.h"
|
||||
#include <til/latch.h>
|
||||
|
||||
namespace winrt::Microsoft::TerminalApp::implementation
|
||||
{
|
||||
|
@ -36,6 +37,8 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
|||
winrt::weak_ref<Microsoft::Terminal::TerminalConnection::ITerminalConnection> _wrappedConnection;
|
||||
winrt::weak_ref<Microsoft::Terminal::TerminalConnection::ITerminalConnection> _inputSide;
|
||||
|
||||
til::latch _start{ 1 };
|
||||
|
||||
friend class DebugInputTapConnection;
|
||||
};
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -40,7 +40,8 @@ enum class Borders : int
|
|||
Top = 0x1,
|
||||
Bottom = 0x2,
|
||||
Left = 0x4,
|
||||
Right = 0x8
|
||||
Right = 0x8,
|
||||
All = 0xF
|
||||
};
|
||||
DEFINE_ENUM_FLAG_OPERATORS(Borders);
|
||||
|
||||
|
@ -58,7 +59,14 @@ public:
|
|||
const winrt::Microsoft::Terminal::Control::TermControl& control,
|
||||
const bool lastFocused = false);
|
||||
|
||||
Pane(std::shared_ptr<Pane> first,
|
||||
std::shared_ptr<Pane> second,
|
||||
const SplitState splitType,
|
||||
const float splitPosition,
|
||||
const bool lastFocused = false);
|
||||
|
||||
std::shared_ptr<Pane> GetActivePane();
|
||||
winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl();
|
||||
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl();
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
|
||||
|
||||
|
@ -142,25 +150,43 @@ public:
|
|||
// - true if the predicate returned true on any pane.
|
||||
template<typename F>
|
||||
//requires std::predicate<F, std::shared_ptr<Pane>>
|
||||
bool WalkTree(F f)
|
||||
auto WalkTree(F f) -> decltype(f(shared_from_this()))
|
||||
{
|
||||
if (f(shared_from_this()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
using R = std::invoke_result_t<F, std::shared_ptr<Pane>>;
|
||||
static constexpr auto IsVoid = std::is_void_v<R>;
|
||||
|
||||
if (!_IsLeaf())
|
||||
if constexpr (IsVoid)
|
||||
{
|
||||
return _firstChild->WalkTree(f) || _secondChild->WalkTree(f);
|
||||
f(shared_from_this());
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
_firstChild->WalkTree(f);
|
||||
_secondChild->WalkTree(f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f(shared_from_this()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
return _firstChild->WalkTree(f) || _secondChild->WalkTree(f);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states);
|
||||
|
||||
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
|
||||
DECLARE_EVENT(GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
|
||||
using gotFocusArgs = winrt::delegate<std::shared_ptr<Pane>, winrt::Windows::UI::Xaml::FocusState>;
|
||||
|
||||
DECLARE_EVENT(GotFocus, _GotFocusHandlers, gotFocusArgs);
|
||||
DECLARE_EVENT(LostFocus, _LostFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
DECLARE_EVENT(PaneRaiseBell, _PaneRaiseBellHandlers, winrt::Windows::Foundation::EventHandler<bool>);
|
||||
DECLARE_EVENT(Detached, _PaneDetachedHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
|
@ -173,7 +199,8 @@ private:
|
|||
struct LayoutSizeNode;
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::Grid _root{};
|
||||
winrt::Windows::UI::Xaml::Controls::Border _border{};
|
||||
winrt::Windows::UI::Xaml::Controls::Border _borderFirst{};
|
||||
winrt::Windows::UI::Xaml::Controls::Border _borderSecond{};
|
||||
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
|
||||
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_focusedBorderBrush;
|
||||
|
@ -185,6 +212,7 @@ private:
|
|||
float _desiredSplitPosition;
|
||||
|
||||
std::optional<uint32_t> _id;
|
||||
std::weak_ptr<Pane> _parentChildPath{};
|
||||
|
||||
bool _lastActive{ false };
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
|
||||
|
@ -205,6 +233,7 @@ private:
|
|||
bool _IsLeaf() const noexcept;
|
||||
bool _HasFocusedChild() const noexcept;
|
||||
void _SetupChildCloseHandlers();
|
||||
bool _HasChild(const std::shared_ptr<Pane> child);
|
||||
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> _Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
|
||||
const float splitSize,
|
||||
|
@ -232,6 +261,7 @@ private:
|
|||
void _CloseChild(const bool closeFirst, const bool isDetaching);
|
||||
winrt::fire_and_forget _CloseChildRoutine(const bool closeFirst);
|
||||
|
||||
void _Focus();
|
||||
void _FocusFirstChild();
|
||||
void _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
|
||||
void _ControlWarningBellHandler(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
|
|
|
@ -190,6 +190,9 @@
|
|||
<data name="CloseWindowWarningTitle" xml:space="preserve">
|
||||
<value>Do you want to close all tabs?</value>
|
||||
</data>
|
||||
<data name="MultiplePanes" xml:space="preserve">
|
||||
<value>Multiple panes</value>
|
||||
</data>
|
||||
<data name="TabCloseSubMenu" xml:space="preserve">
|
||||
<value>Close...</value>
|
||||
</data>
|
||||
|
@ -381,6 +384,9 @@
|
|||
<data name="CmdFocusDesc" xml:space="preserve">
|
||||
<value>Launch the window in focus mode</value>
|
||||
</data>
|
||||
<data name="CmdSavedLayoutArgDesc" xml:space="preserve">
|
||||
<value>This parameter is an internal implementation detail and should not be used.</value>
|
||||
</data>
|
||||
<data name="CmdWindowTargetArgDesc" xml:space="preserve">
|
||||
<value>Specify a terminal window to run the given commandline in. "0" always refers to the current window. </value>
|
||||
</data>
|
||||
|
@ -712,10 +718,17 @@
|
|||
<data name="CloseOnExitInfoBar.Message" xml:space="preserve">
|
||||
<value>Termination behavior can be configured in advanced profile settings.</value>
|
||||
</data>
|
||||
<data name="SetAsDefaultInfoBar.Message" xml:space="preserve">
|
||||
<value>Windows Terminal can be set as the default terminal application in your settings.</value>
|
||||
</data>
|
||||
<data name="InfoBarDismissButton.Content" xml:space="preserve">
|
||||
<value>Don't show again</value>
|
||||
</data>
|
||||
<data name="ElevationShield.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>This Terminal window is running as Admin</value>
|
||||
</data>
|
||||
<data name="SetAsDefaultTip_OpenSettingsLink.Content" xml:space="preserve">
|
||||
<value>Open Settings</value>
|
||||
<comment>This is a call-to-action hyperlink; it will open the settings.</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#include "ColorHelper.h"
|
||||
#include "DebugTapConnection.h"
|
||||
#include "SettingsTab.h"
|
||||
#include "..\TerminalSettingsModel\FileUtils.h"
|
||||
|
||||
#include <shlobj.h>
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
|
@ -410,33 +413,45 @@ namespace winrt::TerminalApp::implementation
|
|||
// - tab: tab to export
|
||||
winrt::fire_and_forget TerminalPage::_ExportTab(const TerminalTab& tab)
|
||||
{
|
||||
// This will be used to set up the file picker "filter", to select .txt
|
||||
// files by default.
|
||||
static constexpr COMDLG_FILTERSPEC supportedFileTypes[] = {
|
||||
{ L"Text Files (*.txt)", L"*.txt" },
|
||||
{ L"All Files (*.*)", L"*.*" }
|
||||
};
|
||||
// An arbitrary GUID to associate with all instances of this
|
||||
// dialog, so they all re-open in the same path as they were
|
||||
// open before:
|
||||
static constexpr winrt::guid clientGuidExportFile{ 0xF6AF20BB, 0x0800, 0x48E6, { 0xB0, 0x17, 0xA1, 0x4C, 0xD8, 0x73, 0xDD, 0x58 } };
|
||||
|
||||
try
|
||||
{
|
||||
if (const auto control{ tab.GetActiveTerminalControl() })
|
||||
{
|
||||
const FileSavePicker savePicker;
|
||||
savePicker.as<IInitializeWithWindow>()->Initialize(*_hostingHwnd);
|
||||
savePicker.SuggestedStartLocation(PickerLocationId::Downloads);
|
||||
const auto fileChoices = single_threaded_vector<hstring>({ L".txt" });
|
||||
savePicker.FileTypeChoices().Insert(RS_(L"PlainText"), fileChoices);
|
||||
savePicker.SuggestedFileName(control.Title());
|
||||
// GH#11356 - we can't use the UWP apis for writing the file,
|
||||
// because they don't work elevated (shocker) So just use the
|
||||
// shell32 file picker manually.
|
||||
auto path = co_await SaveFilePicker(*_hostingHwnd, [control](auto&& dialog) {
|
||||
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExportFile));
|
||||
try
|
||||
{
|
||||
// Default to the Downloads folder
|
||||
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_Downloads, KF_FLAG_DEFAULT, nullptr) };
|
||||
dialog->SetDefaultFolder(folderShellItem.get());
|
||||
}
|
||||
CATCH_LOG(); // non-fatal
|
||||
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
|
||||
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
|
||||
THROW_IF_FAILED(dialog->SetDefaultExtension(L"txt"));
|
||||
|
||||
const StorageFile file = co_await savePicker.PickSaveFileAsync();
|
||||
if (file != nullptr)
|
||||
// Default to using the tab title as the file name
|
||||
THROW_IF_FAILED(dialog->SetFileName((control.Title() + L".txt").c_str()));
|
||||
});
|
||||
|
||||
if (!path.empty())
|
||||
{
|
||||
const auto buffer = control.ReadEntireBuffer();
|
||||
CachedFileManager::DeferUpdates(file);
|
||||
co_await FileIO::WriteTextAsync(file, buffer);
|
||||
const auto status = co_await CachedFileManager::CompleteUpdatesAsync(file);
|
||||
switch (status)
|
||||
{
|
||||
case FileUpdateStatus::Complete:
|
||||
case FileUpdateStatus::CompleteAndRenamed:
|
||||
_ShowControlNoticeDialog(RS_(L"NoticeInfo"), RS_(L"ExportSuccess"));
|
||||
break;
|
||||
default:
|
||||
_ShowControlNoticeDialog(RS_(L"NoticeError"), RS_(L"ExportFailure"));
|
||||
}
|
||||
CascadiaSettings::ExportFile(path, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -501,7 +516,9 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
// If we are supposed to save state, make sure we clear it out
|
||||
// if the user manually closed all tabs.
|
||||
if (!_maintainStateOnTabClose && ShouldUsePersistedLayout(_settings))
|
||||
// Do this only if we are the last window; the monarch will notice
|
||||
// we are missing and remove us that way otherwise.
|
||||
if (!_maintainStateOnTabClose && ShouldUsePersistedLayout(_settings) && _numOpenWindows == 1)
|
||||
{
|
||||
auto state = ApplicationState::SharedInstance();
|
||||
state.PersistedWindowLayouts(nullptr);
|
||||
|
@ -734,31 +751,32 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
_UnZoomIfNeeded();
|
||||
|
||||
auto pane = terminalTab->GetActivePane();
|
||||
|
||||
if (const auto pane{ terminalTab->GetActivePane() })
|
||||
{
|
||||
if (const auto control{ pane->GetTerminalControl() })
|
||||
if (pane->ContainsReadOnly())
|
||||
{
|
||||
if (control.ReadOnly())
|
||||
ContentDialogResult warningResult = co_await _ShowCloseReadOnlyDialog();
|
||||
|
||||
// If the user didn't explicitly click on close tab - leave
|
||||
if (warningResult != ContentDialogResult::Primary)
|
||||
{
|
||||
ContentDialogResult warningResult = co_await _ShowCloseReadOnlyDialog();
|
||||
|
||||
// If the user didn't explicitly click on close tab - leave
|
||||
if (warningResult != ContentDialogResult::Primary)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
// Clean read-only mode to prevent additional prompt if closing the pane triggers closing of a hosting tab
|
||||
if (control.ReadOnly())
|
||||
{
|
||||
control.ToggleReadOnly();
|
||||
}
|
||||
co_return;
|
||||
}
|
||||
|
||||
pane->Close();
|
||||
// Clean read-only mode to prevent additional prompt if closing the pane triggers closing of a hosting tab
|
||||
pane->WalkTree([](auto p) {
|
||||
if (const auto control{ p->GetTerminalControl() })
|
||||
{
|
||||
if (control.ReadOnly())
|
||||
{
|
||||
control.ToggleReadOnly();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
pane->Close();
|
||||
}
|
||||
}
|
||||
else if (auto index{ _GetFocusedTabIndex() })
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<mux:TabView.TabStripHeader>
|
||||
<!-- EA18 is the "Shield" glyph -->
|
||||
<FontIcon x:Uid="ElevationShield"
|
||||
Margin="9,4,0,0"
|
||||
Margin="9,4,0,4"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="16"
|
||||
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
|
||||
|
|
|
@ -218,7 +218,7 @@ namespace winrt::TerminalApp::implementation
|
|||
_RegisterActionCallbacks();
|
||||
|
||||
// Hook up inbound connection event handler
|
||||
TerminalConnection::ConptyConnection::NewConnection({ this, &TerminalPage::_OnNewConnection });
|
||||
ConptyConnection::NewConnection({ this, &TerminalPage::_OnNewConnection });
|
||||
|
||||
//Event Bindings (Early)
|
||||
_newTabButton.Click([weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
|
@ -287,6 +287,8 @@ namespace winrt::TerminalApp::implementation
|
|||
_defaultPointerCursor = CoreWindow::GetForCurrentThread().PointerCursor();
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
ShowSetAsDefaultInfoBar();
|
||||
}
|
||||
|
||||
// Method Description;
|
||||
|
@ -298,10 +300,37 @@ namespace winrt::TerminalApp::implementation
|
|||
// - true if the ApplicationState should be used.
|
||||
bool TerminalPage::ShouldUsePersistedLayout(CascadiaSettings& settings) const
|
||||
{
|
||||
// If the setting is enabled, and we are the only window.
|
||||
// GH#5000 Until there is a separate state file for elevated sessions we should just not
|
||||
// save at all while in an elevated window.
|
||||
return Feature_PersistedWindowLayout::IsEnabled() &&
|
||||
settings.GlobalSettings().FirstWindowPreference() == FirstWindowPreference::PersistedWindowLayout &&
|
||||
_numOpenWindows == 1;
|
||||
!IsElevated() &&
|
||||
settings.GlobalSettings().FirstWindowPreference() == FirstWindowPreference::PersistedWindowLayout;
|
||||
}
|
||||
|
||||
// Method Description;
|
||||
// - Checks if the current window is configured to load a particular layout
|
||||
// Arguments:
|
||||
// - settings: The settings to use as this may be called before the page is
|
||||
// fully initialized.
|
||||
// Return Value:
|
||||
// - non-null if there is a particular saved layout to use
|
||||
std::optional<uint32_t> TerminalPage::LoadPersistedLayoutIdx(CascadiaSettings& settings) const
|
||||
{
|
||||
return ShouldUsePersistedLayout(settings) ? _loadFromPersistedLayoutIdx : std::nullopt;
|
||||
}
|
||||
|
||||
WindowLayout TerminalPage::LoadPersistedLayout(CascadiaSettings& settings) const
|
||||
{
|
||||
if (const auto idx = LoadPersistedLayoutIdx(settings))
|
||||
{
|
||||
const auto i = idx.value();
|
||||
const auto layouts = ApplicationState::SharedInstance().PersistedWindowLayouts();
|
||||
if (layouts && layouts.Size() > i)
|
||||
{
|
||||
return layouts.GetAt(i);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TerminalPage::NewTerminalByDrop(winrt::Windows::UI::Xaml::DragEventArgs& e)
|
||||
|
@ -387,30 +416,13 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
_startupState = StartupState::InStartup;
|
||||
|
||||
// If the user selected to save their tab layout, we are the first
|
||||
// window opened, and wt was not run with any other arguments, then
|
||||
// we should use the saved settings.
|
||||
auto firstActionIsDefault = [](ActionAndArgs action) {
|
||||
if (action.Action() != ShortcutAction::NewTab)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If no commands were given, we will have default args
|
||||
if (const auto args = action.Args().try_as<NewTabArgs>())
|
||||
{
|
||||
NewTerminalArgs defaultArgs{};
|
||||
return args.TerminalArgs() == nullptr || args.TerminalArgs().Equals(defaultArgs);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
if (ShouldUsePersistedLayout(_settings) && _startupActions.Size() == 1 && firstActionIsDefault(_startupActions.GetAt(0)))
|
||||
// If we are provided with an index, the cases where we have
|
||||
// commandline args and startup actions are already handled.
|
||||
if (const auto layout = LoadPersistedLayout(_settings))
|
||||
{
|
||||
auto layouts = ApplicationState::SharedInstance().PersistedWindowLayouts();
|
||||
if (layouts && layouts.Size() > 0 && layouts.GetAt(0).TabLayout() && layouts.GetAt(0).TabLayout().Size() > 0)
|
||||
if (layout.TabLayout().Size() > 0)
|
||||
{
|
||||
_startupActions = layouts.GetAt(0).TabLayout();
|
||||
_startupActions = layout.TabLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1289,12 +1301,19 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
// Method Description:
|
||||
// - Saves the window position and tab layout to the application state
|
||||
// - This does not create the InitialPosition field, that needs to be
|
||||
// added externally.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::PersistWindowLayout()
|
||||
// - the window layout
|
||||
WindowLayout TerminalPage::GetWindowLayout()
|
||||
{
|
||||
if (_startupState != StartupState::Initialized)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<ActionAndArgs> actions;
|
||||
|
||||
for (auto tab : _tabs)
|
||||
|
@ -1302,7 +1321,7 @@ namespace winrt::TerminalApp::implementation
|
|||
if (auto terminalTab = _GetTerminalTabImpl(tab))
|
||||
{
|
||||
auto tabActions = terminalTab->BuildStartupActions();
|
||||
actions.insert(actions.end(), tabActions.begin(), tabActions.end());
|
||||
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
|
||||
}
|
||||
else if (tab.try_as<SettingsTab>())
|
||||
{
|
||||
|
@ -1311,7 +1330,7 @@ namespace winrt::TerminalApp::implementation
|
|||
OpenSettingsArgs args{ SettingsTarget::SettingsUI };
|
||||
action.Args(args);
|
||||
|
||||
actions.push_back(action);
|
||||
actions.emplace_back(std::move(action));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1324,7 +1343,18 @@ namespace winrt::TerminalApp::implementation
|
|||
SwitchToTabArgs switchToTabArgs{ idx.value() };
|
||||
action.Args(switchToTabArgs);
|
||||
|
||||
actions.push_back(action);
|
||||
actions.emplace_back(std::move(action));
|
||||
}
|
||||
|
||||
// If the user set a custom name, save it
|
||||
if (_WindowName != L"")
|
||||
{
|
||||
ActionAndArgs action;
|
||||
action.Action(ShortcutAction::RenameWindow);
|
||||
RenameWindowArgs args{ _WindowName };
|
||||
action.Args(args);
|
||||
|
||||
actions.emplace_back(std::move(action));
|
||||
}
|
||||
|
||||
WindowLayout layout{};
|
||||
|
@ -1337,33 +1367,7 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
layout.InitialSize(windowSize);
|
||||
|
||||
if (_hostingHwnd)
|
||||
{
|
||||
// Get the position of the current window. This includes the
|
||||
// non-client already.
|
||||
RECT window{};
|
||||
GetWindowRect(_hostingHwnd.value(), &window);
|
||||
|
||||
// We want to remove the non-client area so calculate that.
|
||||
// We don't have access to the (NonClient)IslandWindow directly so
|
||||
// just replicate the logic.
|
||||
const auto windowStyle = static_cast<DWORD>(GetWindowLong(_hostingHwnd.value(), GWL_STYLE));
|
||||
|
||||
auto dpi = GetDpiForWindow(_hostingHwnd.value());
|
||||
RECT nonClientArea{};
|
||||
LOG_IF_WIN32_BOOL_FALSE(AdjustWindowRectExForDpi(&nonClientArea, windowStyle, false, 0, dpi));
|
||||
|
||||
// The nonClientArea adjustment is negative, so subtract that out.
|
||||
// This way we save the user-visible location of the terminal.
|
||||
LaunchPosition pos{};
|
||||
pos.X = window.left - nonClientArea.left;
|
||||
pos.Y = window.top;
|
||||
|
||||
layout.InitialPosition(pos);
|
||||
}
|
||||
|
||||
auto state = ApplicationState::SharedInstance();
|
||||
state.PersistedWindowLayouts(winrt::single_threaded_vector<WindowLayout>({ layout }));
|
||||
return layout;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -1392,8 +1396,9 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
if (ShouldUsePersistedLayout(_settings))
|
||||
{
|
||||
PersistWindowLayout();
|
||||
// don't delete the ApplicationState when all of the tabs are removed.
|
||||
// Don't delete the ApplicationState when all of the tabs are removed.
|
||||
// If there is still a monarch living they will get the event that
|
||||
// a window closed and trigger a new save without this window.
|
||||
_maintainStateOnTabClose = true;
|
||||
}
|
||||
|
||||
|
@ -2692,52 +2697,40 @@ namespace winrt::TerminalApp::implementation
|
|||
return _isAlwaysOnTop;
|
||||
}
|
||||
|
||||
HRESULT TerminalPage::_OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection)
|
||||
HRESULT TerminalPage::_OnNewConnection(const ConptyConnection& connection)
|
||||
{
|
||||
// We need to be on the UI thread in order for _OpenNewTab to run successfully.
|
||||
// HasThreadAccess will return true if we're currently on a UI thread and false otherwise.
|
||||
// When we're on a COM thread, we'll need to dispatch the calls to the UI thread
|
||||
// and wait on it hence the locking mechanism.
|
||||
if (Dispatcher().HasThreadAccess())
|
||||
{
|
||||
try
|
||||
{
|
||||
NewTerminalArgs newTerminalArgs{};
|
||||
// TODO GH#10952: When we pass the actual commandline (or originating application), the
|
||||
// settings model can choose the right settings based on command matching, or synthesize
|
||||
// a profile from the registry/link settings (TODO GH#9458).
|
||||
// TODO GH#9458: Get and pass the LNK/EXE filenames.
|
||||
// Passing in a commandline forces GetProfileForArgs to use Base Layer instead of Default Profile;
|
||||
// in the future, it can make a better decision based on the value we pull out of the process handle.
|
||||
// TODO GH#5047: When we hang on to the N.T.A., try not to spawn "default... .exe" :)
|
||||
newTerminalArgs.Commandline(L"default-terminal-invocation-placeholder");
|
||||
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
|
||||
const auto settings{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
|
||||
|
||||
_CreateNewTabWithProfileAndSettings(profile, settings, connection);
|
||||
|
||||
// Request a summon of this window to the foreground
|
||||
_SummonWindowRequestedHandlers(*this, nullptr);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
if (!Dispatcher().HasThreadAccess())
|
||||
{
|
||||
til::latch latch{ 1 };
|
||||
HRESULT finalVal = S_OK;
|
||||
|
||||
Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [&]() {
|
||||
// Re-running ourselves under the dispatcher will cause us to take the first branch above.
|
||||
finalVal = _OnNewConnection(connection);
|
||||
|
||||
latch.count_down();
|
||||
});
|
||||
|
||||
latch.wait();
|
||||
return finalVal;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
NewTerminalArgs newTerminalArgs;
|
||||
newTerminalArgs.Commandline(connection.Commandline());
|
||||
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
|
||||
const auto settings{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
|
||||
|
||||
_CreateNewTabWithProfileAndSettings(profile, settings, connection);
|
||||
|
||||
// Request a summon of this window to the foreground
|
||||
_SummonWindowRequestedHandlers(*this, nullptr);
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -2890,6 +2883,30 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Displays a info popup guiding the user into setting their default terminal.
|
||||
void TerminalPage::ShowSetAsDefaultInfoBar() const
|
||||
{
|
||||
if (!CascadiaSettings::IsDefaultTerminalAvailable() || _IsMessageDismissed(InfoBarMessage::SetAsDefault))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the user has already configured any terminal for hand-off we
|
||||
// shouldn't inform them again about the possibility to do so.
|
||||
if (CascadiaSettings::IsDefaultTerminalSet())
|
||||
{
|
||||
_DismissMessage(InfoBarMessage::SetAsDefault);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
|
||||
{
|
||||
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipPresented", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
infoBar.IsOpen(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Helper function to get the OS-localized name for the "Touch Keyboard
|
||||
// and Handwriting Panel Service". If we can't open up the service for any
|
||||
|
@ -3106,6 +3123,11 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
void TerminalPage::SetPersistedLayoutIdx(const uint32_t idx)
|
||||
{
|
||||
_loadFromPersistedLayoutIdx = idx;
|
||||
}
|
||||
|
||||
void TerminalPage::SetNumberOfOpenWindows(const uint64_t num)
|
||||
{
|
||||
_numOpenWindows = num;
|
||||
|
@ -3305,6 +3327,40 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Persists the user's choice not to show the information bar warning about "Windows Terminal can be set as your default terminal application"
|
||||
// Then hides this information buffer.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_SetAsDefaultDismissHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/)
|
||||
{
|
||||
_DismissMessage(InfoBarMessage::SetAsDefault);
|
||||
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
|
||||
{
|
||||
infoBar.IsOpen(false);
|
||||
}
|
||||
|
||||
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipDismissed", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
_FocusCurrentTab(true);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Dismisses the Default Terminal tip and opens the settings.
|
||||
void TerminalPage::_SetAsDefaultOpenSettingsHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/)
|
||||
{
|
||||
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
|
||||
{
|
||||
infoBar.IsOpen(false);
|
||||
}
|
||||
|
||||
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipInteracted", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
_OpenSettingsUI();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Checks whether information bar message was dismissed earlier (in the application state)
|
||||
// Arguments:
|
||||
|
@ -3334,13 +3390,20 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
void TerminalPage::_DismissMessage(const InfoBarMessage& message)
|
||||
{
|
||||
auto dismissedMessages = ApplicationState::SharedInstance().DismissedMessages();
|
||||
if (!dismissedMessages)
|
||||
const auto applicationState = ApplicationState::SharedInstance();
|
||||
std::vector<InfoBarMessage> messages;
|
||||
|
||||
if (const auto values = applicationState.DismissedMessages())
|
||||
{
|
||||
dismissedMessages = winrt::single_threaded_vector<InfoBarMessage>();
|
||||
messages.resize(values.Size());
|
||||
values.GetMany(0, messages);
|
||||
}
|
||||
|
||||
dismissedMessages.Append(message);
|
||||
ApplicationState::SharedInstance().DismissedMessages(dismissedMessages);
|
||||
if (std::none_of(messages.begin(), messages.end(), [&](const auto& m) { return m == message; }))
|
||||
{
|
||||
messages.emplace_back(message);
|
||||
}
|
||||
|
||||
applicationState.DismissedMessages(std::move(messages));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,9 @@ namespace winrt::TerminalApp::implementation
|
|||
void Create();
|
||||
|
||||
bool ShouldUsePersistedLayout(Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const;
|
||||
std::optional<uint32_t> LoadPersistedLayoutIdx(Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const;
|
||||
winrt::Microsoft::Terminal::Settings::Model::WindowLayout LoadPersistedLayout(Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const;
|
||||
Microsoft::Terminal::Settings::Model::WindowLayout GetWindowLayout();
|
||||
|
||||
winrt::fire_and_forget NewTerminalByDrop(winrt::Windows::UI::Xaml::DragEventArgs& e);
|
||||
|
||||
|
@ -82,7 +85,6 @@ namespace winrt::TerminalApp::implementation
|
|||
bool AlwaysOnTop() const;
|
||||
|
||||
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
|
||||
void PersistWindowLayout();
|
||||
|
||||
void SetInboundListener(bool isEmbedding);
|
||||
static std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> ConvertExecuteCommandlineToActions(const Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
|
||||
|
@ -93,6 +95,7 @@ namespace winrt::TerminalApp::implementation
|
|||
winrt::TerminalApp::TaskbarState TaskbarState() const;
|
||||
|
||||
void ShowKeyboardServiceWarning() const;
|
||||
void ShowSetAsDefaultInfoBar() const;
|
||||
winrt::hstring KeyboardServiceDisabledText();
|
||||
|
||||
winrt::fire_and_forget IdentifyWindow();
|
||||
|
@ -111,6 +114,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void WindowId(const uint64_t& value);
|
||||
|
||||
void SetNumberOfOpenWindows(const uint64_t value);
|
||||
void SetPersistedLayoutIdx(const uint32_t value);
|
||||
|
||||
winrt::hstring WindowIdForDisplay() const noexcept;
|
||||
winrt::hstring WindowNameForDisplay() const noexcept;
|
||||
|
@ -133,6 +137,7 @@ namespace winrt::TerminalApp::implementation
|
|||
TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs);
|
||||
TYPED_EVENT(IsQuakeWindowChanged, IInspectable, IInspectable);
|
||||
TYPED_EVENT(SummonWindowRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(CloseRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(OpenSystemMenu, IInspectable, IInspectable);
|
||||
TYPED_EVENT(QuitRequested, IInspectable, IInspectable);
|
||||
|
||||
|
@ -166,6 +171,7 @@ namespace winrt::TerminalApp::implementation
|
|||
bool _isAlwaysOnTop{ false };
|
||||
winrt::hstring _WindowName{};
|
||||
uint64_t _WindowId{ 0 };
|
||||
std::optional<uint32_t> _loadFromPersistedLayoutIdx{};
|
||||
uint64_t _numOpenWindows{ 0 };
|
||||
|
||||
bool _maintainStateOnTabClose{ false };
|
||||
|
@ -257,6 +263,26 @@ namespace winrt::TerminalApp::implementation
|
|||
bool _SwapPane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _MovePane(const uint32_t tabIdx);
|
||||
|
||||
template<typename F>
|
||||
bool _ApplyToActiveControls(F f)
|
||||
{
|
||||
if (const auto tab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (const auto activePane = tab->GetActivePane())
|
||||
{
|
||||
activePane->WalkTree([&](auto p) {
|
||||
if (const auto& control{ p->GetTerminalControl() })
|
||||
{
|
||||
f(control);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl();
|
||||
std::optional<uint32_t> _GetFocusedTabIndex() const noexcept;
|
||||
TerminalApp::TabBase _GetFocusedTab() const noexcept;
|
||||
|
@ -360,9 +386,9 @@ namespace winrt::TerminalApp::implementation
|
|||
void _EndPreviewColorScheme();
|
||||
void _PreviewColorScheme(const Microsoft::Terminal::Settings::Model::SetColorSchemeArgs& args);
|
||||
winrt::Microsoft::Terminal::Settings::Model::Command _lastPreviewedCommand{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Model::TerminalSettings _originalSettings{ nullptr };
|
||||
std::vector<std::function<void()>> _restorePreviewFuncs{};
|
||||
|
||||
HRESULT _OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||
HRESULT _OnNewConnection(const winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection& connection);
|
||||
void _HandleToggleInboundPty(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
|
||||
void _WindowRenamerActionClick(const IInspectable& sender, const IInspectable& eventArgs);
|
||||
|
@ -378,6 +404,8 @@ namespace winrt::TerminalApp::implementation
|
|||
winrt::fire_and_forget _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
||||
void _CloseOnExitInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
||||
void _KeyboardServiceWarningInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
||||
void _SetAsDefaultDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||
void _SetAsDefaultOpenSettingsHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
|
||||
static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace TerminalApp
|
|||
UInt64 WindowId;
|
||||
String WindowNameForDisplay { get; };
|
||||
String WindowIdForDisplay { get; };
|
||||
void SetNumberOfOpenWindows(UInt64 num);
|
||||
void RenameFailed();
|
||||
Boolean IsQuakeWindow();
|
||||
|
||||
|
@ -58,6 +57,7 @@ namespace TerminalApp
|
|||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IsQuakeWindowChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,6 +141,20 @@
|
|||
Click="_CloseOnExitInfoDismissHandler" />
|
||||
</mux:InfoBar.ActionButton>
|
||||
</mux:InfoBar>
|
||||
|
||||
<mux:InfoBar x:Name="SetAsDefaultInfoBar"
|
||||
x:Uid="SetAsDefaultInfoBar"
|
||||
x:Load="False"
|
||||
CloseButtonClick="_SetAsDefaultDismissHandler"
|
||||
IsClosable="True"
|
||||
IsIconVisible="True"
|
||||
IsOpen="False"
|
||||
Severity="Informational">
|
||||
<mux:InfoBar.ActionButton>
|
||||
<HyperlinkButton x:Uid="SetAsDefaultTip_OpenSettingsLink"
|
||||
Click="_SetAsDefaultOpenSettingsHandler" />
|
||||
</mux:InfoBar.ActionButton>
|
||||
</mux:InfoBar>
|
||||
</StackPanel>
|
||||
|
||||
<!--
|
||||
|
|
|
@ -67,8 +67,11 @@ namespace winrt::TerminalApp::implementation
|
|||
_rootPane->FocusPane(firstId);
|
||||
_activePane = _rootPane->GetActivePane();
|
||||
}
|
||||
// Set the active control
|
||||
_mruPanes.insert(_mruPanes.begin(), _activePane->Id().value());
|
||||
// If the focused pane is a leaf, add it to the MRU panes
|
||||
if (const auto id = _activePane->Id())
|
||||
{
|
||||
_mruPanes.insert(_mruPanes.begin(), id.value());
|
||||
}
|
||||
|
||||
_Setup();
|
||||
}
|
||||
|
@ -180,8 +183,8 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
// Method Description:
|
||||
// - Returns nullptr if no children of this tab were the last control to be
|
||||
// focused, or the TermControl that _was_ the last control to be focused (if
|
||||
// there was one).
|
||||
// focused, the active control of the current pane, or the last active child control
|
||||
// of the active pane if it is a parent.
|
||||
// - This control might not currently be focused, if the tab itself is not
|
||||
// currently focused.
|
||||
// Arguments:
|
||||
|
@ -193,7 +196,7 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
if (_activePane)
|
||||
{
|
||||
return _activePane->GetTerminalControl();
|
||||
return _activePane->GetLastFocusedTerminalControl();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -390,6 +393,10 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
return _runtimeTabText;
|
||||
}
|
||||
if (!_activePane->_IsLeaf())
|
||||
{
|
||||
return RS_(L"MultiplePanes");
|
||||
}
|
||||
const auto lastFocusedControl = GetActiveTerminalControl();
|
||||
return lastFocusedControl ? lastFocusedControl.Title() : L"";
|
||||
}
|
||||
|
@ -450,12 +457,25 @@ namespace winrt::TerminalApp::implementation
|
|||
// 1 for the child after the first split.
|
||||
auto state = _rootPane->BuildStartupActions(0, 1);
|
||||
|
||||
ActionAndArgs newTabAction{};
|
||||
newTabAction.Action(ShortcutAction::NewTab);
|
||||
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane() };
|
||||
newTabAction.Args(newTabArgs);
|
||||
{
|
||||
ActionAndArgs newTabAction{};
|
||||
newTabAction.Action(ShortcutAction::NewTab);
|
||||
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane() };
|
||||
newTabAction.Args(newTabArgs);
|
||||
|
||||
state.args.emplace(state.args.begin(), std::move(newTabAction));
|
||||
state.args.emplace(state.args.begin(), std::move(newTabAction));
|
||||
}
|
||||
|
||||
if (_runtimeTabColor)
|
||||
{
|
||||
ActionAndArgs setColorAction{};
|
||||
setColorAction.Action(ShortcutAction::SetTabColor);
|
||||
|
||||
SetTabColorArgs setColorArgs{ _runtimeTabColor.value() };
|
||||
setColorAction.Args(setColorArgs);
|
||||
|
||||
state.args.emplace_back(std::move(setColorAction));
|
||||
}
|
||||
|
||||
// If we only have one arg, we only have 1 pane so we don't need any
|
||||
// special focus logic
|
||||
|
@ -501,19 +521,14 @@ namespace winrt::TerminalApp::implementation
|
|||
// either the first or second child, but this will always return the
|
||||
// original pane first.
|
||||
auto [original, newPane] = _activePane->Split(splitType, splitSize, profile, control);
|
||||
// The active pane has an id if it is a leaf
|
||||
if (activePaneId)
|
||||
{
|
||||
original->Id(activePaneId.value());
|
||||
newPane->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
}
|
||||
else
|
||||
{
|
||||
original->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
newPane->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
}
|
||||
newPane->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
|
||||
_activePane = original;
|
||||
|
||||
// Add a event handlers to the new panes' GotFocus event. When the pane
|
||||
|
@ -538,8 +553,8 @@ namespace winrt::TerminalApp::implementation
|
|||
// - The removed pane, if the remove succeeded.
|
||||
std::shared_ptr<Pane> TerminalTab::DetachPane()
|
||||
{
|
||||
// if we only have one pane, remove it entirely
|
||||
// and close this tab
|
||||
// if we only have one pane, or the focused pane is the root, remove it
|
||||
// entirely and close this tab
|
||||
if (_rootPane == _activePane)
|
||||
{
|
||||
return DetachRoot();
|
||||
|
@ -614,16 +629,12 @@ namespace winrt::TerminalApp::implementation
|
|||
// Add the new pane as an automatic split on the active pane.
|
||||
auto first = _activePane->AttachPane(pane, SplitDirection::Automatic);
|
||||
|
||||
// under current assumptions this condition should always be true.
|
||||
// This will be true if the original _activePane is a leaf pane.
|
||||
// If it is a parent pane then we don't want to set an ID on it.
|
||||
if (previousId)
|
||||
{
|
||||
first->Id(previousId.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
first->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
}
|
||||
|
||||
// Update with event handlers on the new child.
|
||||
_activePane = first;
|
||||
|
@ -699,7 +710,10 @@ namespace winrt::TerminalApp::implementation
|
|||
// throughout the entire tree.
|
||||
if (const auto newFocus = _rootPane->NavigateDirection(_activePane, direction, _mruPanes))
|
||||
{
|
||||
// Mark that we want the active pane to changed
|
||||
_changingActivePane = true;
|
||||
const auto res = _rootPane->FocusPane(newFocus);
|
||||
_changingActivePane = false;
|
||||
|
||||
if (_zoomedPane)
|
||||
{
|
||||
|
@ -722,11 +736,22 @@ namespace winrt::TerminalApp::implementation
|
|||
// - true if two panes were swapped.
|
||||
bool TerminalTab::SwapPane(const FocusDirection& direction)
|
||||
{
|
||||
// You cannot swap panes with the parent/child pane because of the
|
||||
// circular reference.
|
||||
if (direction == FocusDirection::Parent || direction == FocusDirection::Child)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// NOTE: This _must_ be called on the root pane, so that it can propagate
|
||||
// throughout the entire tree.
|
||||
if (auto neighbor = _rootPane->NavigateDirection(_activePane, direction, _mruPanes))
|
||||
{
|
||||
return _rootPane->SwapPanes(_activePane, neighbor);
|
||||
// SwapPanes will refocus the terminal to make sure that it has focus
|
||||
// even after moving.
|
||||
_changingActivePane = true;
|
||||
const auto res = _rootPane->SwapPanes(_activePane, neighbor);
|
||||
_changingActivePane = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -734,7 +759,10 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
bool TerminalTab::FocusPane(const uint32_t id)
|
||||
{
|
||||
return _rootPane->FocusPane(id);
|
||||
_changingActivePane = true;
|
||||
const auto res = _rootPane->FocusPane(id);
|
||||
_changingActivePane = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -1027,7 +1055,7 @@ namespace winrt::TerminalApp::implementation
|
|||
auto weakThis{ get_weak() };
|
||||
std::weak_ptr<Pane> weakPane{ pane };
|
||||
|
||||
auto gotFocusToken = pane->GotFocus([weakThis](std::shared_ptr<Pane> sender) {
|
||||
auto gotFocusToken = pane->GotFocus([weakThis](std::shared_ptr<Pane> sender, WUX::FocusState focus) {
|
||||
// Do nothing if the Tab's lifetime is expired or pane isn't new.
|
||||
auto tab{ weakThis.get() };
|
||||
|
||||
|
@ -1035,8 +1063,20 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
if (sender != tab->_activePane)
|
||||
{
|
||||
tab->_UpdateActivePane(sender);
|
||||
tab->_RecalculateAndApplyTabColor();
|
||||
auto senderIsChild = tab->_activePane->_HasChild(sender);
|
||||
|
||||
// Only move focus if we the program moved focus, or the
|
||||
// user moved with their mouse. This is a problem because a
|
||||
// pane isn't a control itself, and if we have the parent
|
||||
// focused we are fine if the terminal control is focused,
|
||||
// but we don't want to update the active pane.
|
||||
if (!senderIsChild ||
|
||||
(focus == WUX::FocusState::Programmatic && tab->_changingActivePane) ||
|
||||
focus == WUX::FocusState::Pointer)
|
||||
{
|
||||
tab->_UpdateActivePane(sender);
|
||||
tab->_RecalculateAndApplyTabColor();
|
||||
}
|
||||
}
|
||||
tab->_focusState = WUX::FocusState::Programmatic;
|
||||
// This tab has gained focus, remove the bell indicator if it is active
|
||||
|
@ -1071,8 +1111,19 @@ namespace winrt::TerminalApp::implementation
|
|||
tab->Content(tab->_rootPane->GetRootElement());
|
||||
tab->ExitZoom();
|
||||
}
|
||||
|
||||
if (auto pane = weakPane.lock())
|
||||
{
|
||||
// When a parent pane is selected, but one of its children
|
||||
// close out under it we still need to update title/focus information
|
||||
// but the GotFocus handler will rightly see that the _activePane
|
||||
// did not actually change. Triggering
|
||||
if (pane != tab->_activePane && !tab->_activePane->_IsLeaf())
|
||||
{
|
||||
co_await winrt::resume_foreground(tab->Content().Dispatcher());
|
||||
tab->_UpdateActivePane(tab->_activePane);
|
||||
}
|
||||
|
||||
for (auto i = tab->_mruPanes.begin(); i != tab->_mruPanes.end(); ++i)
|
||||
{
|
||||
if (*i == pane->Id())
|
||||
|
@ -1290,11 +1341,13 @@ namespace winrt::TerminalApp::implementation
|
|||
// - The tab's color, if any
|
||||
std::optional<winrt::Windows::UI::Color> TerminalTab::GetTabColor()
|
||||
{
|
||||
const auto currControlColor{ GetActiveTerminalControl().TabColor() };
|
||||
std::optional<winrt::Windows::UI::Color> controlTabColor;
|
||||
if (currControlColor != nullptr)
|
||||
if (const auto& control = GetActiveTerminalControl())
|
||||
{
|
||||
controlTabColor = currControlColor.Value();
|
||||
if (const auto color = control.TabColor())
|
||||
{
|
||||
controlTabColor = color.Value();
|
||||
}
|
||||
}
|
||||
|
||||
// A Tab's color will be the result of layering a variety of sources,
|
||||
|
@ -1407,6 +1460,10 @@ namespace winrt::TerminalApp::implementation
|
|||
// TabViewItem().Background() only sets the color of the tab background
|
||||
// when the TabViewItem is unselected. So we still need to set the other
|
||||
// properties ourselves.
|
||||
//
|
||||
// In GH#11294 we thought we'd still need to set
|
||||
// TabViewItemHeaderBackground manually, but GH#11382 discovered that
|
||||
// Background() was actually okay after all.
|
||||
TabViewItem().Background(deselectedTabBrush);
|
||||
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundSelected"), selectedTabBrush);
|
||||
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPointerOver"), hoverTabBrush);
|
||||
|
@ -1453,6 +1510,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void TerminalTab::_ClearTabBackgroundColor()
|
||||
{
|
||||
winrt::hstring keys[] = {
|
||||
L"TabViewItemHeaderBackground",
|
||||
L"TabViewItemHeaderBackgroundSelected",
|
||||
L"TabViewItemHeaderBackgroundPointerOver",
|
||||
L"TabViewItemHeaderForeground",
|
||||
|
@ -1473,8 +1531,10 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
// Clear out the Background.
|
||||
TabViewItem().Background(nullptr);
|
||||
// GH#11382 DON'T set the background to null. If you do that, then the
|
||||
// tab won't be hit testable at all. Transparent, however, is a totally
|
||||
// valid hit test target. That makes sense.
|
||||
TabViewItem().Background(WUX::Media::SolidColorBrush{ Windows::UI::Colors::Transparent() });
|
||||
|
||||
_RefreshVisualState();
|
||||
_colorCleared();
|
||||
|
@ -1585,6 +1645,11 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
void TerminalTab::EnterZoom()
|
||||
{
|
||||
// Clear the content first, because with parent focusing it is possible
|
||||
// to zoom the root pane, but setting the content will not trigger the
|
||||
// property changed event since it is the same and you would end up with
|
||||
// an empty tab.
|
||||
Content(nullptr);
|
||||
_zoomedPane = _activePane;
|
||||
_rootPane->Maximize(_zoomedPane);
|
||||
// Update the tab header to show the magnifying glass
|
||||
|
@ -1593,6 +1658,7 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
void TerminalTab::ExitZoom()
|
||||
{
|
||||
Content(nullptr);
|
||||
_rootPane->Restore(_zoomedPane);
|
||||
_zoomedPane = nullptr;
|
||||
// Update the tab header to hide the magnifying glass
|
||||
|
@ -1607,13 +1673,34 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
// Method Description:
|
||||
// - Toggle read-only mode on the active pane
|
||||
// - If a parent pane is selected, this will ensure that all children have
|
||||
// the same read-only status.
|
||||
void TerminalTab::TogglePaneReadOnly()
|
||||
{
|
||||
auto control = GetActiveTerminalControl();
|
||||
if (control)
|
||||
{
|
||||
control.ToggleReadOnly();
|
||||
}
|
||||
auto hasReadOnly = false;
|
||||
auto allReadOnly = true;
|
||||
_activePane->WalkTree([&](auto p) {
|
||||
if (const auto& control{ p->GetTerminalControl() })
|
||||
{
|
||||
hasReadOnly |= control.ReadOnly();
|
||||
allReadOnly &= control.ReadOnly();
|
||||
}
|
||||
});
|
||||
_activePane->WalkTree([&](auto p) {
|
||||
if (const auto& control{ p->GetTerminalControl() })
|
||||
{
|
||||
// If all controls have the same read only state then just toggle
|
||||
if (allReadOnly || !hasReadOnly)
|
||||
{
|
||||
control.ToggleReadOnly();
|
||||
}
|
||||
// otherwise set to all read only.
|
||||
else if (!control.ReadOnly())
|
||||
{
|
||||
control.ToggleReadOnly();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -139,6 +139,7 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
bool _receivedKeyDown{ false };
|
||||
bool _iconHidden{ false };
|
||||
bool _changingActivePane{ false };
|
||||
|
||||
winrt::hstring _runtimeTabText{};
|
||||
bool _inRename{ false };
|
||||
|
|
|
@ -99,29 +99,57 @@ static HRESULT _duplicateHandle(const HANDLE in, HANDLE& out) noexcept
|
|||
// from the registered handler event function.
|
||||
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client)
|
||||
{
|
||||
// Stash a local copy of _pfnHandoff before we stop listening.
|
||||
auto localPfnHandoff = _pfnHandoff;
|
||||
try
|
||||
{
|
||||
// Stash a local copy of _pfnHandoff before we stop listening.
|
||||
auto localPfnHandoff = _pfnHandoff;
|
||||
|
||||
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
|
||||
// COM does not automatically clean that up for us. We must do it.
|
||||
s_StopListening();
|
||||
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
|
||||
// COM does not automatically clean that up for us. We must do it.
|
||||
s_StopListening();
|
||||
|
||||
std::unique_lock lock{ _mtx };
|
||||
std::unique_lock lock{ _mtx };
|
||||
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
THROW_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
|
||||
|
||||
// Duplicate the handles from what we received.
|
||||
// The contract with COM specifies that any HANDLEs we receive from the caller belong
|
||||
// to the caller and will be freed when we leave the scope of this method.
|
||||
// Making our own duplicate copy ensures they hang around in our lifetime.
|
||||
RETURN_IF_FAILED(_duplicateHandle(in, in));
|
||||
RETURN_IF_FAILED(_duplicateHandle(out, out));
|
||||
RETURN_IF_FAILED(_duplicateHandle(signal, signal));
|
||||
RETURN_IF_FAILED(_duplicateHandle(ref, ref));
|
||||
RETURN_IF_FAILED(_duplicateHandle(server, server));
|
||||
RETURN_IF_FAILED(_duplicateHandle(client, client));
|
||||
// Duplicate the handles from what we received.
|
||||
// The contract with COM specifies that any HANDLEs we receive from the caller belong
|
||||
// to the caller and will be freed when we leave the scope of this method.
|
||||
// Making our own duplicate copy ensures they hang around in our lifetime.
|
||||
THROW_IF_FAILED(_duplicateHandle(in, in));
|
||||
THROW_IF_FAILED(_duplicateHandle(out, out));
|
||||
THROW_IF_FAILED(_duplicateHandle(signal, signal));
|
||||
THROW_IF_FAILED(_duplicateHandle(ref, ref));
|
||||
THROW_IF_FAILED(_duplicateHandle(server, server));
|
||||
THROW_IF_FAILED(_duplicateHandle(client, client));
|
||||
|
||||
// Call registered handler from when we started listening.
|
||||
return localPfnHandoff(in, out, signal, ref, server, client);
|
||||
// Call registered handler from when we started listening.
|
||||
THROW_IF_FAILED(localPfnHandoff(in, out, signal, ref, server, client));
|
||||
|
||||
#pragma warning(suppress : 26477)
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalConnectionProvider,
|
||||
"ReceiveTerminalHandoff_Success",
|
||||
TraceLoggingDescription("successfully received a terminal handoff"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
const auto hr = wil::ResultFromCaughtException();
|
||||
|
||||
#pragma warning(suppress : 26477)
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalConnectionProvider,
|
||||
"ReceiveTerminalHandoff_Failed",
|
||||
TraceLoggingDescription("failed while receiving a terminal handoff"),
|
||||
TraceLoggingHResult(hr),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "ConptyConnection.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <userenv.h>
|
||||
#include <UserEnv.h>
|
||||
#include <winternl.h>
|
||||
|
||||
#include "ConptyConnection.g.cpp"
|
||||
#include "CTerminalHandoff.h"
|
||||
|
@ -276,24 +276,18 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||
const HANDLE hClientProcess) :
|
||||
_initialRows{ 25 },
|
||||
_initialCols{ 80 },
|
||||
_commandline{ L"" },
|
||||
_startingDirectory{ L"" },
|
||||
_startingTitle{ L"" },
|
||||
_environment{ nullptr },
|
||||
_guid{},
|
||||
_u8State{},
|
||||
_u16Str{},
|
||||
_buffer{},
|
||||
_guid{ Utils::CreateGuid() },
|
||||
_inPipe{ hIn },
|
||||
_outPipe{ hOut }
|
||||
{
|
||||
THROW_IF_FAILED(ConptyPackPseudoConsole(hServerProcess, hRef, hSig, &_hPC));
|
||||
if (_guid == guid{})
|
||||
{
|
||||
_guid = Utils::CreateGuid();
|
||||
}
|
||||
|
||||
_piClient.hProcess = hClientProcess;
|
||||
|
||||
try
|
||||
{
|
||||
_commandline = _commandlineFromProcess(hClientProcess);
|
||||
}
|
||||
CATCH_LOG()
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
|
@ -355,6 +349,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||
return _guid;
|
||||
}
|
||||
|
||||
winrt::hstring ConptyConnection::Commandline() const
|
||||
{
|
||||
return _commandline;
|
||||
}
|
||||
|
||||
void ConptyConnection::Start()
|
||||
try
|
||||
{
|
||||
|
@ -560,6 +559,38 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||
}
|
||||
CATCH_LOG()
|
||||
|
||||
// Returns the command line of the given process.
|
||||
// Requires PROCESS_BASIC_INFORMATION | PROCESS_VM_READ privileges.
|
||||
winrt::hstring ConptyConnection::_commandlineFromProcess(HANDLE process)
|
||||
{
|
||||
struct PROCESS_BASIC_INFORMATION
|
||||
{
|
||||
NTSTATUS ExitStatus;
|
||||
PPEB PebBaseAddress;
|
||||
ULONG_PTR AffinityMask;
|
||||
KPRIORITY BasePriority;
|
||||
ULONG_PTR UniqueProcessId;
|
||||
ULONG_PTR InheritedFromUniqueProcessId;
|
||||
} info;
|
||||
THROW_IF_NTSTATUS_FAILED(NtQueryInformationProcess(process, ProcessBasicInformation, &info, sizeof(info), nullptr));
|
||||
|
||||
// PEB: Process Environment Block
|
||||
// This is a funny structure allocated by the kernel which contains all sorts of useful
|
||||
// information, only a tiny fraction of which are documented publicly unfortunately.
|
||||
// Fortunately however it contains a copy of the command line the process launched with.
|
||||
PEB peb;
|
||||
THROW_IF_WIN32_BOOL_FALSE(ReadProcessMemory(process, info.PebBaseAddress, &peb, sizeof(peb), nullptr));
|
||||
|
||||
RTL_USER_PROCESS_PARAMETERS params;
|
||||
THROW_IF_WIN32_BOOL_FALSE(ReadProcessMemory(process, peb.ProcessParameters, ¶ms, sizeof(params), nullptr));
|
||||
|
||||
// Yeah I know... Don't use "impl" stuff... But why do you make something _that_ useful private? :(
|
||||
// The hstring_builder allows us to create a hstring without intermediate copies. Neat!
|
||||
winrt::impl::hstring_builder commandline{ params.CommandLine.Length / 2u };
|
||||
THROW_IF_WIN32_BOOL_FALSE(ReadProcessMemory(process, params.CommandLine.Buffer, commandline.data(), params.CommandLine.Length, nullptr));
|
||||
return commandline.to_hstring();
|
||||
}
|
||||
|
||||
DWORD ConptyConnection::_OutputThread()
|
||||
{
|
||||
// Keep us alive until the output thread terminates; the destructor
|
||||
|
@ -636,8 +667,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||
HRESULT ConptyConnection::NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept
|
||||
try
|
||||
{
|
||||
auto conn = winrt::make<implementation::ConptyConnection>(signal, in, out, ref, server, client);
|
||||
_newConnectionHandlers(conn);
|
||||
_newConnectionHandlers(winrt::make<ConptyConnection>(signal, in, out, ref, server, client));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||
void ClearBuffer();
|
||||
|
||||
winrt::guid Guid() const noexcept;
|
||||
winrt::hstring Commandline() const;
|
||||
|
||||
static void StartInboundListener();
|
||||
static void StopInboundListener();
|
||||
|
@ -56,12 +57,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||
WINRT_CALLBACK(TerminalOutput, TerminalOutputHandler);
|
||||
|
||||
private:
|
||||
static HRESULT NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept;
|
||||
static winrt::hstring _commandlineFromProcess(HANDLE process);
|
||||
|
||||
HRESULT _LaunchAttachedClient() noexcept;
|
||||
void _indicateExitWithStatus(unsigned int status) noexcept;
|
||||
void _ClientTerminated() noexcept;
|
||||
|
||||
static HRESULT NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept;
|
||||
|
||||
uint32_t _initialRows{};
|
||||
uint32_t _initialCols{};
|
||||
hstring _commandline{};
|
||||
|
|
|
@ -5,10 +5,13 @@ import "ITerminalConnection.idl";
|
|||
|
||||
namespace Microsoft.Terminal.TerminalConnection
|
||||
{
|
||||
delegate void NewConnectionHandler(ConptyConnection connection);
|
||||
|
||||
[default_interface] runtimeclass ConptyConnection : ITerminalConnection
|
||||
{
|
||||
ConptyConnection();
|
||||
Guid Guid { get; };
|
||||
String Commandline { get; };
|
||||
void ClearBuffer();
|
||||
|
||||
static event NewConnectionHandler NewConnection;
|
||||
|
|
|
@ -29,6 +29,4 @@ namespace Microsoft.Terminal.TerminalConnection
|
|||
event Windows.Foundation.TypedEventHandler<ITerminalConnection, Object> StateChanged;
|
||||
ConnectionState State { get; };
|
||||
};
|
||||
|
||||
delegate void NewConnectionHandler(ITerminalConnection connection);
|
||||
}
|
||||
|
|
|
@ -274,10 +274,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_updateAntiAliasingMode(_renderEngine.get());
|
||||
|
||||
// GH#5098: Inform the engine of the opacity of the default text background.
|
||||
if (_settings.UseAcrylic())
|
||||
{
|
||||
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.Opacity()));
|
||||
}
|
||||
// GH#11315: Always do this, even if they don't have acrylic on.
|
||||
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.Opacity()));
|
||||
|
||||
THROW_IF_FAILED(_renderEngine->Enable());
|
||||
|
||||
|
@ -444,6 +442,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
Opacity(newOpacity);
|
||||
|
||||
// GH#11285 - If the user is on Windows 10, and they changed the
|
||||
// transparency of the control s.t. it should be partially opaque, then
|
||||
// opt them in to acrylic. It's the only way to have transparency on
|
||||
// Windows 10.
|
||||
// We'll also turn the acrylic back off when they're fully opaque, which
|
||||
// is what the Terminal did prior to 1.12.
|
||||
if (!IsVintageOpacityAvailable())
|
||||
{
|
||||
_settings.UseAcrylic(newOpacity < 1.0);
|
||||
}
|
||||
|
||||
auto eventArgs = winrt::make_self<TransparencyChangedEventArgs>(newOpacity);
|
||||
_TransparencyChangedHandlers(*this, *eventArgs);
|
||||
}
|
||||
|
@ -469,6 +478,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
{
|
||||
_renderEngine->ToggleShaderEffects();
|
||||
}
|
||||
// Always redraw after toggling effects. This way even if the control
|
||||
// does not have focus it will update immediately.
|
||||
_renderer->TriggerRedrawAll();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -570,6 +582,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_settings = settings;
|
||||
|
||||
_runtimeOpacity = std::nullopt;
|
||||
_runtimeUseAcrylic = std::nullopt;
|
||||
|
||||
// GH#11285 - If the user is on Windows 10, and they wanted opacity, but
|
||||
// didn't explicitly request acrylic, then opt them in to acrylic.
|
||||
// On Windows 11+, this isn't needed, because we can have vintage opacity.
|
||||
if (!IsVintageOpacityAvailable() && _settings.Opacity() < 1.0 && !_settings.UseAcrylic())
|
||||
{
|
||||
_runtimeUseAcrylic = true;
|
||||
}
|
||||
|
||||
// Initialize our font information.
|
||||
const auto fontFace = _settings.FontFace();
|
||||
|
@ -1026,7 +1047,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
TerminalConnection::ConnectionState ControlCore::ConnectionState() const
|
||||
{
|
||||
return _connection.State();
|
||||
return _connection ? _connection.State() : TerminalConnection::ConnectionState::Closed;
|
||||
}
|
||||
|
||||
hstring ControlCore::Title()
|
||||
|
@ -1546,4 +1567,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
return hstring(ss.str());
|
||||
}
|
||||
|
||||
// Helper to check if we're on Windows 11 or not. This is used to check if
|
||||
// we need to use acrylic to achieve transparency, because vintage opacity
|
||||
// doesn't work in islands on win10.
|
||||
// Remove when we can remove the rest of GH#11285
|
||||
bool ControlCore::IsVintageOpacityAvailable() noexcept
|
||||
{
|
||||
OSVERSIONINFOEXW osver{};
|
||||
osver.dwOSVersionInfoSize = sizeof(osver);
|
||||
osver.dwBuildNumber = 22000;
|
||||
|
||||
DWORDLONG dwlConditionMask = 0;
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
|
||||
|
||||
return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,7 +158,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
hstring ReadEntireBuffer() const;
|
||||
|
||||
static bool IsVintageOpacityAvailable() noexcept;
|
||||
|
||||
RUNTIME_SETTING(double, Opacity, _settings.Opacity());
|
||||
RUNTIME_SETTING(bool, UseAcrylic, _settings.UseAcrylic());
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// clang-format off
|
||||
|
|
|
@ -43,6 +43,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
{
|
||||
_controlPadding = padding;
|
||||
}
|
||||
void InteractivityAutomationPeer::ParentProvider(AutomationPeer parentProvider)
|
||||
{
|
||||
_parentProvider = parentProvider;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the terminal's selection has
|
||||
|
@ -110,30 +114,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// ScreenInfoUiaProvider doesn't actually use parameter, so just pass in nullptr
|
||||
THROW_IF_FAILED(_uiaProvider->RangeFromChild(/* IRawElementProviderSimple */ nullptr,
|
||||
&returnVal));
|
||||
|
||||
const auto parentProvider = this->ProviderFromPeer(*this);
|
||||
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
|
||||
return xutr.as<XamlAutomation::ITextRangeProvider>();
|
||||
return _CreateXamlUiaTextRange(returnVal);
|
||||
}
|
||||
|
||||
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::RangeFromPoint(Windows::Foundation::Point screenLocation)
|
||||
{
|
||||
UIA::ITextRangeProvider* returnVal;
|
||||
THROW_IF_FAILED(_uiaProvider->RangeFromPoint({ screenLocation.X, screenLocation.Y }, &returnVal));
|
||||
|
||||
const auto parentProvider = this->ProviderFromPeer(*this);
|
||||
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
|
||||
return xutr.as<XamlAutomation::ITextRangeProvider>();
|
||||
return _CreateXamlUiaTextRange(returnVal);
|
||||
}
|
||||
|
||||
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::DocumentRange()
|
||||
{
|
||||
UIA::ITextRangeProvider* returnVal;
|
||||
THROW_IF_FAILED(_uiaProvider->get_DocumentRange(&returnVal));
|
||||
|
||||
const auto parentProvider = this->ProviderFromPeer(*this);
|
||||
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
|
||||
return xutr.as<XamlAutomation::ITextRangeProvider>();
|
||||
return _CreateXamlUiaTextRange(returnVal);
|
||||
}
|
||||
|
||||
XamlAutomation::SupportedTextSelection InteractivityAutomationPeer::SupportedTextSelection()
|
||||
|
@ -180,6 +175,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
}
|
||||
#pragma endregion
|
||||
|
||||
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::_CreateXamlUiaTextRange(UIA::ITextRangeProvider* returnVal) const
|
||||
{
|
||||
// LOAD-BEARING: use _parentProvider->ProviderFromPeer(_parentProvider) instead of this->ProviderFromPeer(*this).
|
||||
// Since we split the automation peer into TermControlAutomationPeer and InteractivityAutomationPeer,
|
||||
// using "this" returns null. This can cause issues with some UIA Client scenarios like any navigation in Narrator.
|
||||
const auto parent{ _parentProvider.get() };
|
||||
if (!parent)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parent.ProviderFromPeer(parent));
|
||||
return xutr.as<XamlAutomation::ITextRangeProvider>();
|
||||
};
|
||||
|
||||
// Method Description:
|
||||
// - extracts the UiaTextRanges from the SAFEARRAY and converts them to Xaml ITextRangeProviders
|
||||
// Arguments:
|
||||
|
@ -194,11 +203,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
std::vector<XamlAutomation::ITextRangeProvider> vec;
|
||||
vec.reserve(count);
|
||||
auto parentProvider = this->ProviderFromPeer(*this);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
auto xutr = make_self<XamlUiaTextRange>(providers[i].detach(), parentProvider);
|
||||
vec.emplace_back(xutr.as<XamlAutomation::ITextRangeProvider>());
|
||||
if (auto xutr = _CreateXamlUiaTextRange(providers[i].detach()))
|
||||
{
|
||||
vec.emplace_back(std::move(xutr));
|
||||
}
|
||||
}
|
||||
|
||||
com_array<XamlAutomation::ITextRangeProvider> result{ vec };
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
void SetControlBounds(const Windows::Foundation::Rect bounds);
|
||||
void SetControlPadding(const Core::Padding padding);
|
||||
void ParentProvider(Windows::UI::Xaml::Automation::Peers::AutomationPeer parentProvider);
|
||||
|
||||
#pragma region IUiaEventDispatcher
|
||||
void SignalSelectionChanged() override;
|
||||
|
@ -74,8 +75,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
TYPED_EVENT(CursorChanged, IInspectable, IInspectable);
|
||||
|
||||
private:
|
||||
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider _CreateXamlUiaTextRange(::ITextRangeProvider* returnVal) const;
|
||||
|
||||
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
|
||||
winrt::Microsoft::Terminal::Control::implementation::ControlInteractivity* _interactivity;
|
||||
weak_ref<Windows::UI::Xaml::Automation::Peers::AutomationPeer> _parentProvider;
|
||||
|
||||
til::rectangle _controlBounds{};
|
||||
til::rectangle _controlPadding{};
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Microsoft.Terminal.Control
|
||||
{
|
||||
[default_interface] runtimeclass InteractivityAutomationPeer :
|
||||
|
@ -10,6 +9,7 @@ namespace Microsoft.Terminal.Control
|
|||
|
||||
void SetControlBounds(Windows.Foundation.Rect bounds);
|
||||
void SetControlPadding(Microsoft.Terminal.Core.Padding padding);
|
||||
void ParentProvider(Windows.UI.Xaml.Automation.Peers.AutomationPeer parentProvider);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SelectionChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TextChanged;
|
||||
|
|
|
@ -454,7 +454,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
}
|
||||
|
||||
// GH#5098: Inform the engine of the new opacity of the default text background.
|
||||
_core.SetBackgroundOpacity(::base::saturated_cast<float>(_core.Opacity()));
|
||||
//
|
||||
// TODO! This sure seems contrived, shouldn't the core... already
|
||||
// know this?
|
||||
_core.SetBackgroundOpacity(_core.Opacity());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_contentAutomationPeer.SelectionChanged([this](auto&&, auto&&) { SignalSelectionChanged(); });
|
||||
_contentAutomationPeer.TextChanged([this](auto&&, auto&&) { SignalTextChanged(); });
|
||||
_contentAutomationPeer.CursorChanged([this](auto&&, auto&&) { SignalCursorChanged(); });
|
||||
_contentAutomationPeer.ParentProvider(*this);
|
||||
};
|
||||
|
||||
// Method Description:
|
||||
|
@ -226,30 +227,4 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// Method Description:
|
||||
// - extracts the UiaTextRanges from the SAFEARRAY and converts them to Xaml ITextRangeProviders
|
||||
// Arguments:
|
||||
// - SAFEARRAY of UIA::UiaTextRange (ITextRangeProviders)
|
||||
// Return Value:
|
||||
// - com_array of Xaml Wrapped UiaTextRange (ITextRangeProviders)
|
||||
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges)
|
||||
{
|
||||
// transfer ownership of UiaTextRanges to this new vector
|
||||
auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges);
|
||||
int count = gsl::narrow<int>(providers.size());
|
||||
|
||||
std::vector<XamlAutomation::ITextRangeProvider> vec;
|
||||
vec.reserve(count);
|
||||
auto parentProvider = this->ProviderFromPeer(*this);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
auto xutr = make_self<XamlUiaTextRange>(providers[i].detach(), parentProvider);
|
||||
vec.emplace_back(xutr.as<XamlAutomation::ITextRangeProvider>());
|
||||
}
|
||||
|
||||
com_array<XamlAutomation::ITextRangeProvider> result{ vec };
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,5 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
private:
|
||||
winrt::Microsoft::Terminal::Control::implementation::TermControl* _termControl;
|
||||
Control::InteractivityAutomationPeer _contentAutomationPeer;
|
||||
|
||||
winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "../types/TermControlUiaTextRange.hpp"
|
||||
#include <UIAutomationClient.h>
|
||||
#include <UIAutomationCoreApi.h>
|
||||
#include "../types/UiaTracing.h"
|
||||
|
||||
// the same as COR_E_NOTSUPPORTED
|
||||
// we don't want to import the CLR headers to get it
|
||||
|
@ -182,6 +183,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
XamlAutomation::IRawElementProviderSimple XamlUiaTextRange::GetEnclosingElement()
|
||||
{
|
||||
::Microsoft::Console::Types::UiaTracing::TextRange::GetEnclosingElement(*static_cast<::Microsoft::Console::Types::UiaTextRangeBase*>(_uiaProvider.get()));
|
||||
return _parentProvider;
|
||||
}
|
||||
|
||||
|
|
228
src/cascadia/TerminalCore/ColorFix.cpp
Normal file
228
src/cascadia/TerminalCore/ColorFix.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// A lot of code was taken from
|
||||
// https://github.com/Maximus5/ConEmu/blob/master/src/ConEmu/ColorFix.cpp
|
||||
// and then adjusted to fit our style guidelines
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include "ColorFix.hpp"
|
||||
|
||||
static constexpr double gMinThreshold = 12.0;
|
||||
static constexpr double gExpThreshold = 20.0;
|
||||
static constexpr double gLStep = 5.0;
|
||||
|
||||
static constexpr double rad006 = 0.104719755119659774;
|
||||
static constexpr double rad025 = 0.436332312998582394;
|
||||
static constexpr double rad030 = 0.523598775598298873;
|
||||
static constexpr double rad060 = 1.047197551196597746;
|
||||
static constexpr double rad063 = 1.099557428756427633;
|
||||
static constexpr double rad180 = 3.141592653589793238;
|
||||
static constexpr double rad275 = 4.799655442984406336;
|
||||
static constexpr double rad360 = 6.283185307179586476;
|
||||
|
||||
ColorFix::ColorFix(COLORREF color)
|
||||
{
|
||||
rgb = color;
|
||||
_ToLab();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper function to calculate HPrime
|
||||
double ColorFix::_GetHPrimeFn(double x, double y)
|
||||
{
|
||||
if (x == 0 && y == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto hueAngle = atan2(x, y);
|
||||
return hueAngle >= 0 ? hueAngle : hueAngle + rad360;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Given 2 colors, computes the DeltaE value between them
|
||||
// Arguments:
|
||||
// - x1: the first color
|
||||
// - x2: the second color
|
||||
// Return Value:
|
||||
// - The DeltaE value between x1 and x2
|
||||
double ColorFix::_GetDeltaE(ColorFix x1, ColorFix x2)
|
||||
{
|
||||
constexpr double kSubL = 1;
|
||||
constexpr double kSubC = 1;
|
||||
constexpr double kSubH = 1;
|
||||
|
||||
// Delta L Prime
|
||||
const double deltaLPrime = x2.L - x1.L;
|
||||
|
||||
// L Bar
|
||||
const double lBar = (x1.L + x2.L) / 2;
|
||||
|
||||
// C1 & C2
|
||||
const double c1 = sqrt(pow(x1.A, 2) + pow(x1.B, 2));
|
||||
const double c2 = sqrt(pow(x2.A, 2) + pow(x2.B, 2));
|
||||
|
||||
// C Bar
|
||||
const double cBar = (c1 + c2) / 2;
|
||||
|
||||
// A Prime 1
|
||||
const double aPrime1 = x1.A + (x1.A / 2) * (1 - sqrt(pow(cBar, 7) / (pow(cBar, 7) + pow(25.0, 7))));
|
||||
|
||||
// A Prime 2
|
||||
const double aPrime2 = x2.A + (x2.A / 2) * (1 - sqrt(pow(cBar, 7) / (pow(cBar, 7) + pow(25.0, 7))));
|
||||
|
||||
// C Prime 1
|
||||
const double cPrime1 = sqrt(pow(aPrime1, 2) + pow(x1.B, 2));
|
||||
|
||||
// C Prime 2
|
||||
const double cPrime2 = sqrt(pow(aPrime2, 2) + pow(x2.B, 2));
|
||||
|
||||
// C Bar Prime
|
||||
const double cBarPrime = (cPrime1 + cPrime2) / 2;
|
||||
|
||||
// Delta C Prime
|
||||
const double deltaCPrime = cPrime2 - cPrime1;
|
||||
|
||||
// S sub L
|
||||
const double sSubL = 1 + ((0.015 * pow(lBar - 50, 2)) / sqrt(20 + pow(lBar - 50, 2)));
|
||||
|
||||
// S sub C
|
||||
const double sSubC = 1 + 0.045 * cBarPrime;
|
||||
|
||||
// h Prime 1
|
||||
const double hPrime1 = _GetHPrimeFn(x1.B, aPrime1);
|
||||
|
||||
// h Prime 2
|
||||
const double hPrime2 = _GetHPrimeFn(x2.B, aPrime2);
|
||||
|
||||
// Delta H Prime
|
||||
const double deltaHPrime = 0 == c1 || 0 == c2 ? 0 : 2 * sqrt(cPrime1 * cPrime2) * sin(abs(hPrime1 - hPrime2) <= rad180 ? hPrime2 - hPrime1 : (hPrime2 <= hPrime1 ? hPrime2 - hPrime1 + rad360 : hPrime2 - hPrime1 - rad360) / 2);
|
||||
|
||||
// H Bar Prime
|
||||
const double hBarPrime = (abs(hPrime1 - hPrime2) > rad180) ? (hPrime1 + hPrime2 + rad360) / 2 : (hPrime1 + hPrime2) / 2;
|
||||
|
||||
// T
|
||||
const double t = 1 - 0.17 * cos(hBarPrime - rad030) + 0.24 * cos(2 * hBarPrime) + 0.32 * cos(3 * hBarPrime + rad006) - 0.20 * cos(4 * hBarPrime - rad063);
|
||||
|
||||
// S sub H
|
||||
const double sSubH = 1 + 0.015 * cBarPrime * t;
|
||||
|
||||
// R sub T
|
||||
const double rSubT = -2 * sqrt(pow(cBarPrime, 7) / (pow(cBarPrime, 7) + pow(25.0, 7))) * sin(rad060 * exp(-pow((hBarPrime - rad275) / rad025, 2)));
|
||||
|
||||
// Put it all together!
|
||||
const double lightness = deltaLPrime / (kSubL * sSubL);
|
||||
const double chroma = deltaCPrime / (kSubC * sSubC);
|
||||
const double hue = deltaHPrime / (kSubH * sSubH);
|
||||
|
||||
return sqrt(pow(lightness, 2) + pow(chroma, 2) + pow(hue, 2) + rSubT * chroma * hue);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Populates our L, A, B values, based on our r, g, b values
|
||||
// - Converts a color in rgb format to a color in lab format
|
||||
// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1
|
||||
void ColorFix::_ToLab()
|
||||
{
|
||||
double var_R = r / 255.0;
|
||||
double var_G = g / 255.0;
|
||||
double var_B = b / 255.0;
|
||||
|
||||
var_R = var_R > 0.04045 ? pow(((var_R + 0.055) / 1.055), 2.4) : var_R / 12.92;
|
||||
var_G = var_G > 0.04045 ? pow(((var_G + 0.055) / 1.055), 2.4) : var_G / 12.92;
|
||||
var_B = var_B > 0.04045 ? pow(((var_B + 0.055) / 1.055), 2.4) : var_B / 12.92;
|
||||
|
||||
var_R = var_R * 100.;
|
||||
var_G = var_G * 100.;
|
||||
var_B = var_B * 100.;
|
||||
|
||||
//Observer. = 2 degrees, Illuminant = D65
|
||||
const double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;
|
||||
const double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;
|
||||
const double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;
|
||||
|
||||
double var_X = X / 95.047; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65)
|
||||
double var_Y = Y / 100.000; //ref_Y = 100.000
|
||||
double var_Z = Z / 108.883; //ref_Z = 108.883
|
||||
|
||||
var_X = var_X > 0.008856 ? pow(var_X, (1. / 3.)) : (7.787 * var_X) + (16. / 116.);
|
||||
var_Y = var_Y > 0.008856 ? pow(var_Y, (1. / 3.)) : (7.787 * var_Y) + (16. / 116.);
|
||||
var_Z = var_Z > 0.008856 ? pow(var_Z, (1. / 3.)) : (7.787 * var_Z) + (16. / 116.);
|
||||
|
||||
L = (116. * var_Y) - 16.;
|
||||
A = 500. * (var_X - var_Y);
|
||||
B = 200. * (var_Y - var_Z);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Populates our r, g, b values, based on our L, A, B values
|
||||
// - Converts a color in lab format to a color in rgb format
|
||||
// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1
|
||||
void ColorFix::_ToRGB()
|
||||
{
|
||||
double var_Y = (L + 16.) / 116.;
|
||||
double var_X = A / 500. + var_Y;
|
||||
double var_Z = var_Y - B / 200.;
|
||||
|
||||
var_Y = (pow(var_Y, 3) > 0.008856) ? pow(var_Y, 3) : (var_Y - 16. / 116.) / 7.787;
|
||||
var_X = (pow(var_X, 3) > 0.008856) ? pow(var_X, 3) : (var_X - 16. / 116.) / 7.787;
|
||||
var_Z = (pow(var_Z, 3) > 0.008856) ? pow(var_Z, 3) : (var_Z - 16. / 116.) / 7.787;
|
||||
|
||||
double X = 95.047 * var_X; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65)
|
||||
double Y = 100.000 * var_Y; //ref_Y = 100.000
|
||||
double Z = 108.883 * var_Z; //ref_Z = 108.883
|
||||
|
||||
var_X = X / 100.; //X from 0 to 95.047 (Observer = 2 degrees, Illuminant = D65)
|
||||
var_Y = Y / 100.; //Y from 0 to 100.000
|
||||
var_Z = Z / 100.; //Z from 0 to 108.883
|
||||
|
||||
double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986;
|
||||
double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415;
|
||||
double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570;
|
||||
|
||||
var_R = var_R > 0.0031308 ? 1.055 * pow(var_R, (1 / 2.4)) - 0.055 : var_R = 12.92 * var_R;
|
||||
var_G = var_G > 0.0031308 ? 1.055 * pow(var_G, (1 / 2.4)) - 0.055 : var_G = 12.92 * var_G;
|
||||
var_B = var_B > 0.0031308 ? 1.055 * pow(var_B, (1 / 2.4)) - 0.055 : var_B = 12.92 * var_B;
|
||||
|
||||
r = (BYTE)std::clamp(var_R * 255., 0., 255.);
|
||||
g = (BYTE)std::clamp(var_G * 255., 0., 255.);
|
||||
b = (BYTE)std::clamp(var_B * 255., 0., 255.);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Given foreground and background colors, change the foreground color to
|
||||
// make it more perceivable if necessary
|
||||
// - Arguments:
|
||||
// - fg: the foreground color
|
||||
// - bg: the background color
|
||||
// - Return Value:
|
||||
// - The foreground color after performing any necessary changes to make it more perceivable
|
||||
COLORREF ColorFix::GetPerceivableColor(COLORREF fg, COLORREF bg)
|
||||
{
|
||||
ColorFix backLab(bg);
|
||||
ColorFix frontLab(fg);
|
||||
const double de1 = _GetDeltaE(frontLab, backLab);
|
||||
if (de1 < gMinThreshold)
|
||||
{
|
||||
for (int i = 0; i <= 1; i++)
|
||||
{
|
||||
const double step = (i == 0) ? gLStep : -gLStep;
|
||||
frontLab.L += step;
|
||||
|
||||
while (((i == 0) && (frontLab.L <= 100)) || ((i == 1) && (frontLab.L >= 0)))
|
||||
{
|
||||
const double de2 = _GetDeltaE(frontLab, backLab);
|
||||
if (de2 >= gExpThreshold)
|
||||
{
|
||||
frontLab._ToRGB();
|
||||
return frontLab.rgb;
|
||||
}
|
||||
frontLab.L += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
return frontLab.rgb;
|
||||
}
|
49
src/cascadia/TerminalCore/ColorFix.hpp
Normal file
49
src/cascadia/TerminalCore/ColorFix.hpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- ColorFix
|
||||
|
||||
Abstract:
|
||||
- Implementation of perceptual color nudging, which allows the Terminal
|
||||
to slightly shift the foreground color to make it more perceivable on
|
||||
the current background (for cases where the foreground is very close
|
||||
to being imperceivable on the background).
|
||||
|
||||
Author(s):
|
||||
- Pankaj Bhojwani - Sep 2021
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ColorFix
|
||||
{
|
||||
public:
|
||||
ColorFix(COLORREF color);
|
||||
|
||||
static COLORREF GetPerceivableColor(COLORREF fg, COLORREF bg);
|
||||
|
||||
// RGB
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
BYTE r, g, b, dummy;
|
||||
};
|
||||
COLORREF rgb;
|
||||
};
|
||||
|
||||
// Lab
|
||||
struct
|
||||
{
|
||||
double L, A, B;
|
||||
};
|
||||
|
||||
private:
|
||||
static double _GetHPrimeFn(double x, double y);
|
||||
static double _GetDeltaE(ColorFix x1, ColorFix x2);
|
||||
void _ToLab();
|
||||
void _ToRGB();
|
||||
};
|
|
@ -67,5 +67,6 @@ namespace Microsoft.Terminal.Core
|
|||
CursorStyle CursorShape;
|
||||
UInt32 CursorHeight;
|
||||
Boolean IntenseIsBright;
|
||||
Boolean AdjustIndistinguishableColors;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -53,7 +53,8 @@ Terminal::Terminal() :
|
|||
_taskbarState{ 0 },
|
||||
_taskbarProgress{ 0 },
|
||||
_trimBlockSelection{ false },
|
||||
_intenseIsBright{ true }
|
||||
_intenseIsBright{ true },
|
||||
_adjustIndistinguishableColors{ true }
|
||||
{
|
||||
auto dispatch = std::make_unique<TerminalDispatch>(*this);
|
||||
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
|
||||
|
@ -175,11 +176,16 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
|
|||
_defaultBg = newBackgroundColor.with_alpha(0);
|
||||
_defaultFg = appearance.DefaultForeground();
|
||||
_intenseIsBright = appearance.IntenseIsBright();
|
||||
_adjustIndistinguishableColors = appearance.AdjustIndistinguishableColors();
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_colorTable.at(i) = til::color{ appearance.GetColorTableEntry(i) };
|
||||
}
|
||||
if (_adjustIndistinguishableColors)
|
||||
{
|
||||
_MakeAdjustedColorArray();
|
||||
}
|
||||
|
||||
CursorType cursorShape = CursorType::VerticalBar;
|
||||
switch (appearance.CursorShape())
|
||||
|
@ -849,7 +855,13 @@ WORD Terminal::_TakeVirtualKeyFromLastKeyEvent(const WORD scanCode) noexcept
|
|||
// will release this lock when it's destructed.
|
||||
[[nodiscard]] std::unique_lock<til::ticket_lock> Terminal::LockForReading()
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
return std::unique_lock{ _readWriteLock };
|
||||
#else
|
||||
auto lock = std::unique_lock{ _readWriteLock };
|
||||
_lastLocker = GetCurrentThreadId();
|
||||
return lock;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -859,7 +871,13 @@ WORD Terminal::_TakeVirtualKeyFromLastKeyEvent(const WORD scanCode) noexcept
|
|||
// will release this lock when it's destructed.
|
||||
[[nodiscard]] std::unique_lock<til::ticket_lock> Terminal::LockForWriting()
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
return std::unique_lock{ _readWriteLock };
|
||||
#else
|
||||
auto lock = std::unique_lock{ _readWriteLock };
|
||||
_lastLocker = GetCurrentThreadId();
|
||||
return lock;
|
||||
#endif
|
||||
}
|
||||
|
||||
Viewport Terminal::_GetMutableViewport() const noexcept
|
||||
|
|
|
@ -199,6 +199,7 @@ public:
|
|||
const COORD GetSelectionEnd() const noexcept override;
|
||||
const std::wstring_view GetConsoleTitle() const noexcept override;
|
||||
void ColorSelection(const COORD coordSelectionStart, const COORD coordSelectionEnd, const TextAttribute) override;
|
||||
const bool IsUiaDataInitialized() const noexcept override;
|
||||
#pragma endregion
|
||||
|
||||
void SetWriteInputCallback(std::function<void(std::wstring&)> pfn) noexcept;
|
||||
|
@ -268,6 +269,9 @@ private:
|
|||
// But we can abuse the fact that the surrounding members rarely change and are huge
|
||||
// (std::function is like 64 bytes) to create some natural padding without wasting space.
|
||||
til::ticket_lock _readWriteLock;
|
||||
#ifndef NDEBUG
|
||||
DWORD _lastLocker;
|
||||
#endif
|
||||
|
||||
std::function<void(const int, const int, const int)> _pfnScrollPositionChanged;
|
||||
std::function<void(const til::color)> _pfnBackgroundColorChanged;
|
||||
|
@ -297,6 +301,7 @@ private:
|
|||
bool _bracketedPasteMode;
|
||||
bool _trimBlockSelection;
|
||||
bool _intenseIsBright;
|
||||
bool _adjustIndistinguishableColors;
|
||||
|
||||
size_t _taskbarState;
|
||||
size_t _taskbarProgress;
|
||||
|
@ -397,6 +402,9 @@ private:
|
|||
|
||||
Microsoft::Console::VirtualTerminal::SgrStack _sgrStack;
|
||||
|
||||
void _MakeAdjustedColorArray();
|
||||
std::array<std::array<COLORREF, 18>, 18> _adjustedForegroundColors;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TerminalCoreUnitTests::TerminalBufferTests;
|
||||
friend class TerminalCoreUnitTests::TerminalApiTest;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<ClCompile Include="..\TerminalSelection.cpp" />
|
||||
<ClCompile Include="..\TerminalApi.cpp" />
|
||||
<ClCompile Include="..\Terminal.cpp" />
|
||||
<ClCompile Include="..\ColorFix.cpp" />
|
||||
<ClCompile Include="..\pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
@ -19,6 +20,7 @@
|
|||
<ClInclude Include="..\ITerminalApi.hpp" />
|
||||
<ClInclude Include="..\pch.h" />
|
||||
<ClInclude Include="..\Terminal.hpp" />
|
||||
<ClInclude Include="..\ColorFix.hpp" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -3,11 +3,16 @@
|
|||
|
||||
#include "pch.h"
|
||||
#include "Terminal.hpp"
|
||||
#include "ColorFix.hpp"
|
||||
#include <DefaultSettings.h>
|
||||
|
||||
using namespace Microsoft::Terminal::Core;
|
||||
using namespace Microsoft::Console::Types;
|
||||
using namespace Microsoft::Console::Render;
|
||||
|
||||
static constexpr size_t DefaultBgIndex{ 16 };
|
||||
static constexpr size_t DefaultFgIndex{ 17 };
|
||||
|
||||
Viewport Terminal::GetViewport() noexcept
|
||||
{
|
||||
return _GetVisibleViewport();
|
||||
|
@ -44,14 +49,47 @@ const TextAttribute Terminal::GetDefaultBrushColors() noexcept
|
|||
|
||||
std::pair<COLORREF, COLORREF> Terminal::GetAttributeColors(const TextAttribute& attr) const noexcept
|
||||
{
|
||||
std::pair<COLORREF, COLORREF> colors;
|
||||
_blinkingState.RecordBlinkingUsage(attr);
|
||||
auto colors = attr.CalculateRgbColors(
|
||||
_colorTable,
|
||||
_defaultFg,
|
||||
_defaultBg,
|
||||
_screenReversed,
|
||||
_blinkingState.IsBlinkingFaint(),
|
||||
_intenseIsBright);
|
||||
const auto fgTextColor = attr.GetForeground();
|
||||
const auto bgTextColor = attr.GetBackground();
|
||||
|
||||
// We want to nudge the foreground color to make it more perceivable only for the
|
||||
// default color pairs within the color table
|
||||
if (_adjustIndistinguishableColors &&
|
||||
!(attr.IsFaint() || (attr.IsBlinking() && _blinkingState.IsBlinkingFaint())) &&
|
||||
(fgTextColor.IsDefault() || fgTextColor.IsLegacy()) &&
|
||||
(bgTextColor.IsDefault() || bgTextColor.IsLegacy()))
|
||||
{
|
||||
const auto bgIndex = bgTextColor.IsDefault() ? DefaultBgIndex : bgTextColor.GetIndex();
|
||||
auto fgIndex = fgTextColor.IsDefault() ? DefaultFgIndex : fgTextColor.GetIndex();
|
||||
|
||||
if (fgTextColor.IsIndex16() && (fgIndex < 8) && attr.IsBold() && _intenseIsBright)
|
||||
{
|
||||
// There is a special case for bold here - we need to get the bright version of the foreground color
|
||||
fgIndex += 8;
|
||||
}
|
||||
|
||||
if (attr.IsReverseVideo() ^ _screenReversed)
|
||||
{
|
||||
colors.first = _adjustedForegroundColors[fgIndex][bgIndex];
|
||||
colors.second = fgTextColor.GetColor(_colorTable, _defaultFg);
|
||||
}
|
||||
else
|
||||
{
|
||||
colors.first = _adjustedForegroundColors[bgIndex][fgIndex];
|
||||
colors.second = bgTextColor.GetColor(_colorTable, _defaultBg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
colors = attr.CalculateRgbColors(_colorTable,
|
||||
_defaultFg,
|
||||
_defaultBg,
|
||||
_screenReversed,
|
||||
_blinkingState.IsBlinkingFaint(),
|
||||
_intenseIsBright);
|
||||
}
|
||||
colors.first |= 0xff000000;
|
||||
// We only care about alpha for the default BG (which enables acrylic)
|
||||
// If the bg isn't the default bg color, or reverse video is enabled, make it fully opaque.
|
||||
|
@ -233,6 +271,9 @@ catch (...)
|
|||
void Terminal::LockConsole() noexcept
|
||||
{
|
||||
_readWriteLock.lock();
|
||||
#ifndef NDEBUG
|
||||
_lastLocker = GetCurrentThreadId();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -250,3 +291,43 @@ bool Terminal::IsScreenReversed() const noexcept
|
|||
{
|
||||
return _screenReversed;
|
||||
}
|
||||
|
||||
const bool Terminal::IsUiaDataInitialized() const noexcept
|
||||
{
|
||||
// GH#11135: Windows Terminal needs to create and return an automation peer
|
||||
// when a screen reader requests it. However, the terminal might not be fully
|
||||
// initialized yet. So we use this to check if any crucial components of
|
||||
// UiaData are not yet initialized.
|
||||
return !!_buffer;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates the adjusted color array, which contains the possible foreground colors,
|
||||
// adjusted for perceivability
|
||||
// - The adjusted color array is 2-d, and effectively maps a background and foreground
|
||||
// color pair to the adjusted foreground for that color pair
|
||||
void Terminal::_MakeAdjustedColorArray()
|
||||
{
|
||||
// The color table has 16 colors, but the adjusted color table needs to be 18
|
||||
// to include the default background and default foreground colors
|
||||
std::array<COLORREF, 18> colorTableWithDefaults;
|
||||
std::copy_n(std::begin(_colorTable), 16, std::begin(colorTableWithDefaults));
|
||||
colorTableWithDefaults[DefaultBgIndex] = _defaultBg;
|
||||
colorTableWithDefaults[DefaultFgIndex] = _defaultFg;
|
||||
for (auto fgIndex = 0; fgIndex < 18; ++fgIndex)
|
||||
{
|
||||
const auto fg = til::at(colorTableWithDefaults, fgIndex);
|
||||
for (auto bgIndex = 0; bgIndex < 18; ++bgIndex)
|
||||
{
|
||||
if (fgIndex == bgIndex)
|
||||
{
|
||||
_adjustedForegroundColors[bgIndex][fgIndex] = fg;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto bg = til::at(colorTableWithDefaults, bgIndex);
|
||||
_adjustedForegroundColors[bgIndex][fgIndex] = ColorFix::GetPerceivableColor(fg, bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
@ -369,7 +369,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
{
|
||||
const auto kbdVM{ get_self<KeyBindingViewModel>(_KeyBindingList.GetAt(i)) };
|
||||
const auto& otherKeys{ kbdVM->CurrentKeys() };
|
||||
if (keys.Modifiers() == otherKeys.Modifiers() && keys.Vkey() == otherKeys.Vkey())
|
||||
if (otherKeys && keys.Modifiers() == otherKeys.Modifiers() && keys.Vkey() == otherKeys.Vkey())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
<StackPanel Margin="{StaticResource StandardControlMargin}">
|
||||
<local:SettingContainer x:Uid="AddProfile_Duplicate">
|
||||
<muxc:RadioButtons x:Name="Profiles"
|
||||
AutomationProperties.AccessibilityView="Content"
|
||||
ItemsSource="{x:Bind State.Settings.AllProfiles, Mode=OneWay}">
|
||||
<muxc:RadioButtons.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:Profile">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
@ -7,6 +7,7 @@
|
|||
#include "EnumEntry.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include "..\WinRTUtils\inc\Utils.h"
|
||||
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*++
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
|
@ -93,6 +93,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageStretchMode);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageAlignment);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, IntenseTextStyle);
|
||||
OBSERVABLE_PROJECTED_SETTING(_appearance, AdjustIndistinguishableColors);
|
||||
|
||||
private:
|
||||
Model::AppearanceConfig _appearance;
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Xaml.Media.Stretch, BackgroundImageStretchMode);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.ConvergedAlignment, BackgroundImageAlignment);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.IntenseStyle, IntenseTextStyle);
|
||||
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, AdjustIndistinguishableColors);
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass Appearances : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
|
|
|
@ -72,13 +72,15 @@
|
|||
two font lists causes a crash within the ComboBox code.
|
||||
As a workaround, introduce two ComboBox controls and only display one at a time.
|
||||
-->
|
||||
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
|
||||
<ComboBox x:Uid="Profile_FontFaceBox"
|
||||
ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
|
||||
ItemsSource="{x:Bind SourceProfile.MonospaceFontList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
|
||||
SelectionChanged="FontFace_SelectionChanged"
|
||||
Style="{StaticResource ComboBoxSettingStyle}"
|
||||
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(ShowAllFonts), Mode=OneWay}" />
|
||||
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
|
||||
<ComboBox x:Uid="Profile_FontFaceBox"
|
||||
ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
|
||||
ItemsSource="{x:Bind SourceProfile.CompleteFontList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
|
||||
SelectionChanged="FontFace_SelectionChanged"
|
||||
|
@ -97,7 +99,8 @@
|
|||
HasSettingValue="{x:Bind Appearance.HasFontSize, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.FontSizeOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
|
||||
<muxc:NumberBox AcceptsExpression="False"
|
||||
<muxc:NumberBox x:Uid="Profile_FontSizeBox"
|
||||
AcceptsExpression="False"
|
||||
LargeChange="10"
|
||||
Maximum="128"
|
||||
Minimum="1"
|
||||
|
@ -150,6 +153,14 @@
|
|||
SettingOverrideSource="{x:Bind Appearance.RetroTerminalEffectOverrideSource, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind Appearance.RetroTerminalEffect, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Adjust Indistinguishable Colors -->
|
||||
<local:SettingContainer x:Uid="Profile_AdjustIndistinguishableColors"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearAdjustIndistinguishableColors}"
|
||||
HasSettingValue="{x:Bind Appearance.HasAdjustIndistinguishableColors, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.AdjustIndistinguishableColorsOverrideSource, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind Appearance.AdjustIndistinguishableColors, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Grouping: Cursor -->
|
||||
|
@ -163,7 +174,8 @@
|
|||
ClearSettingValue="{x:Bind Appearance.ClearCursorShape}"
|
||||
HasSettingValue="{x:Bind Appearance.HasCursorShape, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.CursorShapeOverrideSource, Mode=OneWay}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind CursorShapeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentCursorShape, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
@ -226,7 +238,8 @@
|
|||
HasSettingValue="{x:Bind Appearance.HasBackgroundImageStretchMode, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.BackgroundImageStretchModeOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind Appearance.BackgroundImageSettingsVisible, Mode=OneWay}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind BackgroundImageStretchModeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentBackgroundImageStretchMode, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
@ -441,7 +454,8 @@
|
|||
ClearSettingValue="{x:Bind Appearance.ClearIntenseTextStyle}"
|
||||
HasSettingValue="{x:Bind Appearance.HasIntenseTextStyle, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.IntenseTextStyleOverrideSource, Mode=OneWay}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind IntenseTextStyleList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentIntenseTextStyle, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
|
||||
<!-- Theme -->
|
||||
<local:SettingContainer x:Uid="Globals_Theme">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind ThemeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentTheme, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
@ -74,7 +75,8 @@
|
|||
|
||||
<!-- Tab Width Mode -->
|
||||
<local:SettingContainer x:Uid="Globals_TabWidthMode">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind TabWidthModeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentTabWidthMode, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
|
||||
<!-- Copy Format -->
|
||||
<local:SettingContainer x:Uid="Globals_CopyFormat">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind CopyFormatList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentCopyFormat, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
@ -58,7 +59,8 @@
|
|||
|
||||
<!-- Tab Switcher Mode -->
|
||||
<local:SettingContainer x:Uid="Globals_TabSwitcherMode">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind TabSwitcherModeList}"
|
||||
SelectedItem="{x:Bind CurrentTabSwitcherMode, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
|
|
@ -136,22 +136,26 @@
|
|||
<!-- First Window Behavior -->
|
||||
<local:SettingContainer x:Uid="Globals_FirstWindowPreference"
|
||||
Visibility="{x:Bind ShowFirstWindowPreference}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind FirstWindowPreferenceList}"
|
||||
SelectedItem="{x:Bind CurrentFirstWindowPreference, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
|
||||
<!-- Launch Mode -->
|
||||
<local:SettingContainer x:Uid="Globals_LaunchMode">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<local:SettingContainer x:Name="Globals_LaunchMode"
|
||||
x:Uid="Globals_LaunchMode">
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind LaunchModeList}"
|
||||
SelectedItem="{x:Bind CurrentLaunchMode, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Launch Mode -->
|
||||
<local:SettingContainer x:Uid="Globals_WindowingBehavior">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind WindowingBehaviorList}"
|
||||
SelectedItem="{x:Bind CurrentWindowingBehavior, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
@ -166,12 +170,14 @@
|
|||
<!-- Columns -->
|
||||
<local:SettingContainer x:Uid="Globals_InitialCols"
|
||||
Margin="0">
|
||||
<muxc:NumberBox Style="{StaticResource LaunchSizeNumberBoxStyle}"
|
||||
<muxc:NumberBox x:Uid="Globals_InitialColsBox"
|
||||
Style="{StaticResource LaunchSizeNumberBoxStyle}"
|
||||
Value="{x:Bind State.Settings.GlobalSettings.InitialCols, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
<!-- Rows -->
|
||||
<local:SettingContainer x:Uid="Globals_InitialRows">
|
||||
<muxc:NumberBox Style="{StaticResource LaunchSizeNumberBoxStyle}"
|
||||
<muxc:NumberBox x:Uid="Globals_InitialRowsBox"
|
||||
Style="{StaticResource LaunchSizeNumberBoxStyle}"
|
||||
Value="{x:Bind State.Settings.GlobalSettings.InitialRows, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
@ -8,6 +8,7 @@
|
|||
#include "EnumEntry.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include "..\WinRTUtils\inc\Utils.h"
|
||||
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
@ -46,6 +47,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
// NOTE: this is similar to what is done with BackgroundImagePath above
|
||||
_NotifyChanges(L"UseParentProcessDirectory", L"UseCustomStartingDirectory");
|
||||
}
|
||||
else if (viewModelProperty == L"UseAcrylic")
|
||||
{
|
||||
// GH#11372: If we're on Windows 10, and someone turns off
|
||||
// acrylic, we're going to disable opacity for them. Opacity
|
||||
// doesn't work without acrylic on Windows 10.
|
||||
//
|
||||
// BODGY: CascadiaSettings's function IsDefaultTerminalAvailable
|
||||
// is basically a "are we on Windows 11" check, because defterm
|
||||
// only works on Win11. So we'll use that.
|
||||
//
|
||||
// Remove when we can remove the rest of GH#11285
|
||||
if (!UseAcrylic() && !CascadiaSettings::IsDefaultTerminalAvailable())
|
||||
{
|
||||
Opacity(1.0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Do the same for the starting directory
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
@ -22,7 +22,21 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
|
||||
void SetAcrylicOpacityPercentageValue(double value)
|
||||
{
|
||||
_profile.DefaultAppearance().Opacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value));
|
||||
Opacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value));
|
||||
|
||||
// GH#11372: If we're on Windows 10, and someone wants opacity, then
|
||||
// we'll turn acrylic on for them. Opacity doesn't work without
|
||||
// acrylic on Windows 10.
|
||||
//
|
||||
// BODGY: CascadiaSettings's function IsDefaultTerminalAvailable
|
||||
// is basically a "are we on Windows 11" check, because defterm
|
||||
// only works on Win11. So we'll use that.
|
||||
//
|
||||
// Remove when we can remove the rest of GH#11285
|
||||
if (value < 100.0 && winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings::IsDefaultTerminalAvailable())
|
||||
{
|
||||
UseAcrylic(true);
|
||||
}
|
||||
};
|
||||
|
||||
void SetPadding(double value)
|
||||
|
|
|
@ -81,7 +81,8 @@
|
|||
SettingOverrideSource="{x:Bind State.Profile.CommandlineOverrideSource, Mode=OneWay}"
|
||||
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.IsBaseLayer), Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBox IsSpellCheckEnabled="False"
|
||||
<TextBox x:Uid="Profile_CommandlineBox"
|
||||
IsSpellCheckEnabled="False"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind State.Profile.Commandline, Mode=TwoWay}" />
|
||||
<Button x:Uid="Profile_CommandlineBrowse"
|
||||
|
@ -99,7 +100,8 @@
|
|||
SettingOverrideSource="{x:Bind State.Profile.StartingDirectoryOverrideSource, Mode=OneWay}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBox IsEnabled="{x:Bind State.Profile.UseCustomStartingDirectory, Mode=OneWay}"
|
||||
<TextBox x:Uid="Profile_StartingDirectoryBox"
|
||||
IsEnabled="{x:Bind State.Profile.UseCustomStartingDirectory, Mode=OneWay}"
|
||||
IsSpellCheckEnabled="False"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind State.Profile.StartingDirectory, Mode=TwoWay}" />
|
||||
|
@ -121,7 +123,8 @@
|
|||
HasSettingValue="{x:Bind State.Profile.HasIcon, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind State.Profile.IconOverrideSource, Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBox FontFamily="Segoe UI, Segoe MDL2 Assets"
|
||||
<TextBox x:Uid="Profile_IconBox"
|
||||
FontFamily="Segoe UI, Segoe MDL2 Assets"
|
||||
IsSpellCheckEnabled="False"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind State.Profile.Icon, Mode=TwoWay}" />
|
||||
|
@ -246,6 +249,7 @@
|
|||
<!-- Opacity -->
|
||||
<local:SettingContainer x:Name="OpacityContainer"
|
||||
x:Uid="Profile_Opacity"
|
||||
Margin="0"
|
||||
ClearSettingValue="{x:Bind State.Profile.ClearOpacity}"
|
||||
HasSettingValue="{x:Bind State.Profile.HasOpacity, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind State.Profile.OpacityOverrideSource, Mode=OneWay}">
|
||||
|
@ -307,7 +311,8 @@
|
|||
ClearSettingValue="{x:Bind State.Profile.ClearScrollState}"
|
||||
HasSettingValue="{x:Bind State.Profile.HasScrollState, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind State.Profile.ScrollStateOverrideSource, Mode=OneWay}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind ScrollStateList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentScrollState, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
@ -412,7 +417,8 @@
|
|||
ClearSettingValue="{x:Bind State.Profile.ClearAntialiasingMode}"
|
||||
HasSettingValue="{x:Bind State.Profile.HasAntialiasingMode, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind State.Profile.AntialiasingModeOverrideSource, Mode=OneWay}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind AntiAliasingModeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentAntiAliasingMode, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
@ -438,7 +444,8 @@
|
|||
ClearSettingValue="{x:Bind State.Profile.ClearHistorySize}"
|
||||
HasSettingValue="{x:Bind State.Profile.HasHistorySize, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind State.Profile.HistorySizeOverrideSource, Mode=OneWay}">
|
||||
<muxc:NumberBox LargeChange="100"
|
||||
<muxc:NumberBox x:Uid="Profile_HistorySizeBox"
|
||||
LargeChange="100"
|
||||
Minimum="0"
|
||||
SmallChange="10"
|
||||
Style="{StaticResource NumberBoxSettingStyle}"
|
||||
|
@ -450,7 +457,8 @@
|
|||
ClearSettingValue="{x:Bind State.Profile.ClearCloseOnExit}"
|
||||
HasSettingValue="{x:Bind State.Profile.HasCloseOnExit, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind State.Profile.CloseOnExitOverrideSource, Mode=OneWay}">
|
||||
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
ItemsSource="{x:Bind CloseOnExitModeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind CurrentCloseOnExitMode, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
|
|
@ -291,6 +291,14 @@
|
|||
<value>The number of rows displayed in the window upon first load. Measured in characters.</value>
|
||||
<comment>A description for what the "rows" setting does. Presented near "Globals_InitialRows.Header".</comment>
|
||||
</data>
|
||||
<data name="Globals_InitialColsBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Initial Columns</value>
|
||||
<comment>Name for a control to choose the number of columns in the terminal's text grid.</comment>
|
||||
</data>
|
||||
<data name="Globals_InitialRowsBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Initial Rows</value>
|
||||
<comment>Name for a control to choose the number of rows in the terminal's text grid.</comment>
|
||||
</data>
|
||||
<data name="Globals_FirstWindowPreference.Header" xml:space="preserve">
|
||||
<value>When Terminal starts</value>
|
||||
<comment>Header for a control to select how the terminal should load its first window.</comment>
|
||||
|
@ -304,8 +312,8 @@
|
|||
<comment>An option to choose from for the "First window preference" setting. Open the default profile.</comment>
|
||||
</data>
|
||||
<data name="Globals_FirstWindowPreferencePersistedWindowLayout.Content" xml:space="preserve">
|
||||
<value>Open tabs from a previous session</value>
|
||||
<comment>An option to choose from for the "First window preference" setting. Reopen the layout from the last session.</comment>
|
||||
<value>Open windows from a previous session</value>
|
||||
<comment>An option to choose from for the "First window preference" setting. Reopen the layouts from the last session.</comment>
|
||||
</data>
|
||||
<data name="Globals_LaunchMode.Header" xml:space="preserve">
|
||||
<value>Launch mode</value>
|
||||
|
@ -496,7 +504,7 @@
|
|||
<comment>A description for what the "acrylic opacity" setting does. Presented near "Profile_AcrylicOpacity.Header".</comment>
|
||||
</data>
|
||||
<data name="Profile_Opacity.Header" xml:space="preserve">
|
||||
<value>Background Opacity</value>
|
||||
<value>Background opacity</value>
|
||||
<comment>Header for a control to determine the level of opacity for the background of the control. The user can choose to make the background of the app more or less opaque.</comment>
|
||||
</data>
|
||||
<data name="Profile_Opacity.HelpText" xml:space="preserve">
|
||||
|
@ -655,6 +663,10 @@
|
|||
<value>Command line</value>
|
||||
<comment>Header for a control to determine commandline executable (i.e. a .exe file) to run when a terminal session of this profile is launched.</comment>
|
||||
</data>
|
||||
<data name="Profile_CommandlineBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Command line</value>
|
||||
<comment>Name for a control to determine commandline executable (i.e. a .exe file) to run when a terminal session of this profile is launched.</comment>
|
||||
</data>
|
||||
<data name="Profile_Commandline.HelpText" xml:space="preserve">
|
||||
<value>Executable used in the profile.</value>
|
||||
<comment>A description for what the "command line" setting does. Presented near "Profile_Commandline".</comment>
|
||||
|
@ -703,6 +715,10 @@
|
|||
<value>Font face</value>
|
||||
<comment>Header for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFaceBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Font face</value>
|
||||
<comment>Name for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.HelpText" xml:space="preserve">
|
||||
<value>Name of the font face used in the profile.</value>
|
||||
<comment>A description for what the "font face" setting does. Presented near "Profile_FontFace".</comment>
|
||||
|
@ -711,6 +727,10 @@
|
|||
<value>Font size</value>
|
||||
<comment>Header for a control to determine the size of the text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontSizeBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Font size</value>
|
||||
<comment>Name for a control to determine the size of the text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontSize.HelpText" xml:space="preserve">
|
||||
<value>Size of the font in points.</value>
|
||||
<comment>A description for what the "font size" setting does. Presented near "Profile_FontSize".</comment>
|
||||
|
@ -739,6 +759,10 @@
|
|||
<value>History size</value>
|
||||
<comment>Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session.</comment>
|
||||
</data>
|
||||
<data name="Profile_HistorySizeBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>History size</value>
|
||||
<comment>Name for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session.</comment>
|
||||
</data>
|
||||
<data name="Profile_HistorySize.HelpText" xml:space="preserve">
|
||||
<value>The number of lines above the ones displayed in the window you can scroll back to.</value>
|
||||
<comment>A description for what the "history size" setting does. Presented near "Profile_HistorySize".</comment>
|
||||
|
@ -747,6 +771,10 @@
|
|||
<value>Icon</value>
|
||||
<comment>Header for a control to determine what icon can be used to represent this profile. This is not necessarily a file path, but can be one.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Icon</value>
|
||||
<comment>Name for a control to determine what icon can be used to represent this profile. This is not necessarily a file path, but can be one.</comment>
|
||||
</data>
|
||||
<data name="Profile_Icon.HelpText" xml:space="preserve">
|
||||
<value>Emoji or image file location of the icon used in the profile.</value>
|
||||
<comment>A description for what the "icon" setting does. Presented near "Profile_Icon".</comment>
|
||||
|
@ -771,6 +799,14 @@
|
|||
<value>When enabled, enables retro terminal effects such as glowing text and scan lines.</value>
|
||||
<comment>A description for what the "retro terminal effects" setting does. Presented near "Profile_RetroTerminalEffect".</comment>
|
||||
</data>
|
||||
<data name="Profile_AdjustIndistinguishableColors.Header" xml:space="preserve">
|
||||
<value>Automatically adjust lightness of indistinguishable text</value>
|
||||
<comment>Header for a control to toggle if we should adjust the foreground color's lightness to make it more visible when necessary, based on the background color.</comment>
|
||||
</data>
|
||||
<data name="Profile_AdjustIndistinguishableColors.HelpText" xml:space="preserve">
|
||||
<value>When enabled, enables automatic adjustment of indistinguishable colors, which will, only when necessary, adjust the foreground color's lightness to make it more visible (based on the background color).</value>
|
||||
<comment>A description for what the "adjust indistinguishable colors" setting does. Presented near "Profile_AdjustIndistinguishableColors".</comment>
|
||||
</data>
|
||||
<data name="Profile_ScrollbarVisibility.Header" xml:space="preserve">
|
||||
<value>Scrollbar visibility</value>
|
||||
<comment>Header for a control to select the visibility of the scrollbar in a session.</comment>
|
||||
|
@ -791,6 +827,10 @@
|
|||
<value>Starting directory</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Starting directory</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>The directory the profile starts in when it is loaded.</value>
|
||||
<comment>A description for what the "starting directory" setting does. Presented near "Profile_StartingDirectory".</comment>
|
||||
|
@ -1227,7 +1267,7 @@
|
|||
<comment>Header for a control to how text is formatted</comment>
|
||||
</data>
|
||||
<data name="Appearance_IntenseTextStyle.Header" xml:space="preserve">
|
||||
<value>Intense Text Style</value>
|
||||
<value>Intense text style</value>
|
||||
<comment>Header for a control to select how "intense" text is formatted (bold, bright, both or none)</comment>
|
||||
</data>
|
||||
<data name="Appearance_IntenseTextStyleNone.Content" xml:space="preserve">
|
||||
|
|
|
@ -15,30 +15,6 @@ using namespace winrt::Windows::UI::Xaml;
|
|||
|
||||
UTILS_DEFINE_LIBRARY_RESOURCE_SCOPE(L"Microsoft.Terminal.Settings.Editor/Resources");
|
||||
|
||||
// Function Description:
|
||||
// - Helper that opens a file picker pre-seeded with image file types.
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd)
|
||||
{
|
||||
static constexpr COMDLG_FILTERSPEC supportedImageFileTypes[] = {
|
||||
{ L"All Supported Bitmap Types (*.jpg, *.jpeg, *.png, *.bmp, *.gif, *.tiff, *.ico)", L"*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.tiff;*.ico" },
|
||||
{ L"All Files (*.*)", L"*.*" }
|
||||
};
|
||||
|
||||
static constexpr winrt::guid clientGuidImagePicker{ 0x55675F54, 0x74A1, 0x4552, { 0xA3, 0x9D, 0x94, 0xAE, 0x85, 0xD8, 0xF2, 0x7A } };
|
||||
return OpenFilePicker(parentHwnd, [](auto&& dialog) {
|
||||
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidImagePicker));
|
||||
try
|
||||
{
|
||||
auto pictureFolderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_PicturesLibrary, KF_FLAG_DEFAULT, nullptr) };
|
||||
dialog->SetDefaultFolder(pictureFolderShellItem.get());
|
||||
}
|
||||
CATCH_LOG(); // non-fatal
|
||||
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedImageFileTypes), supportedImageFileTypes));
|
||||
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
|
||||
THROW_IF_FAILED(dialog->SetDefaultExtension(L"jpg;jpeg;png;bmp;gif;tiff;ico"));
|
||||
});
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings
|
||||
{
|
||||
hstring GetSelectedItemTag(winrt::Windows::Foundation::IInspectable const& comboBoxAsInspectable)
|
||||
|
|
|
@ -97,42 +97,6 @@ public: \
|
|||
private: \
|
||||
static winrt::Windows::UI::Xaml::DependencyProperty _##name##Property;
|
||||
|
||||
// Function Description:
|
||||
// - This function presents a File Open "common dialog" and returns its selected file asynchronously.
|
||||
// Parameters:
|
||||
// - customize: A lambda that receives an IFileDialog* to customize.
|
||||
// Return value:
|
||||
// (async) path to the selected item.
|
||||
template<typename TLambda>
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenFilePicker(HWND parentHwnd, TLambda&& customize)
|
||||
{
|
||||
auto fileDialog{ winrt::create_instance<IFileDialog>(CLSID_FileOpenDialog) };
|
||||
DWORD flags{};
|
||||
THROW_IF_FAILED(fileDialog->GetOptions(&flags));
|
||||
THROW_IF_FAILED(fileDialog->SetOptions(flags | FOS_FORCEFILESYSTEM | FOS_NOCHANGEDIR | FOS_DONTADDTORECENT)); // filesystem objects only; no recent places
|
||||
customize(fileDialog.get());
|
||||
|
||||
auto hr{ fileDialog->Show(parentHwnd) };
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
|
||||
{
|
||||
co_return winrt::hstring{};
|
||||
}
|
||||
THROW_HR(hr);
|
||||
}
|
||||
|
||||
winrt::com_ptr<IShellItem> result;
|
||||
THROW_IF_FAILED(fileDialog->GetResult(result.put()));
|
||||
|
||||
wil::unique_cotaskmem_string filePath;
|
||||
THROW_IF_FAILED(result->GetDisplayName(SIGDN_FILESYSPATH, &filePath));
|
||||
|
||||
co_return winrt::hstring{ filePath.get() };
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd);
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings
|
||||
{
|
||||
winrt::hstring GetSelectedItemTag(winrt::Windows::Foundation::IInspectable const& comboBoxAsInspectable);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "MultipleActionsArgs.g.cpp"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include <WtExeUtils.h>
|
||||
|
||||
using namespace winrt::Microsoft::Terminal::Control;
|
||||
|
||||
|
@ -121,15 +122,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
if (!StartingDirectory().empty())
|
||||
{
|
||||
// If the directory ends in a '\', we need to add another one on so that the enclosing quote added
|
||||
// afterwards isn't escaped
|
||||
const auto trailingBackslashEscape = StartingDirectory().back() == L'\\' ? L"\\" : L"";
|
||||
ss << fmt::format(L"--startingDirectory \"{}{}\" ", StartingDirectory(), trailingBackslashEscape);
|
||||
ss << fmt::format(L"--startingDirectory {} ", QuoteAndEscapeCommandlineArg(StartingDirectory()));
|
||||
}
|
||||
|
||||
if (!TabTitle().empty())
|
||||
{
|
||||
ss << fmt::format(L"--title \"{}\" ", TabTitle());
|
||||
ss << fmt::format(L"--title {} ", QuoteAndEscapeCommandlineArg(TabTitle()));
|
||||
}
|
||||
|
||||
if (TabColor())
|
||||
|
@ -152,7 +150,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
if (!ColorScheme().empty())
|
||||
{
|
||||
ss << fmt::format(L"--colorScheme \"{}\" ", ColorScheme());
|
||||
ss << fmt::format(L"--colorScheme {} ", QuoteAndEscapeCommandlineArg(ColorScheme()));
|
||||
}
|
||||
|
||||
if (!Commandline().empty())
|
||||
|
@ -300,6 +298,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
return RS_(L"MoveFocusPreviousInOrder");
|
||||
case FocusDirection::First:
|
||||
return RS_(L"MoveFocusFirstPane");
|
||||
case FocusDirection::Parent:
|
||||
return RS_(L"MoveFocusParentPane");
|
||||
case FocusDirection::Child:
|
||||
return RS_(L"MoveFocusChildPane");
|
||||
}
|
||||
|
||||
return winrt::hstring{
|
||||
|
|
|
@ -864,6 +864,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
struct SetTabColorArgs : public SetTabColorArgsT<SetTabColorArgs>
|
||||
{
|
||||
SetTabColorArgs() = default;
|
||||
SetTabColorArgs(Windows::UI::Color tabColor) :
|
||||
_TabColor{ tabColor } {}
|
||||
ACTION_ARG(Windows::Foundation::IReference<Windows::UI::Color>, TabColor, nullptr);
|
||||
|
||||
static constexpr std::string_view ColorKey{ "color" };
|
||||
|
@ -1582,6 +1584,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
struct RenameWindowArgs : public RenameWindowArgsT<RenameWindowArgs>
|
||||
{
|
||||
RenameWindowArgs() = default;
|
||||
RenameWindowArgs(winrt::hstring name) :
|
||||
_Name{ name } {};
|
||||
ACTION_ARG(winrt::hstring, Name);
|
||||
static constexpr std::string_view NameKey{ "name" };
|
||||
|
||||
|
@ -1679,7 +1683,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
JsonUtils::SetValueForKey(json, NameKey, args->_Name);
|
||||
JsonUtils::SetValueForKey(json, DesktopKey, args->_Desktop);
|
||||
JsonUtils::SetValueForKey(json, MonitorKey, args->_Monitor);
|
||||
JsonUtils::GetValueForKey(json, DropdownDurationKey, args->_DropdownDuration);
|
||||
JsonUtils::SetValueForKey(json, DropdownDurationKey, args->_DropdownDuration);
|
||||
JsonUtils::SetValueForKey(json, ToggleVisibilityKey, args->_ToggleVisibility);
|
||||
return json;
|
||||
}
|
||||
|
@ -1869,9 +1873,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
|
|||
BASIC_FACTORY(NewTabArgs);
|
||||
BASIC_FACTORY(MoveFocusArgs);
|
||||
BASIC_FACTORY(MovePaneArgs);
|
||||
BASIC_FACTORY(SetTabColorArgs);
|
||||
BASIC_FACTORY(SwapPaneArgs);
|
||||
BASIC_FACTORY(SplitPaneArgs);
|
||||
BASIC_FACTORY(SetColorSchemeArgs);
|
||||
BASIC_FACTORY(RenameWindowArgs);
|
||||
BASIC_FACTORY(ExecuteCommandlineArgs);
|
||||
BASIC_FACTORY(CloseOtherTabsArgs);
|
||||
BASIC_FACTORY(CloseTabsAfterArgs);
|
||||
|
|
|
@ -38,7 +38,9 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
Previous,
|
||||
PreviousInOrder,
|
||||
NextInOrder,
|
||||
First
|
||||
First,
|
||||
Parent,
|
||||
Child
|
||||
};
|
||||
|
||||
enum SplitDirection
|
||||
|
@ -213,6 +215,7 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
|
||||
[default_interface] runtimeclass SetTabColorArgs : IActionArgs
|
||||
{
|
||||
SetTabColorArgs(Windows.UI.Color tabColor);
|
||||
Windows.Foundation.IReference<Windows.UI.Color> TabColor { get; };
|
||||
};
|
||||
|
||||
|
@ -294,6 +297,7 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
|
||||
[default_interface] runtimeclass RenameWindowArgs : IActionArgs
|
||||
{
|
||||
RenameWindowArgs(String name);
|
||||
String Name { get; };
|
||||
};
|
||||
|
||||
|
|
|
@ -94,15 +94,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
static void RegisterShortcutAction(ShortcutAction shortcutAction, std::unordered_map<hstring, Model::ActionAndArgs>& list, std::unordered_set<InternalActionID>& visited)
|
||||
{
|
||||
const auto actionAndArgs{ make_self<ActionAndArgs>(shortcutAction) };
|
||||
if (actionAndArgs->Action() != ShortcutAction::Invalid)
|
||||
/*We have a valid action.*/
|
||||
/*Check if the action was already added.*/
|
||||
if (visited.find(Hash(*actionAndArgs)) == visited.end())
|
||||
{
|
||||
/*We have a valid action.*/
|
||||
/*Check if the action was already added.*/
|
||||
if (visited.find(Hash(*actionAndArgs)) == visited.end())
|
||||
/*This is an action that wasn't added!*/
|
||||
/*Let's add it if it has a name.*/
|
||||
if (const auto name{ actionAndArgs->GenerateName() }; !name.empty())
|
||||
{
|
||||
/*This is an action that wasn't added!*/
|
||||
/*Let's add it.*/
|
||||
const auto name{ actionAndArgs->GenerateName() };
|
||||
list.insert({ name, *actionAndArgs });
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue