mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 07:47:54 +01:00
Fixes issue on restore window size after maximize causing width shrinking
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
/// <summary>Enqueue a window size event if the window size has changed.</summary>
|
||||
/// <param name="winHeight"></param>
|
||||
/// <param name="winWidth"></param>
|
||||
/// <param name="buffHeight"></param>
|
||||
/// <param name="buffWidth"></param>
|
||||
/// <returns></returns>
|
||||
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)
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user