Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/cascadia/TerminalApp/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,15 @@ the MIT License. See LICENSE in the project root for license information. -->
<ResourceDictionary x:Key="Dark">
<!-- Define resources for Dark mode here -->
<SolidColorBrush x:Key="TabViewBackground" Color="#FF333333" />
<SolidColorBrush x:Key="ReadOnlyPaneBorderColor" Color="#FFFF6F69" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to make the read-only border it's own PR, just so that it gets its own design review

<SolidColorBrush x:Key="BroadcastPaneBorderColor" Color="#FF96CEB4" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any way we could make the broadcast border SystemAccentColorLight2 / SystemAccentColorDark2? That would make it similar to the active pane border, but still definitely different.

@cinnamon-msft for design input here

</ResourceDictionary>

<ResourceDictionary x:Key="Light">
<!-- Define resources for Light mode here -->
<SolidColorBrush x:Key="TabViewBackground" Color="#FFCCCCCC" />
<SolidColorBrush x:Key="ReadOnlyPaneBorderColor" Color="#FFFF6F69" />
<SolidColorBrush x:Key="BroadcastPaneBorderColor" Color="#FF96CEB4" />
</ResourceDictionary>

</ResourceDictionary.ThemeDictionaries>
Expand Down
11 changes: 11 additions & 0 deletions src/cascadia/TerminalApp/AppActionHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,17 @@ namespace winrt::TerminalApp::implementation
args.Handled(true);
}

void TerminalPage::_HandleToggleInputBroadcast(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto activeTab{ _GetFocusedTabImpl() })
{
activeTab->ToggleInputBroadcast();
}

args.Handled(true);
}

void TerminalPage::_HandleScrollUpPage(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
Expand Down
7 changes: 7 additions & 0 deletions src/cascadia/TerminalApp/CommandPalette.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,13 @@ the MIT License. See LICENSE in the project root for license information. -->
FontSize="12"
Margin="0,0,8,0"/>

<FontIcon x:Name="HeaderBroadcastIcon"
FontFamily="Segoe MDL2 Assets"
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsInputBroadcastActive, Mode=OneWay}"
Glyph="&#xEC05;"
FontSize="12"
Margin="0,0,8,0"/>

</StackPanel>
</Grid>
</ListViewItem>
Expand Down
112 changes: 110 additions & 2 deletions src/cascadia/TerminalApp/Pane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ static const Duration AnimationDuration = DurationHelper::FromTimeSpan(winrt::Wi

winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_focusedBorderBrush = { nullptr };
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_unfocusedBorderBrush = { nullptr };
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_readOnlyBorderBrush = { nullptr };
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_broadcastBorderBrush = { nullptr };

Pane::Pane(const GUID& profile, const TermControl& control, const bool lastFocused) :
_control{ control },
Expand All @@ -44,11 +46,12 @@ Pane::Pane(const GUID& profile, const TermControl& control, const bool lastFocus

_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
_readOnlyChangedToken = _control.ReadOnlyChanged({ this, &Pane::_ControlReadOnlyChangedHandler });

// On the first Pane's creation, lookup resources we'll use to theme the
// Pane, including the brushed to use for the focused/unfocused border
// color.
if (s_focusedBorderBrush == nullptr || s_unfocusedBorderBrush == nullptr)
if (s_focusedBorderBrush == nullptr || s_unfocusedBorderBrush == nullptr || s_readOnlyBorderBrush == nullptr || s_broadcastBorderBrush == nullptr)
{
_SetupResources();
}
Expand Down Expand Up @@ -586,7 +589,7 @@ bool Pane::_HasFocusedChild() const noexcept
// - <none>
void Pane::UpdateVisuals()
{
_border.BorderBrush(_lastActive ? s_focusedBorderBrush : s_unfocusedBorderBrush);
_border.BorderBrush(_ComputeBorderColor());
}

// Method Description:
Expand Down Expand Up @@ -698,6 +701,7 @@ void Pane::_CloseChild(const bool closeFirst)
// Add our new event handler before revoking the old one.
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
_readOnlyChangedToken = _control.ReadOnlyChanged({ this, &Pane::_ControlReadOnlyChangedHandler });

// Revoke the old event handlers. Remove both the handlers for the panes
// themselves closing, and remove their handlers for their controls
Expand All @@ -709,6 +713,8 @@ void Pane::_CloseChild(const bool closeFirst)
remainingChild->_control.ConnectionStateChanged(remainingChild->_connectionStateChangedToken);
closedChild->_control.WarningBell(closedChild->_warningBellToken);
remainingChild->_control.WarningBell(remainingChild->_warningBellToken);
closedChild->_control.ReadOnlyChanged(closedChild->_readOnlyChangedToken);
remainingChild->_control.ReadOnlyChanged(remainingChild->_readOnlyChangedToken);

// If either of our children was focused, we want to take that focus from
// them.
Expand Down Expand Up @@ -1440,6 +1446,8 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState
_connectionStateChangedToken.value = 0;
_control.WarningBell(_warningBellToken);
_warningBellToken.value = 0;
_control.ReadOnlyChanged(_readOnlyChangedToken);
_readOnlyChangedToken.value = 0;

// Remove our old GotFocus handler from the control. We don't what the
// control telling us that it's now focused, we want it telling its new
Expand Down Expand Up @@ -2022,6 +2030,34 @@ void Pane::_SetupResources()
// will eat focus.
s_unfocusedBorderBrush = SolidColorBrush{ Colors::Black() };
}

const auto readOnlyColorKey = winrt::box_value(L"ReadOnlyPaneBorderColor");
if (res.HasKey(readOnlyColorKey))
{
winrt::Windows::Foundation::IInspectable obj = res.Lookup(readOnlyColorKey);
s_readOnlyBorderBrush = obj.try_as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
}
else
{
// DON'T use Transparent here - if it's "Transparent", then it won't
// be able to hittest for clicks, and then clicking on the border
// will eat focus.
s_readOnlyBorderBrush = SolidColorBrush{ Colors::Black() };
}

const auto broadcastColorKey = winrt::box_value(L"BroadcastPaneBorderColor");
if (res.HasKey(broadcastColorKey))
{
winrt::Windows::Foundation::IInspectable obj = res.Lookup(broadcastColorKey);
s_broadcastBorderBrush = obj.try_as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
}
else
{
// DON'T use Transparent here - if it's "Transparent", then it won't
// be able to hittest for clicks, and then clicking on the border
// will eat focus.
s_broadcastBorderBrush = SolidColorBrush{ Colors::Black() };
}
}

int Pane::GetLeafPaneCount() const noexcept
Expand Down Expand Up @@ -2101,6 +2137,78 @@ bool Pane::ContainsReadOnly() const
return _IsLeaf() ? _control.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
}

void Pane::EnableBroadcast(bool enabled)
{
if (_IsLeaf())
{
_broadcastEnabled = enabled;
UpdateVisuals();
}
else
{
_firstChild->EnableBroadcast(enabled);
_secondChild->EnableBroadcast(enabled);
}
}


void Pane::BroadcastKey(const winrt::Microsoft::Terminal::TerminalControl::TermControl& sourceControl, const WORD vkey, const WORD scanCode, const DWORD modifiers, const bool keyDown)
{
if (_IsLeaf())
{
if (_control != sourceControl && !_control.ReadOnly())
{
_control.TrySendKeyEvent(vkey, scanCode, modifiers, keyDown);
}
}
else
{
_firstChild->BroadcastKey(sourceControl, vkey, scanCode, modifiers, keyDown);
_secondChild->BroadcastKey(sourceControl, vkey, scanCode, modifiers, keyDown);
}
}

void Pane::BroadcastChar(const winrt::Microsoft::Terminal::TerminalControl::TermControl& sourceControl, const wchar_t character, const WORD scanCode, const DWORD modifiers)
{
if (_IsLeaf())
{
if (_control != sourceControl && !_control.ReadOnly())
{
_control.TrySendChar(character, scanCode, modifiers);
}
}
else
{
_firstChild->BroadcastChar(sourceControl, character, scanCode, modifiers);
_secondChild->BroadcastChar(sourceControl, character, scanCode, modifiers);
}
}

void Pane::_ControlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::Foundation::IInspectable& /*e*/)
{
UpdateVisuals();
}

winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::_ComputeBorderColor()
{
if (_lastActive)
{
return s_focusedBorderBrush;
}

if (_control && _control.ReadOnly())
{
return s_readOnlyBorderBrush;
}

if (_broadcastEnabled)
{
return s_broadcastBorderBrush;
}

return s_unfocusedBorderBrush;
}

DEFINE_EVENT(Pane, GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
DEFINE_EVENT(Pane, LostFocus, _LostFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
DEFINE_EVENT(Pane, PaneRaiseBell, _PaneRaiseBellHandlers, winrt::Windows::Foundation::EventHandler<bool>);
11 changes: 11 additions & 0 deletions src/cascadia/TerminalApp/Pane.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ class Pane : public std::enable_shared_from_this<Pane>

bool ContainsReadOnly() const;

void EnableBroadcast(bool enabled);
void BroadcastKey(const winrt::Microsoft::Terminal::TerminalControl::TermControl& sourceControl, const WORD vkey, const WORD scanCode, const DWORD modifiers, const bool keyDown);
void BroadcastChar(const winrt::Microsoft::Terminal::TerminalControl::TermControl& sourceControl, const wchar_t vkey, const WORD scanCode, const DWORD modifiers);

WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
DECLARE_EVENT(GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
DECLARE_EVENT(LostFocus, _LostFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
Expand All @@ -98,6 +102,8 @@ class Pane : public std::enable_shared_from_this<Pane>
winrt::Microsoft::Terminal::TerminalControl::TermControl _control{ nullptr };
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_focusedBorderBrush;
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_unfocusedBorderBrush;
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_readOnlyBorderBrush;
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_broadcastBorderBrush;

std::shared_ptr<Pane> _firstChild{ nullptr };
std::shared_ptr<Pane> _secondChild{ nullptr };
Expand All @@ -112,6 +118,7 @@ class Pane : public std::enable_shared_from_this<Pane>
winrt::event_token _firstClosedToken{ 0 };
winrt::event_token _secondClosedToken{ 0 };
winrt::event_token _warningBellToken{ 0 };
winrt::event_token _readOnlyChangedToken{ 0 };

winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker;
winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker;
Expand All @@ -123,6 +130,7 @@ class Pane : public std::enable_shared_from_this<Pane>
std::atomic<bool> _isClosing{ false };

bool _zoomed{ false };
bool _broadcastEnabled{ false };

bool _IsLeaf() const noexcept;
bool _HasFocusedChild() const noexcept;
Expand All @@ -137,6 +145,7 @@ class Pane : public std::enable_shared_from_this<Pane>
void _ApplySplitDefinitions();
void _SetupEntranceAnimation();
void _UpdateBorders();
winrt::Windows::UI::Xaml::Media::SolidColorBrush _ComputeBorderColor();

bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
bool _NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
Expand All @@ -153,6 +162,8 @@ class Pane : public std::enable_shared_from_this<Pane>
void _ControlLostFocusHandler(winrt::Windows::Foundation::IInspectable const& sender,
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);

void _ControlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e);

std::pair<float, float> _CalcChildrenSizes(const float fullSize) const;
SnapChildrenSizeResult _CalcSnappedChildrenSizes(const bool widthOrHeight, const float fullSize) const;
SnapSizeResult _CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
Expand Down
5 changes: 5 additions & 0 deletions src/cascadia/TerminalApp/ShortcutActionDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,11 @@ namespace winrt::TerminalApp::implementation
_NewWindowHandlers(*this, eventArgs);
break;
}
case ShortcutAction::ToggleInputBroadcast:
{
_ToggleInputBroadcastHandlers(*this, eventArgs);
break;
}
default:
return false;
}
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/ShortcutActionDispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ namespace winrt::TerminalApp::implementation
TYPED_EVENT(FindMatch, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
TYPED_EVENT(TogglePaneReadOnly, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
TYPED_EVENT(NewWindow, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
TYPED_EVENT(ToggleInputBroadcast, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
// clang-format on

private:
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/ShortcutActionDispatch.idl
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> FindMatch;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> TogglePaneReadOnly;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> NewWindow;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ToggleInputBroadcast;
}
}
6 changes: 6 additions & 0 deletions src/cascadia/TerminalApp/TabHeaderControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ the MIT License. See LICENSE in the project root for license information. -->
Glyph="&#xE72E;"
FontSize="12"
Margin="0,0,8,0"/>
<FontIcon x:Name="HeaderBroadcastIcon"
FontFamily="Segoe MDL2 Assets"
Visibility="{x:Bind TabStatus.IsInputBroadcastActive, Mode=OneWay}"
Glyph="&#xEC05;"
FontSize="12"
Margin="0,0,8,0"/>
<TextBlock x:Name="HeaderTextBlock"
Visibility="Visible"
Text="{x:Bind Title, Mode=OneWay}"/>
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,7 @@ namespace winrt::TerminalApp::implementation
_actionDispatch->FindMatch({ this, &TerminalPage::_HandleFindMatch });
_actionDispatch->TogglePaneReadOnly({ this, &TerminalPage::_HandleTogglePaneReadOnly });
_actionDispatch->NewWindow({ this, &TerminalPage::_HandleNewWindow });
_actionDispatch->ToggleInputBroadcast({ this, &TerminalPage::_HandleToggleInputBroadcast });
}

// Method Description:
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ namespace winrt::TerminalApp::implementation
void _HandleFindMatch(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
void _HandleTogglePaneReadOnly(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
void _HandleNewWindow(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
void _HandleToggleInputBroadcast(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);

// Make sure to hook new actions up in _RegisterActionCallbacks!
#pragma endregion
Expand Down
35 changes: 34 additions & 1 deletion src/cascadia/TerminalApp/TerminalTab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,6 @@ namespace winrt::TerminalApp::implementation
++_nextPaneId;
}
_activePane = first;
_AttachEventHandlersToControl(control);

// Add a event handlers to the new panes' GotFocus event. When the pane
// gains focus, we'll mark it as the new active pane.
Expand Down Expand Up @@ -629,6 +628,32 @@ namespace winrt::TerminalApp::implementation
}
}
});

control.KeySent([weakThis](auto&& sender, auto&& e) {
if (const auto tab{ weakThis.get() })
{
if (tab->_tabStatus.IsInputBroadcastActive())
{
if (const auto termControl{ sender.try_as<winrt::Microsoft::Terminal::TerminalControl::TermControl>() })
{
tab->_rootPane->BroadcastKey(termControl, e.VKey(), e.ScanCode(), e.Modifiers(), e.KeyDown());
}
}
}
});

control.CharSent([weakThis](auto&& sender, auto&& e) {
if (const auto tab{ weakThis.get() })
{
if (tab->_tabStatus.IsInputBroadcastActive())
{
if (const auto termControl{ sender.try_as<winrt::Microsoft::Terminal::TerminalControl::TermControl>() })
{
tab->_rootPane->BroadcastChar(termControl, e.Character(), e.ScanCode(), e.Modifiers());
}
}
}
});
}

// Method Description:
Expand Down Expand Up @@ -1156,6 +1181,14 @@ namespace winrt::TerminalApp::implementation
}
}

// Method Description:
// - Toggle read-only mode on the active pane
void TerminalTab::ToggleInputBroadcast()
{
_tabStatus.IsInputBroadcastActive(!_tabStatus.IsInputBroadcastActive());
_rootPane->EnableBroadcast(_tabStatus.IsInputBroadcastActive());
}

// Method Description:
// - Calculates if the tab is read-only.
// The tab is considered read-only if one of the panes is read-only.
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalApp/TerminalTab.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ namespace winrt::TerminalApp::implementation
int GetLeafPaneCount() const noexcept;

void TogglePaneReadOnly();
void ToggleInputBroadcast();

std::shared_ptr<Pane> GetActivePane() const;

winrt::TerminalApp::TerminalTabStatus TabStatus()
Expand Down
Loading