diff --git a/Terminal.Gui/Drivers/NetDriver/NetDriver.cs b/Terminal.Gui/Drivers/NetDriver/NetDriver.cs
index fa2ccadd9..aec306da5 100644
--- a/Terminal.Gui/Drivers/NetDriver/NetDriver.cs
+++ b/Terminal.Gui/Drivers/NetDriver/NetDriver.cs
@@ -339,7 +339,37 @@ internal class NetDriver : ConsoleDriver
Left = 0;
Cols = inputEvent.WindowSizeEvent.Size.Width;
Rows = Math.Max (inputEvent.WindowSizeEvent.Size.Height, 0);
- ;
+
+ if (!RunningUnitTests)
+ {
+ if (IsWinPlatform)
+ {
+ try
+ {
+ Size newSize = NetWinConsole!.SetConsoleWindow ((short)Cols, (short)Rows);
+
+ if (Cols != newSize.Width)
+ {
+ Cols = newSize.Width;
+ }
+
+ if (Rows != newSize.Height)
+ {
+ Rows = newSize.Height;
+ }
+ }
+ catch (Exception e)
+ {
+ // If we can't resize the console, we just log the error.
+ Console.WriteLine (e);
+ }
+ }
+ else
+ {
+ Console.Out.Write (EscSeqUtils.CSI_SetTerminalWindowSize (Rows, Cols));
+ }
+ }
+
ResizeScreen ();
ClearContents ();
_winSizeChanging = false;
@@ -744,49 +774,8 @@ internal class NetDriver : ConsoleDriver
}
}
- public virtual void ResizeScreen ()
+ public void ResizeScreen ()
{
- // Not supported on Unix.
- if (IsWinPlatform)
- {
- // Can raise an exception while is still resizing.
- try
- {
-#pragma warning disable CA1416
- if (Console.WindowHeight > 0)
- {
- Console.CursorTop = 0;
- Console.CursorLeft = 0;
- Console.WindowTop = 0;
- Console.WindowLeft = 0;
-
- if (Console.WindowHeight > Rows)
- {
- Console.SetWindowSize (Cols, Rows);
- }
-
- Console.SetBufferSize (Cols, Rows);
- }
-#pragma warning restore CA1416
- }
- // INTENT: Why are these eating the exceptions?
- // Comments would be good here.
- catch (IOException)
- {
- // CONCURRENCY: Unsynchronized access to Clip is not safe.
- Clip = new (Screen);
- }
- catch (ArgumentOutOfRangeException)
- {
- // CONCURRENCY: Unsynchronized access to Clip is not safe.
- Clip = new (Screen);
- }
- }
- else
- {
- Console.Out.Write (EscSeqUtils.CSI_SetTerminalWindowSize (Rows, Cols));
- }
-
// CONCURRENCY: Unsynchronized access to Clip is not safe.
Clip = new (Screen);
}
diff --git a/Terminal.Gui/Drivers/NetDriver/NetEvents.cs b/Terminal.Gui/Drivers/NetDriver/NetEvents.cs
index 94b01baaf..fb8f22bd0 100644
--- a/Terminal.Gui/Drivers/NetDriver/NetEvents.cs
+++ b/Terminal.Gui/Drivers/NetDriver/NetEvents.cs
@@ -143,6 +143,8 @@ internal class NetEvents : IDisposable
);
}
+ private Size? _lastWindowSizeBeforeMaximized = null;
+
private void CheckWindowSizeChange ()
{
void RequestWindowSize ()
@@ -151,25 +153,50 @@ internal class NetEvents : IDisposable
{
// Wait for a while then check if screen has changed sizes
Task.Delay (500, _netEventsDisposed.Token).Wait (_netEventsDisposed.Token);
-
- int buffHeight, buffWidth;
+ Size windowSize;
if (((NetDriver)_consoleDriver).IsWinPlatform)
{
- buffHeight = Math.Max (Console.BufferHeight, 0);
- buffWidth = Math.Max (Console.BufferWidth, 0);
+ Size largestWindowSize = ((NetDriver)_consoleDriver).NetWinConsole!.GetLargestConsoleWindowSize ();
+ windowSize = ((NetDriver)_consoleDriver).NetWinConsole!.GetConsoleBufferWindow (out _);
+
+ if (_lastWindowSizeBeforeMaximized is null && windowSize == largestWindowSize)
+ {
+ _lastWindowSizeBeforeMaximized = new (_consoleDriver.Cols, _consoleDriver.Rows);
+ }
+ else if (_lastWindowSizeBeforeMaximized is { } && windowSize != largestWindowSize)
+ {
+ if (windowSize != _lastWindowSizeBeforeMaximized)
+ {
+ windowSize = new (_lastWindowSizeBeforeMaximized.Value.Width, _lastWindowSizeBeforeMaximized.Value.Height);
+
+ while (Console.WindowWidth != _lastWindowSizeBeforeMaximized.Value.Width
+ && Console.WindowHeight != _lastWindowSizeBeforeMaximized.Value.Height)
+ {
+ try
+ {
+ windowSize = ((NetDriver)_consoleDriver).NetWinConsole!.SetConsoleWindow (
+ (short)_lastWindowSizeBeforeMaximized.Value.Width,
+ (short)_lastWindowSizeBeforeMaximized.Value.Height);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine (e);
+ }
+ }
+ }
+
+ _lastWindowSizeBeforeMaximized = null;
+ }
}
else
{
- buffHeight = _consoleDriver.Rows;
- buffWidth = _consoleDriver.Cols;
+ windowSize = new (Console.WindowWidth, Console.WindowHeight);
}
if (EnqueueWindowSizeEvent (
- Math.Max (Console.WindowHeight, 0),
- Math.Max (Console.WindowWidth, 0),
- buffHeight,
- buffWidth
+ Math.Max (windowSize.Height, 0),
+ Math.Max (windowSize.Width, 0)
))
{
return;
@@ -198,10 +225,8 @@ internal class NetEvents : IDisposable
/// Enqueue a window size event if the window size has changed.
///
///
- ///
- ///
///
- private bool EnqueueWindowSizeEvent (int winHeight, int winWidth, int buffHeight, int buffWidth)
+ private bool EnqueueWindowSizeEvent (int winHeight, int winWidth)
{
if (winWidth == _consoleDriver.Cols && winHeight == _consoleDriver.Rows)
{
@@ -446,8 +471,6 @@ internal class NetEvents : IDisposable
{
case EscSeqUtils.CSI_ReportTerminalSizeInChars_ResponseValue:
EnqueueWindowSizeEvent (
- Math.Max (int.Parse (values [1]), 0),
- Math.Max (int.Parse (values [2]), 0),
Math.Max (int.Parse (values [1]), 0),
Math.Max (int.Parse (values [2]), 0)
);
diff --git a/Terminal.Gui/Drivers/NetDriver/NetWinVTConsole.cs b/Terminal.Gui/Drivers/NetDriver/NetWinVTConsole.cs
index 4750a32e8..247f1cf58 100644
--- a/Terminal.Gui/Drivers/NetDriver/NetWinVTConsole.cs
+++ b/Terminal.Gui/Drivers/NetDriver/NetWinVTConsole.cs
@@ -1,4 +1,5 @@
#nullable enable
+using System.ComponentModel;
using System.Runtime.InteropServices;
namespace Terminal.Gui.Drivers;
@@ -112,6 +113,85 @@ internal class NetWinVTConsole
}
}
+ internal Size GetConsoleBufferWindow (out Point position)
+ {
+ if (_outputHandle == nint.Zero)
+ {
+ position = Point.Empty;
+
+ return Size.Empty;
+ }
+
+ var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
+ csbi.cbSize = (uint)Marshal.SizeOf (csbi);
+
+ if (!GetConsoleScreenBufferInfoEx (_outputHandle, ref csbi))
+ {
+ //throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
+ position = Point.Empty;
+
+ return Size.Empty;
+ }
+
+ Size sz = new (
+ csbi.srWindow.Right - csbi.srWindow.Left + 1,
+ csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
+ position = new (csbi.srWindow.Left, csbi.srWindow.Top);
+
+ return sz;
+ }
+
+ internal Size SetConsoleWindow (short cols, short rows)
+ {
+ var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
+ csbi.cbSize = (uint)Marshal.SizeOf (csbi);
+
+ if (!GetConsoleScreenBufferInfoEx (_outputHandle, ref csbi))
+ {
+ throw new Win32Exception (Marshal.GetLastWin32Error ());
+ }
+
+ Coord maxWinSize = GetLargestConsoleWindowSize (_outputHandle);
+ short newCols = Math.Min (cols, maxWinSize.X);
+ short newRows = Math.Min (rows, maxWinSize.Y);
+ csbi.dwSize = new Coord (newCols, Math.Max (newRows, (short)1));
+ csbi.srWindow = new SmallRect (0, 0, newCols, newRows);
+ csbi.dwMaximumWindowSize = new Coord (newCols, newRows);
+
+ if (!SetConsoleScreenBufferInfoEx (_outputHandle, ref csbi))
+ {
+ throw new Win32Exception (Marshal.GetLastWin32Error ());
+ }
+
+ var winRect = new SmallRect (0, 0, (short)(newCols - 1), (short)Math.Max (newRows - 1, 0));
+
+ if (!SetConsoleWindowInfo (_outputHandle, true, ref winRect))
+ {
+ //throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
+ return new (cols, rows);
+ }
+
+ SetConsoleOutputWindow (csbi);
+
+ return new (winRect.Right + 1, newRows - 1 < 0 ? 0 : winRect.Bottom + 1);
+ }
+
+ private void SetConsoleOutputWindow (CONSOLE_SCREEN_BUFFER_INFOEX csbi)
+ {
+ if (_outputHandle != nint.Zero && !SetConsoleScreenBufferInfoEx (_outputHandle, ref csbi))
+ {
+ throw new Win32Exception (Marshal.GetLastWin32Error ());
+ }
+ }
+
+ internal Size GetLargestConsoleWindowSize ()
+ {
+ Coord maxWinSize = GetLargestConsoleWindowSize (_outputHandle);
+
+ return new (maxWinSize.X, maxWinSize.Y);
+ }
+
+ // --------------Imports-----------------
[DllImport ("kernel32.dll")]
private static extern bool GetConsoleMode (nint hConsoleHandle, out uint lpMode);
@@ -123,4 +203,103 @@ internal class NetWinVTConsole
[DllImport ("kernel32.dll")]
private static extern bool SetConsoleMode (nint hConsoleHandle, uint dwMode);
+
+ [DllImport ("kernel32.dll", SetLastError = true)]
+ private static extern bool GetConsoleScreenBufferInfoEx (nint hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFOEX csbi);
+
+ [DllImport ("kernel32.dll", SetLastError = true)]
+ private static extern Coord GetLargestConsoleWindowSize (
+ nint hConsoleOutput
+ );
+
+ [DllImport ("kernel32.dll", SetLastError = true)]
+ private static extern bool SetConsoleScreenBufferInfoEx (nint hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFOEX consoleScreenBufferInfo);
+
+ [DllImport ("kernel32.dll", SetLastError = true)]
+ private static extern bool SetConsoleWindowInfo (
+ nint hConsoleOutput,
+ bool bAbsolute,
+ [In] ref SmallRect lpConsoleWindow
+ );
+
+ // -----------structs-----------------
+ [StructLayout (LayoutKind.Sequential)]
+ public struct CONSOLE_SCREEN_BUFFER_INFOEX
+ {
+ public uint cbSize;
+ public Coord dwSize;
+ public Coord dwCursorPosition;
+ public ushort wAttributes;
+ public SmallRect srWindow;
+ public Coord dwMaximumWindowSize;
+ public ushort wPopupAttributes;
+ public bool bFullscreenSupported;
+
+ [MarshalAs (UnmanagedType.ByValArray, SizeConst = 16)]
+ public COLORREF [] ColorTable;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct Coord
+ {
+ public short X;
+ public short Y;
+
+ public Coord (short x, short y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ public readonly override string ToString () { return $"({X},{Y})"; }
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct SmallRect
+ {
+ public short Left;
+ public short Top;
+ public short Right;
+ public short Bottom;
+
+ public SmallRect (short left, short top, short right, short bottom)
+ {
+ Left = left;
+ Top = top;
+ Right = right;
+ Bottom = bottom;
+ }
+ }
+
+ [StructLayout (LayoutKind.Explicit, Size = 4)]
+ public struct COLORREF
+ {
+ public COLORREF (byte r, byte g, byte b)
+ {
+ Value = 0;
+ R = r;
+ G = g;
+ B = b;
+ }
+
+ public COLORREF (uint value)
+ {
+ R = 0;
+ G = 0;
+ B = 0;
+ Value = value & 0x00FFFFFF;
+ }
+
+ [FieldOffset (0)]
+ public byte R;
+
+ [FieldOffset (1)]
+ public byte G;
+
+ [FieldOffset (2)]
+ public byte B;
+
+ [FieldOffset (0)]
+ public uint Value;
+ }
}