mirror of
https://github.com/microsoft/terminal.git
synced 2026-07-08 18:16:28 +00:00
PRE-MERGE #20014 Add settings for "notifying" on "activity"
This commit is contained in:
@@ -2906,6 +2906,85 @@
|
||||
"description": "Sets the sound played when the application emits a BEL. When set to an array, the terminal will pick one of those sounds at random.",
|
||||
"$ref": "#/$defs/BellSound"
|
||||
},
|
||||
"notifyOnActivity": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"taskbar",
|
||||
"audible",
|
||||
"tab",
|
||||
"notification"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"taskbar",
|
||||
"audible",
|
||||
"tab",
|
||||
"notification",
|
||||
"all",
|
||||
"none"
|
||||
]
|
||||
}
|
||||
],
|
||||
"description": "Controls how you are notified when an inactive tab produces new output."
|
||||
},
|
||||
"notifyOnNextPrompt": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"taskbar",
|
||||
"audible",
|
||||
"tab",
|
||||
"notification"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"taskbar",
|
||||
"audible",
|
||||
"tab",
|
||||
"notification",
|
||||
"all",
|
||||
"none"
|
||||
]
|
||||
}
|
||||
],
|
||||
"description": "Controls how you are notified when a new shell prompt is detected. Requires shell integration."
|
||||
},
|
||||
"notifyOnActivityThreshold": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 5,
|
||||
"description": "Minimum number of seconds between consecutive activity notifications for this profile. Use this to suppress repeated notifications from chatty processes. The first notification after the pane has been silent always fires; subsequent notifications within this window are suppressed. Use 0 to always notify."
|
||||
},
|
||||
"notifyOnNextPromptThreshold": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 5,
|
||||
"description": "Suppress the next-prompt notification unless the just-finished command ran for at least this many seconds. Requires shell integration. Use 0 to always notify."
|
||||
},
|
||||
"autoDetectRunningCommand": {
|
||||
"default": false,
|
||||
"description": "Automatically detect when a command is running and show a progress indicator in the tab and taskbar.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"closeOnExit": {
|
||||
"default": "automatic",
|
||||
"description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"automatic\" (behave as \"graceful\" only for processes launched by terminal, behave as \"always\" otherwise)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.",
|
||||
|
||||
@@ -231,6 +231,12 @@
|
||||
Glyph=""
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).BellIndicator, Mode=OneWay}" />
|
||||
|
||||
<FontIcon Margin="0,0,8,0"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="8"
|
||||
Glyph=""
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).ActivityIndicator, Mode=OneWay}" />
|
||||
|
||||
<FontIcon Margin="0,0,8,0"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace TerminalApp
|
||||
{
|
||||
String Title { get; };
|
||||
String Body { get; };
|
||||
Microsoft.Terminal.Control.OutputNotificationStyle Style { get; };
|
||||
Boolean AlwaysNotify { get; };
|
||||
};
|
||||
|
||||
interface IPaneContent
|
||||
@@ -31,7 +33,7 @@ namespace TerminalApp
|
||||
Windows.Foundation.Size MinimumSize { get; };
|
||||
|
||||
String Title { get; };
|
||||
UInt64 TaskbarState { get; };
|
||||
Microsoft.Terminal.Control.TaskbarState TaskbarState { get; };
|
||||
UInt64 TaskbarProgress { get; };
|
||||
Boolean ReadOnly { get; };
|
||||
String Icon { get; };
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const;
|
||||
|
||||
winrt::hstring Title() { return _filePath; }
|
||||
uint64_t TaskbarState() { return 0; }
|
||||
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState() { return winrt::Microsoft::Terminal::Control::TaskbarState::Clear; }
|
||||
uint64_t TaskbarProgress() { return 0; }
|
||||
bool ReadOnly() { return false; }
|
||||
winrt::hstring Icon() const;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const;
|
||||
|
||||
winrt::hstring Title() { return L"Scratchpad"; }
|
||||
uint64_t TaskbarState() { return 0; }
|
||||
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState() { return winrt::Microsoft::Terminal::Control::TaskbarState::Clear; }
|
||||
uint64_t TaskbarProgress() { return 0; }
|
||||
bool ReadOnly() { return false; }
|
||||
winrt::hstring Icon() const;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(const BuildStartupKind kind) const;
|
||||
|
||||
winrt::hstring Title() { return RS_(L"SettingsTab"); }
|
||||
uint64_t TaskbarState() { return 0; }
|
||||
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState() { return winrt::Microsoft::Terminal::Control::TaskbarState::Clear; }
|
||||
uint64_t TaskbarProgress() { return 0; }
|
||||
bool ReadOnly() { return false; }
|
||||
winrt::hstring Icon() const;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const;
|
||||
|
||||
winrt::hstring Title() { return RS_(L"SnippetPaneTitle/Text"); }
|
||||
uint64_t TaskbarState() { return 0; }
|
||||
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState() { return winrt::Microsoft::Terminal::Control::TaskbarState::Clear; }
|
||||
uint64_t TaskbarProgress() { return 0; }
|
||||
bool ReadOnly() { return false; }
|
||||
winrt::hstring Icon() const;
|
||||
|
||||
@@ -123,6 +123,12 @@ namespace winrt::TerminalApp::implementation
|
||||
_bellIndicatorTimer.Stop();
|
||||
}
|
||||
|
||||
void Tab::_ActivityIndicatorTimerTick(const Windows::Foundation::IInspectable& /*sender*/, const Windows::Foundation::IInspectable& /*e*/)
|
||||
{
|
||||
ShowActivityIndicator(false);
|
||||
_activityIndicatorTimer.Stop();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Initializes a TabViewItem for this Tab instance.
|
||||
// Arguments:
|
||||
@@ -329,6 +335,10 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
ShowBellIndicator(false);
|
||||
}
|
||||
if (_tabStatus.ActivityIndicator())
|
||||
{
|
||||
ShowActivityIndicator(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,6 +469,26 @@ namespace winrt::TerminalApp::implementation
|
||||
_bellIndicatorTimer.Start();
|
||||
}
|
||||
|
||||
void Tab::ShowActivityIndicator(const bool show)
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
|
||||
_tabStatus.ActivityIndicator(show);
|
||||
}
|
||||
|
||||
void Tab::ActivateActivityIndicatorTimer()
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
|
||||
if (!_activityIndicatorTimer)
|
||||
{
|
||||
_activityIndicatorTimer.Interval(std::chrono::milliseconds(2000));
|
||||
_activityIndicatorTimer.Tick({ get_weak(), &Tab::_ActivityIndicatorTimerTick });
|
||||
}
|
||||
|
||||
_activityIndicatorTimer.Start();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Gets the title string of the last focused terminal control in our tree.
|
||||
// Returns the empty string if there is no such control.
|
||||
@@ -1181,8 +1211,45 @@ namespace winrt::TerminalApp::implementation
|
||||
co_await wil::resume_foreground(dispatcher);
|
||||
if (const auto tab{ weakThisCopy.get() })
|
||||
{
|
||||
const auto title = notifArgs.Title().empty() ? tab->Title() : notifArgs.Title();
|
||||
tab->TabToastNotificationRequested.raise(title, notifArgs.Body(), sender);
|
||||
const auto activeContent = tab->GetActiveContent();
|
||||
const auto isActivePaneContent = activeContent && activeContent == sender;
|
||||
|
||||
if (!notifArgs.AlwaysNotify() && isActivePaneContent &&
|
||||
tab->_focusState != WUX::FocusState::Unfocused)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
const auto style = notifArgs.Style();
|
||||
|
||||
if (WI_IsFlagSet(style, OutputNotificationStyle::Taskbar))
|
||||
{
|
||||
tab->TabRaiseVisualBell.raise();
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Audible))
|
||||
{
|
||||
if (const auto termContent{ sender.try_as<TerminalApp::TerminalPaneContent>() })
|
||||
{
|
||||
termContent.PlayNotificationSound();
|
||||
}
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Tab))
|
||||
{
|
||||
tab->ShowActivityIndicator(true);
|
||||
|
||||
if (tab->_focusState != WUX::FocusState::Unfocused)
|
||||
{
|
||||
tab->ActivateActivityIndicatorTimer();
|
||||
}
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Notification))
|
||||
{
|
||||
const auto title = notifArgs.Title().empty() ? tab->Title() : notifArgs.Title();
|
||||
tab->TabToastNotificationRequested.raise(title, notifArgs.Body(), sender);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1242,11 +1309,10 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto taskbarState = state.State();
|
||||
// The progress of the control changed, but not necessarily the progress of the tab.
|
||||
// Set the tab's progress ring to the active pane's progress
|
||||
if (taskbarState > 0)
|
||||
if (taskbarState != winrt::Microsoft::Terminal::Control::TaskbarState::Clear)
|
||||
{
|
||||
if (taskbarState == 3)
|
||||
if (taskbarState == winrt::Microsoft::Terminal::Control::TaskbarState::Indeterminate)
|
||||
{
|
||||
// 3 is the indeterminate state, set the progress ring as such
|
||||
_tabStatus.IsProgressRingIndeterminate(true);
|
||||
}
|
||||
else
|
||||
@@ -1422,6 +1488,10 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
tab->ShowBellIndicator(false);
|
||||
}
|
||||
if (tab->_tabStatus.ActivityIndicator())
|
||||
{
|
||||
tab->ShowActivityIndicator(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void ShowBellIndicator(const bool show);
|
||||
void ActivateBellIndicatorTimer();
|
||||
|
||||
void ShowActivityIndicator(const bool show);
|
||||
void ActivateActivityIndicatorTimer();
|
||||
|
||||
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitDirection> PreCalculateCanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
|
||||
const float splitSize,
|
||||
@@ -215,6 +218,9 @@ namespace winrt::TerminalApp::implementation
|
||||
SafeDispatcherTimer _bellIndicatorTimer;
|
||||
void _BellIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
|
||||
|
||||
SafeDispatcherTimer _activityIndicatorTimer;
|
||||
void _ActivityIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
|
||||
|
||||
void _UpdateHeaderControlMaxWidth();
|
||||
|
||||
void _CreateContextMenu();
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
FontSize="12"
|
||||
Glyph=""
|
||||
Visibility="{x:Bind TabStatus.BellIndicator, Mode=OneWay}" />
|
||||
<FontIcon x:Name="HeaderActivityIndicator"
|
||||
Margin="0,0,8,0"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="8"
|
||||
Glyph=""
|
||||
Visibility="{x:Bind TabStatus.ActivityIndicator, Mode=OneWay}" />
|
||||
<FontIcon x:Name="HeaderZoomIcon"
|
||||
Margin="0,0,8,0"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
|
||||
@@ -1416,8 +1416,8 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// The toast Activated callback runs on a background thread.
|
||||
// Marshal to the UI thread for tab focus and window summon.
|
||||
page->Dispatcher().RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [weakPage{ page->get_weak() }, weakTab, weakContent]() {
|
||||
if (const auto p{ weakPage.get() })
|
||||
page->Dispatcher().RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis, weakTab, weakContent]() {
|
||||
if (const auto p{ weakThis.get() })
|
||||
{
|
||||
if (const auto t{ weakTab.get() })
|
||||
{
|
||||
|
||||
@@ -9,27 +9,28 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Default to unset, 0%.
|
||||
TaskbarState::TaskbarState() :
|
||||
TaskbarState(0, 0) {};
|
||||
TaskbarState(winrt::Microsoft::Terminal::Control::TaskbarState::Clear, 0) {};
|
||||
|
||||
TaskbarState::TaskbarState(const uint64_t dispatchTypesState, const uint64_t progressParam) :
|
||||
_State{ dispatchTypesState },
|
||||
TaskbarState::TaskbarState(const winrt::Microsoft::Terminal::Control::TaskbarState state, const uint64_t progressParam) :
|
||||
_State{ state },
|
||||
_Progress{ progressParam } {}
|
||||
|
||||
uint64_t TaskbarState::Priority() const
|
||||
{
|
||||
// This seemingly nonsensical ordering is from
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group
|
||||
using TbState = winrt::Microsoft::Terminal::Control::TaskbarState;
|
||||
switch (_State)
|
||||
{
|
||||
case 0: // Clear = 0,
|
||||
case TbState::Clear:
|
||||
return 5;
|
||||
case 1: // Set = 1,
|
||||
case TbState::Set:
|
||||
return 3;
|
||||
case 2: // Error = 2,
|
||||
case TbState::Error:
|
||||
return 1;
|
||||
case 3: // Indeterminate = 3,
|
||||
case TbState::Indeterminate:
|
||||
return 4;
|
||||
case 4: // Paused = 4
|
||||
case TbState::Paused:
|
||||
return 2;
|
||||
}
|
||||
// Here, return 6, to definitely be greater than all the other valid values.
|
||||
|
||||
@@ -16,13 +16,13 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
public:
|
||||
TaskbarState();
|
||||
TaskbarState(const uint64_t dispatchTypesState, const uint64_t progress);
|
||||
TaskbarState(const winrt::Microsoft::Terminal::Control::TaskbarState state, const uint64_t progress);
|
||||
|
||||
static int ComparePriority(const winrt::TerminalApp::TaskbarState& lhs, const winrt::TerminalApp::TaskbarState& rhs);
|
||||
|
||||
uint64_t Priority() const;
|
||||
|
||||
WINRT_PROPERTY(uint64_t, State, 0);
|
||||
WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::TaskbarState, State, winrt::Microsoft::Terminal::Control::TaskbarState::Clear);
|
||||
WINRT_PROPERTY(uint64_t, Progress, 0);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace TerminalApp
|
||||
[default_interface] runtimeclass TaskbarState
|
||||
{
|
||||
TaskbarState();
|
||||
TaskbarState(UInt64 dispatchTypesState, UInt64 progress);
|
||||
TaskbarState(Microsoft.Terminal.Control.TaskbarState state, UInt64 progress);
|
||||
|
||||
UInt64 State{ get; };
|
||||
Microsoft.Terminal.Control.TaskbarState State{ get; };
|
||||
UInt64 Progress{ get; };
|
||||
UInt64 Priority { get; };
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
#include "BellEventArgs.g.cpp"
|
||||
#include "NotificationEventArgs.g.cpp"
|
||||
#include "TerminalPaneContent.g.cpp"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
@@ -34,6 +35,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &TerminalPaneContent::_controlConnectionStateChangedHandler });
|
||||
_controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlWarningBellHandler });
|
||||
_controlEvents._PromptStarted = _control.PromptStarted(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlPromptStartedHandler });
|
||||
_controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_closeTerminalRequestedHandler });
|
||||
_controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_restartTerminalRequestedHandler });
|
||||
|
||||
@@ -42,6 +44,8 @@ namespace winrt::TerminalApp::implementation
|
||||
_controlEvents._SetTaskbarProgress = _control.SetTaskbarProgress(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlSetTaskbarProgress });
|
||||
_controlEvents._ReadOnlyChanged = _control.ReadOnlyChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlReadOnlyChanged });
|
||||
_controlEvents._FocusFollowMouseRequested = _control.FocusFollowMouseRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlFocusFollowMouseRequested });
|
||||
_controlEvents._OutputStarted = _control.OutputStarted(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlOutputStartedHandler });
|
||||
_controlEvents._OutputBurstEnded = _control.OutputIdle(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlOutputBurstEndedHandler });
|
||||
_controlEvents._ShowNotification = _control.ShowNotification(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlShowNotification });
|
||||
}
|
||||
void TerminalPaneContent::_removeControlEvents()
|
||||
@@ -162,6 +166,16 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
TaskbarProgressChanged.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
winrt::Microsoft::Terminal::Control::TaskbarState TerminalPaneContent::TaskbarState()
|
||||
{
|
||||
return _control.TaskbarState();
|
||||
}
|
||||
|
||||
uint64_t TerminalPaneContent::TaskbarProgress()
|
||||
{
|
||||
return _control.TaskbarProgress();
|
||||
}
|
||||
void TerminalPaneContent::_controlReadOnlyChanged(const IInspectable&, const IInspectable&)
|
||||
{
|
||||
ReadOnlyChanged.raise(*this, nullptr);
|
||||
@@ -173,7 +187,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void TerminalPaneContent::_controlShowNotification(const IInspectable& /*sender*/, const ShowNotificationEventArgs& args)
|
||||
{
|
||||
NotificationRequested.raise(*this, winrt::make<implementation::NotificationEventArgs>(args.Title(), args.Body()));
|
||||
NotificationRequested.raise(*this, winrt::make<implementation::NotificationEventArgs>(OutputNotificationStyle::Notification, true /*alwaysNotify*/, args.Title(), args.Body()));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -255,6 +269,26 @@ namespace winrt::TerminalApp::implementation
|
||||
// has the 'visual' flag set
|
||||
// Arguments:
|
||||
// - <unused>
|
||||
void TerminalPaneContent::PlayNotificationSound()
|
||||
{
|
||||
if (_profile)
|
||||
{
|
||||
auto sounds{ _profile.BellSound() };
|
||||
if (sounds && sounds.Size() > 0)
|
||||
{
|
||||
// Sound paths are resolved and validated by CascadiaSettings
|
||||
// before we reach this point.
|
||||
auto soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
|
||||
PlaySoundW(soundPath.c_str(), nullptr, SND_FILENAME | SND_ASYNC | SND_SENTRY | SND_NODEFAULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto soundAlias = reinterpret_cast<LPCWSTR>(SND_ALIAS_SYSTEMHAND);
|
||||
PlaySoundW(soundAlias, nullptr, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPaneContent::_controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
|
||||
{
|
||||
@@ -266,19 +300,7 @@ namespace winrt::TerminalApp::implementation
|
||||
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible))
|
||||
{
|
||||
// Audible is set, play the sound
|
||||
auto sounds{ _profile.BellSound() };
|
||||
if (sounds && sounds.Size() > 0)
|
||||
{
|
||||
// Sound paths are resolved and validated by CascadiaSettings
|
||||
// before we reach this point.
|
||||
auto soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
|
||||
PlaySoundW(soundPath.c_str(), nullptr, SND_FILENAME | SND_ASYNC | SND_SENTRY | SND_NODEFAULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto soundAlias = reinterpret_cast<LPCWSTR>(SND_ALIAS_SYSTEMHAND);
|
||||
PlaySoundW(soundAlias, nullptr, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
|
||||
}
|
||||
PlayNotificationSound();
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
|
||||
@@ -295,6 +317,67 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPaneContent::_controlPromptStartedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
|
||||
{
|
||||
if (_profile)
|
||||
{
|
||||
const auto notifyStyle = _profile.NotifyOnNextPrompt();
|
||||
if (notifyStyle != OutputNotificationStyle::None)
|
||||
{
|
||||
if (const auto thresholdInSeconds = _profile.NotifyOnNextPromptThreshold(); thresholdInSeconds > 0)
|
||||
{
|
||||
if (_lastOutputStartedAt == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (const auto elapsedMs = GetTickCount64() - _lastOutputStartedAt; elapsedMs < (static_cast<uint64_t>(thresholdInSeconds) * 1000))
|
||||
{
|
||||
_lastOutputStartedAt = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_lastOutputStartedAt = 0;
|
||||
|
||||
NotificationRequested.raise(*this,
|
||||
*winrt::make_self<TerminalApp::implementation::NotificationEventArgs>(notifyStyle, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPaneContent::_controlOutputStartedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
|
||||
{
|
||||
_lastOutputStartedAt = GetTickCount64();
|
||||
}
|
||||
|
||||
// The underlying TermControl::OutputIdle event is fired on the trailing
|
||||
// edge of a 100ms-debounced output burst (see ControlCore::Initialize).
|
||||
// When "notifyOnActivity" is enabled, we get one event per burst of
|
||||
// output, which naturally coalesces a stream of output into a single notification.
|
||||
void TerminalPaneContent::_controlOutputBurstEndedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
|
||||
{
|
||||
if (_profile)
|
||||
{
|
||||
const auto notifyStyle = _profile.NotifyOnActivity();
|
||||
if (notifyStyle != OutputNotificationStyle::None)
|
||||
{
|
||||
const auto now = GetTickCount64();
|
||||
const auto thresholdSeconds = _profile.NotifyOnActivityThreshold();
|
||||
if (thresholdSeconds > 0 &&
|
||||
_lastActivityNotificationAt != 0 &&
|
||||
(now - _lastActivityNotificationAt) < (static_cast<uint64_t>(thresholdSeconds) * 1000))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_lastActivityNotificationAt = now;
|
||||
|
||||
NotificationRequested.raise(*this,
|
||||
*winrt::make_self<TerminalApp::implementation::NotificationEventArgs>(notifyStyle, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
void TerminalPaneContent::_closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
{
|
||||
|
||||
@@ -24,9 +24,11 @@ namespace winrt::TerminalApp::implementation
|
||||
struct NotificationEventArgs : public NotificationEventArgsT<NotificationEventArgs>
|
||||
{
|
||||
public:
|
||||
NotificationEventArgs(const winrt::hstring& title = {}, const winrt::hstring& body = {}) :
|
||||
Title(title), Body(body) {}
|
||||
NotificationEventArgs(winrt::Microsoft::Terminal::Control::OutputNotificationStyle style, bool alwaysNotify = true, const winrt::hstring& title = {}, const winrt::hstring& body = {}) :
|
||||
Style(style), AlwaysNotify(alwaysNotify), Title(title), Body(body) {}
|
||||
|
||||
til::property<winrt::Microsoft::Terminal::Control::OutputNotificationStyle> Style;
|
||||
til::property<bool> AlwaysNotify;
|
||||
til::property<winrt::hstring> Title;
|
||||
til::property<winrt::hstring> Body;
|
||||
};
|
||||
@@ -48,6 +50,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
|
||||
|
||||
void MarkAsDefterm();
|
||||
void PlayNotificationSound();
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const
|
||||
{
|
||||
@@ -55,8 +58,8 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
winrt::hstring Title() { return _control.Title(); }
|
||||
uint64_t TaskbarState() { return _control.TaskbarState(); }
|
||||
uint64_t TaskbarProgress() { return _control.TaskbarProgress(); }
|
||||
winrt::Microsoft::Terminal::Control::TaskbarState TaskbarState();
|
||||
uint64_t TaskbarProgress();
|
||||
bool ReadOnly() { return _control.ReadOnly(); }
|
||||
winrt::hstring Icon() const;
|
||||
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept;
|
||||
@@ -76,10 +79,18 @@ namespace winrt::TerminalApp::implementation
|
||||
std::shared_ptr<TerminalSettingsCache> _cache{};
|
||||
bool _isDefTermSession{ false };
|
||||
|
||||
// Tracks the GetTickCount64() for NotifyOnActivityThreshold
|
||||
// and NotifyOnNextPromptThreshold respectively.
|
||||
uint64_t _lastActivityNotificationAt{ 0 };
|
||||
uint64_t _lastOutputStartedAt{ 0 };
|
||||
|
||||
struct ControlEventTokens
|
||||
{
|
||||
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::WarningBell_revoker _WarningBell;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::PromptStarted_revoker _PromptStarted;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::OutputStarted_revoker _OutputStarted;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::OutputIdle_revoker _OutputBurstEnded;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::CloseTerminalRequested_revoker _CloseTerminalRequested;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::RestartTerminalRequested_revoker _RestartTerminalRequested;
|
||||
|
||||
@@ -97,6 +108,9 @@ namespace winrt::TerminalApp::implementation
|
||||
safe_void_coroutine _controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
|
||||
void _controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& e);
|
||||
void _controlPromptStartedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& eventArgs);
|
||||
void _controlOutputStartedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& eventArgs);
|
||||
void _controlOutputBurstEndedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& eventArgs);
|
||||
void _controlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e);
|
||||
|
||||
void _controlTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace TerminalApp
|
||||
Microsoft.Terminal.Control.TermControl GetTermControl();
|
||||
|
||||
void MarkAsDefterm();
|
||||
void PlayNotificationSound();
|
||||
|
||||
Microsoft.Terminal.Settings.Model.Profile GetProfile();
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace winrt::TerminalApp::implementation
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingActive, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingIndeterminate, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, BellIndicator, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, ActivityIndicator, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, IsReadOnlyActive, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(uint32_t, ProgressValue, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, IsInputBroadcastActive, PropertyChanged.raise);
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace TerminalApp
|
||||
Boolean IsProgressRingActive { get; set; };
|
||||
Boolean IsProgressRingIndeterminate { get; set; };
|
||||
Boolean BellIndicator { get; set; };
|
||||
Boolean ActivityIndicator { get; set; };
|
||||
UInt32 ProgressValue { get; set; };
|
||||
Boolean IsReadOnlyActive { get; set; };
|
||||
Boolean IsInputBroadcastActive { get; set; };
|
||||
|
||||
@@ -139,6 +139,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto pfnSearchMissingCommand = [this](auto&& PH1, auto&& PH2) { _terminalSearchMissingCommand(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2)); };
|
||||
_terminal->SetSearchMissingCommandCallback(pfnSearchMissingCommand);
|
||||
|
||||
auto pfnPromptStarted = [this] { _terminalPromptStarted(); };
|
||||
_terminal->SetPromptStartedCallback(pfnPromptStarted);
|
||||
|
||||
auto pfnOutputStarted = [this] { _terminalOutputStarted(); };
|
||||
_terminal->SetOutputStartedCallback(pfnOutputStarted);
|
||||
|
||||
auto pfnShowNotification = [this](auto&& PH1, auto&& PH2) { _terminalShowNotification(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2)); };
|
||||
_terminal->SetShowNotificationCallback(pfnShowNotification);
|
||||
|
||||
@@ -916,6 +922,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_hasUnfocusedAppearance = static_cast<bool>(newAppearance);
|
||||
_unfocusedAppearance = _hasUnfocusedAppearance ? newAppearance : settings;
|
||||
|
||||
// Cache the auto-detect setting in an atomic so the off-thread output/prompt
|
||||
// callbacks can read it without synchronizing with _settings. If the effective
|
||||
// taskbar state changes (because a command is currently active and the setting
|
||||
// toggled), notify listeners.
|
||||
const auto nowEnabled = _settings.AutoDetectRunningCommand();
|
||||
const auto wasEnabled = _autoDetectCommandActivity.exchange(nowEnabled, std::memory_order_relaxed);
|
||||
if (wasEnabled != nowEnabled && _commandActive.load(std::memory_order_relaxed))
|
||||
{
|
||||
TaskbarProgressChanged.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
|
||||
_builtinGlyphs = _settings.EnableBuiltinGlyphs();
|
||||
@@ -1551,10 +1568,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - Gets the internal taskbar state value
|
||||
// Return Value:
|
||||
// - The taskbar state of this control
|
||||
const size_t ControlCore::TaskbarState() const noexcept
|
||||
const Control::TaskbarState ControlCore::TaskbarState() const noexcept
|
||||
{
|
||||
const auto lock = _terminal->LockForReading();
|
||||
return _terminal->GetTaskbarState();
|
||||
const auto vtState = static_cast<Control::TaskbarState>(_terminal->GetTaskbarState());
|
||||
if (vtState == Control::TaskbarState::Clear &&
|
||||
_autoDetectCommandActivity.load(std::memory_order_relaxed) &&
|
||||
_commandActive.load(std::memory_order_relaxed))
|
||||
{
|
||||
return Control::TaskbarState::Indeterminate;
|
||||
}
|
||||
return vtState;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1603,6 +1627,26 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
WarningBell.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void ControlCore::_terminalPromptStarted()
|
||||
{
|
||||
if (_commandActive.exchange(false, std::memory_order_relaxed) &&
|
||||
_autoDetectCommandActivity.load(std::memory_order_relaxed))
|
||||
{
|
||||
TaskbarProgressChanged.raise(*this, nullptr);
|
||||
}
|
||||
PromptStarted.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void ControlCore::_terminalOutputStarted()
|
||||
{
|
||||
if (!_commandActive.exchange(true, std::memory_order_relaxed) &&
|
||||
_autoDetectCommandActivity.load(std::memory_order_relaxed))
|
||||
{
|
||||
TaskbarProgressChanged.raise(*this, nullptr);
|
||||
}
|
||||
OutputStarted.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called for the Terminal's TitleChanged callback. This will re-raise
|
||||
// a new winrt TypedEvent that can be listened to.
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void OpenCWD();
|
||||
|
||||
#pragma region ICoreState
|
||||
const size_t TaskbarState() const noexcept;
|
||||
const Control::TaskbarState TaskbarState() const noexcept;
|
||||
const size_t TaskbarProgress() const noexcept;
|
||||
|
||||
hstring Title();
|
||||
@@ -275,6 +275,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
til::typed_event<IInspectable, Control::TitleChangedEventArgs> TitleChanged;
|
||||
til::typed_event<IInspectable, Control::WriteToClipboardEventArgs> WriteToClipboard;
|
||||
til::typed_event<> WarningBell;
|
||||
til::typed_event<> PromptStarted;
|
||||
til::typed_event<> OutputStarted;
|
||||
til::typed_event<> TabColorChanged;
|
||||
til::typed_event<> BackgroundColorChanged;
|
||||
til::typed_event<IInspectable, Control::ScrollPositionChangedArgs> ScrollPositionChanged;
|
||||
@@ -324,6 +326,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
#pragma region TerminalCoreCallbacks
|
||||
void _terminalWarningBell();
|
||||
void _terminalPromptStarted();
|
||||
void _terminalOutputStarted();
|
||||
void _terminalTitleChanged(std::wstring_view wstr);
|
||||
void _terminalScrollPositionChanged(const int viewTop,
|
||||
const int viewHeight,
|
||||
@@ -422,6 +426,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
std::optional<til::point> _lastHoveredCell;
|
||||
uint16_t _lastHoveredId{ 0 };
|
||||
std::atomic<bool> _initializedTerminal{ false };
|
||||
std::atomic<bool> _autoDetectCommandActivity{ false };
|
||||
std::atomic<bool> _commandActive{ false };
|
||||
bool _isReadOnly{ false };
|
||||
bool _closing{ false };
|
||||
|
||||
|
||||
@@ -192,6 +192,8 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, WriteToClipboardEventArgs> WriteToClipboard;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> PromptStarted;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OutputStarted;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> BackgroundColorChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;
|
||||
|
||||
@@ -29,6 +29,30 @@ namespace Microsoft.Terminal.Control
|
||||
MinGW,
|
||||
};
|
||||
|
||||
[flags]
|
||||
enum OutputNotificationStyle
|
||||
{
|
||||
None = 0,
|
||||
Taskbar = 0x1,
|
||||
Audible = 0x2,
|
||||
Tab = 0x4,
|
||||
Notification = 0x8,
|
||||
All = 0xffffffff
|
||||
};
|
||||
|
||||
// Mirrors Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState
|
||||
// (which is shared with conhost and lives outside the WinRT projection).
|
||||
// Values must remain numerically identical so the conversion at the
|
||||
// ControlCore boundary is a 1:1 cast.
|
||||
enum TaskbarState
|
||||
{
|
||||
Clear = 0,
|
||||
Set = 1,
|
||||
Error = 2,
|
||||
Indeterminate = 3,
|
||||
Paused = 4,
|
||||
};
|
||||
|
||||
// Class Description:
|
||||
// TerminalSettings encapsulates all settings that control the
|
||||
// TermControl's behavior. In these settings there is both the entirety
|
||||
@@ -78,6 +102,12 @@ namespace Microsoft.Terminal.Control
|
||||
PathTranslationStyle PathTranslationStyle { get; };
|
||||
String DragDropDelimiter { get; };
|
||||
|
||||
OutputNotificationStyle NotifyOnActivity { get; };
|
||||
OutputNotificationStyle NotifyOnNextPrompt { get; };
|
||||
Int32 NotifyOnActivityThreshold { get; };
|
||||
Int32 NotifyOnNextPromptThreshold { get; };
|
||||
Boolean AutoDetectRunningCommand { get; };
|
||||
|
||||
// NOTE! When adding something here, make sure to update ControlProperties.h too!
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "IControlSettings.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Control
|
||||
{
|
||||
enum MarkCategory
|
||||
@@ -31,7 +33,7 @@ namespace Microsoft.Terminal.Control
|
||||
interface ICoreState
|
||||
{
|
||||
String Title { get; };
|
||||
UInt64 TaskbarState { get; };
|
||||
Microsoft.Terminal.Control.TaskbarState TaskbarState { get; };
|
||||
UInt64 TaskbarProgress { get; };
|
||||
|
||||
String WorkingDirectory { get; };
|
||||
|
||||
@@ -394,6 +394,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// attached content before we set up the throttled func, and that'll A/V
|
||||
_revokers.coreScrollPositionChanged = _core.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
|
||||
_revokers.WarningBell = _core.WarningBell(winrt::auto_revoke, { get_weak(), &TermControl::_coreWarningBell });
|
||||
_revokers.PromptStarted = _core.PromptStarted(winrt::auto_revoke, { get_weak(), &TermControl::_corePromptStarted });
|
||||
_revokers.OutputStarted = _core.OutputStarted(winrt::auto_revoke, { get_weak(), &TermControl::_coreOutputStarted });
|
||||
|
||||
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
|
||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||
@@ -3357,7 +3359,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - Gets the internal taskbar state value
|
||||
// Return Value:
|
||||
// - The taskbar state of this control
|
||||
const uint64_t TermControl::TaskbarState() const noexcept
|
||||
const Control::TaskbarState TermControl::TaskbarState() const noexcept
|
||||
{
|
||||
return _core.TaskbarState();
|
||||
}
|
||||
@@ -3727,6 +3729,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_playWarningBell->Run();
|
||||
}
|
||||
|
||||
void TermControl::_corePromptStarted(const IInspectable& /*sender*/, const IInspectable& /*args*/)
|
||||
{
|
||||
PromptStarted.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void TermControl::_coreOutputStarted(const IInspectable& /*sender*/, const IInspectable& /*args*/)
|
||||
{
|
||||
OutputStarted.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
hstring TermControl::ReadEntireBuffer() const
|
||||
{
|
||||
return _core.ReadEntireBuffer();
|
||||
@@ -3844,6 +3856,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControl::_coreOutputIdle(const IInspectable& /*sender*/, const IInspectable& /*args*/)
|
||||
{
|
||||
_refreshSearch();
|
||||
OutputIdle.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void TermControl::OwningHwnd(uint64_t owner)
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ColorSelection(Control::SelectionColor fg, Control::SelectionColor bg, Core::MatchMode matchMode);
|
||||
|
||||
#pragma region ICoreState
|
||||
const uint64_t TaskbarState() const noexcept;
|
||||
const Control::TaskbarState TaskbarState() const noexcept;
|
||||
const uint64_t TaskbarProgress() const noexcept;
|
||||
|
||||
hstring Title();
|
||||
@@ -211,6 +211,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
til::typed_event<IInspectable, IInspectable> FocusFollowMouseRequested;
|
||||
til::typed_event<Control::TermControl, Windows::UI::Xaml::RoutedEventArgs> Initialized;
|
||||
til::typed_event<> WarningBell;
|
||||
til::typed_event<> PromptStarted;
|
||||
til::typed_event<> OutputStarted;
|
||||
til::typed_event<> OutputIdle;
|
||||
til::typed_event<IInspectable, Control::KeySentEventArgs> KeySent;
|
||||
til::typed_event<IInspectable, Control::CharSentEventArgs> CharSent;
|
||||
til::typed_event<IInspectable, Control::StringSentEventArgs> StringSent;
|
||||
@@ -425,6 +428,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
|
||||
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
|
||||
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
|
||||
void _corePromptStarted(const IInspectable& sender, const IInspectable& args);
|
||||
void _coreOutputStarted(const IInspectable& sender, const IInspectable& args);
|
||||
void _coreOutputIdle(const IInspectable& sender, const IInspectable& args);
|
||||
|
||||
winrt::Windows::Foundation::Point _toPosInDips(const Core::Point terminalCellPos);
|
||||
@@ -450,6 +455,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
Control::ControlCore::ScrollPositionChanged_revoker coreScrollPositionChanged;
|
||||
Control::ControlCore::WarningBell_revoker WarningBell;
|
||||
Control::ControlCore::PromptStarted_revoker PromptStarted;
|
||||
Control::ControlCore::OutputStarted_revoker OutputStarted;
|
||||
Control::ControlCore::RendererEnteredErrorState_revoker RendererEnteredErrorState;
|
||||
Control::ControlCore::BackgroundColorChanged_revoker BackgroundColorChanged;
|
||||
Control::ControlCore::FontSizeChanged_revoker FontSizeChanged;
|
||||
|
||||
@@ -69,6 +69,9 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> PromptStarted;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OutputStarted;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OutputIdle;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HidePointerCursor;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RestorePointerCursor;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
||||
|
||||
@@ -768,6 +768,11 @@ TerminalInput::OutputType Terminal::SendCharEvent(const wchar_t ch, const WORD s
|
||||
// This changed the scrollbar marks - raise a notification to update them
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
// regardless, notify that we started command output
|
||||
if (_pfnOutputStarted)
|
||||
{
|
||||
_pfnOutputStarted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1253,7 +1258,7 @@ const std::optional<til::color> Terminal::GetTabColor() const
|
||||
// - Gets the internal taskbar state value
|
||||
// Return Value:
|
||||
// - The taskbar state
|
||||
const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarState() const noexcept
|
||||
const Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState Microsoft::Terminal::Core::Terminal::GetTaskbarState() const noexcept
|
||||
{
|
||||
return _taskbarState;
|
||||
}
|
||||
@@ -1287,6 +1292,16 @@ void Microsoft::Terminal::Core::Terminal::SetClearQuickFixCallback(std::function
|
||||
_pfnClearQuickFix.swap(pfn);
|
||||
}
|
||||
|
||||
void Terminal::SetPromptStartedCallback(std::function<void()> pfn) noexcept
|
||||
{
|
||||
_pfnPromptStarted.swap(pfn);
|
||||
}
|
||||
|
||||
void Terminal::SetOutputStartedCallback(std::function<void()> pfn) noexcept
|
||||
{
|
||||
_pfnOutputStarted.swap(pfn);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Stores the search highlighted regions in the terminal
|
||||
void Terminal::SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept
|
||||
|
||||
@@ -159,7 +159,7 @@ public:
|
||||
|
||||
bool IsVtInputEnabled() const noexcept override;
|
||||
void NotifyBufferRotation(const int delta) override;
|
||||
void NotifyShellIntegrationMark() override;
|
||||
void NotifyShellIntegrationMark(ShellIntegrationMark mark) override;
|
||||
|
||||
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;
|
||||
|
||||
@@ -238,6 +238,8 @@ public:
|
||||
void SetShowNotificationCallback(std::function<void(std::wstring_view, std::wstring_view)> pfn) noexcept;
|
||||
void SetClearQuickFixCallback(std::function<void()> pfn) noexcept;
|
||||
void SetWindowSizeChangedCallback(std::function<void(int32_t, int32_t)> pfn) noexcept;
|
||||
void SetPromptStartedCallback(std::function<void()> pfn) noexcept;
|
||||
void SetOutputStartedCallback(std::function<void()> pfn) noexcept;
|
||||
void SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept;
|
||||
void SetSearchHighlightFocused(size_t focusedIdx) noexcept;
|
||||
void ScrollToSearchHighlight(til::CoordType searchScrollOffset);
|
||||
@@ -246,7 +248,7 @@ public:
|
||||
|
||||
const std::optional<til::color> GetTabColor() const;
|
||||
|
||||
const size_t GetTaskbarState() const noexcept;
|
||||
const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState GetTaskbarState() const noexcept;
|
||||
const size_t GetTaskbarProgress() const noexcept;
|
||||
|
||||
void ColorSelection(const TextAttribute& attr, winrt::Microsoft::Terminal::Core::MatchMode matchMode);
|
||||
@@ -347,6 +349,8 @@ private:
|
||||
std::function<void(std::wstring_view, std::wstring_view)> _pfnShowNotification;
|
||||
std::function<void()> _pfnClearQuickFix;
|
||||
std::function<void(int32_t, int32_t)> _pfnWindowSizeChanged;
|
||||
std::function<void()> _pfnPromptStarted;
|
||||
std::function<void()> _pfnOutputStarted;
|
||||
|
||||
RenderSettings _renderSettings;
|
||||
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
|
||||
@@ -367,6 +371,9 @@ private:
|
||||
|
||||
til::enumset<Mode> _systemMode{ Mode::AutoWrap };
|
||||
|
||||
::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState _taskbarState{ ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState::Clear };
|
||||
size_t _taskbarProgress = 0;
|
||||
|
||||
bool _focused = false;
|
||||
bool _snapOnInput = true;
|
||||
bool _altGrAliasing = true;
|
||||
@@ -375,9 +382,6 @@ private:
|
||||
bool _autoMarkPrompts = false;
|
||||
bool _rainbowSuggestions = false;
|
||||
|
||||
size_t _taskbarState = 0;
|
||||
size_t _taskbarProgress = 0;
|
||||
|
||||
size_t _hyperlinkPatternId = 0;
|
||||
|
||||
std::wstring _answerbackMessage;
|
||||
|
||||
@@ -173,7 +173,7 @@ void Terminal::SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::D
|
||||
{
|
||||
_assertLocked();
|
||||
|
||||
_taskbarState = static_cast<size_t>(state);
|
||||
_taskbarState = state;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
@@ -424,8 +424,26 @@ void Terminal::NotifyBufferRotation(const int delta)
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::NotifyShellIntegrationMark()
|
||||
void Terminal::NotifyShellIntegrationMark(ShellIntegrationMark mark)
|
||||
{
|
||||
// Notify the scrollbar that marks have been added so it can refresh the mark indicators
|
||||
_NotifyScrollEvent();
|
||||
|
||||
switch (mark)
|
||||
{
|
||||
case ShellIntegrationMark::Prompt:
|
||||
if (_pfnPromptStarted)
|
||||
{
|
||||
_pfnPromptStarted();
|
||||
}
|
||||
break;
|
||||
case ShellIntegrationMark::Output:
|
||||
if (_pfnOutputStarted)
|
||||
{
|
||||
_pfnOutputStarted();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,6 +371,11 @@ namespace winrt::Microsoft::Terminal::Settings
|
||||
_AllowOscNotifications = profile.AllowOscNotifications();
|
||||
_PathTranslationStyle = profile.PathTranslationStyle();
|
||||
_DragDropDelimiter = profile.DragDropDelimiter();
|
||||
_NotifyOnActivity = profile.NotifyOnActivity();
|
||||
_NotifyOnNextPrompt = profile.NotifyOnNextPrompt();
|
||||
_NotifyOnActivityThreshold = profile.NotifyOnActivityThreshold();
|
||||
_NotifyOnNextPromptThreshold = profile.NotifyOnNextPromptThreshold();
|
||||
_AutoDetectRunningCommand = profile.AutoDetectRunningCommand();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -107,6 +107,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
_NotifyChanges(L"CurrentPathTranslationStyle");
|
||||
}
|
||||
else if (viewModelProperty == L"NotifyOnActivity")
|
||||
{
|
||||
_NotifyChanges(L"IsNotifyOnActivityFlagSet", L"NotifyOnActivityPreview");
|
||||
}
|
||||
else if (viewModelProperty == L"NotifyOnNextPrompt")
|
||||
{
|
||||
_NotifyChanges(L"IsNotifyOnNextPromptFlagSet", L"NotifyOnNextPromptPreview");
|
||||
}
|
||||
else if (viewModelProperty == L"Padding")
|
||||
{
|
||||
_parsedPadding = StringToXamlThickness(_profile.Padding());
|
||||
@@ -419,7 +427,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// Compile-time tripwire. PROFILE_INHERITABLE_SETTINGS now generates both the
|
||||
// property accessors and the dispatch above, so those two can no longer drift.
|
||||
#define PROFILE_COUNT(target, name) +1
|
||||
static_assert(0 PROFILE_INHERITABLE_SETTINGS(PROFILE_COUNT) == 34,
|
||||
static_assert(0 PROFILE_INHERITABLE_SETTINGS(PROFILE_COUNT) == 39,
|
||||
"The set of inheritable profile settings changed. Update this count, then make "
|
||||
"sure the new/removed setting is also reflected in ProfileViewModel.idl and in the "
|
||||
"XAML reset buttons.");
|
||||
@@ -636,6 +644,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return iconPath.empty() || iconPath == IconPicker::HideIconValue;
|
||||
}
|
||||
|
||||
#pragma region BellStyle
|
||||
hstring ProfileViewModel::BellStylePreview() const
|
||||
{
|
||||
const auto bellStyle = BellStyle();
|
||||
@@ -715,6 +724,147 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
WI_UpdateFlag(currentStyle, Model::BellStyle::Notification, winrt::unbox_value<bool>(on));
|
||||
BellStyle(currentStyle);
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region NotifyOnActivity
|
||||
hstring ProfileViewModel::NotifyOnActivityPreview() const
|
||||
{
|
||||
using Ons = Control::OutputNotificationStyle;
|
||||
const auto style = NotifyOnActivity();
|
||||
if (WI_AreAllFlagsSet(style, Ons::Taskbar | Ons::Audible | Ons::Tab | Ons::Notification))
|
||||
{
|
||||
return RS_(L"Profile_OutputNotificationStyleAll/Content");
|
||||
}
|
||||
else if (style == Ons::None)
|
||||
{
|
||||
return RS_(L"Profile_OutputNotificationStyleNone/Content");
|
||||
}
|
||||
|
||||
std::wstring result;
|
||||
const auto appendIfFlagSet = [&](Ons flag, std::wstring_view resource) {
|
||||
// WI_IsFlagSet requires a compile-time constant flag; `flag` is a runtime parameter here.
|
||||
if ((WI_EnumValue(style) & WI_EnumValue(flag)) != 0)
|
||||
{
|
||||
if (!result.empty())
|
||||
{
|
||||
result.append(L", ");
|
||||
}
|
||||
result.append(resource);
|
||||
}
|
||||
};
|
||||
|
||||
appendIfFlagSet(Ons::Taskbar, RS_(L"Profile_OutputNotificationStyleTaskbar/Content"));
|
||||
appendIfFlagSet(Ons::Audible, RS_(L"Profile_OutputNotificationStyleAudible/Content"));
|
||||
appendIfFlagSet(Ons::Tab, RS_(L"Profile_OutputNotificationStyleTab/Content"));
|
||||
appendIfFlagSet(Ons::Notification, RS_(L"Profile_OutputNotificationStyleNotification/Content"));
|
||||
|
||||
return hstring{ result };
|
||||
}
|
||||
|
||||
bool ProfileViewModel::IsNotifyOnActivityFlagSet(const uint32_t flag)
|
||||
{
|
||||
return (WI_EnumValue(NotifyOnActivity()) & flag) == flag;
|
||||
}
|
||||
|
||||
void ProfileViewModel::SetNotifyOnActivityTaskbar(winrt::Windows::Foundation::IReference<bool> on)
|
||||
{
|
||||
auto currentStyle = NotifyOnActivity();
|
||||
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Taskbar, winrt::unbox_value<bool>(on));
|
||||
NotifyOnActivity(currentStyle);
|
||||
}
|
||||
|
||||
void ProfileViewModel::SetNotifyOnActivityAudible(winrt::Windows::Foundation::IReference<bool> on)
|
||||
{
|
||||
auto currentStyle = NotifyOnActivity();
|
||||
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Audible, winrt::unbox_value<bool>(on));
|
||||
NotifyOnActivity(currentStyle);
|
||||
}
|
||||
|
||||
void ProfileViewModel::SetNotifyOnActivityTab(winrt::Windows::Foundation::IReference<bool> on)
|
||||
{
|
||||
auto currentStyle = NotifyOnActivity();
|
||||
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Tab, winrt::unbox_value<bool>(on));
|
||||
NotifyOnActivity(currentStyle);
|
||||
}
|
||||
|
||||
void ProfileViewModel::SetNotifyOnActivityNotification(winrt::Windows::Foundation::IReference<bool> on)
|
||||
{
|
||||
auto currentStyle = NotifyOnActivity();
|
||||
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Notification, winrt::unbox_value<bool>(on));
|
||||
NotifyOnActivity(currentStyle);
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region NotifyOnNextPrompt
|
||||
hstring ProfileViewModel::NotifyOnNextPromptPreview() const
|
||||
{
|
||||
using Ons = Control::OutputNotificationStyle;
|
||||
const auto style = NotifyOnNextPrompt();
|
||||
if (WI_AreAllFlagsSet(style, Ons::Taskbar | Ons::Audible | Ons::Tab | Ons::Notification))
|
||||
{
|
||||
return RS_(L"Profile_OutputNotificationStyleAll/Content");
|
||||
}
|
||||
else if (style == Ons::None)
|
||||
{
|
||||
return RS_(L"Profile_OutputNotificationStyleNone/Content");
|
||||
}
|
||||
|
||||
std::wstring result;
|
||||
const auto appendIfFlagSet = [&](Ons flag, std::wstring_view resource) {
|
||||
// WI_IsFlagSet requires a compile-time constant flag; `flag` is a runtime parameter here.
|
||||
if ((WI_EnumValue(style) & WI_EnumValue(flag)) != 0)
|
||||
{
|
||||
if (!result.empty())
|
||||
{
|
||||
result.append(L", ");
|
||||
}
|
||||
result.append(resource);
|
||||
}
|
||||
};
|
||||
|
||||
appendIfFlagSet(Ons::Taskbar, RS_(L"Profile_OutputNotificationStyleTaskbar/Content"));
|
||||
appendIfFlagSet(Ons::Audible, RS_(L"Profile_OutputNotificationStyleAudible/Content"));
|
||||
appendIfFlagSet(Ons::Tab, RS_(L"Profile_OutputNotificationStyleTab/Content"));
|
||||
appendIfFlagSet(Ons::Notification, RS_(L"Profile_OutputNotificationStyleNotification/Content"));
|
||||
|
||||
return hstring{ result };
|
||||
}
|
||||
|
||||
bool ProfileViewModel::IsNotifyOnNextPromptFlagSet(const uint32_t flag)
|
||||
{
|
||||
return (WI_EnumValue(NotifyOnNextPrompt()) & flag) == flag;
|
||||
}
|
||||
|
||||
void ProfileViewModel::SetNotifyOnNextPromptTaskbar(winrt::Windows::Foundation::IReference<bool> on)
|
||||
{
|
||||
auto currentStyle = NotifyOnNextPrompt();
|
||||
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Taskbar, winrt::unbox_value<bool>(on));
|
||||
NotifyOnNextPrompt(currentStyle);
|
||||
}
|
||||
|
||||
void ProfileViewModel::SetNotifyOnNextPromptAudible(winrt::Windows::Foundation::IReference<bool> on)
|
||||
{
|
||||
auto currentStyle = NotifyOnNextPrompt();
|
||||
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Audible, winrt::unbox_value<bool>(on));
|
||||
NotifyOnNextPrompt(currentStyle);
|
||||
}
|
||||
|
||||
void ProfileViewModel::SetNotifyOnNextPromptTab(winrt::Windows::Foundation::IReference<bool> on)
|
||||
{
|
||||
auto currentStyle = NotifyOnNextPrompt();
|
||||
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Tab, winrt::unbox_value<bool>(on));
|
||||
NotifyOnNextPrompt(currentStyle);
|
||||
}
|
||||
|
||||
void ProfileViewModel::SetNotifyOnNextPromptNotification(winrt::Windows::Foundation::IReference<bool> on)
|
||||
{
|
||||
auto currentStyle = NotifyOnNextPrompt();
|
||||
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Notification, winrt::unbox_value<bool>(on));
|
||||
NotifyOnNextPrompt(currentStyle);
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region BellSound
|
||||
|
||||
// Method Description:
|
||||
// - Construct _CurrentBellSounds by importing the _inherited_ value from the model
|
||||
@@ -853,6 +1003,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_NotifyChanges(L"CurrentBellSounds");
|
||||
}
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
void ProfileViewModel::_RefreshDefaultAppearanceViewModel()
|
||||
{
|
||||
|
||||
@@ -49,6 +49,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void SetBellStyleTaskbar(winrt::Windows::Foundation::IReference<bool> on);
|
||||
void SetBellStyleNotification(winrt::Windows::Foundation::IReference<bool> on);
|
||||
|
||||
// notify on activity bits
|
||||
hstring NotifyOnActivityPreview() const;
|
||||
bool IsNotifyOnActivityFlagSet(const uint32_t flag);
|
||||
void SetNotifyOnActivityTaskbar(winrt::Windows::Foundation::IReference<bool> on);
|
||||
void SetNotifyOnActivityAudible(winrt::Windows::Foundation::IReference<bool> on);
|
||||
void SetNotifyOnActivityTab(winrt::Windows::Foundation::IReference<bool> on);
|
||||
void SetNotifyOnActivityNotification(winrt::Windows::Foundation::IReference<bool> on);
|
||||
|
||||
// notify on next prompt bits
|
||||
hstring NotifyOnNextPromptPreview() const;
|
||||
bool IsNotifyOnNextPromptFlagSet(const uint32_t flag);
|
||||
void SetNotifyOnNextPromptTaskbar(winrt::Windows::Foundation::IReference<bool> on);
|
||||
void SetNotifyOnNextPromptAudible(winrt::Windows::Foundation::IReference<bool> on);
|
||||
void SetNotifyOnNextPromptTab(winrt::Windows::Foundation::IReference<bool> on);
|
||||
void SetNotifyOnNextPromptNotification(winrt::Windows::Foundation::IReference<bool> on);
|
||||
|
||||
hstring BellSoundPreview();
|
||||
void RequestAddBellSound(hstring path);
|
||||
void RequestDeleteBellSound(const Editor::BellSoundViewModel& vm);
|
||||
@@ -159,7 +175,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
X(_profile, AnswerbackMessage) \
|
||||
X(_profile, RainbowSuggestions) \
|
||||
X(_profile, PathTranslationStyle) \
|
||||
X(_profile, DragDropDelimiter)
|
||||
X(_profile, DragDropDelimiter) \
|
||||
X(_profile, NotifyOnActivity) \
|
||||
X(_profile, NotifyOnNextPrompt) \
|
||||
X(_profile, NotifyOnActivityThreshold) \
|
||||
X(_profile, NotifyOnNextPromptThreshold) \
|
||||
X(_profile, AutoDetectRunningCommand)
|
||||
|
||||
// Generate the projected property accessors from the list above.
|
||||
#define PROFILE_GEN_PROJECTED(target, name) OBSERVABLE_PROJECTED_SETTING(target, name);
|
||||
|
||||
@@ -52,6 +52,20 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
void SetBellStyleTaskbar(Windows.Foundation.IReference<Boolean> on);
|
||||
void SetBellStyleNotification(Windows.Foundation.IReference<Boolean> on);
|
||||
|
||||
String NotifyOnActivityPreview { get; };
|
||||
Boolean IsNotifyOnActivityFlagSet(UInt32 flag);
|
||||
void SetNotifyOnActivityTaskbar(Windows.Foundation.IReference<Boolean> on);
|
||||
void SetNotifyOnActivityAudible(Windows.Foundation.IReference<Boolean> on);
|
||||
void SetNotifyOnActivityTab(Windows.Foundation.IReference<Boolean> on);
|
||||
void SetNotifyOnActivityNotification(Windows.Foundation.IReference<Boolean> on);
|
||||
|
||||
String NotifyOnNextPromptPreview { get; };
|
||||
Boolean IsNotifyOnNextPromptFlagSet(UInt32 flag);
|
||||
void SetNotifyOnNextPromptTaskbar(Windows.Foundation.IReference<Boolean> on);
|
||||
void SetNotifyOnNextPromptAudible(Windows.Foundation.IReference<Boolean> on);
|
||||
void SetNotifyOnNextPromptTab(Windows.Foundation.IReference<Boolean> on);
|
||||
void SetNotifyOnNextPromptNotification(Windows.Foundation.IReference<Boolean> on);
|
||||
|
||||
String BellSoundPreview { get; };
|
||||
Windows.Foundation.Collections.IObservableVector<BellSoundViewModel> CurrentBellSounds { get; };
|
||||
void RequestAddBellSound(String path);
|
||||
@@ -145,5 +159,10 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, DragDropDelimiter);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowVtClipboardWrite);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowOscNotifications);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnActivity);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnNextPrompt);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Int32, NotifyOnActivityThreshold);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Int32, NotifyOnNextPromptThreshold);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AutoDetectRunningCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +221,104 @@
|
||||
</local:SettingsExpander.ItemsHeader>
|
||||
</local:SettingsExpander>
|
||||
|
||||
<!-- Notify On Activity -->
|
||||
<local:SettingsExpander x:Name="NotifyOnActivity"
|
||||
x:Uid="Profile_NotifyOnActivity">
|
||||
<local:SettingsExpander.Content>
|
||||
<StackPanel Style="{StaticResource SettingControlStackStyle}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Style="{StaticResource SettingContainerCurrentValueTextBlockStyle}"
|
||||
Text="{x:Bind Profile.NotifyOnActivityPreview, Mode=OneWay}" />
|
||||
<local:SettingResetButton SettingName="NotifyOnActivity"
|
||||
Target="{x:Bind Profile}" />
|
||||
</StackPanel>
|
||||
</local:SettingsExpander.Content>
|
||||
<local:SettingsExpander.ItemsHeader>
|
||||
<ContentPresenter Padding="16,12,16,16">
|
||||
<StackPanel>
|
||||
<CheckBox x:Uid="Profile_OutputNotificationStyleTaskbar"
|
||||
IsChecked="{x:Bind Profile.IsNotifyOnActivityFlagSet(1), BindBack=Profile.SetNotifyOnActivityTaskbar, Mode=TwoWay}" />
|
||||
<CheckBox x:Uid="Profile_OutputNotificationStyleAudible"
|
||||
IsChecked="{x:Bind Profile.IsNotifyOnActivityFlagSet(2), BindBack=Profile.SetNotifyOnActivityAudible, Mode=TwoWay}" />
|
||||
<CheckBox x:Uid="Profile_OutputNotificationStyleTab"
|
||||
IsChecked="{x:Bind Profile.IsNotifyOnActivityFlagSet(4), BindBack=Profile.SetNotifyOnActivityTab, Mode=TwoWay}" />
|
||||
<CheckBox x:Uid="Profile_OutputNotificationStyleNotification"
|
||||
IsChecked="{x:Bind Profile.IsNotifyOnActivityFlagSet(8), BindBack=Profile.SetNotifyOnActivityNotification, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</ContentPresenter>
|
||||
</local:SettingsExpander.ItemsHeader>
|
||||
</local:SettingsExpander>
|
||||
|
||||
<!-- Notify On Activity Minimum Duration -->
|
||||
<local:SettingsCard x:Name="NotifyOnActivityThreshold"
|
||||
x:Uid="Profile_NotifyOnActivityThreshold">
|
||||
<StackPanel Style="{StaticResource SettingControlStackStyle}">
|
||||
<muxc:NumberBox AutomationProperties.Name="{Binding ElementName=NotifyOnActivityThreshold, Path=Header}"
|
||||
LargeChange="10"
|
||||
Minimum="0"
|
||||
SmallChange="1"
|
||||
Style="{StaticResource NumberBoxSettingStyle}"
|
||||
Value="{x:Bind Profile.NotifyOnActivityThreshold, Mode=TwoWay}" />
|
||||
<local:SettingResetButton SettingName="NotifyOnActivityThreshold"
|
||||
Target="{x:Bind Profile}" />
|
||||
</StackPanel>
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Notify On Next Prompt -->
|
||||
<local:SettingsExpander x:Name="NotifyOnNextPrompt"
|
||||
x:Uid="Profile_NotifyOnNextPrompt">
|
||||
<local:SettingsExpander.Content>
|
||||
<StackPanel Style="{StaticResource SettingControlStackStyle}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Style="{StaticResource SettingContainerCurrentValueTextBlockStyle}"
|
||||
Text="{x:Bind Profile.NotifyOnNextPromptPreview, Mode=OneWay}" />
|
||||
<local:SettingResetButton SettingName="NotifyOnNextPrompt"
|
||||
Target="{x:Bind Profile}" />
|
||||
</StackPanel>
|
||||
</local:SettingsExpander.Content>
|
||||
<local:SettingsExpander.ItemsHeader>
|
||||
<ContentPresenter Padding="16,12,16,16">
|
||||
<StackPanel>
|
||||
<CheckBox x:Uid="Profile_OutputNotificationStyleTaskbar"
|
||||
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(1), BindBack=Profile.SetNotifyOnNextPromptTaskbar, Mode=TwoWay}" />
|
||||
<CheckBox x:Uid="Profile_OutputNotificationStyleAudible"
|
||||
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(2), BindBack=Profile.SetNotifyOnNextPromptAudible, Mode=TwoWay}" />
|
||||
<CheckBox x:Uid="Profile_OutputNotificationStyleTab"
|
||||
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(4), BindBack=Profile.SetNotifyOnNextPromptTab, Mode=TwoWay}" />
|
||||
<CheckBox x:Uid="Profile_OutputNotificationStyleNotification"
|
||||
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(8), BindBack=Profile.SetNotifyOnNextPromptNotification, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</ContentPresenter>
|
||||
</local:SettingsExpander.ItemsHeader>
|
||||
</local:SettingsExpander>
|
||||
|
||||
<!-- Notify On Next Prompt Minimum Duration -->
|
||||
<local:SettingsCard x:Name="NotifyOnNextPromptThreshold"
|
||||
x:Uid="Profile_NotifyOnNextPromptThreshold">
|
||||
<StackPanel Style="{StaticResource SettingControlStackStyle}">
|
||||
<muxc:NumberBox AutomationProperties.Name="{Binding ElementName=NotifyOnNextPromptThreshold, Path=Header}"
|
||||
LargeChange="10"
|
||||
Minimum="0"
|
||||
SmallChange="1"
|
||||
Style="{StaticResource NumberBoxSettingStyle}"
|
||||
Value="{x:Bind Profile.NotifyOnNextPromptThreshold, Mode=TwoWay}" />
|
||||
<local:SettingResetButton SettingName="NotifyOnNextPromptThreshold"
|
||||
Target="{x:Bind Profile}" />
|
||||
</StackPanel>
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Auto Detect Running Command -->
|
||||
<local:SettingsCard x:Name="AutoDetectRunningCommand"
|
||||
x:Uid="Profile_AutoDetectRunningCommand">
|
||||
<StackPanel Style="{StaticResource SettingControlStackStyle}">
|
||||
<ToggleSwitch VerticalAlignment="Center"
|
||||
IsOn="{x:Bind Profile.AutoDetectRunningCommand, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
<local:SettingResetButton SettingName="AutoDetectRunningCommand"
|
||||
Target="{x:Bind Profile}" />
|
||||
</StackPanel>
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- RightClickContextMenu -->
|
||||
<local:SettingsCard x:Name="RightClickContextMenu"
|
||||
x:Uid="Profile_RightClickContextMenu">
|
||||
|
||||
@@ -1554,6 +1554,70 @@
|
||||
<value>Flash window</value>
|
||||
<comment>An option to choose from for the "bell style" setting. When selected, a visual notification is used to notify the user. In this case, the window is flashed.</comment>
|
||||
</data>
|
||||
<data name="Profile_OutputNotificationStyleNone.Content" xml:space="preserve">
|
||||
<value>None</value>
|
||||
<comment>An option to choose from for the notification style setting. When selected, no notification is sent.</comment>
|
||||
</data>
|
||||
<data name="Profile_OutputNotificationStyleAll.Content" xml:space="preserve">
|
||||
<value>All</value>
|
||||
<comment>An option to choose from for the notification style setting. When selected, all notification methods are used.</comment>
|
||||
</data>
|
||||
<data name="Profile_OutputNotificationStyleTaskbar.Content" xml:space="preserve">
|
||||
<value>Flash taskbar</value>
|
||||
<comment>An option to choose from for the notification style setting. Flashes the taskbar icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_OutputNotificationStyleAudible.Content" xml:space="preserve">
|
||||
<value>Play sound</value>
|
||||
<comment>An option to choose from for the notification style setting. Plays an audible notification sound.</comment>
|
||||
</data>
|
||||
<data name="Profile_OutputNotificationStyleTab.Content" xml:space="preserve">
|
||||
<value>Show tab indicator</value>
|
||||
<comment>An option to choose from for the notification style setting. Shows an activity indicator on the tab.</comment>
|
||||
</data>
|
||||
<data name="Profile_OutputNotificationStyleNotification.Content" xml:space="preserve">
|
||||
<value>Desktop notification</value>
|
||||
<comment>An option to choose from for the notification style setting. Sends a Windows desktop notification (toast).</comment>
|
||||
</data>
|
||||
<data name="Profile_NotifyOnActivity.Header" xml:space="preserve">
|
||||
<value>Notify on activity</value>
|
||||
<comment>Header for a control to set the notification style when a background tab has new activity (output).</comment>
|
||||
</data>
|
||||
<data name="Profile_NotifyOnActivity.Description" xml:space="preserve">
|
||||
<value>Choose how to be notified when a background tab produces new output.</value>
|
||||
<comment>Help text for the notify on activity setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_NotifyOnActivityThreshold.Header" xml:space="preserve">
|
||||
<value>Minimum seconds between activity notifications</value>
|
||||
<comment>Header for a numeric control that sets the minimum number of seconds between consecutive "notify on activity" notifications. Useful for chatty programs.</comment>
|
||||
</data>
|
||||
<data name="Profile_NotifyOnActivityThreshold.Description" xml:space="preserve">
|
||||
<value>Suppress repeated activity notifications within this many seconds of the previous one. Set to 0 to always notify.</value>
|
||||
<comment>Help text for the minimum duration threshold applied to "notify on activity" notifications.</comment>
|
||||
</data>
|
||||
<data name="Profile_NotifyOnNextPrompt.Header" xml:space="preserve">
|
||||
<value>Notify on next prompt</value>
|
||||
<comment>Header for a control to set the notification style when a new shell prompt is detected (requires shell integration).</comment>
|
||||
</data>
|
||||
<data name="Profile_NotifyOnNextPrompt.Description" xml:space="preserve">
|
||||
<value>Choose how to be notified when a command finishes and a new prompt appears. Requires shell integration.</value>
|
||||
<comment>Help text for the notify on next prompt setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_NotifyOnNextPromptThreshold.Header" xml:space="preserve">
|
||||
<value>Minimum duration for the next prompt notification</value>
|
||||
<comment>Header for a numeric control that sets the minimum number of seconds a command must run before its completion triggers a "notify on next prompt" notification.</comment>
|
||||
</data>
|
||||
<data name="Profile_NotifyOnNextPromptThreshold.Description" xml:space="preserve">
|
||||
<value>Only notify when the command ran for at least this many seconds. Requires shell integration. Set to 0 to always notify.</value>
|
||||
<comment>Help text for the minimum duration threshold applied to "notify on next prompt" notifications.</comment>
|
||||
</data>
|
||||
<data name="Profile_AutoDetectRunningCommand.Header" xml:space="preserve">
|
||||
<value>Auto-detect running command</value>
|
||||
<comment>Header for a control to configure automatic detection of a running command's progress state.</comment>
|
||||
</data>
|
||||
<data name="Profile_AutoDetectRunningCommand.Description" xml:space="preserve">
|
||||
<value>Automatically show a progress indicator when a command is running. Requires shell integration.</value>
|
||||
<comment>Help text for the auto-detect running command setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_BellStyleNotification.Content" xml:space="preserve">
|
||||
<value>Desktop notification</value>
|
||||
<comment>An option to choose from for the "bell style" setting. When selected, a Windows desktop notification (toast) is sent to notify the user.</comment>
|
||||
|
||||
@@ -80,38 +80,43 @@ Author(s):
|
||||
// * TerminalSettings.cpp: TerminalSettings::_ApplyProfileSettings
|
||||
// * IControlSettings.idl or ICoreSettings.idl
|
||||
// * ControlProperties.h
|
||||
#define MTSM_PROFILE_SETTINGS(X) \
|
||||
X(int32_t, HistorySize, "historySize", DEFAULT_HISTORY_SIZE) \
|
||||
X(bool, SnapOnInput, "snapOnInput", true) \
|
||||
X(bool, AltGrAliasing, "altGrAliasing", true) \
|
||||
X(hstring, AnswerbackMessage, "answerbackMessage") \
|
||||
X(hstring, Commandline, "commandline", L"%SystemRoot%\\System32\\cmd.exe") \
|
||||
X(Microsoft::Terminal::Control::ScrollbarState, ScrollState, "scrollbarState", Microsoft::Terminal::Control::ScrollbarState::Visible) \
|
||||
X(Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, "antialiasingMode", Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale) \
|
||||
X(hstring, StartingDirectory, "startingDirectory") \
|
||||
X(IMediaResource, Icon, "icon", implementation::MediaResource::FromString(L"\uE756")) \
|
||||
X(bool, SuppressApplicationTitle, "suppressApplicationTitle", false) \
|
||||
X(guid, ConnectionType, "connectionType") \
|
||||
X(CloseOnExitMode, CloseOnExit, "closeOnExit", CloseOnExitMode::Automatic) \
|
||||
X(hstring, TabTitle, "tabTitle") \
|
||||
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
|
||||
X(IEnvironmentVariableMap, EnvironmentVariables, "environment", nullptr) \
|
||||
X(bool, RightClickContextMenu, "rightClickContextMenu", false) \
|
||||
X(Windows::Foundation::Collections::IVector<IMediaResource>, BellSound, "bellSound", nullptr) \
|
||||
X(bool, Elevate, "elevate", false) \
|
||||
X(bool, AutoMarkPrompts, "autoMarkPrompts", true) \
|
||||
X(bool, ShowMarks, "showMarksOnScrollbar", false) \
|
||||
X(bool, RepositionCursorWithMouse, "experimental.repositionCursorWithMouse", false) \
|
||||
X(bool, ReloadEnvironmentVariables, "compatibility.reloadEnvironmentVariables", true) \
|
||||
X(bool, RainbowSuggestions, "experimental.rainbowSuggestions", false) \
|
||||
X(bool, ForceVTInput, "compatibility.input.forceVT", false) \
|
||||
X(bool, AllowKittyKeyboardMode, "compatibility.kittyKeyboardMode", true) \
|
||||
X(bool, AllowVtChecksumReport, "compatibility.allowDECRQCRA", false) \
|
||||
X(bool, AllowVtClipboardWrite, "compatibility.allowOSC52", true) \
|
||||
X(bool, AllowOscNotifications, "compatibility.allowOSC777", false) \
|
||||
X(bool, AllowKeypadMode, "compatibility.allowDECNKM", false) \
|
||||
X(hstring, DragDropDelimiter, "dragDropDelimiter", L" ") \
|
||||
X(Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, "pathTranslationStyle", Microsoft::Terminal::Control::PathTranslationStyle::None)
|
||||
#define MTSM_PROFILE_SETTINGS(X) \
|
||||
X(int32_t, HistorySize, "historySize", DEFAULT_HISTORY_SIZE) \
|
||||
X(bool, SnapOnInput, "snapOnInput", true) \
|
||||
X(bool, AltGrAliasing, "altGrAliasing", true) \
|
||||
X(hstring, AnswerbackMessage, "answerbackMessage") \
|
||||
X(hstring, Commandline, "commandline", L"%SystemRoot%\\System32\\cmd.exe") \
|
||||
X(Microsoft::Terminal::Control::ScrollbarState, ScrollState, "scrollbarState", Microsoft::Terminal::Control::ScrollbarState::Visible) \
|
||||
X(Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, "antialiasingMode", Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale) \
|
||||
X(hstring, StartingDirectory, "startingDirectory") \
|
||||
X(IMediaResource, Icon, "icon", implementation::MediaResource::FromString(L"\uE756")) \
|
||||
X(bool, SuppressApplicationTitle, "suppressApplicationTitle", false) \
|
||||
X(guid, ConnectionType, "connectionType") \
|
||||
X(CloseOnExitMode, CloseOnExit, "closeOnExit", CloseOnExitMode::Automatic) \
|
||||
X(hstring, TabTitle, "tabTitle") \
|
||||
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
|
||||
X(IEnvironmentVariableMap, EnvironmentVariables, "environment", nullptr) \
|
||||
X(bool, RightClickContextMenu, "rightClickContextMenu", false) \
|
||||
X(Windows::Foundation::Collections::IVector<IMediaResource>, BellSound, "bellSound", nullptr) \
|
||||
X(bool, Elevate, "elevate", false) \
|
||||
X(bool, AutoMarkPrompts, "autoMarkPrompts", true) \
|
||||
X(bool, ShowMarks, "showMarksOnScrollbar", false) \
|
||||
X(bool, RepositionCursorWithMouse, "experimental.repositionCursorWithMouse", false) \
|
||||
X(bool, ReloadEnvironmentVariables, "compatibility.reloadEnvironmentVariables", true) \
|
||||
X(bool, RainbowSuggestions, "experimental.rainbowSuggestions", false) \
|
||||
X(bool, ForceVTInput, "compatibility.input.forceVT", false) \
|
||||
X(bool, AllowKittyKeyboardMode, "compatibility.kittyKeyboardMode", true) \
|
||||
X(bool, AllowVtChecksumReport, "compatibility.allowDECRQCRA", false) \
|
||||
X(bool, AllowVtClipboardWrite, "compatibility.allowOSC52", true) \
|
||||
X(bool, AllowOscNotifications, "compatibility.allowOSC777", false) \
|
||||
X(bool, AllowKeypadMode, "compatibility.allowDECNKM", false) \
|
||||
X(hstring, DragDropDelimiter, "dragDropDelimiter", L" ") \
|
||||
X(Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, "pathTranslationStyle", Microsoft::Terminal::Control::PathTranslationStyle::None) \
|
||||
X(Microsoft::Terminal::Control::OutputNotificationStyle, NotifyOnActivity, "notifyOnActivity", Microsoft::Terminal::Control::OutputNotificationStyle::None) \
|
||||
X(Microsoft::Terminal::Control::OutputNotificationStyle, NotifyOnNextPrompt, "notifyOnNextPrompt", Microsoft::Terminal::Control::OutputNotificationStyle::None) \
|
||||
X(int32_t, NotifyOnActivityThreshold, "notifyOnActivityThreshold", 5) \
|
||||
X(int32_t, NotifyOnNextPromptThreshold, "notifyOnNextPromptThreshold", 5) \
|
||||
X(bool, AutoDetectRunningCommand, "autoDetectRunningCommand", false)
|
||||
|
||||
// Intentionally omitted Profile settings:
|
||||
// * Name
|
||||
|
||||
@@ -97,5 +97,10 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.PathTranslationStyle, PathTranslationStyle);
|
||||
INHERITABLE_PROFILE_SETTING(String, DragDropDelimiter);
|
||||
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnActivity);
|
||||
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnNextPrompt);
|
||||
INHERITABLE_PROFILE_SETTING(Int32, NotifyOnActivityThreshold);
|
||||
INHERITABLE_PROFILE_SETTING(Int32, NotifyOnNextPromptThreshold);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AutoDetectRunningCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,37 @@ JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::BellStyle)
|
||||
}
|
||||
};
|
||||
|
||||
JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::Control::OutputNotificationStyle)
|
||||
{
|
||||
static constexpr std::array<pair_type, 6> mappings = {
|
||||
pair_type{ "none", AllClear },
|
||||
pair_type{ "taskbar", ValueType::Taskbar },
|
||||
pair_type{ "audible", ValueType::Audible },
|
||||
pair_type{ "tab", ValueType::Tab },
|
||||
pair_type{ "notification", ValueType::Notification },
|
||||
pair_type{ "all", AllSet },
|
||||
};
|
||||
|
||||
auto FromJson(const Json::Value& json)
|
||||
{
|
||||
if (json.isBool())
|
||||
{
|
||||
return json.asBool() ? ValueType::Tab : AllClear;
|
||||
}
|
||||
return BaseFlagMapper::FromJson(json);
|
||||
}
|
||||
|
||||
bool CanConvert(const Json::Value& json)
|
||||
{
|
||||
return BaseFlagMapper::CanConvert(json) || json.isBool();
|
||||
}
|
||||
|
||||
Json::Value ToJson(const ::winrt::Microsoft::Terminal::Control::OutputNotificationStyle& style)
|
||||
{
|
||||
return BaseFlagMapper::ToJson(style);
|
||||
}
|
||||
};
|
||||
|
||||
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::ConvergedAlignment)
|
||||
{
|
||||
// reduce repetition
|
||||
|
||||
@@ -265,66 +265,68 @@ void TerminalCoreUnitTests::TerminalApiTest::SetTaskbarProgress()
|
||||
|
||||
auto& stateMachine = *(term._stateMachine);
|
||||
|
||||
using TaskbarState = ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState;
|
||||
|
||||
// Initial values for taskbar state and progress should be 0
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Clear);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
|
||||
|
||||
// Set some values for taskbar state and progress through state machine
|
||||
stateMachine.ProcessString(L"\x1b]9;4;1;50\x1b\\");
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Set);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(50));
|
||||
|
||||
// Reset to 0
|
||||
stateMachine.ProcessString(L"\x1b]9;4;0;0\x1b\\");
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Clear);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
|
||||
|
||||
// Set an out of bounds value for state
|
||||
stateMachine.ProcessString(L"\x1b]9;4;5;50\x1b\\");
|
||||
// Nothing should have changed (dispatch should have returned false)
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Clear);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
|
||||
|
||||
// Set an out of bounds value for progress
|
||||
stateMachine.ProcessString(L"\x1b]9;4;1;999\x1b\\");
|
||||
// Progress should have been clamped to 100
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Set);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(100));
|
||||
|
||||
// Don't specify any params
|
||||
stateMachine.ProcessString(L"\x1b]9;4\x1b\\");
|
||||
// State and progress should both be reset to 0
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Clear);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
|
||||
|
||||
// Specify additional params
|
||||
stateMachine.ProcessString(L"\x1b]9;4;1;80;123\x1b\\");
|
||||
// Additional params should be ignored, state and progress still set normally
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Set);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
|
||||
|
||||
// Edge cases + trailing semicolon testing
|
||||
stateMachine.ProcessString(L"\x1b]9;4;2;\x1b\\");
|
||||
// String should be processed correctly despite the trailing semicolon,
|
||||
// taskbar progress should remain unchanged from previous value
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(2));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Error);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;4;3;75\x1b\\");
|
||||
// Given progress value should be ignored because this is the indeterminate state,
|
||||
// so the progress value should remain unchanged
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(3));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Indeterminate);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;4;0;50\x1b\\");
|
||||
// Taskbar progress should be 0 (the given value should be ignored)
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Clear);
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;4;2;\x1b\\");
|
||||
// String should be processed correctly despite the trailing semicolon,
|
||||
// taskbar progress should be set to a 'minimum', non-zero value
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(2));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), TaskbarState::Error);
|
||||
VERIFY_IS_GREATER_THAN(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ void AppHost::SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable&
|
||||
if (_windowLogic)
|
||||
{
|
||||
const auto state = _windowLogic.TaskbarState();
|
||||
_window->SetTaskbarProgress(gsl::narrow_cast<size_t>(state.State()),
|
||||
_window->SetTaskbarProgress(state.State(),
|
||||
gsl::narrow_cast<size_t>(state.Progress()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,27 +930,28 @@ void IslandWindow::FlashTaskbar()
|
||||
// Arguments:
|
||||
// - state: indicates the progress state
|
||||
// - progress: indicates the progress value
|
||||
void IslandWindow::SetTaskbarProgress(const size_t state, const size_t progress)
|
||||
void IslandWindow::SetTaskbarProgress(const winrt::Microsoft::Terminal::Control::TaskbarState state, const size_t progress)
|
||||
{
|
||||
if (_taskbar)
|
||||
{
|
||||
using TbState = winrt::Microsoft::Terminal::Control::TaskbarState;
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
case TbState::Clear:
|
||||
// removes the taskbar progress indicator
|
||||
_taskbar->SetProgressState(_window.get(), TBPF_NOPROGRESS);
|
||||
break;
|
||||
case 1:
|
||||
case TbState::Set:
|
||||
// sets the progress value to value given by the 'progress' parameter
|
||||
_taskbar->SetProgressState(_window.get(), TBPF_NORMAL);
|
||||
_taskbar->SetProgressValue(_window.get(), progress, 100);
|
||||
break;
|
||||
case 2:
|
||||
case TbState::Error:
|
||||
// sets the progress indicator to an error state
|
||||
_taskbar->SetProgressState(_window.get(), TBPF_ERROR);
|
||||
_taskbar->SetProgressValue(_window.get(), progress, 100);
|
||||
break;
|
||||
case 3:
|
||||
case TbState::Indeterminate:
|
||||
// sets the progress indicator to an indeterminate state.
|
||||
// FIRST, set the progress to "no progress". That'll clear out any
|
||||
// progress value from the previous state. Otherwise, a transition
|
||||
@@ -959,7 +960,7 @@ void IslandWindow::SetTaskbarProgress(const size_t state, const size_t progress)
|
||||
_taskbar->SetProgressState(_window.get(), TBPF_NOPROGRESS);
|
||||
_taskbar->SetProgressState(_window.get(), TBPF_INDETERMINATE);
|
||||
break;
|
||||
case 4:
|
||||
case TbState::Paused:
|
||||
// sets the progress indicator to a pause state
|
||||
_taskbar->SetProgressState(_window.get(), TBPF_PAUSED);
|
||||
_taskbar->SetProgressValue(_window.get(), progress, 100);
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
virtual void SetShowTabsFullscreen(const bool newShowTabsFullscreen);
|
||||
|
||||
void FlashTaskbar();
|
||||
void SetTaskbarProgress(const size_t state, const size_t progress);
|
||||
void SetTaskbarProgress(const winrt::Microsoft::Terminal::Control::TaskbarState state, const size_t progress);
|
||||
|
||||
void SummonWindow(winrt::TerminalApp::SummonWindowBehavior args);
|
||||
|
||||
|
||||
@@ -61,32 +61,37 @@
|
||||
|
||||
// --------------------------- Control Settings ---------------------------
|
||||
// All of these settings are defined in IControlSettings.
|
||||
#define CONTROL_SETTINGS(X) \
|
||||
X(winrt::guid, SessionId) \
|
||||
X(bool, EnableUnfocusedAcrylic, false) \
|
||||
X(winrt::hstring, Padding, DEFAULT_PADDING) \
|
||||
X(winrt::hstring, FontFace, L"Consolas") \
|
||||
X(float, FontSize, DEFAULT_FONT_SIZE) \
|
||||
X(winrt::Windows::UI::Text::FontWeight, FontWeight) \
|
||||
X(IFontFeatureMap, FontFeatures) \
|
||||
X(IFontAxesMap, FontAxes) \
|
||||
X(bool, EnableBuiltinGlyphs, true) \
|
||||
X(bool, EnableColorGlyphs, true) \
|
||||
X(winrt::hstring, CellWidth) \
|
||||
X(winrt::hstring, CellHeight) \
|
||||
X(winrt::hstring, Commandline) \
|
||||
X(winrt::hstring, StartingDirectory) \
|
||||
X(winrt::Microsoft::Terminal::Control::ScrollbarState, ScrollState, winrt::Microsoft::Terminal::Control::ScrollbarState::Visible) \
|
||||
X(winrt::Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale) \
|
||||
X(winrt::Microsoft::Terminal::Control::GraphicsAPI, GraphicsAPI) \
|
||||
X(bool, DisablePartialInvalidation, false) \
|
||||
X(bool, SoftwareRendering, false) \
|
||||
X(winrt::Microsoft::Terminal::Control::TextMeasurement, TextMeasurement) \
|
||||
X(winrt::Microsoft::Terminal::Control::AmbiguousWidth, AmbiguousWidth, winrt::Microsoft::Terminal::Control::AmbiguousWidth::Narrow) \
|
||||
X(winrt::Microsoft::Terminal::Control::DefaultInputScope, DefaultInputScope, winrt::Microsoft::Terminal::Control::DefaultInputScope::Default) \
|
||||
X(bool, UseBackgroundImageForWindow, false) \
|
||||
X(bool, ShowMarks, false) \
|
||||
X(winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, 0) \
|
||||
X(bool, RightClickContextMenu, false) \
|
||||
X(winrt::Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, winrt::Microsoft::Terminal::Control::PathTranslationStyle::None) \
|
||||
#define CONTROL_SETTINGS(X) \
|
||||
X(winrt::guid, SessionId) \
|
||||
X(bool, EnableUnfocusedAcrylic, false) \
|
||||
X(winrt::hstring, Padding, DEFAULT_PADDING) \
|
||||
X(winrt::hstring, FontFace, L"Consolas") \
|
||||
X(float, FontSize, DEFAULT_FONT_SIZE) \
|
||||
X(winrt::Windows::UI::Text::FontWeight, FontWeight) \
|
||||
X(IFontFeatureMap, FontFeatures) \
|
||||
X(IFontAxesMap, FontAxes) \
|
||||
X(bool, EnableBuiltinGlyphs, true) \
|
||||
X(bool, EnableColorGlyphs, true) \
|
||||
X(winrt::hstring, CellWidth) \
|
||||
X(winrt::hstring, CellHeight) \
|
||||
X(winrt::hstring, Commandline) \
|
||||
X(winrt::hstring, StartingDirectory) \
|
||||
X(winrt::Microsoft::Terminal::Control::ScrollbarState, ScrollState, winrt::Microsoft::Terminal::Control::ScrollbarState::Visible) \
|
||||
X(winrt::Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale) \
|
||||
X(winrt::Microsoft::Terminal::Control::GraphicsAPI, GraphicsAPI) \
|
||||
X(bool, DisablePartialInvalidation, false) \
|
||||
X(bool, SoftwareRendering, false) \
|
||||
X(winrt::Microsoft::Terminal::Control::TextMeasurement, TextMeasurement) \
|
||||
X(winrt::Microsoft::Terminal::Control::AmbiguousWidth, AmbiguousWidth, winrt::Microsoft::Terminal::Control::AmbiguousWidth::Narrow) \
|
||||
X(winrt::Microsoft::Terminal::Control::DefaultInputScope, DefaultInputScope, winrt::Microsoft::Terminal::Control::DefaultInputScope::Default) \
|
||||
X(bool, UseBackgroundImageForWindow, false) \
|
||||
X(bool, ShowMarks, false) \
|
||||
X(winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, 0) \
|
||||
X(bool, RightClickContextMenu, false) \
|
||||
X(winrt::Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, winrt::Microsoft::Terminal::Control::PathTranslationStyle::None) \
|
||||
X(winrt::Microsoft::Terminal::Control::OutputNotificationStyle, NotifyOnActivity, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::None) \
|
||||
X(winrt::Microsoft::Terminal::Control::OutputNotificationStyle, NotifyOnNextPrompt, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::None) \
|
||||
X(int32_t, NotifyOnActivityThreshold, 5) \
|
||||
X(int32_t, NotifyOnNextPromptThreshold, 5) \
|
||||
X(bool, AutoDetectRunningCommand, false) \
|
||||
X(winrt::hstring, DragDropDelimiter, L" ")
|
||||
|
||||
@@ -446,7 +446,7 @@ void ConhostInternalGetSet::NotifyBufferRotation(const int)
|
||||
{
|
||||
}
|
||||
|
||||
void ConhostInternalGetSet::NotifyShellIntegrationMark()
|
||||
void ConhostInternalGetSet::NotifyShellIntegrationMark(ShellIntegrationMark /*mark*/)
|
||||
{
|
||||
// Not implemented for conhost - shell integration marks are a Terminal app feature.
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
bool IsVtInputEnabled() const override;
|
||||
|
||||
void NotifyBufferRotation(const int delta) override;
|
||||
void NotifyShellIntegrationMark() override;
|
||||
void NotifyShellIntegrationMark(ShellIntegrationMark mark) override;
|
||||
|
||||
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;
|
||||
|
||||
|
||||
@@ -87,7 +87,16 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
virtual bool ResizeWindow(const til::CoordType width, const til::CoordType height) = 0;
|
||||
|
||||
virtual void NotifyBufferRotation(const int delta) = 0;
|
||||
virtual void NotifyShellIntegrationMark() = 0;
|
||||
|
||||
enum class ShellIntegrationMark
|
||||
{
|
||||
Prompt,
|
||||
Command,
|
||||
Output,
|
||||
CommandFinished,
|
||||
Other
|
||||
};
|
||||
virtual void NotifyShellIntegrationMark(ShellIntegrationMark mark) = 0;
|
||||
|
||||
virtual void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) = 0;
|
||||
|
||||
|
||||
@@ -3638,7 +3638,7 @@ void AdaptDispatch::DoConEmuAction(const std::wstring_view string)
|
||||
else if (subParam == 12)
|
||||
{
|
||||
_pages.ActivePage().Buffer().StartCommand();
|
||||
_api.NotifyShellIntegrationMark();
|
||||
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Command);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3673,7 +3673,7 @@ void AdaptDispatch::DoITerm2Action(const std::wstring_view string)
|
||||
if (action == L"SetMark")
|
||||
{
|
||||
_pages.ActivePage().Buffer().StartPrompt();
|
||||
_api.NotifyShellIntegrationMark();
|
||||
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Prompt);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3711,19 +3711,19 @@ void AdaptDispatch::DoFinalTermAction(const std::wstring_view string)
|
||||
case L'A': // FTCS_PROMPT
|
||||
{
|
||||
_pages.ActivePage().Buffer().StartPrompt();
|
||||
_api.NotifyShellIntegrationMark();
|
||||
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Prompt);
|
||||
break;
|
||||
}
|
||||
case L'B': // FTCS_COMMAND_START
|
||||
{
|
||||
_pages.ActivePage().Buffer().StartCommand();
|
||||
_api.NotifyShellIntegrationMark();
|
||||
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Command);
|
||||
break;
|
||||
}
|
||||
case L'C': // FTCS_COMMAND_EXECUTED
|
||||
{
|
||||
_pages.ActivePage().Buffer().StartOutput();
|
||||
_api.NotifyShellIntegrationMark();
|
||||
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Output);
|
||||
break;
|
||||
}
|
||||
case L'D': // FTCS_COMMAND_FINISHED
|
||||
@@ -3744,7 +3744,7 @@ void AdaptDispatch::DoFinalTermAction(const std::wstring_view string)
|
||||
}
|
||||
|
||||
_pages.ActivePage().Buffer().EndCurrentCommand(error);
|
||||
_api.NotifyShellIntegrationMark();
|
||||
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::CommandFinished);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ public:
|
||||
Log::Comment(L"NotifyBufferRotation MOCK called...");
|
||||
}
|
||||
|
||||
void NotifyShellIntegrationMark() override
|
||||
void NotifyShellIntegrationMark(ShellIntegrationMark /*mark*/) override
|
||||
{
|
||||
Log::Comment(L"NotifyShellIntegrationMark MOCK called...");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user