From 6a5a4f78bf72facc144fa9f9bfecfc5c2db2477a Mon Sep 17 00:00:00 2001 From: Javier De la Garza Sanchez Date: Mon, 5 Oct 2020 14:37:32 -0700 Subject: [PATCH 1/9] Added autofill option for WPF container and exposed max columns and rows that the container can host. --- .../PublicTerminalCore/HwndTerminal.cpp | 16 +++- .../PublicTerminalCore/HwndTerminal.hpp | 4 +- .../WpfTerminalControl/NativeMethods.cs | 3 + .../WpfTerminalControl/TerminalContainer.cs | 85 ++++++++++++++----- .../TerminalControl.xaml.cs | 24 +++++- 5 files changed, 106 insertions(+), 26 deletions(-) diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp index 6280ae37e72..0cf9e6384ce 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp @@ -433,7 +433,7 @@ void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data) publicTerminal->SendOutput(data); } -HRESULT _stdcall TerminalTriggerResize(void* terminal, double width, double height, _Out_ COORD* dimensions) +HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ double width, _In_ double height, _Out_ COORD* dimensions) { const auto publicTerminal = static_cast(terminal); @@ -450,6 +450,20 @@ HRESULT _stdcall TerminalTriggerResize(void* terminal, double width, double heig return publicTerminal->Refresh(windowSize, dimensions); } +HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions) +{ + const auto publicTerminal = static_cast(terminal); + + const auto viewInPixels = Viewport::FromDimensions({ 0, 0 }, { width, height }); + const auto viewInCharacters = publicTerminal->_renderEngine->GetViewportInCharacters(viewInPixels); + + dimensions->X = viewInCharacters.Width(); + dimensions->Y = viewInCharacters.Height(); + + return S_OK; +} + + void _stdcall TerminalDpiChanged(void* terminal, int newDpi) { const auto publicTerminal = static_cast(terminal); diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.hpp b/src/cascadia/PublicTerminalCore/HwndTerminal.hpp index 09f7819f312..638673bb40e 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.hpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.hpp @@ -27,8 +27,9 @@ extern "C" { __declspec(dllexport) HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal); __declspec(dllexport) void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data); __declspec(dllexport) void _stdcall TerminalRegisterScrollCallback(void* terminal, void __stdcall callback(int, int, int)); -__declspec(dllexport) HRESULT _stdcall TerminalTriggerResize(void* terminal, double width, double height, _Out_ COORD* dimensions); +__declspec(dllexport) HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ double width, _In_ double height, _Out_ COORD* dimensions); __declspec(dllexport) HRESULT _stdcall TerminalResize(void* terminal, COORD dimensions); +__declspec(dllexport) HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions); __declspec(dllexport) void _stdcall TerminalDpiChanged(void* terminal, int newDpi); __declspec(dllexport) void _stdcall TerminalUserScroll(void* terminal, int viewTop); __declspec(dllexport) void _stdcall TerminalClearSelection(void* terminal); @@ -91,6 +92,7 @@ struct HwndTerminal : ::Microsoft::Console::Types::IControlAccessibilityInfo friend HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal); friend HRESULT _stdcall TerminalResize(void* terminal, COORD dimensions); + friend HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions); friend void _stdcall TerminalDpiChanged(void* terminal, int newDpi); friend void _stdcall TerminalUserScroll(void* terminal, int viewTop); friend void _stdcall TerminalClearSelection(void* terminal); diff --git a/src/cascadia/WpfTerminalControl/NativeMethods.cs b/src/cascadia/WpfTerminalControl/NativeMethods.cs index 0e40d646652..fcd5217bad0 100644 --- a/src/cascadia/WpfTerminalControl/NativeMethods.cs +++ b/src/cascadia/WpfTerminalControl/NativeMethods.cs @@ -192,6 +192,9 @@ public enum SetWindowPosFlags : uint [DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] public static extern uint TerminalResize(IntPtr terminal, COORD dimensions); + [DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] + public static extern uint TerminalCalculateResize(IntPtr terminal, short width, short height, out COORD dimensions); + [DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] public static extern void TerminalDpiChanged(IntPtr terminal, int newDpi); diff --git a/src/cascadia/WpfTerminalControl/TerminalContainer.cs b/src/cascadia/WpfTerminalControl/TerminalContainer.cs index 2f5c6839455..25b6746dab4 100644 --- a/src/cascadia/WpfTerminalControl/TerminalContainer.cs +++ b/src/cascadia/WpfTerminalControl/TerminalContainer.cs @@ -20,20 +20,6 @@ namespace Microsoft.Terminal.Wpf /// public class TerminalContainer : HwndHost { - private static void UnpackKeyMessage(IntPtr wParam, IntPtr lParam, out ushort vkey, out ushort scanCode, out ushort flags) - { - ulong scanCodeAndFlags = (((ulong)lParam) & 0xFFFF0000) >> 16; - scanCode = (ushort)(scanCodeAndFlags & 0x00FFu); - flags = (ushort)(scanCodeAndFlags & 0xFF00u); - vkey = (ushort)wParam; - } - - private static void UnpackCharMessage(IntPtr wParam, IntPtr lParam, out char character, out ushort scanCode, out ushort flags) - { - UnpackKeyMessage(wParam, lParam, out ushort vKey, out scanCode, out flags); - character = (char)vKey; - } - private ITerminalConnection connection; private IntPtr hwnd; private IntPtr terminal; @@ -77,15 +63,33 @@ public TerminalContainer() internal event EventHandler UserScrolled; /// - /// Gets the character rows available to the terminal. + /// Gets or sets a value indicating whether if the renderer should automatically resize to fill the control + /// on user action. + /// + public bool AutoFill { get; set; } = true; + + /// + /// Gets the current character rows available to the terminal. /// internal int Rows { get; private set; } /// - /// Gets the character columns available to the terminal. + /// Gets the current character columns available to the terminal. /// internal int Columns { get; private set; } + /// + /// Gets the maximum amount of character rows that can fit in this control. + /// + /// This will be in sync with unless autofit is set to false. + internal int MaxRows { get; private set; } + + /// + /// Gets the maximum amount of character columns that can fit in this control. + /// + /// This will be in sync with unless autofit is set to false. + internal int MaxColumns { get; private set; } + /// /// Gets the window handle of the terminal. /// @@ -172,7 +176,7 @@ internal string GetSelectedText() } /// - /// Resizes the terminal. + /// Resizes the terminal using row and column count as the new size. /// /// Number of rows to show. /// Number of columns to show. @@ -186,8 +190,16 @@ internal void Resize(uint rows, uint columns) NativeMethods.TerminalResize(this.terminal, dimensions); - this.Rows = dimensions.Y; + // If AutoFill is true, keep Rows and Columns in sync with MaxRows and MaxColumns. + // Otherwise, MaxRows and MaxColumns will be set on startup and on control resize by the user. + if (this.AutoFill) + { + this.MaxColumns = dimensions.X; + this.MaxRows = dimensions.Y; + } + this.Columns = dimensions.X; + this.Rows = dimensions.Y; this.connection?.Resize((uint)dimensions.Y, (uint)dimensions.X); } @@ -238,6 +250,20 @@ protected override void DestroyWindowCore(HandleRef hwnd) this.terminal = IntPtr.Zero; } + private static void UnpackKeyMessage(IntPtr wParam, IntPtr lParam, out ushort vkey, out ushort scanCode, out ushort flags) + { + ulong scanCodeAndFlags = (((ulong)lParam) & 0xFFFF0000) >> 16; + scanCode = (ushort)(scanCodeAndFlags & 0x00FFu); + flags = (ushort)(scanCodeAndFlags & 0xFF00u); + vkey = (ushort)wParam; + } + + private static void UnpackCharMessage(IntPtr wParam, IntPtr lParam, out char character, out ushort scanCode, out ushort flags) + { + UnpackKeyMessage(wParam, lParam, out ushort vKey, out scanCode, out flags); + character = (char)vKey; + } + private void TerminalContainer_GotFocus(object sender, RoutedEventArgs e) { e.Handled = true; @@ -299,13 +325,28 @@ private IntPtr TerminalContainer_MessageHook(IntPtr hwnd, int msg, IntPtr wParam break; } - NativeMethods.TerminalTriggerResize(this.terminal, windowpos.cx, windowpos.cy, out var dimensions); + NativeMethods.COORD dimensions; - this.connection?.Resize((uint)dimensions.Y, (uint)dimensions.X); - this.Columns = dimensions.X; - this.Rows = dimensions.Y; + // We only trigger a resize if we want to autofill to maximum size. + if (this.AutoFill) + { + NativeMethods.TerminalTriggerResize(this.terminal, windowpos.cx, windowpos.cy, out dimensions); + this.Columns = dimensions.X; + this.Rows = dimensions.Y; + this.MaxColumns = dimensions.X; + this.MaxRows = dimensions.Y; + } + else + { + NativeMethods.TerminalCalculateResize(this.terminal, (short)windowpos.cx, (short)windowpos.cy, out dimensions); + this.MaxColumns = dimensions.X; + this.MaxRows = dimensions.Y; + } + + this.connection?.Resize((uint)dimensions.Y, (uint)dimensions.X); break; + case NativeMethods.WindowMessage.WM_MOUSEWHEEL: var delta = (short)(((long)wParam) >> 16); this.UserScrolled?.Invoke(this, delta); diff --git a/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs b/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs index ef8f6b30ae0..1b31c573308 100644 --- a/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs +++ b/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs @@ -32,15 +32,35 @@ public TerminalControl() } /// - /// Gets the character rows available to the terminal. + /// Gets the current character rows available to the terminal. /// public int Rows => this.termContainer.Rows; /// - /// Gets the character columns available to the terminal. + /// Gets the current character columns available to the terminal. /// public int Columns => this.termContainer.Columns; + /// + /// Gets the maximum amount of character rows that can fit in this control. + /// + public int MaxRows => this.termContainer.MaxRows; + + /// + /// Gets the maximum amount of character columns that can fit in this control. + /// + public int MaxColumns => this.termContainer.MaxColumns; + + /// + /// Gets or sets a value indicating whether if the renderer should automatically resize to fill the control + /// on user action. + /// + public bool AutoFill + { + get => this.termContainer.AutoFill; + set => this.termContainer.AutoFill = value; + } + /// /// Sets the connection to a terminal backend. /// From 1291d33e6b43c2719c65133efbb7710034b8d588 Mon Sep 17 00:00:00 2001 From: Javier De la Garza Sanchez Date: Wed, 7 Oct 2020 14:58:16 -0700 Subject: [PATCH 2/9] Added helper methods for converting character viewport into pixel viewport --- src/renderer/dx/DxRenderer.cpp | 8 ++++++++ src/renderer/dx/DxRenderer.hpp | 1 + 2 files changed, 9 insertions(+) diff --git a/src/renderer/dx/DxRenderer.cpp b/src/renderer/dx/DxRenderer.cpp index daabbc8a894..6cd078d93c4 100644 --- a/src/renderer/dx/DxRenderer.cpp +++ b/src/renderer/dx/DxRenderer.cpp @@ -1786,6 +1786,14 @@ CATCH_RETURN(); return Viewport::FromDimensions(viewInPixels.Origin(), { widthInChars, heightInChars }); } +[[nodiscard]] Viewport DxEngine::GetViewportInPixels(const Viewport& viewInCharacters) noexcept +{ + const short widthInPixels = gsl::narrow_cast(viewInCharacters.Width() * _glyphCell.width()); + const short heightInPixels = gsl::narrow_cast(viewInCharacters.Height() * _glyphCell.height()); + + return Viewport::FromDimensions(viewInCharacters.Origin(), { widthInPixels, heightInPixels }); +} + // Routine Description: // - Sets the DPI in this renderer // Arguments: diff --git a/src/renderer/dx/DxRenderer.hpp b/src/renderer/dx/DxRenderer.hpp index a6b6240ab3e..c59b89c5a8f 100644 --- a/src/renderer/dx/DxRenderer.hpp +++ b/src/renderer/dx/DxRenderer.hpp @@ -111,6 +111,7 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override; [[nodiscard]] ::Microsoft::Console::Types::Viewport GetViewportInCharacters(const ::Microsoft::Console::Types::Viewport& viewInPixels) noexcept; + [[nodiscard]] ::Microsoft::Console::Types::Viewport GetViewportInPixels(const ::Microsoft::Console::Types::Viewport& viewInCharacters) noexcept; float GetScaling() const noexcept; From dee6aa4e842cb41aea346f42df19ee27ce75ee8f Mon Sep 17 00:00:00 2001 From: Javier De la Garza Sanchez Date: Wed, 7 Oct 2020 15:04:27 -0700 Subject: [PATCH 3/9] Fixed resizing methods and added the ability to resize using column and row count. --- .../PublicTerminalCore/HwndTerminal.cpp | 56 ++++++++++++++----- .../PublicTerminalCore/HwndTerminal.hpp | 7 ++- .../WpfTerminalControl/NativeMethods.cs | 25 +++++++-- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp index 0cf9e6384ce..a03ec9da27e 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp @@ -433,7 +433,15 @@ void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data) publicTerminal->SendOutput(data); } -HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ double width, _In_ double height, _Out_ COORD* dimensions) +/// +/// Triggers a terminal resize using the new width and height in pixel. +/// +/// Terminal pointer. +/// New width of the terminal in pixels. +/// New height of the terminal in pixels +/// Out parameter containing the columns and rows that fit the new size. +/// HRESULT of the attempted resize. +HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions) { const auto publicTerminal = static_cast(terminal); @@ -446,10 +454,42 @@ HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ double width, _ static_cast(height), 0)); - const SIZE windowSize{ static_cast(width), static_cast(height) }; + const SIZE windowSize{ width, height }; return publicTerminal->Refresh(windowSize, dimensions); } +/// +/// Helper method for resizing the terminal using character column and row counts +/// +/// Pointer to the terminal object. +/// New terminal size in row and column count. +/// Out parameter with the new size of the renderer. +/// HRESULT of the attempted resize. +HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ COORD dimensionsInCharacters, _Out_ SIZE* dimensionsInPixels) +{ + RETURN_HR_IF_NULL(E_INVALIDARG, dimensionsInPixels); + + const auto publicTerminal = static_cast(terminal); + + const auto viewInCharacters = Viewport::FromDimensions({ 0, 0 }, { (dimensionsInCharacters.X), (dimensionsInCharacters.Y) }); + const auto viewInPixels = publicTerminal->_renderEngine->GetViewportInPixels(viewInCharacters); + + dimensionsInPixels->cx = viewInPixels.Width(); + dimensionsInPixels->cy = viewInPixels.Height(); + + COORD unused{ 0, 0 }; + + return TerminalTriggerResize(terminal, viewInPixels.Width(), viewInPixels.Height(), &unused); +} + +/// +/// Calculates the amount of rows and columns that fit in the provided width and height. +/// +/// Terminal pointer +/// Width of the terminal area to calculate. +/// Height of the terminal area to calculate. +/// Out parameter containing the columns and rows that fit the new size. +/// HRESULT of the calculation. HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions) { const auto publicTerminal = static_cast(terminal); @@ -774,18 +814,6 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font publicTerminal->Refresh(windowSize, &dimensions); } -// Resizes the terminal to the specified rows and columns. -HRESULT _stdcall TerminalResize(void* terminal, COORD dimensions) -{ - const auto publicTerminal = static_cast(terminal); - - auto lock = publicTerminal->_terminal->LockForWriting(); - publicTerminal->_terminal->ClearSelection(); - publicTerminal->_renderer->TriggerRedrawAll(); - - return publicTerminal->_terminal->UserResize(dimensions); -} - void _stdcall TerminalBlinkCursor(void* terminal) { const auto publicTerminal = static_cast(terminal); diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.hpp b/src/cascadia/PublicTerminalCore/HwndTerminal.hpp index 638673bb40e..f26f69ccac5 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.hpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.hpp @@ -27,8 +27,8 @@ extern "C" { __declspec(dllexport) HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal); __declspec(dllexport) void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data); __declspec(dllexport) void _stdcall TerminalRegisterScrollCallback(void* terminal, void __stdcall callback(int, int, int)); -__declspec(dllexport) HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ double width, _In_ double height, _Out_ COORD* dimensions); -__declspec(dllexport) HRESULT _stdcall TerminalResize(void* terminal, COORD dimensions); +__declspec(dllexport) HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions); +__declspec(dllexport) HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ COORD dimensions, _Out_ SIZE* dimensionsInPixels); __declspec(dllexport) HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions); __declspec(dllexport) void _stdcall TerminalDpiChanged(void* terminal, int newDpi); __declspec(dllexport) void _stdcall TerminalUserScroll(void* terminal, int viewTop); @@ -91,7 +91,8 @@ struct HwndTerminal : ::Microsoft::Console::Types::IControlAccessibilityInfo std::optional _singleClickTouchdownPos; friend HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal); - friend HRESULT _stdcall TerminalResize(void* terminal, COORD dimensions); + friend HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions); + friend HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ COORD dimensions, _Out_ SIZE* dimensionsInPixels); friend HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions); friend void _stdcall TerminalDpiChanged(void* terminal, int newDpi); friend void _stdcall TerminalUserScroll(void* terminal, int viewTop); diff --git a/src/cascadia/WpfTerminalControl/NativeMethods.cs b/src/cascadia/WpfTerminalControl/NativeMethods.cs index fcd5217bad0..34fe3085746 100644 --- a/src/cascadia/WpfTerminalControl/NativeMethods.cs +++ b/src/cascadia/WpfTerminalControl/NativeMethods.cs @@ -7,7 +7,6 @@ namespace Microsoft.Terminal.Wpf { using System; using System.Runtime.InteropServices; - using System.Windows.Automation.Provider; #pragma warning disable SA1600 // Elements should be documented internal static class NativeMethods @@ -187,10 +186,10 @@ public enum SetWindowPosFlags : uint public static extern void TerminalSendOutput(IntPtr terminal, string lpdata); [DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] - public static extern uint TerminalTriggerResize(IntPtr terminal, double width, double height, out COORD dimensions); + public static extern uint TerminalTriggerResize(IntPtr terminal, short width, short height, out COORD dimensions); [DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] - public static extern uint TerminalResize(IntPtr terminal, COORD dimensions); + public static extern uint TerminalTriggerResizeWithDimension(IntPtr terminal, [MarshalAs(UnmanagedType.Struct)] COORD dimensions, out SIZE dimensionsInPixels); [DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] public static extern uint TerminalCalculateResize(IntPtr terminal, short width, short height, out COORD dimensions); @@ -208,10 +207,10 @@ public enum SetWindowPosFlags : uint public static extern void TerminalUserScroll(IntPtr terminal, int viewTop); [DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] - public static extern uint TerminalStartSelection(IntPtr terminal, NativeMethods.COORD cursorPosition, bool altPressed); + public static extern uint TerminalStartSelection(IntPtr terminal, COORD cursorPosition, bool altPressed); [DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] - public static extern uint TerminalMoveSelection(IntPtr terminal, NativeMethods.COORD cursorPosition); + public static extern uint TerminalMoveSelection(IntPtr terminal, COORD cursorPosition); [DllImport("PublicTerminalCore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] public static extern void TerminalClearSelection(IntPtr terminal); @@ -281,10 +280,24 @@ public struct COORD public short X; /// - /// The x-coordinate of the point. + /// The y-coordinate of the point. /// public short Y; } + + [StructLayout(LayoutKind.Sequential)] + public struct SIZE + { + /// + /// The x size. + /// + public int cx; + + /// + /// The y size. + /// + public int cy; + } } #pragma warning restore SA1600 // Elements should be documented } From 40d61245f4f53434681fe77b80f94c3084eae7e9 Mon Sep 17 00:00:00 2001 From: Javier De la Garza Sanchez Date: Wed, 7 Oct 2020 15:06:54 -0700 Subject: [PATCH 4/9] Autofill now fills in blank space and calculates new margins whe resized --- .../WpfTerminalControl/TerminalContainer.cs | 24 ++++++---- .../WpfTerminalControl/TerminalControl.xaml | 5 ++- .../TerminalControl.xaml.cs | 44 ++++++++++++++++++- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/cascadia/WpfTerminalControl/TerminalContainer.cs b/src/cascadia/WpfTerminalControl/TerminalContainer.cs index 25b6746dab4..be212ef7995 100644 --- a/src/cascadia/WpfTerminalControl/TerminalContainer.cs +++ b/src/cascadia/WpfTerminalControl/TerminalContainer.cs @@ -166,12 +166,16 @@ internal string GetSelectedText() var dpiScale = VisualTreeHelper.GetDpi(this); NativeMethods.COORD dimensions; - NativeMethods.TerminalTriggerResize(this.terminal, renderSize.Width * dpiScale.DpiScaleX, renderSize.Height * dpiScale.DpiScaleY, out dimensions); + NativeMethods.TerminalTriggerResize( + this.terminal, + Convert.ToInt16(renderSize.Width * dpiScale.DpiScaleX), + Convert.ToInt16(renderSize.Height * dpiScale.DpiScaleY), + out dimensions); this.Rows = dimensions.Y; this.Columns = dimensions.X; - this.connection?.Resize((uint)dimensions.Y, (uint)dimensions.X); + this.Connection?.Resize((uint)dimensions.Y, (uint)dimensions.X); return (dimensions.Y, dimensions.X); } @@ -180,15 +184,17 @@ internal string GetSelectedText() /// /// Number of rows to show. /// Number of columns to show. - internal void Resize(uint rows, uint columns) + /// pair with the new width and height size in pixels for the renderer. + internal (int width, int height) Resize(uint rows, uint columns) { + NativeMethods.SIZE dimensionsInPixels; NativeMethods.COORD dimensions = new NativeMethods.COORD { X = (short)columns, Y = (short)rows, }; - NativeMethods.TerminalResize(this.terminal, dimensions); + NativeMethods.TerminalTriggerResizeWithDimension(this.terminal, dimensions, out dimensionsInPixels); // If AutoFill is true, keep Rows and Columns in sync with MaxRows and MaxColumns. // Otherwise, MaxRows and MaxColumns will be set on startup and on control resize by the user. @@ -201,7 +207,9 @@ internal void Resize(uint rows, uint columns) this.Columns = dimensions.X; this.Rows = dimensions.Y; - this.connection?.Resize((uint)dimensions.Y, (uint)dimensions.X); + this.Connection?.Resize((uint)dimensions.Y, (uint)dimensions.X); + + return (dimensionsInPixels.cx, dimensionsInPixels.cy); } /// @@ -330,7 +338,7 @@ private IntPtr TerminalContainer_MessageHook(IntPtr hwnd, int msg, IntPtr wParam // We only trigger a resize if we want to autofill to maximum size. if (this.AutoFill) { - NativeMethods.TerminalTriggerResize(this.terminal, windowpos.cx, windowpos.cy, out dimensions); + NativeMethods.TerminalTriggerResize(this.terminal, (short)windowpos.cx, (short)windowpos.cy, out dimensions); this.Columns = dimensions.X; this.Rows = dimensions.Y; @@ -344,7 +352,7 @@ private IntPtr TerminalContainer_MessageHook(IntPtr hwnd, int msg, IntPtr wParam this.MaxRows = dimensions.Y; } - this.connection?.Resize((uint)dimensions.Y, (uint)dimensions.X); + this.Connection?.Resize((uint)dimensions.Y, (uint)dimensions.X); break; case NativeMethods.WindowMessage.WM_MOUSEWHEEL: @@ -401,7 +409,7 @@ private void OnScroll(int viewTop, int viewHeight, int bufferSize) private void OnWrite(string data) { - this.connection?.WriteInput(data); + this.Connection?.WriteInput(data); } } } diff --git a/src/cascadia/WpfTerminalControl/TerminalControl.xaml b/src/cascadia/WpfTerminalControl/TerminalControl.xaml index b820e73df71..90a1c89205a 100644 --- a/src/cascadia/WpfTerminalControl/TerminalControl.xaml +++ b/src/cascadia/WpfTerminalControl/TerminalControl.xaml @@ -6,8 +6,9 @@ xmlns:local="clr-namespace:Microsoft.Terminal.Wpf" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" - Focusable="True"> - + Focusable="True" + x:Name="terminalUserControl"> + diff --git a/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs b/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs index 1b31c573308..6700ec2c011 100644 --- a/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs +++ b/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs @@ -5,6 +5,7 @@ namespace Microsoft.Terminal.Wpf { + using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -17,6 +18,8 @@ public partial class TerminalControl : UserControl { private int accumulatedDelta = 0; + private (int width, int height) terminalRendererSize; + /// /// Initializes a new instance of the class. /// @@ -88,6 +91,13 @@ public void SetTheme(TerminalTheme theme, string fontFamily, short fontSize) } this.termContainer.SetTheme(theme, fontFamily, fontSize); + + // DefaultBackground uses Win32 COLORREF syntax which is BGR instead of RGB. + byte b = Convert.ToByte((theme.DefaultBackground >> 16) & 0xff); + byte g = Convert.ToByte((theme.DefaultBackground >> 8) & 0xff); + byte r = Convert.ToByte(theme.DefaultBackground & 0xff); + + this.terminalGrid.Background = new SolidColorBrush(Color.FromRgb(r, g, b)); } /// @@ -106,7 +116,18 @@ public string GetSelectedText() /// Number of columns to display. public void Resize(uint rows, uint columns) { - this.termContainer.Resize(rows, columns); + var dpiScale = VisualTreeHelper.GetDpi(this); + + this.terminalRendererSize = this.termContainer.Resize(rows, columns); + + double width = ((this.terminalUserControl.RenderSize.Width * dpiScale.DpiScaleX) - this.terminalRendererSize.width) / dpiScale.DpiScaleX; + double height = ((this.terminalUserControl.RenderSize.Height * dpiScale.DpiScaleY) - this.terminalRendererSize.height) / dpiScale.DpiScaleY; + + // Prevent negative margin size. + width = width < 0 ? 0 : width; + height = height < 0 ? 0 : height; + + this.terminalGrid.Margin = new Thickness(0, 0, width, height); } /// @@ -119,6 +140,27 @@ public void Resize(uint rows, uint columns) return this.termContainer.TriggerResize(rendersize); } + /// + protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) + { + // Renderer will not resize on control resize. We have to manually recalculate the margin to fill in the space. + if (this.AutoFill == false && this.terminalRendererSize.width != 0 && this.terminalRendererSize.height != 0) + { + var dpiScale = VisualTreeHelper.GetDpi(this); + + double width = ((sizeInfo.NewSize.Width * dpiScale.DpiScaleX) - this.terminalRendererSize.width) / dpiScale.DpiScaleX; + double height = ((sizeInfo.NewSize.Height * dpiScale.DpiScaleY) - this.terminalRendererSize.height) / dpiScale.DpiScaleY; + + // Prevent negative margin size. + width = width < 0 ? 0 : width; + height = height < 0 ? 0 : height; + + this.terminalGrid.Margin = new Thickness(0, 0, width, height); + } + + base.OnRenderSizeChanged(sizeInfo); + } + private void TerminalControl_GotFocus(object sender, RoutedEventArgs e) { e.Handled = true; From 75fe3a504078a932dec14c10327cd78d079e279c Mon Sep 17 00:00:00 2001 From: Javier De la Garza Sanchez Date: Wed, 7 Oct 2020 16:04:47 -0700 Subject: [PATCH 5/9] Nit spellcheck changes --- src/cascadia/WpfTerminalControl/TerminalContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cascadia/WpfTerminalControl/TerminalContainer.cs b/src/cascadia/WpfTerminalControl/TerminalContainer.cs index be212ef7995..b242faa0f14 100644 --- a/src/cascadia/WpfTerminalControl/TerminalContainer.cs +++ b/src/cascadia/WpfTerminalControl/TerminalContainer.cs @@ -81,13 +81,13 @@ public TerminalContainer() /// /// Gets the maximum amount of character rows that can fit in this control. /// - /// This will be in sync with unless autofit is set to false. + /// This will be in sync with unless is set to false. internal int MaxRows { get; private set; } /// /// Gets the maximum amount of character columns that can fit in this control. /// - /// This will be in sync with unless autofit is set to false. + /// This will be in sync with unless is set to false. internal int MaxColumns { get; private set; } /// @@ -335,7 +335,7 @@ private IntPtr TerminalContainer_MessageHook(IntPtr hwnd, int msg, IntPtr wParam NativeMethods.COORD dimensions; - // We only trigger a resize if we want to autofill to maximum size. + // We only trigger a resize if we want to fill to maximum size. if (this.AutoFill) { NativeMethods.TerminalTriggerResize(this.terminal, (short)windowpos.cx, (short)windowpos.cy, out dimensions); From d83053ed0b3634b641f6a66091481526fbad981b Mon Sep 17 00:00:00 2001 From: Javier De la Garza Sanchez Date: Thu, 8 Oct 2020 12:53:24 -0700 Subject: [PATCH 6/9] Added scrollbar width to margin size calculation --- .../WpfTerminalControl/TerminalControl.xaml.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs b/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs index 6700ec2c011..8862f1dcf1d 100644 --- a/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs +++ b/src/cascadia/WpfTerminalControl/TerminalControl.xaml.cs @@ -120,14 +120,17 @@ public void Resize(uint rows, uint columns) this.terminalRendererSize = this.termContainer.Resize(rows, columns); - double width = ((this.terminalUserControl.RenderSize.Width * dpiScale.DpiScaleX) - this.terminalRendererSize.width) / dpiScale.DpiScaleX; - double height = ((this.terminalUserControl.RenderSize.Height * dpiScale.DpiScaleY) - this.terminalRendererSize.height) / dpiScale.DpiScaleY; + double marginWidth = ((this.terminalUserControl.RenderSize.Width * dpiScale.DpiScaleX) - this.terminalRendererSize.width) / dpiScale.DpiScaleX; + double marginHeight = ((this.terminalUserControl.RenderSize.Height * dpiScale.DpiScaleY) - this.terminalRendererSize.height) / dpiScale.DpiScaleY; + + // Make space for the scrollbar. + marginWidth -= this.scrollbar.Width; // Prevent negative margin size. - width = width < 0 ? 0 : width; - height = height < 0 ? 0 : height; + marginWidth = marginWidth < 0 ? 0 : marginWidth; + marginHeight = marginHeight < 0 ? 0 : marginHeight; - this.terminalGrid.Margin = new Thickness(0, 0, width, height); + this.terminalGrid.Margin = new Thickness(0, 0, marginWidth, marginHeight); } /// From 629a7412ca2085d2f223976f79e6aff9d68e115f Mon Sep 17 00:00:00 2001 From: Javier De la Garza Sanchez Date: Fri, 9 Oct 2020 09:59:48 -0700 Subject: [PATCH 7/9] Replaced narrow with saturated cast in helper methods --- src/renderer/dx/DxRenderer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/dx/DxRenderer.cpp b/src/renderer/dx/DxRenderer.cpp index 6cd078d93c4..7e182afb74e 100644 --- a/src/renderer/dx/DxRenderer.cpp +++ b/src/renderer/dx/DxRenderer.cpp @@ -1780,16 +1780,16 @@ CATCH_RETURN(); [[nodiscard]] Viewport DxEngine::GetViewportInCharacters(const Viewport& viewInPixels) noexcept { - const short widthInChars = gsl::narrow_cast(viewInPixels.Width() / _glyphCell.width()); - const short heightInChars = gsl::narrow_cast(viewInPixels.Height() / _glyphCell.height()); + const short widthInChars = base::saturated_cast(viewInPixels.Width() / _glyphCell.width()); + const short heightInChars = base::saturated_cast(viewInPixels.Height() / _glyphCell.height()); return Viewport::FromDimensions(viewInPixels.Origin(), { widthInChars, heightInChars }); } [[nodiscard]] Viewport DxEngine::GetViewportInPixels(const Viewport& viewInCharacters) noexcept { - const short widthInPixels = gsl::narrow_cast(viewInCharacters.Width() * _glyphCell.width()); - const short heightInPixels = gsl::narrow_cast(viewInCharacters.Height() * _glyphCell.height()); + const short widthInPixels = base::saturated_cast(viewInCharacters.Width() * _glyphCell.width()); + const short heightInPixels = base::saturated_cast(viewInCharacters.Height() * _glyphCell.height()); return Viewport::FromDimensions(viewInCharacters.Origin(), { widthInPixels, heightInPixels }); } From 9fc6a887b07504e2d8e016f6cb850333610fe101 Mon Sep 17 00:00:00 2001 From: Javier De la Garza Sanchez Date: Fri, 9 Oct 2020 10:10:46 -0700 Subject: [PATCH 8/9] Nit changes --- src/cascadia/PublicTerminalCore/HwndTerminal.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp index a03ec9da27e..9d7806073bc 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp @@ -503,7 +503,6 @@ HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, return S_OK; } - void _stdcall TerminalDpiChanged(void* terminal, int newDpi) { const auto publicTerminal = static_cast(terminal); From c40793376c3542f8c4c608ecb423f106e21083b0 Mon Sep 17 00:00:00 2001 From: Javier De la Garza Sanchez Date: Fri, 9 Oct 2020 13:51:33 -0700 Subject: [PATCH 9/9] Fixed CI build error --- src/cascadia/PublicTerminalCore/HwndTerminal.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp index 9d7806073bc..e25ebf98549 100644 --- a/src/cascadia/PublicTerminalCore/HwndTerminal.cpp +++ b/src/cascadia/PublicTerminalCore/HwndTerminal.cpp @@ -469,7 +469,7 @@ HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ CO { RETURN_HR_IF_NULL(E_INVALIDARG, dimensionsInPixels); - const auto publicTerminal = static_cast(terminal); + const auto publicTerminal = static_cast(terminal); const auto viewInCharacters = Viewport::FromDimensions({ 0, 0 }, { (dimensionsInCharacters.X), (dimensionsInCharacters.Y) }); const auto viewInPixels = publicTerminal->_renderEngine->GetViewportInPixels(viewInCharacters); @@ -492,7 +492,7 @@ HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ CO /// HRESULT of the calculation. HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions) { - const auto publicTerminal = static_cast(terminal); + const auto publicTerminal = static_cast(terminal); const auto viewInPixels = Viewport::FromDimensions({ 0, 0 }, { width, height }); const auto viewInCharacters = publicTerminal->_renderEngine->GetViewportInCharacters(viewInPixels);