Skip to content

Commit 8ffff8e

Browse files
authored
Enable dragging with the entire titlebar (#1948)
* This definitely works for getting shadow, pointy corners back Don't do anything in NCPAINT. If you do, you have to do everything. But the whole point of DwmExtendFrameIntoClientArea is to let you paint the NC area in your normal paint. So just do that dummy. * This doesn't transition across monitors. * This has a window style change I think is wrong. * I'm not sure the margins change is important. * The window style was _not_ important * Still getting a black xaml islands area (the HRGN) when we switch to high DPI * I don't know if this affects anything. * heyo this works. I'm not entirely sure why. But if we only update the titlebar drag region when that actually changes, it's a _lot_ smoother. I'm not super happy with the duplicated work in _UpdateDragRegion and OnSize, but checking this in in case I can't figure that out. * Add more comments and cleanup * Try making the button RightCustomContent * * Make the MinMaxClose's drag bar's min size the same as a caption button * Make the new tab button transparent, to see how that looks * Make sure the TabView doesn't push the MMC off the window * Create a TitlebarControl * The TitlebarControl is owned by the NCIW. It consists of a Content, DragBar, and MMCControl. * The App instatntiates a TabRowControl at runtime, and either places it in the UI (for tabs below titlebar) or hangs on to it, and gives it to the NCIW when the NCIW creates its UI. * When the NCIW is created, it creates a grid with two rows, one for the titlebar and one for the app content. * The MMCControl is only responsible for Min Max Close now, and is closer to the window implementation. * The drag bar takes up all the space from the right of the TabRow to the left of the MMC * Things that **DON'T** work: - When you add tabs, the drag bar doesn't update it's size. It only updates OnSize - The MMCControl's Min and Max buttons don't seem to work anymore. - They should probably just expose their OnMinimizeClick and OnMaximizeClick events for the Titlebar to handle minimizing and maximizing. - The drag bar is Magenta (#ff00ff) currently. - I'm not _sure_ we need a TabRowControl. We could probably get away with removing it from the UI tree, I was just being dumb before. * Fix the MMC buttons not working I forgot to plumb the window handle through * Make the titlebar less magenta * Resize the drag region as we add/remove tabs * Move the actual MMC handling to the TitlebarControl * Some PR nits, fix the titlebar painting on maximize * Put the TabRow in our XAML * Remove dead code in preparation for review * Horrifyingly try Gdi Plus as a solution, that is _wrong_ though * Revert "Horrifyingly try Gdi Plus as a solution, that is _wrong_ though" This reverts commit e038b5d. * This fixes the bottom border but breaks the titlebar painting * Fix the NC bottom border * A bunch of the more minor PR nits * Add a MinimizeClick event to the MMCControl This works for Minimize. This is what I wanted to do originally. * Add events for _all_ of the buttons, not just the Minimize btn * Change hoe setting the titlebar content works Now the app triggers a callcack on the host to set the content, instead of the host querying the app. * Move the tab row to the bottom of it's available space * Fix the theme reloading * PR nits from @miniksa * Update src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Co-Authored-By: Michael Niksa <miniksa@microsoft.com> * This needed to be fixed, was missed in other PR nits * runformat wait _what_ * Does this fix the CI build?
1 parent 57ad2d5 commit 8ffff8e

27 files changed

+608
-188
lines changed

src/cascadia/TerminalApp/App.cpp

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -61,26 +61,13 @@ namespace winrt::TerminalApp::implementation
6161
// - <none>
6262
// Return Value:
6363
// - <none>
64-
void App::Create(uint64_t hWnd)
64+
void App::Create()
6565
{
6666
// Assert that we've already loaded our settings. We have to do
6767
// this as a MTA, before the app is Create()'d
6868
WINRT_ASSERT(_loadedInitialSettings);
6969
TraceLoggingRegister(g_hTerminalAppProvider);
70-
_Create(hWnd);
71-
}
72-
73-
App::~App()
74-
{
75-
TraceLoggingUnregister(g_hTerminalAppProvider);
76-
}
7770

78-
// Method Description:
79-
// - Create all of the initial UI elements of the Terminal app.
80-
// * Initializes the first terminal control, using the default profile,
81-
// and adds it to our list of tabs.
82-
void App::_Create(uint64_t parentHwnd)
83-
{
8471
/* !!! TODO
8572
This is not the correct way to host a XAML page. This exists today because we valued
8673
getting a .xaml over tearing out all of the terminal logic and splitting it across App
@@ -92,15 +79,21 @@ namespace winrt::TerminalApp::implementation
9279
_root = terminalPage.as<winrt::Windows::UI::Xaml::Controls::Control>();
9380
_tabContent = terminalPage->TabContent();
9481
_tabRow = terminalPage->TabRow();
95-
_tabView = terminalPage->TabView();
96-
_newTabButton = terminalPage->NewTabButton();
97-
98-
_minMaxCloseControl = terminalPage->MinMaxCloseControl();
99-
_minMaxCloseControl.ParentWindowHandle(parentHwnd);
82+
_tabView = _tabRow.TabView();
83+
_newTabButton = _tabRow.NewTabButton();
10084

101-
if (!_settings->GlobalSettings().GetShowTabsInTitlebar())
85+
if (_settings->GlobalSettings().GetShowTabsInTitlebar())
10286
{
103-
_minMaxCloseControl.Visibility(Visibility::Collapsed);
87+
// Remove the TabView from the page. We'll hang on to it, we need to
88+
// put it in the titlebar.
89+
uint32_t index = 0;
90+
if (terminalPage->Root().Children().IndexOf(_tabRow, index))
91+
{
92+
terminalPage->Root().Children().RemoveAt(index);
93+
}
94+
95+
// Inform the host that our titlebar content has changed.
96+
_setTitleBarContentHandlers(*this, _tabRow);
10497
}
10598

10699
// Event Bindings (Early)
@@ -118,6 +111,14 @@ namespace winrt::TerminalApp::implementation
118111
_tabContent.SizeChanged({ this, &App::_OnContentSizeChanged });
119112
}
120113

114+
App::~App()
115+
{
116+
if (g_hTerminalAppProvider)
117+
{
118+
TraceLoggingUnregister(g_hTerminalAppProvider);
119+
}
120+
}
121+
121122
// Method Description:
122123
// - Show a ContentDialog with a single button to dismiss. Uses the
123124
// FrameworkElements provided as the title and content of this dialog, and
@@ -456,16 +457,6 @@ namespace winrt::TerminalApp::implementation
456457
winrt::Windows::System::Launcher::LaunchUriAsync({ feedbackUriValue });
457458
}
458459

459-
Windows::UI::Xaml::Controls::Border App::GetDragBar() noexcept
460-
{
461-
if (_minMaxCloseControl)
462-
{
463-
return _minMaxCloseControl.DragBar();
464-
}
465-
466-
return nullptr;
467-
}
468-
469460
// Method Description:
470461
// - Called when the about button is clicked. See _ShowAboutDialog for more info.
471462
// Arguments:
@@ -742,13 +733,16 @@ namespace winrt::TerminalApp::implementation
742733
}
743734

744735
// Method Description:
745-
// - Update the current theme of the application. This will manually update
746-
// all of the elements in our UI to match the given theme.
736+
// - Update the current theme of the application. This will trigger our
737+
// RequestedThemeChanged event, to have our host change the theme of the
738+
// root of the application.
747739
// Arguments:
748740
// - newTheme: The ElementTheme to apply to our elements.
749741
void App::_ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme)
750742
{
751743
_root.RequestedTheme(newTheme);
744+
// Propagate the event to the host layer, so it can update its own UI
745+
_requestedThemeChangedHandlers(*this, newTheme);
752746
}
753747

754748
UIElement App::GetRoot() noexcept
@@ -917,7 +911,11 @@ namespace winrt::TerminalApp::implementation
917911
// Initialize the new tab
918912

919913
// Create a Conhost connection based on the values in our settings object.
920-
TerminalConnection::ITerminalConnection connection = TerminalConnection::ConhostConnection(settings.Commandline(), settings.StartingDirectory(), 30, 80, winrt::guid());
914+
auto connection = TerminalConnection::ConhostConnection(settings.Commandline(),
915+
settings.StartingDirectory(),
916+
30,
917+
80,
918+
winrt::guid());
921919

922920
TermControl term{ settings, connection };
923921

@@ -1318,7 +1316,11 @@ namespace winrt::TerminalApp::implementation
13181316
const auto controlSettings = _settings->MakeSettings(realGuid);
13191317

13201318
// Create a Conhost connection based on the values in our settings object.
1321-
TerminalConnection::ITerminalConnection controlConnection = TerminalConnection::ConhostConnection(controlSettings.Commandline(), controlSettings.StartingDirectory(), 30, 80, winrt::guid());
1319+
auto controlConnection = TerminalConnection::ConhostConnection(controlSettings.Commandline(),
1320+
controlSettings.StartingDirectory(),
1321+
30,
1322+
80,
1323+
winrt::guid());
13221324

13231325
TermControl newControl{ controlSettings, controlConnection };
13241326

@@ -1419,4 +1421,6 @@ namespace winrt::TerminalApp::implementation
14191421
// These macros will define them both for you.
14201422
DEFINE_EVENT(App, TitleChanged, _titleChangeHandlers, TerminalControl::TitleChangedEventArgs);
14211423
DEFINE_EVENT(App, LastTabClosed, _lastTabClosedHandlers, winrt::TerminalApp::LastTabClosedEventArgs);
1424+
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(App, SetTitleBarContent, _setTitleBarContentHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::UIElement);
1425+
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(App, RequestedThemeChanged, _requestedThemeChangedHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::ElementTheme);
14221426
}

src/cascadia/TerminalApp/App.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ namespace winrt::TerminalApp::implementation
2727

2828
Windows::UI::Xaml::UIElement GetRoot() noexcept;
2929

30-
// Gets the current dragglable area in the non client region of the top level window
31-
Windows::UI::Xaml::Controls::Border GetDragBar() noexcept;
32-
33-
void Create(uint64_t hParentWnd);
30+
void Create();
3431
void LoadSettings();
3532

3633
Windows::Foundation::Point GetLaunchDimensions(uint32_t dpi);
@@ -43,6 +40,8 @@ namespace winrt::TerminalApp::implementation
4340
// -------------------------------- WinRT Events ---------------------------------
4441
DECLARE_EVENT(TitleChanged, _titleChangeHandlers, winrt::Microsoft::Terminal::TerminalControl::TitleChangedEventArgs);
4542
DECLARE_EVENT(LastTabClosed, _lastTabClosedHandlers, winrt::TerminalApp::LastTabClosedEventArgs);
43+
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(SetTitleBarContent, _setTitleBarContentHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::UIElement);
44+
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(RequestedThemeChanged, _requestedThemeChangedHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::ElementTheme);
4645

4746
private:
4847
// If you add controls here, but forget to null them either here or in
@@ -53,10 +52,9 @@ namespace winrt::TerminalApp::implementation
5352
// (which is a root when the tabs are in the titlebar.)
5453
Windows::UI::Xaml::Controls::Control _root{ nullptr };
5554
Microsoft::UI::Xaml::Controls::TabView _tabView{ nullptr };
56-
Windows::UI::Xaml::Controls::Grid _tabRow{ nullptr };
55+
TerminalApp::TabRowControl _tabRow{ nullptr };
5756
Windows::UI::Xaml::Controls::Grid _tabContent{ nullptr };
5857
Windows::UI::Xaml::Controls::SplitButton _newTabButton{ nullptr };
59-
winrt::TerminalApp::MinMaxCloseControl _minMaxCloseControl{ nullptr };
6058

6159
std::vector<std::shared_ptr<Tab>> _tabs;
6260

@@ -71,7 +69,6 @@ namespace winrt::TerminalApp::implementation
7169

7270
std::atomic<bool> _settingsReloadQueued{ false };
7371

74-
void _Create(uint64_t parentHWnd);
7572
void _CreateNewTabFlyout();
7673

7774
fire_and_forget _ShowDialog(const winrt::Windows::Foundation::IInspectable& titleElement,

src/cascadia/TerminalApp/App.idl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
namespace TerminalApp
55
{
66
delegate void LastTabClosedEventArgs();
7-
[default_interface]
8-
runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
7+
[default_interface] runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
98
{
109
App();
1110

@@ -16,18 +15,19 @@ namespace TerminalApp
1615
// then it might look like TermApp just failed to activate, which will
1716
// cause you to chase down the rabbit hole of "why is TermApp not
1817
// registered?" when it definitely is.
19-
void Create(UInt64 hParentWnd);
18+
void Create();
2019

2120
void LoadSettings();
2221

2322
Windows.UI.Xaml.UIElement GetRoot();
24-
Windows.UI.Xaml.Controls.Border GetDragBar{ get; };
2523

2624
Windows.Foundation.Point GetLaunchDimensions(UInt32 dpi);
2725
Boolean GetShowTabsInTitlebar();
2826

2927
event Microsoft.Terminal.TerminalControl.TitleChangedEventArgs TitleChanged;
3028
event LastTabClosedEventArgs LastTabClosed;
29+
event Windows.Foundation.TypedEventHandler<App, Windows.UI.Xaml.UIElement> SetTitleBarContent;
30+
event Windows.Foundation.TypedEventHandler<App, Windows.UI.Xaml.ElementTheme> RequestedThemeChanged;
3131

3232
String GetTitle();
3333
}
Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
//
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
//
24
// MinMaxCloseControl.xaml.cpp
35
// Implementation of the MinMaxCloseControl class
46
//
@@ -8,6 +10,7 @@
810
#include "MinMaxCloseControl.h"
911

1012
#include "MinMaxCloseControl.g.cpp"
13+
using namespace winrt::Windows::UI::Xaml;
1114

1215
namespace winrt::TerminalApp::implementation
1316
{
@@ -16,59 +19,37 @@ namespace winrt::TerminalApp::implementation
1619
InitializeComponent();
1720
}
1821

19-
uint64_t MinMaxCloseControl::ParentWindowHandle() const
22+
void MinMaxCloseControl::Maximize()
2023
{
21-
return reinterpret_cast<uint64_t>(_window);
24+
VisualStateManager::GoToState(MaximizeButton(), L"WindowStateMaximized", false);
2225
}
2326

24-
void MinMaxCloseControl::ParentWindowHandle(uint64_t handle)
27+
void MinMaxCloseControl::RestoreDown()
2528
{
26-
_window = reinterpret_cast<HWND>(handle);
29+
VisualStateManager::GoToState(MaximizeButton(), L"WindowStateNormal", false);
2730
}
2831

29-
void MinMaxCloseControl::_OnMaximize(byte flag)
32+
// These event handlers simply forward each buttons click events up to the
33+
// events we've exposed.
34+
void MinMaxCloseControl::_MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender,
35+
RoutedEventArgs const& e)
3036
{
31-
if (_window)
32-
{
33-
POINT point1 = {};
34-
::GetCursorPos(&point1);
35-
const LPARAM lParam = MAKELPARAM(point1.x, point1.y);
36-
WINDOWPLACEMENT placement = { sizeof(placement) };
37-
::GetWindowPlacement(_window, &placement);
38-
if (placement.showCmd == SW_SHOWNORMAL)
39-
{
40-
winrt::Windows::UI::Xaml::VisualStateManager::GoToState(this->Maximize(), L"WindowStateMaximized", false);
41-
::PostMessage(_window, WM_SYSCOMMAND, SC_MAXIMIZE | flag, lParam);
42-
}
43-
else if (placement.showCmd == SW_SHOWMAXIMIZED)
44-
{
45-
winrt::Windows::UI::Xaml::VisualStateManager::GoToState(this->Maximize(), L"WindowStateNormal", false);
46-
::PostMessage(_window, WM_SYSCOMMAND, SC_RESTORE | flag, lParam);
47-
}
48-
}
37+
_minimizeClickHandlers(*this, e);
4938
}
5039

51-
void MinMaxCloseControl::Maximize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
40+
void MinMaxCloseControl::_MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender,
41+
RoutedEventArgs const& e)
5242
{
53-
_OnMaximize(HTMAXBUTTON);
43+
_maximizeClickHandlers(*this, e);
5444
}
55-
56-
void MinMaxCloseControl::DragBar_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e)
45+
void MinMaxCloseControl::_CloseClick(winrt::Windows::Foundation::IInspectable const& sender,
46+
RoutedEventArgs const& e)
5747
{
58-
_OnMaximize(HTCAPTION);
48+
_closeClickHandlers(*this, e);
5949
}
6050

61-
void MinMaxCloseControl::Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
62-
{
63-
if (_window)
64-
{
65-
::PostMessage(_window, WM_SYSCOMMAND, SC_MINIMIZE | HTMINBUTTON, 0);
66-
}
67-
}
68-
69-
void MinMaxCloseControl::Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
70-
{
71-
::PostQuitMessage(0);
72-
}
51+
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(MinMaxCloseControl, MinimizeClick, _minimizeClickHandlers, TerminalApp::MinMaxCloseControl, RoutedEventArgs);
52+
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(MinMaxCloseControl, MaximizeClick, _maximizeClickHandlers, TerminalApp::MinMaxCloseControl, RoutedEventArgs);
53+
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(MinMaxCloseControl, CloseClick, _closeClickHandlers, TerminalApp::MinMaxCloseControl, RoutedEventArgs);
7354

7455
}

src/cascadia/TerminalApp/MinMaxCloseControl.h

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
//
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
//
24
// Declaration of the MainUserControl class.
35
//
46

@@ -8,24 +10,27 @@
810
#include "winrt/Windows.UI.Xaml.Markup.h"
911
#include "winrt/Windows.UI.Xaml.Interop.h"
1012
#include "MinMaxCloseControl.g.h"
13+
#include "../../cascadia/inc/cppwinrt_utils.h"
1114

1215
namespace winrt::TerminalApp::implementation
1316
{
1417
struct MinMaxCloseControl : MinMaxCloseControlT<MinMaxCloseControl>
1518
{
1619
MinMaxCloseControl();
1720

18-
void Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
19-
void Maximize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
20-
void Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
21-
void DragBar_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e);
21+
void Maximize();
22+
void RestoreDown();
2223

23-
uint64_t ParentWindowHandle() const;
24-
void ParentWindowHandle(uint64_t handle);
24+
void _MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender,
25+
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
26+
void _MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender,
27+
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
28+
void _CloseClick(winrt::Windows::Foundation::IInspectable const& sender,
29+
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
2530

26-
private:
27-
void _OnMaximize(byte flag);
28-
HWND _window{ nullptr }; // non-owning handle; should not be freed in the dtor.
31+
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(MinimizeClick, _minimizeClickHandlers, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
32+
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(MaximizeClick, _maximizeClickHandlers, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
33+
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(CloseClick, _closeClickHandlers, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
2934
};
3035
}
3136

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
namespace TerminalApp
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
namespace TerminalApp
25
{
3-
[default_interface]
4-
runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel
6+
[default_interface] runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel
57
{
68
MinMaxCloseControl();
79

8-
Windows.UI.Xaml.Controls.Grid Content{ get; };
9-
Windows.UI.Xaml.Controls.Border DragBar{ get; };
10+
void Maximize();
11+
void RestoreDown();
1012

11-
UInt64 ParentWindowHandle;
13+
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MinimizeClick;
14+
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MaximizeClick;
15+
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> CloseClick;
1216
}
1317
}

0 commit comments

Comments
 (0)