|
6 | 6 | #include "TerminalPage.h" |
7 | 7 |
|
8 | 8 | #include <LibraryResources.h> |
| 9 | +#include <TerminalThemeHelpers.h> |
9 | 10 | #include <TerminalCore/ControlKeyStates.hpp> |
10 | 11 | #include <Utils.h> |
11 | 12 |
|
@@ -102,6 +103,13 @@ namespace winrt::TerminalApp::implementation |
102 | 103 | // before restoring previous tabs in that scenario. |
103 | 104 | } |
104 | 105 | } |
| 106 | + |
| 107 | + _adjustProcessPriorityThrottled = std::make_shared<ThrottledFuncTrailing<>>( |
| 108 | + DispatcherQueue::GetForCurrentThread(), |
| 109 | + std::chrono::milliseconds{ 100 }, |
| 110 | + [=]() { |
| 111 | + _adjustProcessPriority(); |
| 112 | + }); |
105 | 113 | _hostingHwnd = hwnd; |
106 | 114 | return S_OK; |
107 | 115 | } |
@@ -1946,7 +1954,7 @@ namespace winrt::TerminalApp::implementation |
1946 | 1954 | return false; |
1947 | 1955 | } |
1948 | 1956 |
|
1949 | | - TermControl TerminalPage::_GetActiveControl() |
| 1957 | + TermControl TerminalPage::_GetActiveControl() const |
1950 | 1958 | { |
1951 | 1959 | if (const auto terminalTab{ _GetFocusedTabImpl() }) |
1952 | 1960 | { |
@@ -2410,6 +2418,8 @@ namespace winrt::TerminalApp::implementation |
2410 | 2418 | auto profile = tab->GetFocusedProfile(); |
2411 | 2419 | _UpdateBackground(profile); |
2412 | 2420 | } |
| 2421 | + |
| 2422 | + _adjustProcessPriorityThrottled->Run(); |
2413 | 2423 | } |
2414 | 2424 |
|
2415 | 2425 | uint32_t TerminalPage::NumberOfTabs() const |
@@ -4611,9 +4621,12 @@ namespace winrt::TerminalApp::implementation |
4611 | 4621 | if (const auto coreState{ sender.try_as<winrt::Microsoft::Terminal::Control::ICoreState>() }) |
4612 | 4622 | { |
4613 | 4623 | const auto newConnectionState = coreState.ConnectionState(); |
| 4624 | + co_await wil::resume_foreground(Dispatcher()); |
| 4625 | + |
| 4626 | + _adjustProcessPriorityThrottled->Run(); |
| 4627 | + |
4614 | 4628 | if (newConnectionState == ConnectionState::Failed && !_IsMessageDismissed(InfoBarMessage::CloseOnExitInfo)) |
4615 | 4629 | { |
4616 | | - co_await wil::resume_foreground(Dispatcher()); |
4617 | 4630 | if (const auto infoBar = FindName(L"CloseOnExitInfoBar").try_as<MUX::Controls::InfoBar>()) |
4618 | 4631 | { |
4619 | 4632 | infoBar.IsOpen(true); |
@@ -4878,13 +4891,103 @@ namespace winrt::TerminalApp::implementation |
4878 | 4891 | } |
4879 | 4892 | } |
4880 | 4893 |
|
| 4894 | + void TerminalPage::_adjustProcessPriority() const |
| 4895 | + { |
| 4896 | + // Windowing is single-threaded, so this will not cause a race condition. |
| 4897 | + static bool supported{ true }; |
| 4898 | + |
| 4899 | + if (!supported || !_hostingHwnd.has_value()) |
| 4900 | + { |
| 4901 | + return; |
| 4902 | + } |
| 4903 | + |
| 4904 | + std::array<HANDLE, 32> processes; |
| 4905 | + auto it = processes.begin(); |
| 4906 | + const auto end = processes.end(); |
| 4907 | + |
| 4908 | + auto&& appendFromControl = [&](auto&& control) { |
| 4909 | + if (it == end) |
| 4910 | + { |
| 4911 | + return; |
| 4912 | + } |
| 4913 | + if (control) |
| 4914 | + { |
| 4915 | + if (const auto conn{ control.Connection() }) |
| 4916 | + { |
| 4917 | + if (const auto pty{ conn.try_as<winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection>() }) |
| 4918 | + { |
| 4919 | + if (const uint64_t process{ pty.RootProcessHandle() }; process != 0) |
| 4920 | + { |
| 4921 | + *it++ = reinterpret_cast<HANDLE>(process); |
| 4922 | + } |
| 4923 | + } |
| 4924 | + } |
| 4925 | + } |
| 4926 | + }; |
| 4927 | + |
| 4928 | + auto&& appendFromTab = [&](auto&& tabImpl) { |
| 4929 | + if (const auto pane{ tabImpl->GetRootPane() }) |
| 4930 | + { |
| 4931 | + pane->WalkTree([&](auto&& child) { |
| 4932 | + if (const auto& control{ child->GetTerminalControl() }) |
| 4933 | + { |
| 4934 | + appendFromControl(control); |
| 4935 | + } |
| 4936 | + }); |
| 4937 | + } |
| 4938 | + }; |
| 4939 | + |
| 4940 | + if (!_activated) |
| 4941 | + { |
| 4942 | + // When a window is out of focus, we want to attach all of the processes |
| 4943 | + // under it to the window so they all go into the background at the same time. |
| 4944 | + for (auto&& tab : _tabs) |
| 4945 | + { |
| 4946 | + if (auto tabImpl{ _GetTerminalTabImpl(tab) }) |
| 4947 | + { |
| 4948 | + appendFromTab(tabImpl); |
| 4949 | + } |
| 4950 | + } |
| 4951 | + } |
| 4952 | + else |
| 4953 | + { |
| 4954 | + // When a window is in focus, propagate our foreground boost (if we have one) |
| 4955 | + // to current all panes in the current tab. |
| 4956 | + if (auto tabImpl{ _GetFocusedTabImpl() }) |
| 4957 | + { |
| 4958 | + appendFromTab(tabImpl); |
| 4959 | + } |
| 4960 | + } |
| 4961 | + |
| 4962 | + const auto count{ gsl::narrow_cast<DWORD>(it - processes.begin()) }; |
| 4963 | + const auto hr = TerminalTrySetWindowAssociatedProcesses(_hostingHwnd.value(), count, count ? processes.data() : nullptr); |
| 4964 | + if (S_FALSE == hr) |
| 4965 | + { |
| 4966 | + // Don't bother trying again or logging. The wrapper tells us it's unsupported. |
| 4967 | + supported = false; |
| 4968 | + return; |
| 4969 | + } |
| 4970 | + |
| 4971 | + TraceLoggingWrite( |
| 4972 | + g_hTerminalAppProvider, |
| 4973 | + "CalledNewQoSAPI", |
| 4974 | + TraceLoggingValue(reinterpret_cast<uintptr_t>(_hostingHwnd.value()), "hwnd"), |
| 4975 | + TraceLoggingValue(count), |
| 4976 | + TraceLoggingHResult(hr)); |
| 4977 | +#ifdef _DEBUG |
| 4978 | + OutputDebugStringW(fmt::format(FMT_COMPILE(L"Submitted {} processes to TerminalTrySetWindowAssociatedProcesses; return=0x{:08x}\n"), count, hr).c_str()); |
| 4979 | +#endif |
| 4980 | + } |
| 4981 | + |
4881 | 4982 | void TerminalPage::WindowActivated(const bool activated) |
4882 | 4983 | { |
4883 | 4984 | // Stash if we're activated. Use that when we reload |
4884 | 4985 | // the settings, change active panes, etc. |
4885 | 4986 | _activated = activated; |
4886 | 4987 | _updateThemeColors(); |
4887 | 4988 |
|
| 4989 | + _adjustProcessPriorityThrottled->Run(); |
| 4990 | + |
4888 | 4991 | if (const auto& tab{ _GetFocusedTabImpl() }) |
4889 | 4992 | { |
4890 | 4993 | if (tab->TabStatus().IsInputBroadcastActive()) |
|
0 commit comments