Skip to content

Commit 09c47c6

Browse files
committed
Add settings for "notifying" on "activity"
1 parent 9df166e commit 09c47c6

37 files changed

+815
-40
lines changed

doc/cascadia/profiles.schema.json

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2849,6 +2849,78 @@
28492849
"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.",
28502850
"$ref": "#/$defs/BellSound"
28512851
},
2852+
"notifyOnInactiveOutput": {
2853+
"oneOf": [
2854+
{
2855+
"type": "boolean"
2856+
},
2857+
{
2858+
"type": "array",
2859+
"items": {
2860+
"type": "string",
2861+
"enum": [
2862+
"taskbar",
2863+
"audible",
2864+
"tab",
2865+
"notification"
2866+
]
2867+
}
2868+
},
2869+
{
2870+
"type": "string",
2871+
"enum": [
2872+
"taskbar",
2873+
"audible",
2874+
"tab",
2875+
"notification",
2876+
"all",
2877+
"none"
2878+
]
2879+
}
2880+
],
2881+
"description": "Controls how you are notified when an inactive tab produces new output."
2882+
},
2883+
"notifyOnNextPrompt": {
2884+
"oneOf": [
2885+
{
2886+
"type": "boolean"
2887+
},
2888+
{
2889+
"type": "array",
2890+
"items": {
2891+
"type": "string",
2892+
"enum": [
2893+
"taskbar",
2894+
"audible",
2895+
"tab",
2896+
"notification"
2897+
]
2898+
}
2899+
},
2900+
{
2901+
"type": "string",
2902+
"enum": [
2903+
"taskbar",
2904+
"audible",
2905+
"tab",
2906+
"notification",
2907+
"all",
2908+
"none"
2909+
]
2910+
}
2911+
],
2912+
"description": "Controls how you are notified when a new shell prompt is detected. Requires shell integration."
2913+
},
2914+
"autoDetectRunningCommand": {
2915+
"default": "disabled",
2916+
"description": "Automatically detect when a command is running and show a progress indicator in the tab and taskbar.",
2917+
"enum": [
2918+
"disabled",
2919+
"automatic",
2920+
"progress"
2921+
],
2922+
"type": "string"
2923+
},
28522924
"closeOnExit": {
28532925
"default": "automatic",
28542926
"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.",

src/cascadia/TerminalApp/IPaneContent.idl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ namespace TerminalApp
1818

1919
runtimeclass NotificationEventArgs
2020
{
21+
Microsoft.Terminal.Control.OutputNotificationStyle Style { get; };
22+
Boolean OnlyWhenInactive { get; };
2123
String Title { get; };
2224
String Body { get; };
2325
};

src/cascadia/TerminalApp/Tab.cpp

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ namespace winrt::TerminalApp::implementation
123123
_bellIndicatorTimer.Stop();
124124
}
125125

126+
void Tab::_ActivityIndicatorTimerTick(const Windows::Foundation::IInspectable& /*sender*/, const Windows::Foundation::IInspectable& /*e*/)
127+
{
128+
ShowActivityIndicator(false);
129+
_activityIndicatorTimer.Stop();
130+
}
131+
126132
// Method Description:
127133
// - Initializes a TabViewItem for this Tab instance.
128134
// Arguments:
@@ -329,6 +335,10 @@ namespace winrt::TerminalApp::implementation
329335
{
330336
ShowBellIndicator(false);
331337
}
338+
if (_tabStatus.ActivityIndicator())
339+
{
340+
ShowActivityIndicator(false);
341+
}
332342
}
333343
}
334344

@@ -459,6 +469,26 @@ namespace winrt::TerminalApp::implementation
459469
_bellIndicatorTimer.Start();
460470
}
461471

472+
void Tab::ShowActivityIndicator(const bool show)
473+
{
474+
ASSERT_UI_THREAD();
475+
476+
_tabStatus.ActivityIndicator(show);
477+
}
478+
479+
void Tab::ActivateActivityIndicatorTimer()
480+
{
481+
ASSERT_UI_THREAD();
482+
483+
if (!_activityIndicatorTimer)
484+
{
485+
_activityIndicatorTimer.Interval(std::chrono::milliseconds(2000));
486+
_activityIndicatorTimer.Tick({ get_weak(), &Tab::_ActivityIndicatorTimerTick });
487+
}
488+
489+
_activityIndicatorTimer.Start();
490+
}
491+
462492
// Method Description:
463493
// - Gets the title string of the last focused terminal control in our tree.
464494
// Returns the empty string if there is no such control.
@@ -1068,6 +1098,7 @@ namespace winrt::TerminalApp::implementation
10681098
dispatcher,
10691099
til::throttled_func_options{
10701100
.delay = std::chrono::milliseconds{ 200 },
1101+
.leading = true,
10711102
.trailing = true,
10721103
},
10731104
[weakThis]() {
@@ -1168,20 +1199,57 @@ namespace winrt::TerminalApp::implementation
11681199

11691200
events.NotificationRequested = content.NotificationRequested(
11701201
winrt::auto_revoke,
1171-
[dispatcher, weakThis](TerminalApp::IPaneContent /*sender*/, auto notifArgs) -> safe_void_coroutine {
1202+
[dispatcher, weakThis](TerminalApp::IPaneContent sender, auto notifArgs) -> safe_void_coroutine {
11721203
const auto weakThisCopy = weakThis;
11731204
co_await wil::resume_foreground(dispatcher);
11741205
if (const auto tab{ weakThisCopy.get() })
11751206
{
1176-
const auto notifTitle = notifArgs.Title();
1177-
const auto notifBody = notifArgs.Body();
1178-
if (!notifTitle.empty())
1207+
const auto activeContent = tab->GetActiveContent();
1208+
const auto isActivePaneContent = activeContent && activeContent == sender;
1209+
1210+
if (notifArgs.OnlyWhenInactive() && isActivePaneContent &&
1211+
tab->_focusState != WUX::FocusState::Unfocused)
11791212
{
1180-
tab->TabToastNotificationRequested.raise(notifTitle, notifBody, tab->TabViewIndex());
1213+
co_return;
11811214
}
1182-
else
1215+
1216+
const auto style = notifArgs.Style();
1217+
1218+
if (WI_IsFlagSet(style, OutputNotificationStyle::Taskbar))
11831219
{
1184-
tab->TabToastNotificationRequested.raise(tab->Title(), L"", tab->TabViewIndex());
1220+
tab->TabRaiseVisualBell.raise();
1221+
}
1222+
1223+
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Audible))
1224+
{
1225+
if (const auto termContent{ sender.try_as<TerminalApp::TerminalPaneContent>() })
1226+
{
1227+
termContent.PlayNotificationSound();
1228+
}
1229+
}
1230+
1231+
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Tab))
1232+
{
1233+
tab->ShowActivityIndicator(true);
1234+
1235+
if (tab->_focusState != WUX::FocusState::Unfocused)
1236+
{
1237+
tab->ActivateActivityIndicatorTimer();
1238+
}
1239+
}
1240+
1241+
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Notification))
1242+
{
1243+
const auto notifTitle = notifArgs.Title();
1244+
const auto notifBody = notifArgs.Body();
1245+
if (!notifTitle.empty())
1246+
{
1247+
tab->TabToastNotificationRequested.raise(notifTitle, notifBody, tab->TabViewIndex());
1248+
}
1249+
else
1250+
{
1251+
tab->TabToastNotificationRequested.raise(tab->Title(), L"", tab->TabViewIndex());
1252+
}
11851253
}
11861254
}
11871255
});
@@ -1413,6 +1481,10 @@ namespace winrt::TerminalApp::implementation
14131481
{
14141482
tab->ShowBellIndicator(false);
14151483
}
1484+
if (tab->_tabStatus.ActivityIndicator())
1485+
{
1486+
tab->ShowActivityIndicator(false);
1487+
}
14161488
}
14171489
});
14181490

src/cascadia/TerminalApp/Tab.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ namespace winrt::TerminalApp::implementation
4848
void ShowBellIndicator(const bool show);
4949
void ActivateBellIndicatorTimer();
5050

51+
void ShowActivityIndicator(const bool show);
52+
void ActivateActivityIndicatorTimer();
53+
5154
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
5255
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitDirection> PreCalculateCanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
5356
const float splitSize,
@@ -212,6 +215,9 @@ namespace winrt::TerminalApp::implementation
212215
SafeDispatcherTimer _bellIndicatorTimer;
213216
void _BellIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
214217

218+
SafeDispatcherTimer _activityIndicatorTimer;
219+
void _ActivityIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
220+
215221
void _UpdateHeaderControlMaxWidth();
216222

217223
void _CreateContextMenu();

src/cascadia/TerminalApp/TabHeaderControl.xaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
FontSize="12"
3333
Glyph="&#xEA8F;"
3434
Visibility="{x:Bind TabStatus.BellIndicator, Mode=OneWay}" />
35+
<FontIcon x:Name="HeaderActivityIndicator"
36+
Margin="0,0,8,0"
37+
FontFamily="{ThemeResource SymbolThemeFontFamily}"
38+
FontSize="8"
39+
Glyph="&#xF127;"
40+
Visibility="{x:Bind TabStatus.ActivityIndicator, Mode=OneWay}" />
3541
<FontIcon x:Name="HeaderZoomIcon"
3642
Margin="0,0,8,0"
3743
FontFamily="{ThemeResource SymbolThemeFontFamily}"

0 commit comments

Comments
 (0)