From 639c182dcdd6835647ff39ad126bf481c53850c6 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Fri, 15 Nov 2024 02:01:57 +0100 Subject: [PATCH] wip --- src/cascadia/TerminalApp/TerminalPage.cpp | 205 +++++++----------- src/cascadia/TerminalApp/TerminalPage.h | 14 +- src/cascadia/TerminalApp/TerminalWindow.cpp | 65 +++--- src/cascadia/TerminalApp/TerminalWindow.h | 2 +- src/cascadia/TerminalControl/TermControl.cpp | 34 +-- src/cascadia/TerminalControl/TermControl.h | 6 +- src/cascadia/WindowsTerminal/AppHost.cpp | 158 +++++--------- src/cascadia/WindowsTerminal/AppHost.h | 8 +- src/cascadia/WindowsTerminal/IslandWindow.cpp | 6 +- src/cascadia/WindowsTerminal/IslandWindow.h | 2 +- .../WindowsTerminal/WindowEmperor.cpp | 121 ++++++----- src/cascadia/WindowsTerminal/WindowEmperor.h | 1 + 12 files changed, 246 insertions(+), 376 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 3d7c0fc4b40..66735369173 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -2345,18 +2345,14 @@ namespace winrt::TerminalApp::implementation // reattach instead of create new content, so this method simply needs to // parse the JSON and pump it into our action handler. Almost the same as // doing something like `wt -w 0 nt`. - safe_void_coroutine TerminalPage::AttachContent(IVector args, - uint32_t tabIndex) + void TerminalPage::AttachContent(IVector args, uint32_t tabIndex) { if (args == nullptr || args.Size() == 0) { - co_return; + return; } - // Switch to the UI thread before selecting a tab or dispatching actions. - co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::High); - const auto& firstAction = args.GetAt(0); const bool firstIsSplitPane{ firstAction.Action() == ShortcutAction::SplitPane }; @@ -4290,57 +4286,49 @@ namespace winrt::TerminalApp::implementation // - // Return Value: // - - safe_void_coroutine TerminalPage::IdentifyWindow() + void TerminalPage::IdentifyWindow() { - auto weakThis{ get_weak() }; - co_await wil::resume_foreground(Dispatcher()); - if (auto page{ weakThis.get() }) + // If we haven't ever loaded the TeachingTip, then do so now and + // create the toast for it. + if (_windowIdToast == nullptr) { - // If we haven't ever loaded the TeachingTip, then do so now and - // create the toast for it. - if (page->_windowIdToast == nullptr) + if (auto tip{ FindName(L"WindowIdToast").try_as() }) { - if (auto tip{ page->FindName(L"WindowIdToast").try_as() }) - { - page->_windowIdToast = std::make_shared(tip); - // Make sure to use the weak ref when setting up this - // callback. - tip.Closed({ page->get_weak(), &TerminalPage::_FocusActiveControl }); - } + _windowIdToast = std::make_shared(tip); + // IsLightDismissEnabled == true is bugged and poorly interacts with multi-windowing. + // It causes the tip to be immediately dismissed when another tip is opened in another window. + tip.IsLightDismissEnabled(false); + // Make sure to use the weak ref when setting up this callback. + tip.Closed({ get_weak(), &TerminalPage::_FocusActiveControl }); } - _UpdateTeachingTipTheme(WindowIdToast().try_as()); + } + _UpdateTeachingTipTheme(WindowIdToast().try_as()); - if (page->_windowIdToast != nullptr) - { - page->_windowIdToast->Open(); - } + if (_windowIdToast != nullptr) + { + _windowIdToast->Open(); } } - safe_void_coroutine TerminalPage::ShowTerminalWorkingDirectory() + void TerminalPage::ShowTerminalWorkingDirectory() { - auto weakThis{ get_weak() }; - co_await wil::resume_foreground(Dispatcher()); - if (auto page{ weakThis.get() }) + // If we haven't ever loaded the TeachingTip, then do so now and + // create the toast for it. + if (_windowCwdToast == nullptr) { - // If we haven't ever loaded the TeachingTip, then do so now and - // create the toast for it. - if (page->_windowCwdToast == nullptr) + if (auto tip{ FindName(L"WindowCwdToast").try_as() }) { - if (auto tip{ page->FindName(L"WindowCwdToast").try_as() }) - { - page->_windowCwdToast = std::make_shared(tip); - // Make sure to use the weak ref when setting up this - // callback. - tip.Closed({ page->get_weak(), &TerminalPage::_FocusActiveControl }); - } + _windowCwdToast = std::make_shared(tip); + // Make sure to use the weak ref when setting up this + // callback. + tip.Closed({ get_weak(), &TerminalPage::_FocusActiveControl }); } - _UpdateTeachingTipTheme(WindowCwdToast().try_as()); + } + _UpdateTeachingTipTheme(WindowCwdToast().try_as()); - if (page->_windowCwdToast != nullptr) - { - page->_windowCwdToast->Open(); - } + if (_windowCwdToast != nullptr) + { + _windowCwdToast->Open(); } } @@ -5045,25 +5033,18 @@ namespace winrt::TerminalApp::implementation // Handler for our WindowProperties's PropertyChanged event. We'll use this // to pop the "Identify Window" toast when the user renames our window. - safe_void_coroutine TerminalPage::_windowPropertyChanged(const IInspectable& /*sender*/, - const WUX::Data::PropertyChangedEventArgs& args) + void TerminalPage::_windowPropertyChanged(const IInspectable& /*sender*/, const WUX::Data::PropertyChangedEventArgs& args) { if (args.PropertyName() != L"WindowName") { - co_return; + return; } - auto weakThis{ get_weak() }; - // On the foreground thread, raise property changed notifications, and - // display the success toast. - co_await wil::resume_foreground(Dispatcher()); - if (auto page{ weakThis.get() }) + + // DON'T display the confirmation if this is the name we were + // given on startup! + if (_startupState == StartupState::Initialized) { - // DON'T display the confirmation if this is the name we were - // given on startup! - if (page->_startupState == StartupState::Initialized) - { - page->IdentifyWindow(); - } + IdentifyWindow(); } } @@ -5136,8 +5117,8 @@ namespace winrt::TerminalApp::implementation // - Called on the TARGET of a tab drag/drop. We'll unpack the DataPackage // to find who the tab came from. We'll then ask the Monarch to ask the // sender to move that tab to us. - safe_void_coroutine TerminalPage::_onTabStripDrop(winrt::Windows::Foundation::IInspectable /*sender*/, - winrt::Windows::UI::Xaml::DragEventArgs e) + void TerminalPage::_onTabStripDrop(winrt::Windows::Foundation::IInspectable /*sender*/, + winrt::Windows::UI::Xaml::DragEventArgs e) { // Get the PID and make sure it is the same as ours. if (const auto& pidObj{ e.DataView().Properties().TryLookup(L"pid") }) @@ -5146,20 +5127,20 @@ namespace winrt::TerminalApp::implementation if (pid != GetCurrentProcessId()) { // The PID doesn't match ours. We can't handle this drop. - co_return; + return; } } else { // No PID? We can't handle this drop. Bail. - co_return; + return; } const auto& windowIdObj{ e.DataView().Properties().TryLookup(L"windowId") }; if (windowIdObj == nullptr) { // No windowId? Bail. - co_return; + return; } const uint64_t src{ winrt::unbox_value(windowIdObj) }; @@ -5167,38 +5148,32 @@ namespace winrt::TerminalApp::implementation // index to the request. This is largely taken from the WinUI sample // app. - // We need to be on OUR UI thread to figure out where we dropped - auto weakThis{ get_weak() }; - co_await wil::resume_foreground(Dispatcher()); - if (const auto& page{ weakThis.get() }) - { - // First we need to get the position in the List to drop to - auto index = -1; + // First we need to get the position in the List to drop to + auto index = -1; - // Determine which items in the list our pointer is between. - for (auto i = 0u; i < _tabView.TabItems().Size(); i++) + // Determine which items in the list our pointer is between. + for (auto i = 0u; i < _tabView.TabItems().Size(); i++) + { + if (const auto& item{ _tabView.ContainerFromIndex(i).try_as() }) { - if (const auto& item{ _tabView.ContainerFromIndex(i).try_as() }) + const auto posX{ e.GetPosition(item).X }; // The point of the drop, relative to the tab + const auto itemWidth{ item.ActualWidth() }; // The right of the tab + // If the drag point is on the left half of the tab, then insert here. + if (posX < itemWidth / 2) { - const auto posX{ e.GetPosition(item).X }; // The point of the drop, relative to the tab - const auto itemWidth{ item.ActualWidth() }; // The right of the tab - // If the drag point is on the left half of the tab, then insert here. - if (posX < itemWidth / 2) - { - index = i; - break; - } + index = i; + break; } } + } - // `this` is safe to use - const auto request = winrt::make_self(src, _WindowProperties.WindowId(), index); + // `this` is safe to use + const auto request = winrt::make_self(src, _WindowProperties.WindowId(), index); - // This will go up to the monarch, who will then dispatch the request - // back down to the source TerminalPage, who will then perform a - // RequestMoveContent to move their tab to us. - RequestReceiveContent.raise(*this, *request); - } + // This will go up to the monarch, who will then dispatch the request + // back down to the source TerminalPage, who will then perform a + // RequestMoveContent to move their tab to us. + RequestReceiveContent.raise(*this, *request); } // Method Description: @@ -5208,33 +5183,23 @@ namespace winrt::TerminalApp::implementation // the destination window. // - Fortunately, sending the tab is basically just a MoveTab action, so we // can largely reuse that. - safe_void_coroutine TerminalPage::SendContentToOther(winrt::TerminalApp::RequestReceiveContentArgs args) + void TerminalPage::SendContentToOther(winrt::TerminalApp::RequestReceiveContentArgs args) { // validate that we're the source window of the tab in this request if (args.SourceWindow() != _WindowProperties.WindowId()) { - co_return; + return; } if (!_stashed.draggedTab) { - co_return; + return; } - // must do the work of adding/removing tabs on the UI thread. - auto weakThis{ get_weak() }; - co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal); - if (const auto& page{ weakThis.get() }) - { - // `this` is safe to use in here. - - _sendDraggedTabToWindow(winrt::to_hstring(args.TargetWindow()), - args.TabIndex(), - std::nullopt); - } + _sendDraggedTabToWindow(winrt::to_hstring(args.TargetWindow()), args.TabIndex(), std::nullopt); } - safe_void_coroutine TerminalPage::_onTabDroppedOutside(winrt::IInspectable sender, - winrt::MUX::Controls::TabViewTabDroppedOutsideEventArgs e) + void TerminalPage::_onTabDroppedOutside(winrt::IInspectable sender, + winrt::MUX::Controls::TabViewTabDroppedOutsideEventArgs e) { // Get the current pointer point from the CoreWindow const auto& pointerPoint{ CoreWindow::GetForCurrentThread().PointerPosition() }; @@ -5246,29 +5211,21 @@ namespace winrt::TerminalApp::implementation if (!_stashed.draggedTab) { - co_return; + return; } - // must do the work of adding/removing tabs on the UI thread. - auto weakThis{ get_weak() }; - co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal); - if (const auto& page{ weakThis.get() }) - { - // `this` is safe to use in here. - - // We need to convert the pointer point to a point that we can use - // to position the new window. We'll use the drag offset from before - // so that the tab in the new window is positioned so that it's - // basically still directly under the cursor. + // We need to convert the pointer point to a point that we can use + // to position the new window. We'll use the drag offset from before + // so that the tab in the new window is positioned so that it's + // basically still directly under the cursor. - // -1 is the magic number for "new window" - // 0 as the tab index, because we don't care. It's making a new window. It'll be the only tab. - const winrt::Windows::Foundation::Point adjusted = { - pointerPoint.X - _stashed.dragOffset.X, - pointerPoint.Y - _stashed.dragOffset.Y, - }; - _sendDraggedTabToWindow(winrt::hstring{ L"-1" }, 0, adjusted); - } + // -1 is the magic number for "new window" + // 0 as the tab index, because we don't care. It's making a new window. It'll be the only tab. + const winrt::Windows::Foundation::Point adjusted = { + pointerPoint.X - _stashed.dragOffset.X, + pointerPoint.Y - _stashed.dragOffset.Y, + }; + _sendDraggedTabToWindow(winrt::hstring{ L"-1" }, 0, adjusted); } void TerminalPage::_sendDraggedTabToWindow(const winrt::hstring& windowId, diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 9a61153a426..7e919a4c9b7 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -139,10 +139,10 @@ namespace winrt::TerminalApp::implementation void ShowKeyboardServiceWarning() const; winrt::hstring KeyboardServiceDisabledText(); - safe_void_coroutine IdentifyWindow(); + void IdentifyWindow(); void ActionSaved(winrt::hstring input, winrt::hstring name, winrt::hstring keyChord); void ActionSaveFailed(winrt::hstring message); - safe_void_coroutine ShowTerminalWorkingDirectory(); + void ShowTerminalWorkingDirectory(); safe_void_coroutine ProcessStartupActions(Windows::Foundation::Collections::IVector actions, const bool initial, @@ -159,8 +159,8 @@ namespace winrt::TerminalApp::implementation bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down); - safe_void_coroutine AttachContent(Windows::Foundation::Collections::IVector args, uint32_t tabIndex); - safe_void_coroutine SendContentToOther(winrt::TerminalApp::RequestReceiveContentArgs args); + void AttachContent(Windows::Foundation::Collections::IVector args, uint32_t tabIndex); + void SendContentToOther(winrt::TerminalApp::RequestReceiveContentArgs args); uint32_t NumberOfTabs() const; @@ -527,12 +527,12 @@ namespace winrt::TerminalApp::implementation Windows::Foundation::IAsyncOperation> _FindPackageAsync(hstring query); void _WindowSizeChanged(const IInspectable sender, const winrt::Microsoft::Terminal::Control::WindowSizeChangedEventArgs args); - safe_void_coroutine _windowPropertyChanged(const IInspectable& sender, const winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs& args); + void _windowPropertyChanged(const IInspectable& sender, const winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs& args); void _onTabDragStarting(const winrt::Microsoft::UI::Xaml::Controls::TabView& sender, const winrt::Microsoft::UI::Xaml::Controls::TabViewTabDragStartingEventArgs& e); void _onTabStripDragOver(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::DragEventArgs& e); - safe_void_coroutine _onTabStripDrop(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::DragEventArgs e); - safe_void_coroutine _onTabDroppedOutside(winrt::Windows::Foundation::IInspectable sender, winrt::Microsoft::UI::Xaml::Controls::TabViewTabDroppedOutsideEventArgs e); + void _onTabStripDrop(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::DragEventArgs e); + void _onTabDroppedOutside(winrt::Windows::Foundation::IInspectable sender, winrt::Microsoft::UI::Xaml::Controls::TabViewTabDroppedOutsideEventArgs e); void _DetachPaneFromWindow(std::shared_ptr pane); void _DetachTabFromWindow(const winrt::com_ptr& terminalTab); diff --git a/src/cascadia/TerminalApp/TerminalWindow.cpp b/src/cascadia/TerminalApp/TerminalWindow.cpp index d704cf4d777..64440556857 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.cpp +++ b/src/cascadia/TerminalApp/TerminalWindow.cpp @@ -768,51 +768,36 @@ namespace winrt::TerminalApp::implementation // This may be called on a background thread, or the main thread, but almost // definitely not on OUR UI thread. - safe_void_coroutine TerminalWindow::UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args) + void TerminalWindow::UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args) { - // GH#17620: We have a bug somewhere where a window doesn't get unregistered from the window list. - // This causes UpdateSettings calls where the thread dispatcher is already null. - const auto dispatcher = _root->Dispatcher(); - if (!dispatcher) - { - co_return; - } - - const auto weakThis{ get_weak() }; - co_await wil::resume_foreground(dispatcher); - - // Back on our UI thread... - if (auto logic{ weakThis.get() }) - { - _settings = args.NewSettings(); + _settings = args.NewSettings(); - // Update the settings in TerminalPage - // We're on our UI thread right now, so this is safe - _root->SetSettings(_settings, true); + // Update the settings in TerminalPage + // We're on our UI thread right now, so this is safe + _root->SetSettings(_settings, true); - // Bubble the notification up to the AppHost, now that we've updated our _settings. - SettingsChanged.raise(*this, args); + // Bubble the notification up to the AppHost, now that we've updated our _settings. + SettingsChanged.raise(*this, args); - if (FAILED(args.Result())) - { - const winrt::hstring titleKey = USES_RESOURCE(L"ReloadJsonParseErrorTitle"); - const winrt::hstring textKey = USES_RESOURCE(L"ReloadJsonParseErrorText"); - _ShowLoadErrorsDialog(titleKey, - textKey, - gsl::narrow_cast(args.Result()), - args.ExceptionText()); - co_return; - } - else if (args.Result() == S_FALSE) - { - _ShowLoadWarningsDialog(args.Warnings()); - } - else if (args.Result() == S_OK) - { - DismissDialog(); - } - _RefreshThemeRoutine(); + if (FAILED(args.Result())) + { + const winrt::hstring titleKey = USES_RESOURCE(L"ReloadJsonParseErrorTitle"); + const winrt::hstring textKey = USES_RESOURCE(L"ReloadJsonParseErrorText"); + _ShowLoadErrorsDialog(titleKey, + textKey, + gsl::narrow_cast(args.Result()), + args.ExceptionText()); + return; } + else if (args.Result() == S_FALSE) + { + _ShowLoadWarningsDialog(args.Warnings()); + } + else if (args.Result() == S_OK) + { + DismissDialog(); + } + _RefreshThemeRoutine(); } void TerminalWindow::_OpenSettingsUI() diff --git a/src/cascadia/TerminalApp/TerminalWindow.h b/src/cascadia/TerminalApp/TerminalWindow.h index e2cde9985df..5e704dcdc59 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.h +++ b/src/cascadia/TerminalApp/TerminalWindow.h @@ -75,7 +75,7 @@ namespace winrt::TerminalApp::implementation void PersistState(); - safe_void_coroutine UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args); + void UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args); bool HasCommandlineArguments() const noexcept; diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 8ac4deacae1..3a6d87008f6 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -763,40 +763,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - Given Settings having been updated, applies the settings to the current terminal. // Return Value: // - - safe_void_coroutine TermControl::UpdateControlSettings(IControlSettings settings, - IControlAppearance unfocusedAppearance) + void TermControl::UpdateControlSettings(IControlSettings settings, IControlAppearance unfocusedAppearance) { - auto weakThis{ get_weak() }; - - // Dispatch a call to the UI thread to apply the new settings to the - // terminal. - co_await wil::resume_foreground(Dispatcher()); + _core.UpdateSettings(settings, unfocusedAppearance); - if (auto strongThis{ weakThis.get() }) - { - _core.UpdateSettings(settings, unfocusedAppearance); + _UpdateSettingsFromUIThread(); - _UpdateSettingsFromUIThread(); - - _UpdateAppearanceFromUIThread(_focused ? _core.FocusedAppearance() : _core.UnfocusedAppearance()); - } + _UpdateAppearanceFromUIThread(_focused ? _core.FocusedAppearance() : _core.UnfocusedAppearance()); } // Method Description: // - Dispatches a call to the UI thread and updates the appearance // Arguments: // - newAppearance: the new appearance to set - safe_void_coroutine TermControl::UpdateAppearance(IControlAppearance newAppearance) + void TermControl::UpdateAppearance(IControlAppearance newAppearance) { - auto weakThis{ get_weak() }; - - // Dispatch a call to the UI thread - co_await wil::resume_foreground(Dispatcher()); - - if (auto strongThis{ weakThis.get() }) - { - _UpdateAppearanceFromUIThread(newAppearance); - } + _UpdateAppearanceFromUIThread(newAppearance); } // Method Description: @@ -2175,10 +2157,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - // Return Value: // - - safe_void_coroutine TermControl::_coreTransparencyChanged(IInspectable /*sender*/, - Control::TransparencyChangedEventArgs /*args*/) + void TermControl::_coreTransparencyChanged(IInspectable /*sender*/, Control::TransparencyChangedEventArgs /*args*/) { - co_await wil::resume_foreground(Dispatcher()); try { _changeBackgroundOpacity(); diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 96a02c51a0f..69f8f1ba05c 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -53,7 +53,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation static Control::TermControl NewControlByAttachingContent(Control::ControlInteractivity content, const Microsoft::Terminal::Control::IKeyBindings& keyBindings); void UpdateControlSettings(Control::IControlSettings settings); - safe_void_coroutine UpdateControlSettings(Control::IControlSettings settings, Control::IControlAppearance unfocusedAppearance); + void UpdateControlSettings(Control::IControlSettings settings, Control::IControlAppearance unfocusedAppearance); IControlSettings Settings() const; uint64_t ContentId() const; @@ -345,7 +345,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void _UpdateAppearanceFromUIThread(Control::IControlAppearance newAppearance); void _ApplyUISettings(); - safe_void_coroutine UpdateAppearance(Control::IControlAppearance newAppearance); + void UpdateAppearance(Control::IControlAppearance newAppearance); void _SetBackgroundImage(const IControlAppearance& newAppearance); void _InitializeBackgroundBrush(); @@ -426,7 +426,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation safe_void_coroutine _updateSelectionMarkers(IInspectable sender, Control::UpdateSelectionMarkersEventArgs args); void _coreFontSizeChanged(const IInspectable& s, const Control::FontSizeChangedArgs& args); - safe_void_coroutine _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args); + 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 _coreOutputIdle(const IInspectable& sender, const IInspectable& args); diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index 60c8d6f011c..f2d3c256805 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -30,43 +30,34 @@ using namespace std::chrono_literals; // This magic flag is "documented" at https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301(v=vs.85).aspx // "If the high-order bit is 1, the key is down; otherwise, it is up." static constexpr short KeyPressed{ gsl::narrow_cast(0x8000) }; +static constexpr auto FrameUpdateInterval = std::chrono::milliseconds(16); -constexpr const auto FrameUpdateInterval = std::chrono::milliseconds(16); +static winrt::com_ptr _desktopManager; -AppHost::AppHost(const winrt::TerminalApp::AppLogic& logic, winrt::TerminalApp::WindowRequestedArgs args, std::weak_ptr manager, std::unique_ptr window) noexcept : +AppHost::AppHost(const winrt::TerminalApp::AppLogic& logic, winrt::TerminalApp::WindowRequestedArgs args, std::weak_ptr manager) noexcept : _appLogic{ logic }, _windowLogic{ nullptr }, // don't make one, we're going to take a ref on app's - _windowManager{ manager }, - _desktopManager{ winrt::try_create_instance(__uuidof(VirtualDesktopManager)) } + _windowManager{ std::move(manager) } { + if (!_desktopManager) + { + _desktopManager = winrt::try_create_instance(__uuidof(VirtualDesktopManager)); + } + _started = std::chrono::high_resolution_clock::now(); _HandleCommandlineArgs(args); - // Don't attempt to session restore if we're just making a window for tear-out - if (args.Content().empty()) - { - _HandleSessionRestore(args); - } - // _HandleCommandlineArgs will create a _windowLogic _useNonClientArea = _windowLogic.GetShowTabsInTitlebar(); - const bool isWarmStart = window != nullptr; - if (isWarmStart) + if (_useNonClientArea) { - _window = std::move(window); + _window = std::make_unique(_windowLogic.GetRequestedTheme()); } else { - if (_useNonClientArea) - { - _window = std::make_unique(_windowLogic.GetRequestedTheme()); - } - else - { - _window = std::make_unique(); - } + _window = std::make_unique(); } // Update our own internal state tracking if we're in quake mode or not. @@ -147,103 +138,42 @@ void AppHost::_HandleCommandlineArgs(const winrt::TerminalApp::WindowRequestedAr // We don't have XAML yet, but we do have other stuff. _windowLogic = _appLogic.CreateNewWindow(); + if (const auto content = windowArgs.Content(); !content.empty()) { - const bool startedForContent = !windowArgs.Content().empty(); - if (startedForContent) - { - _windowLogic.SetStartupContent(windowArgs.Content(), windowArgs.InitialBounds()); - } - else + _windowLogic.SetStartupContent(content, windowArgs.InitialBounds()); + } + else + { + const auto result = _windowLogic.SetStartupCommandline(windowArgs.Commandline(), windowArgs.CurrentDirectory(), windowArgs.CurrentEnvironment()); + const auto message = _windowLogic.ParseCommandlineMessage(); + if (!message.empty()) { - const auto result = _windowLogic.SetStartupCommandline(windowArgs.Commandline(), windowArgs.CurrentDirectory(), windowArgs.CurrentEnvironment()); - const auto message = _windowLogic.ParseCommandlineMessage(); - if (!message.empty()) - { - AppHost::s_DisplayMessageBox({ message, result }); + AppHost::s_DisplayMessageBox({ message, result }); - if (_windowLogic.ShouldExitEarly()) - { - ExitThread(result); - } + if (_windowLogic.ShouldExitEarly()) + { + _CloseRequested(nullptr, nullptr); } } - - _launchShowWindowCommand = windowArgs.ShowWindowCommand(); - - // This is a fix for GH#12190 and hopefully GH#12169. - // - // If the commandline we were provided is going to result in us only - // opening elevated terminal instances, then we need to not even create - // the window at all here. In that case, we're going through this - // special escape hatch to dispatch all the calls to elevate-shim, and - // then we're going to exit immediately. - if (_windowLogic.ShouldImmediatelyHandoffToElevated()) - { - _windowLogic.HandoffToElevated(); - return; - } - - _windowLogic.WindowName(windowArgs.WindowName()); - _windowLogic.WindowId(windowArgs.Id()); } -} -void AppHost::_HandleSessionRestore(const winrt::TerminalApp::WindowRequestedArgs& args) -{ - // This is logic that almost seems like it belongs on the WindowEmperor. - // It probably does. However, it needs to muck with our own window so - // much, that there was no reasonable way of moving this. Moving it also - // seemed to reorder bits of init so much that everything broke. So - // we'll leave it here. - // TODO: What the fuck is even going on here - /*const auto numPeasants = _windowManager.GetNumberOfPeasants(); - if (numPeasants != 1 || !_appLogic.ShouldUsePersistedLayout()) - { - return; - }*/ + _launchShowWindowCommand = windowArgs.ShowWindowCommand(); - const auto state = ApplicationState::SharedInstance(); - const auto layouts = state.PersistedWindowLayouts(); - - if (layouts && layouts.Size() > 0) + // This is a fix for GH#12190 and hopefully GH#12169. + // + // If the commandline we were provided is going to result in us only + // opening elevated terminal instances, then we need to not even create + // the window at all here. In that case, we're going through this + // special escape hatch to dispatch all the calls to elevate-shim, and + // then we're going to exit immediately. + if (_windowLogic.ShouldImmediatelyHandoffToElevated()) { - uint32_t startIdx = 0; - // We want to create a window for every saved layout. - // If we are the only window, and no commandline arguments were provided - // then we should just use the current window to load the first layout. - // Otherwise create this window normally with its commandline, and create - // a new window using the first saved layout information. - // The 2nd+ layout will always get a new window. - if (!_windowLogic.HasCommandlineArguments() && - !_appLogic.HasSettingsStartupActions()) - { - _windowLogic.SetPersistedLayoutIdx(startIdx); - startIdx += 1; - } - - // Create new windows for each of the other saved layouts. - for (const auto size = layouts.Size(); startIdx < size; startIdx += 1) - { - auto newWindowArgs = fmt::format(FMT_COMPILE(L"{} -w new -s {}"), args.Commandline()[0], startIdx); - - STARTUPINFO si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - wil::unique_process_information pi; - - LOG_IF_WIN32_BOOL_FALSE(CreateProcessW(nullptr, - newWindowArgs.data(), - nullptr, // lpProcessAttributes - nullptr, // lpThreadAttributes - false, // bInheritHandles - DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT, // doCreationFlags - nullptr, // lpEnvironment - nullptr, // lpStartingDirectory - &si, // lpStartupInfo - &pi // lpProcessInformation - )); - } + _windowLogic.HandoffToElevated(); + return; } + + _windowLogic.WindowName(windowArgs.WindowName()); + _windowLogic.WindowId(windowArgs.Id()); } // Method Description: @@ -890,7 +820,7 @@ void AppHost::_WindowActivated(bool activated) { _windowLogic.WindowActivated(activated); - if (activated && _isWindowInitialized) + if (activated && _isWindowInitialized != WindowInitializedState::NotInitialized) { _peasantNotifyActivateWindow(); } @@ -917,6 +847,16 @@ safe_void_coroutine AppHost::_peasantNotifyActivateWindow() { co_return; } + + // TODO: projects/5 - in the future, we'll want to actually get the + // desktop GUID in IslandWindow, and bubble that up here, then down to + // the Peasant. For now, we're just leaving space for it. + /*peasant.ActivateWindow({ + peasant.GetID(), + reinterpret_cast(hwnd), + currentDesktopGuid, + winrt::clock().now(), + });*/ } void AppHost::_HandleSummon(const winrt::Windows::Foundation::IInspectable& /*sender*/, diff --git a/src/cascadia/WindowsTerminal/AppHost.h b/src/cascadia/WindowsTerminal/AppHost.h index 877340abce1..39a8c3ce5a5 100644 --- a/src/cascadia/WindowsTerminal/AppHost.h +++ b/src/cascadia/WindowsTerminal/AppHost.h @@ -12,9 +12,7 @@ class WindowEmperor; class AppHost : public std::enable_shared_from_this { public: - static constexpr DWORD WM_REFRIGERATE = WM_APP + 0; - - AppHost(const winrt::TerminalApp::AppLogic& logic, winrt::TerminalApp::WindowRequestedArgs args, std::weak_ptr manager, std::unique_ptr window = nullptr) noexcept; + AppHost(const winrt::TerminalApp::AppLogic& logic, winrt::TerminalApp::WindowRequestedArgs args, std::weak_ptr manager) noexcept; void AppTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, winrt::hstring newTitle); void Initialize(); @@ -34,9 +32,8 @@ class AppHost : public std::enable_shared_from_this winrt::TerminalApp::AppLogic _appLogic; winrt::TerminalApp::TerminalWindow _windowLogic; std::weak_ptr _windowManager; - winrt::com_ptr _desktopManager{ nullptr }; - enum WindowInitializedState : uint32_t + enum class WindowInitializedState : uint32_t { NotInitialized = 0, Initializing = 1, @@ -57,7 +54,6 @@ class AppHost : public std::enable_shared_from_this void _revokeWindowCallbacks(); void _HandleCommandlineArgs(const winrt::TerminalApp::WindowRequestedArgs& args); - void _HandleSessionRestore(const winrt::TerminalApp::WindowRequestedArgs& args); winrt::Microsoft::Terminal::Settings::Model::LaunchPosition _GetWindowLaunchPosition(); diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index ea6324c12c6..e17ece2fa9b 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -1253,11 +1253,9 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled) // - toggleVisibility: controls how we should behave when already in the foreground. // Return Value: // - -safe_void_coroutine IslandWindow::SummonWindow(winrt::TerminalApp::SummonWindowBehavior args) +void IslandWindow::SummonWindow(winrt::TerminalApp::SummonWindowBehavior args) { - // On the foreground thread: - co_await wil::resume_foreground(_rootGrid.Dispatcher()); - _summonWindowRoutineBody(args); + _summonWindowRoutineBody(std::move(args)); } // Method Description: diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h index 5c8c345ac63..472f4b3d56a 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.h +++ b/src/cascadia/WindowsTerminal/IslandWindow.h @@ -53,7 +53,7 @@ class IslandWindow : void FlashTaskbar(); void SetTaskbarProgress(const size_t state, const size_t progress); - safe_void_coroutine SummonWindow(winrt::TerminalApp::SummonWindowBehavior args); + void SummonWindow(winrt::TerminalApp::SummonWindowBehavior args); bool IsQuakeWindow() const noexcept; void IsQuakeWindow(bool isQuakeWindow) noexcept; diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp index 48be06e661b..ed20e32fbf6 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp +++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp @@ -199,6 +199,11 @@ HWND WindowEmperor::GetMainWindow() const noexcept return _window.get(); } +void WindowEmperor::ForcePersistence(bool force) noexcept +{ + _requiresPersistenceCleanupOnExit = force; +} + void WindowEmperor::HandleCommandlineArgs(int nCmdShow) { _app.Logic().ReloadSettings(); @@ -447,60 +452,6 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c { switch (message) { - case WM_SETTINGCHANGE: - { - // Currently, we only support checking when the OS theme changes. In - // that case, wParam is 0. Re-evaluate when we decide to reload env vars - // (GH#1125) - if (wParam == 0 && lParam != 0) - { - // ImmersiveColorSet seems to be the notification that the OS theme - // changed. If that happens, let the app know, so it can hot-reload - // themes, color schemes that might depend on the OS theme - if (wcscmp(reinterpret_cast(lParam), L"ImmersiveColorSet") == 0) - { - try - { - // GH#15732: Don't update the settings, unless the theme - // _actually_ changed. ImmersiveColorSet gets sent more often - // than just on a theme change. It notably gets sent when the PC - // is locked, or the UAC prompt opens. - const auto isCurrentlyDark = Theme::IsSystemInDarkTheme(); - if (isCurrentlyDark != _currentSystemThemeIsDark) - { - _currentSystemThemeIsDark = isCurrentlyDark; - _app.Logic().ReloadSettings(); - } - } - CATCH_LOG(); - } - } - return 0; - } - case WM_COPYDATA: - { - const auto cds = reinterpret_cast(lParam); - if (cds->dwData == TERMINAL_HANDOFF_MAGIC) - { - try - { - const auto handoff = deserializeHandoffPayload(static_cast(cds->lpData), static_cast(cds->lpData) + cds->cbData); - const winrt::hstring args{ handoff.args }; - const winrt::hstring env{ handoff.env }; - const winrt::hstring cwd{ handoff.cwd }; - const auto argv = buildArgsFromCommandline(args.c_str()); - const winrt::TerminalApp::CommandlineArgs eventArgs{ argv, cwd, gsl::narrow_cast(handoff.show), env }; - _createNewWindowThread(winrt::TerminalApp::WindowRequestedArgs{ eventArgs }); - } - CATCH_LOG(); - } - return 0; - } - case WM_HOTKEY: - { - _hotkeyPressed(static_cast(wParam)); - return 0; - } case WM_CLOSE_TERMINAL_WINDOW: { const auto host = reinterpret_cast(lParam); @@ -523,6 +474,14 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c } return 0; } + case WM_IDENTIFY_ALL_WINDOWS: + { + for (const auto& host : _windows) + { + host->Logic().IdentifyWindow(); + } + return 0; + } case WM_NOTIFY_FROM_NOTIFICATION_AREA: { switch (LOWORD(lParam)) @@ -648,6 +607,60 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c } return 0; } + case WM_SETTINGCHANGE: + { + // Currently, we only support checking when the OS theme changes. In + // that case, wParam is 0. Re-evaluate when we decide to reload env vars + // (GH#1125) + if (wParam == 0 && lParam != 0) + { + // ImmersiveColorSet seems to be the notification that the OS theme + // changed. If that happens, let the app know, so it can hot-reload + // themes, color schemes that might depend on the OS theme + if (wcscmp(reinterpret_cast(lParam), L"ImmersiveColorSet") == 0) + { + try + { + // GH#15732: Don't update the settings, unless the theme + // _actually_ changed. ImmersiveColorSet gets sent more often + // than just on a theme change. It notably gets sent when the PC + // is locked, or the UAC prompt opens. + const auto isCurrentlyDark = Theme::IsSystemInDarkTheme(); + if (isCurrentlyDark != _currentSystemThemeIsDark) + { + _currentSystemThemeIsDark = isCurrentlyDark; + _app.Logic().ReloadSettings(); + } + } + CATCH_LOG(); + } + } + return 0; + } + case WM_COPYDATA: + { + const auto cds = reinterpret_cast(lParam); + if (cds->dwData == TERMINAL_HANDOFF_MAGIC) + { + try + { + const auto handoff = deserializeHandoffPayload(static_cast(cds->lpData), static_cast(cds->lpData) + cds->cbData); + const winrt::hstring args{ handoff.args }; + const winrt::hstring env{ handoff.env }; + const winrt::hstring cwd{ handoff.cwd }; + const auto argv = buildArgsFromCommandline(args.c_str()); + const winrt::TerminalApp::CommandlineArgs eventArgs{ argv, cwd, gsl::narrow_cast(handoff.show), env }; + _createNewWindowThread(winrt::TerminalApp::WindowRequestedArgs{ eventArgs }); + } + CATCH_LOG(); + } + return 0; + } + case WM_HOTKEY: + { + _hotkeyPressed(static_cast(wParam)); + return 0; + } default: { // We'll want to receive this message when explorer.exe restarts diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.h b/src/cascadia/WindowsTerminal/WindowEmperor.h index 3a36edc2139..2d7c3456d02 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.h +++ b/src/cascadia/WindowsTerminal/WindowEmperor.h @@ -32,6 +32,7 @@ class WindowEmperor : public std::enable_shared_from_this WindowEmperor() noexcept; HWND GetMainWindow() const noexcept; + void ForcePersistence(bool force) noexcept; void HandleCommandlineArgs(int nCmdShow); private: