Use standard 1px window borders on NC Island Window (#3394)
We take the standard window frame except that we remove the top part (see `NonClientIslandWindow::_OnNcCalcSize`), then we put little 1 pixel wide top border back in the client area using `DwmExtendFrameIntoClientArea` and then we put the XAML island and the drag bar on top. Most of this PR is comments to explain how the code works and also removing complex code that was needed to handle the weird cases when the borders were custom. I've also refactored a little bit the `NonClientIslandWindow` class. * Fix DwmExtendFrameIntoClientArea values * Fix WM_NCHITTEST handling * Position the XAML island window correctly * Fix weird colors in drag bar and hide old title bar buttons * Fix the window's position when maximized * Add support for dark theme on the frame * DRY shared code between conhost and new terminal * Fix drag bar and remove dead code * Remove dead code and use cached DPI * Refactor code * Remove impossible TODO * Use system metrics instead of hardcoding resize border height * Use theme from app settings instead of system theme. Improve comments. Remove unused DWM frame on maximize. * Fix initial position DPI handling bug and apply review changes * Fix thick borders with DPI > 96 Closes #3064. Closes #1307. Closes #3136. Closes #1897. Closes #3222. Closes #1859.
This commit is contained in:
parent
6f36f8b23f
commit
5dfc021d8e
|
@ -335,7 +335,8 @@ namespace winrt::TerminalApp::implementation
|
|||
TerminalSettings settings = _settings->MakeSettings(std::nullopt);
|
||||
|
||||
// TODO MSFT:21150597 - If the global setting "Always show tab bar" is
|
||||
// set, then we'll need to add the height of the tab bar here.
|
||||
// set or if "Show tabs in title bar" is set, then we'll need to add
|
||||
// the height of the tab bar here.
|
||||
|
||||
return TermControl::GetProposedDimensions(settings, dpi);
|
||||
}
|
||||
|
@ -394,6 +395,17 @@ namespace winrt::TerminalApp::implementation
|
|||
return point;
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::ElementTheme App::GetRequestedTheme()
|
||||
{
|
||||
if (!_loadedInitialSettings)
|
||||
{
|
||||
// Load settings if we haven't already
|
||||
LoadSettings();
|
||||
}
|
||||
|
||||
return _settings->GlobalSettings().GetRequestedTheme();
|
||||
}
|
||||
|
||||
bool App::GetShowTabsInTitlebar()
|
||||
{
|
||||
if (!_loadedInitialSettings)
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
Windows::Foundation::Point GetLaunchDimensions(uint32_t dpi);
|
||||
winrt::Windows::Foundation::Point GetLaunchInitialPositions(int32_t defaultInitialX, int32_t defaultInitialY);
|
||||
winrt::Windows::UI::Xaml::ElementTheme GetRequestedTheme();
|
||||
LaunchMode GetLaunchMode();
|
||||
bool GetShowTabsInTitlebar();
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace TerminalApp
|
|||
|
||||
Windows.Foundation.Point GetLaunchDimensions(UInt32 dpi);
|
||||
Windows.Foundation.Point GetLaunchInitialPositions(Int32 defaultInitialX, Int32 defaultInitialY);
|
||||
Windows.UI.Xaml.ElementTheme GetRequestedTheme();
|
||||
LaunchMode GetLaunchMode();
|
||||
Boolean GetShowTabsInTitlebar();
|
||||
void TitlebarClicked();
|
||||
|
|
|
@ -22,7 +22,7 @@ AppHost::AppHost() noexcept :
|
|||
|
||||
if (_useNonClientArea)
|
||||
{
|
||||
_window = std::make_unique<NonClientIslandWindow>();
|
||||
_window = std::make_unique<NonClientIslandWindow>(_app.GetRequestedTheme());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -188,54 +188,25 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, winrt::Ter
|
|||
|
||||
auto initialSize = _app.GetLaunchDimensions(dpix);
|
||||
|
||||
const short _currentWidth = Utils::ClampToShortMax(
|
||||
const short islandWidth = Utils::ClampToShortMax(
|
||||
static_cast<long>(ceil(initialSize.X)), 1);
|
||||
const short _currentHeight = Utils::ClampToShortMax(
|
||||
const short islandHeight = Utils::ClampToShortMax(
|
||||
static_cast<long>(ceil(initialSize.Y)), 1);
|
||||
|
||||
// Create a RECT from our requested client size
|
||||
auto nonClient = Viewport::FromDimensions({ _currentWidth,
|
||||
_currentHeight })
|
||||
.ToRect();
|
||||
RECT islandFrame = {};
|
||||
bool succeeded = AdjustWindowRectExForDpi(&islandFrame, WS_OVERLAPPEDWINDOW, false, 0, dpix);
|
||||
// If we failed to get the correct window size for whatever reason, log
|
||||
// the error and go on. We'll use whatever the control proposed as the
|
||||
// size of our window, which will be at least close.
|
||||
LOG_LAST_ERROR_IF(!succeeded);
|
||||
|
||||
// Get the size of a window we'd need to host that client rect. This will
|
||||
// add the titlebar space.
|
||||
if (_useNonClientArea)
|
||||
{
|
||||
// If we're in NC tabs mode, do the math ourselves. Get the margins
|
||||
// we're using for the window - this will include the size of the
|
||||
// titlebar content.
|
||||
const auto pNcWindow = static_cast<NonClientIslandWindow*>(_window.get());
|
||||
const MARGINS margins = pNcWindow->GetFrameMargins();
|
||||
nonClient.left = 0;
|
||||
nonClient.top = 0;
|
||||
nonClient.right = margins.cxLeftWidth + nonClient.right + margins.cxRightWidth;
|
||||
nonClient.bottom = margins.cyTopHeight + nonClient.bottom + margins.cyBottomHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool succeeded = AdjustWindowRectExForDpi(&nonClient, WS_OVERLAPPEDWINDOW, false, 0, dpix);
|
||||
if (!succeeded)
|
||||
{
|
||||
// If we failed to get the correct window size for whatever reason, log
|
||||
// the error and go on. We'll use whatever the control proposed as the
|
||||
// size of our window, which will be at least close.
|
||||
LOG_LAST_ERROR();
|
||||
nonClient = Viewport::FromDimensions({ _currentWidth,
|
||||
_currentHeight })
|
||||
.ToRect();
|
||||
}
|
||||
|
||||
// For client island scenario, there is an invisible border of 8 pixels.
|
||||
// We need to remove this border to guarantee the left edge of the window
|
||||
// coincides with the screen
|
||||
const auto pCWindow = static_cast<IslandWindow*>(_window.get());
|
||||
const RECT frame = pCWindow->GetFrameBorderMargins(dpix);
|
||||
proposedRect.left += frame.left;
|
||||
islandFrame.top = -NonClientIslandWindow::topBorderVisibleHeight;
|
||||
}
|
||||
|
||||
adjustedHeight = nonClient.bottom - nonClient.top;
|
||||
adjustedWidth = nonClient.right - nonClient.left;
|
||||
adjustedWidth = -islandFrame.left + islandWidth + islandFrame.right;
|
||||
adjustedHeight = -islandFrame.top + islandHeight + islandFrame.bottom;
|
||||
}
|
||||
|
||||
const COORD origin{ gsl::narrow<short>(proposedRect.left),
|
||||
|
@ -294,5 +265,5 @@ void AppHost::_UpdateTitleBarContent(const winrt::Windows::Foundation::IInspecta
|
|||
// - <none>
|
||||
void AppHost::_UpdateTheme(const winrt::TerminalApp::App&, const winrt::Windows::UI::Xaml::ElementTheme& arg)
|
||||
{
|
||||
_window->UpdateTheme(arg);
|
||||
_window->OnApplicationThemeChanged(arg);
|
||||
}
|
||||
|
|
|
@ -34,10 +34,8 @@ public:
|
|||
WINRT_ASSERT(that);
|
||||
WINRT_ASSERT(!that->_window);
|
||||
that->_window = wil::unique_hwnd(window);
|
||||
SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(that));
|
||||
|
||||
EnableNonClientDpiScaling(window);
|
||||
that->_currentDpi = GetDpiForWindow(window);
|
||||
return that->_OnNcCreate(wparam, lparam);
|
||||
}
|
||||
else if (T* that = GetThisFromHandle(window))
|
||||
{
|
||||
|
@ -245,6 +243,20 @@ protected:
|
|||
std::wstring _title = L"";
|
||||
|
||||
bool _minimized = false;
|
||||
|
||||
// Method Description:
|
||||
// - This method is called when the window receives the WM_NCCREATE message.
|
||||
// Return Value:
|
||||
// - The value returned from the window proc.
|
||||
virtual [[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
SetWindowLongPtr(_window.get(), GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||
|
||||
EnableNonClientDpiScaling(_window.get());
|
||||
_currentDpi = GetDpiForWindow(_window.get());
|
||||
|
||||
return DefWindowProc(_window.get(), WM_NCCREATE, wParam, lParam);
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -243,15 +243,6 @@ IRawElementProviderSimple* IslandWindow::_GetUiaProvider()
|
|||
return _pUiaProvider;
|
||||
}
|
||||
|
||||
RECT IslandWindow::GetFrameBorderMargins(unsigned int currentDpi)
|
||||
{
|
||||
const auto windowStyle = GetWindowStyle(_window.get());
|
||||
const auto targetStyle = windowStyle & ~WS_DLGFRAME;
|
||||
RECT frame{};
|
||||
AdjustWindowRectExForDpi(&frame, targetStyle, false, GetWindowExStyle(_window.get()), currentDpi);
|
||||
return frame;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the window has been resized (or maximized)
|
||||
// Arguments:
|
||||
|
@ -300,7 +291,7 @@ void IslandWindow::OnAppInitialized()
|
|||
// - arg: the ElementTheme to use as the new theme for the UI
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void IslandWindow::UpdateTheme(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme)
|
||||
void IslandWindow::OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme)
|
||||
{
|
||||
_rootGrid.RequestedTheme(requestedTheme);
|
||||
// Invalidate the window rect, so that we'll repaint any elements we're
|
||||
|
|
|
@ -23,19 +23,17 @@ public:
|
|||
|
||||
[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
|
||||
IRawElementProviderSimple* _GetUiaProvider();
|
||||
RECT GetFrameBorderMargins(unsigned int currentDpi);
|
||||
void OnResize(const UINT width, const UINT height) override;
|
||||
void OnMinimize() override;
|
||||
void OnRestore() override;
|
||||
virtual void OnAppInitialized();
|
||||
virtual void SetContent(winrt::Windows::UI::Xaml::UIElement content);
|
||||
virtual void OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
|
||||
|
||||
virtual void Initialize();
|
||||
|
||||
void SetCreateCallback(std::function<void(const HWND, const RECT, winrt::TerminalApp::LaunchMode& launchMode)> pfn) noexcept;
|
||||
|
||||
void UpdateTheme(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
|
||||
|
||||
#pragma region IUiaWindow
|
||||
void ChangeViewport(const SMALL_RECT /*NewWindow*/)
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,48 +21,58 @@ Author(s):
|
|||
#include "IslandWindow.h"
|
||||
#include "../../types/inc/Viewport.hpp"
|
||||
#include <dwmapi.h>
|
||||
#include <wil\resource.h>
|
||||
#include <wil/resource.h>
|
||||
|
||||
class NonClientIslandWindow : public IslandWindow
|
||||
{
|
||||
public:
|
||||
NonClientIslandWindow() noexcept;
|
||||
// this is the same for all DPIs
|
||||
static constexpr const int topBorderVisibleHeight = 1;
|
||||
|
||||
NonClientIslandWindow(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme) noexcept;
|
||||
virtual ~NonClientIslandWindow() override;
|
||||
|
||||
virtual void OnSize(const UINT width, const UINT height) override;
|
||||
|
||||
[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
|
||||
|
||||
MARGINS GetFrameMargins() const noexcept;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
void OnAppInitialized() override;
|
||||
void SetContent(winrt::Windows::UI::Xaml::UIElement content) override;
|
||||
void SetTitlebarContent(winrt::Windows::UI::Xaml::UIElement content);
|
||||
void OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme) override;
|
||||
|
||||
private:
|
||||
std::optional<COORD> _oldIslandPos;
|
||||
|
||||
winrt::TerminalApp::TitlebarControl _titlebar{ nullptr };
|
||||
winrt::Windows::UI::Xaml::UIElement _clientContent{ nullptr };
|
||||
|
||||
wil::unique_hbrush _backgroundBrush;
|
||||
COLORREF _backgroundBrushColor;
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::Border _dragBar{ nullptr };
|
||||
wil::unique_hrgn _dragBarRegion;
|
||||
|
||||
MARGINS _maximizedMargins = { 0 };
|
||||
winrt::Windows::UI::Xaml::ElementTheme _theme;
|
||||
|
||||
bool _isMaximized;
|
||||
winrt::Windows::UI::Xaml::Controls::Border _dragBar{ nullptr };
|
||||
|
||||
RECT GetDragAreaRect() const noexcept;
|
||||
int _GetResizeHandleHeight() const noexcept;
|
||||
RECT _GetDragAreaRect() const noexcept;
|
||||
int _GetTopBorderHeight() const noexcept;
|
||||
|
||||
[[nodiscard]] LRESULT HitTestNCA(POINT ptMouse) const noexcept;
|
||||
[[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept override;
|
||||
[[nodiscard]] LRESULT _OnNcCalcSize(const WPARAM wParam, const LPARAM lParam) noexcept;
|
||||
[[nodiscard]] LRESULT _OnNcHitTest(POINT ptMouse) const noexcept;
|
||||
[[nodiscard]] LRESULT _OnPaint() noexcept;
|
||||
void _OnMaximizeChange() noexcept;
|
||||
void _OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs eventArgs) const;
|
||||
|
||||
[[nodiscard]] HRESULT _UpdateFrameMargins() const noexcept;
|
||||
|
||||
void _HandleActivateWindow();
|
||||
bool _HandleWindowPosChanging(WINDOWPOS* const windowPos);
|
||||
void _UpdateDragRegion();
|
||||
|
||||
void OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs eventArgs);
|
||||
|
||||
RECT GetMaxWindowRectInPixels(const RECT* const prcSuggested, _Out_opt_ UINT* pDpiSuggested);
|
||||
void _UpdateMaximizedState();
|
||||
void _UpdateIslandPosition(const UINT windowWidth, const UINT windowHeight);
|
||||
void _UpdateIslandRegion() const;
|
||||
void _UpdateFrameTheme() const;
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
<AdditionalIncludeDirectories>"$(OpenConsoleDir)src\cascadia\TerminalCore\lib\Generated Files";%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>gdi32.lib;dwmapi.lib;Shcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>gdi32.lib;dwmapi.lib;Shcore.lib;UxTheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<PropertyGroup>
|
||||
|
|
19
src/types/ThemeUtils.cpp
Normal file
19
src/types/ThemeUtils.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include "precomp.h"
|
||||
#include "inc/ThemeUtils.h"
|
||||
|
||||
namespace Microsoft::Console::ThemeUtils
|
||||
{
|
||||
// Routine Description:
|
||||
// - Attempts to enable/disable the dark mode on the frame of a window.
|
||||
// Arguments:
|
||||
// - hwnd: handle to the window to change
|
||||
// - enabled: whether to enable or not the dark mode on the window's frame
|
||||
// Return Value:
|
||||
// - S_OK or suitable HRESULT from DWM engines.
|
||||
[[nodiscard]] HRESULT SetWindowFrameDarkMode(HWND /* hwnd */, bool /* enabled */) noexcept
|
||||
{
|
||||
// TODO:GH #3425 implement the new DWM API and change
|
||||
// src/interactivity/win32/windowtheme.cpp to use it.
|
||||
return S_OK;
|
||||
}
|
||||
}
|
8
src/types/inc/ThemeUtils.h
Normal file
8
src/types/inc/ThemeUtils.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Microsoft::Console::ThemeUtils
|
||||
{
|
||||
[[nodiscard]] HRESULT SetWindowFrameDarkMode(HWND hwnd, bool enabled) noexcept;
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
<ClCompile Include="..\MenuEvent.cpp" />
|
||||
<ClCompile Include="..\ModifierKeyState.cpp" />
|
||||
<ClCompile Include="..\ScreenInfoUiaProviderBase.cpp" />
|
||||
<ClCompile Include="..\ThemeUtils.cpp" />
|
||||
<ClCompile Include="..\UiaTextRangeBase.cpp" />
|
||||
<ClCompile Include="..\Utf16Parser.cpp" />
|
||||
<ClCompile Include="..\UTF8OutPipeReader.cpp" />
|
||||
|
@ -30,7 +31,9 @@
|
|||
<ClInclude Include="..\inc\convert.hpp" />
|
||||
<ClInclude Include="..\inc\GlyphWidth.hpp" />
|
||||
<ClInclude Include="..\inc\IInputEvent.hpp" />
|
||||
<ClInclude Include="..\inc\ThemeUtils.h" />
|
||||
<ClInclude Include="..\inc\UTF8OutPipeReader.hpp" />
|
||||
<ClInclude Include="..\inc\utils.hpp" />
|
||||
<ClInclude Include="..\inc\Viewport.hpp" />
|
||||
<ClInclude Include="..\inc\Utf16Parser.hpp" />
|
||||
<ClInclude Include="..\IUiaData.h" />
|
||||
|
@ -38,7 +41,6 @@
|
|||
<ClInclude Include="..\precomp.h" />
|
||||
<ClInclude Include="..\ScreenInfoUiaProviderBase.h" />
|
||||
<ClInclude Include="..\UiaTextRangeBase.hpp" />
|
||||
<ClInclude Include="..\utils.hpp" />
|
||||
<ClInclude Include="..\WindowUiaProviderBase.hpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
|
@ -51,4 +53,4 @@
|
|||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||
<Import Project="$(SolutionDir)src\common.build.lib.props" />
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
</Project>
|
||||
</Project>
|
|
@ -60,9 +60,6 @@
|
|||
<ClCompile Include="..\UTF8OutPipeReader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\WindowUiaProvider.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ScreenInfoUiaProviderBase.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -72,6 +69,9 @@
|
|||
<ClCompile Include="..\WindowUiaProviderBase.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\ThemeUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\inc\IInputEvent.hpp">
|
||||
|
@ -95,21 +95,12 @@
|
|||
<ClInclude Include="..\inc\GlyphWidth.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\utils.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\inc\UTF8OutPipeReader.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\WindowUiaProvider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\IConsoleWindow.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ScreenInfoUiaProvider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\UiaTextRangeBase.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -161,8 +152,14 @@
|
|||
<ClInclude Include="..\IBaseData.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\inc\utils.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\inc\ThemeUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -41,6 +41,7 @@ SOURCES= \
|
|||
..\convert.cpp \
|
||||
..\Utf16Parser.cpp \
|
||||
..\utils.cpp \
|
||||
..\ThemeUtils.cpp \
|
||||
|
||||
INCLUDES= \
|
||||
$(INCLUDES); \
|
||||
|
|
Loading…
Reference in a new issue