diff --git a/Terminal.Gui/ConsoleDrivers/V2/ConsoleDriverFacade.cs b/Terminal.Gui/ConsoleDrivers/V2/ConsoleDriverFacade.cs
index 700caf72cb..2cebd145d7 100644
--- a/Terminal.Gui/ConsoleDrivers/V2/ConsoleDriverFacade.cs
+++ b/Terminal.Gui/ConsoleDrivers/V2/ConsoleDriverFacade.cs
@@ -141,7 +141,11 @@ public int Top
/// , indicating that the cannot support TrueColor.
///
///
- public bool Force16Colors { get; set; }
+ public bool Force16Colors
+ {
+ get => Application.Force16Colors || !SupportsTrueColor;
+ set => Application.Force16Colors = value || !SupportsTrueColor;
+ }
///
/// The that will be used for the next or
diff --git a/Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs b/Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs
index 2effde3b73..9594bb08bc 100644
--- a/Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs
+++ b/Terminal.Gui/ConsoleDrivers/V2/MainLoopCoordinator.cs
@@ -25,6 +25,7 @@ internal class MainLoopCoordinator : IMainLoopCoordinator
private ConsoleDriverFacade _facade;
private Task _inputTask;
private readonly ITimedEvents _timedEvents;
+ private readonly bool _isWindowsTerminal;
private readonly SemaphoreSlim _startupSemaphore = new (0, 1);
@@ -60,6 +61,7 @@ IMainLoop loop
_inputProcessor = inputProcessor;
_outputFactory = outputFactory;
_loop = loop;
+ _isWindowsTerminal = Environment.GetEnvironmentVariable ("WT_SESSION") is { } || Environment.GetEnvironmentVariable ("VSAPPIDNAME") != null;
}
///
@@ -159,6 +161,12 @@ private void BuildFacadeIfPossible ()
_output,
_loop.AnsiRequestScheduler,
_loop.WindowSizeMonitor);
+
+ if (!_isWindowsTerminal)
+ {
+ Application.Force16Colors = _facade.Force16Colors = true;
+ }
+
Application.Driver = _facade;
_startupSemaphore.Release ();
diff --git a/Terminal.Gui/ConsoleDrivers/V2/WindowsOutput.cs b/Terminal.Gui/ConsoleDrivers/V2/WindowsOutput.cs
index ba111c130f..81142fb83c 100644
--- a/Terminal.Gui/ConsoleDrivers/V2/WindowsOutput.cs
+++ b/Terminal.Gui/ConsoleDrivers/V2/WindowsOutput.cs
@@ -56,6 +56,9 @@ private enum DesiredAccess : uint
[DllImport ("kernel32.dll")]
private static extern bool SetConsoleCursorPosition (nint hConsoleOutput, Coord dwCursorPosition);
+ [DllImport ("kernel32.dll", SetLastError = true)]
+ private static extern bool SetConsoleCursorInfo (nint hConsoleOutput, [In] ref ConsoleCursorInfo lpConsoleCursorInfo);
+
private readonly nint _screenBuffer;
public WindowsOutput ()
@@ -170,7 +173,7 @@ public void Write (IOutputBuffer buffer)
outputBuffer,
bufferCoords,
damageRegion,
- false))
+ Application.Driver!.Force16Colors))
{
int err = Marshal.GetLastWin32Error ();
@@ -304,10 +307,23 @@ public Size GetWindowSize ()
///
public void SetCursorVisibility (CursorVisibility visibility)
{
- string cursorVisibilitySequence = visibility != CursorVisibility.Invisible
- ? EscSeqUtils.CSI_ShowCursor
- : EscSeqUtils.CSI_HideCursor;
- Write (cursorVisibilitySequence);
+ if (Application.Driver!.Force16Colors)
+ {
+ var info = new ConsoleCursorInfo
+ {
+ dwSize = (uint)visibility & 0x00FF,
+ bVisible = ((uint)visibility & 0xFF00) != 0
+ };
+
+ SetConsoleCursorInfo (_screenBuffer, ref info);
+ }
+ else
+ {
+ string cursorVisibilitySequence = visibility != CursorVisibility.Invisible
+ ? EscSeqUtils.CSI_ShowCursor
+ : EscSeqUtils.CSI_HideCursor;
+ Write (cursorVisibilitySequence);
+ }
}
private Point _lastCursorPosition;
diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs
index f2fa41e25b..0a6d12e967 100644
--- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs
+++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs
@@ -17,7 +17,7 @@ internal partial class WindowsConsole
private readonly nint _inputHandle;
private nint _outputHandle;
- //private nint _screenBuffer;
+ private nint _screenBuffer;
private readonly uint _originalConsoleMode;
private CursorVisibility? _initialCursorVisibility;
private CursorVisibility? _currentCursorVisibility;
@@ -147,10 +147,12 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord
{
//Debug.WriteLine ("WriteToConsole");
- //if (_screenBuffer == nint.Zero)
- //{
- // ReadFromConsoleOutput (size, bufferSize, ref window);
- //}
+ if (!IsWindowsTerminal && _screenBuffer == nint.Zero)
+ {
+ ReadFromConsoleOutput (size, bufferSize, ref window);
+ }
+
+ SetInitialCursorVisibility ();
var result = false;
@@ -169,7 +171,7 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord
};
}
- result = WriteConsoleOutput (_outputHandle, ci, bufferSize, new Coord { X = window.Left, Y = window.Top }, ref window);
+ result = WriteConsoleOutput (IsWindowsTerminal ? _outputHandle : _screenBuffer, ci, bufferSize, new Coord { X = window.Left, Y = window.Top }, ref window);
}
else
{
@@ -222,7 +224,7 @@ public bool WriteToConsole (Size size, ExtendedCharInfo [] charInfoBuffer, Coord
foreach (var sixel in Application.Sixel)
{
SetCursorPosition (new Coord ((short)sixel.ScreenPosition.X, (short)sixel.ScreenPosition.Y));
- WriteConsole (_outputHandle, sixel.SixelData, (uint)sixel.SixelData.Length, out uint _, nint.Zero);
+ WriteConsole (IsWindowsTerminal ? _outputHandle : _screenBuffer, sixel.SixelData, (uint)sixel.SixelData.Length, out uint _, nint.Zero);
}
}
@@ -252,34 +254,32 @@ internal bool WriteANSI (string ansi)
public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window)
{
- //_screenBuffer = CreateConsoleScreenBuffer (
- // DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
- // ShareMode.FileShareRead | ShareMode.FileShareWrite,
- // nint.Zero,
- // 1,
- // nint.Zero
- // );
-
- //if (_screenBuffer == INVALID_HANDLE_VALUE)
- //{
- // int err = Marshal.GetLastWin32Error ();
-
- // if (err != 0)
- // {
- // throw new Win32Exception (err);
- // }
- //}
+ _screenBuffer = CreateConsoleScreenBuffer (
+ DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
+ ShareMode.FileShareRead | ShareMode.FileShareWrite,
+ nint.Zero,
+ 1,
+ nint.Zero
+ );
- SetInitialCursorVisibility ();
+ if (_screenBuffer == INVALID_HANDLE_VALUE)
+ {
+ int err = Marshal.GetLastWin32Error ();
+
+ if (err != 0)
+ {
+ throw new Win32Exception (err);
+ }
+ }
- //if (!SetConsoleActiveScreenBuffer (_screenBuffer))
- //{
- // throw new Win32Exception (Marshal.GetLastWin32Error ());
- //}
+ if (!SetConsoleActiveScreenBuffer (_screenBuffer))
+ {
+ throw new Win32Exception (Marshal.GetLastWin32Error ());
+ }
_originalStdOutChars = new CharInfo [size.Height * size.Width];
- if (!ReadConsoleOutput (_outputHandle, _originalStdOutChars, coords, new Coord { X = 0, Y = 0 }, ref window))
+ if (!ReadConsoleOutput (_screenBuffer, _originalStdOutChars, coords, new Coord { X = 0, Y = 0 }, ref window))
{
throw new Win32Exception (Marshal.GetLastWin32Error ());
}
@@ -287,7 +287,7 @@ public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window
public bool SetCursorPosition (Coord position)
{
- return SetConsoleCursorPosition (_outputHandle, position);
+ return SetConsoleCursorPosition (IsWindowsTerminal ? _outputHandle : _screenBuffer, position);
}
public void SetInitialCursorVisibility ()
@@ -300,14 +300,14 @@ public void SetInitialCursorVisibility ()
public bool GetCursorVisibility (out CursorVisibility visibility)
{
- if (_outputHandle == nint.Zero)
+ if ((IsWindowsTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
{
visibility = CursorVisibility.Invisible;
return false;
}
- if (!GetConsoleCursorInfo (_outputHandle, out ConsoleCursorInfo info))
+ if (!GetConsoleCursorInfo (IsWindowsTerminal ? _outputHandle : _screenBuffer, out ConsoleCursorInfo info))
{
int err = Marshal.GetLastWin32Error ();
@@ -375,7 +375,7 @@ public bool SetCursorVisibility (CursorVisibility visibility)
bVisible = ((uint)visibility & 0xFF00) != 0
};
- if (!SetConsoleCursorInfo (_outputHandle, ref info))
+ if (!SetConsoleCursorInfo (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref info))
{
return false;
}
@@ -411,12 +411,12 @@ public void Cleanup ()
Console.WriteLine ("Error: {0}", err);
}
- //if (_screenBuffer != nint.Zero)
- //{
- // CloseHandle (_screenBuffer);
- //}
+ if (_screenBuffer != nint.Zero)
+ {
+ CloseHandle (_screenBuffer);
+ }
- //_screenBuffer = nint.Zero;
+ _screenBuffer = nint.Zero;
_inputReadyCancellationTokenSource?.Cancel ();
_inputReadyCancellationTokenSource?.Dispose ();
@@ -425,7 +425,7 @@ public void Cleanup ()
internal Size GetConsoleBufferWindow (out Point position)
{
- if (_outputHandle == nint.Zero)
+ if ((IsWindowsTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
{
position = Point.Empty;
@@ -435,7 +435,7 @@ internal Size GetConsoleBufferWindow (out Point position)
var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
csbi.cbSize = (uint)Marshal.SizeOf (csbi);
- if (!GetConsoleScreenBufferInfoEx (_outputHandle, ref csbi))
+ if (!GetConsoleScreenBufferInfoEx (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref csbi))
{
//throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
position = Point.Empty;
@@ -469,85 +469,89 @@ internal Size GetConsoleOutputWindow (out Point position)
return sz;
}
- //internal Size SetConsoleWindow (short cols, short rows)
- //{
- // var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
- // csbi.cbSize = (uint)Marshal.SizeOf (csbi);
-
- // if (!GetConsoleScreenBufferInfoEx (_screenBuffer, ref csbi))
- // {
- // throw new Win32Exception (Marshal.GetLastWin32Error ());
- // }
-
- // Coord maxWinSize = GetLargestConsoleWindowSize (_screenBuffer);
- // 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 (_screenBuffer, 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 (_screenBuffer != nint.Zero && !SetConsoleScreenBufferInfoEx (_screenBuffer, ref csbi))
- // {
- // throw new Win32Exception (Marshal.GetLastWin32Error ());
- // }
- //}
-
- //internal Size SetConsoleOutputWindow (out Point position)
- //{
- // if (_screenBuffer == nint.Zero)
- // {
- // position = Point.Empty;
-
- // return Size.Empty;
- // }
-
- // var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
- // csbi.cbSize = (uint)Marshal.SizeOf (csbi);
-
- // if (!GetConsoleScreenBufferInfoEx (_screenBuffer, ref csbi))
- // {
- // throw new Win32Exception (Marshal.GetLastWin32Error ());
- // }
-
- // Size sz = new (
- // csbi.srWindow.Right - csbi.srWindow.Left + 1,
- // Math.Max (csbi.srWindow.Bottom - csbi.srWindow.Top + 1, 0));
- // position = new (csbi.srWindow.Left, csbi.srWindow.Top);
- // SetConsoleOutputWindow (csbi);
- // var winRect = new SmallRect (0, 0, (short)(sz.Width - 1), (short)Math.Max (sz.Height - 1, 0));
-
- // if (!SetConsoleScreenBufferInfoEx (_outputHandle, ref csbi))
- // {
- // throw new Win32Exception (Marshal.GetLastWin32Error ());
- // }
-
- // if (!SetConsoleWindowInfo (_outputHandle, true, ref winRect))
- // {
- // throw new Win32Exception (Marshal.GetLastWin32Error ());
- // }
-
- // return sz;
- //}
+ internal Size SetConsoleWindow (short cols, short rows)
+ {
+ var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
+ csbi.cbSize = (uint)Marshal.SizeOf (csbi);
+
+ if (!GetConsoleScreenBufferInfoEx (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref csbi))
+ {
+ throw new Win32Exception (Marshal.GetLastWin32Error ());
+ }
+
+ Coord maxWinSize = GetLargestConsoleWindowSize (IsWindowsTerminal ? _outputHandle : _screenBuffer);
+ 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 (IsWindowsTerminal ? _outputHandle : _screenBuffer, 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 ((IsWindowsTerminal
+ ? _outputHandle
+ : _screenBuffer) != nint.Zero && !SetConsoleScreenBufferInfoEx (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref csbi))
+ {
+ throw new Win32Exception (Marshal.GetLastWin32Error ());
+ }
+ }
+
+ internal Size SetConsoleOutputWindow (out Point position)
+ {
+ if ((IsWindowsTerminal ? _outputHandle : _screenBuffer) == nint.Zero)
+ {
+ position = Point.Empty;
+
+ return Size.Empty;
+ }
+
+ var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
+ csbi.cbSize = (uint)Marshal.SizeOf (csbi);
+
+ if (!GetConsoleScreenBufferInfoEx (IsWindowsTerminal ? _outputHandle : _screenBuffer, ref csbi))
+ {
+ throw new Win32Exception (Marshal.GetLastWin32Error ());
+ }
+
+ Size sz = new (
+ csbi.srWindow.Right - csbi.srWindow.Left + 1,
+ Math.Max (csbi.srWindow.Bottom - csbi.srWindow.Top + 1, 0));
+ position = new (csbi.srWindow.Left, csbi.srWindow.Top);
+ SetConsoleOutputWindow (csbi);
+ var winRect = new SmallRect (0, 0, (short)(sz.Width - 1), (short)Math.Max (sz.Height - 1, 0));
+
+ if (!SetConsoleScreenBufferInfoEx (_outputHandle, ref csbi))
+ {
+ throw new Win32Exception (Marshal.GetLastWin32Error ());
+ }
+
+ if (!SetConsoleWindowInfo (_outputHandle, true, ref winRect))
+ {
+ throw new Win32Exception (Marshal.GetLastWin32Error ());
+ }
+
+ return sz;
+ }
+
+ internal bool IsWindowsTerminal { get; set; }
private uint ConsoleMode
{
diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs
index 1fc1eb8424..b45f7d4ebe 100644
--- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs
@@ -14,7 +14,7 @@
// the WindowsConsole.EventType.WindowBufferSize event. However, on Init the window size is
// still incorrect so we still need this hack.
-//#define HACK_CHECK_WINCHANGED
+#define HACK_CHECK_WINCHANGED
using System.ComponentModel;
using System.Diagnostics;
@@ -57,8 +57,12 @@ public WindowsDriver ()
// TODO: if some other Windows-based terminal supports true color, update this logic to not
// force 16color mode (.e.g ConEmu which really doesn't work well at all).
- _isWindowsTerminal = _isWindowsTerminal =
- Environment.GetEnvironmentVariable ("WT_SESSION") is { } || Environment.GetEnvironmentVariable ("VSAPPIDNAME") != null;
+ if (!RunningUnitTests)
+ {
+ WinConsole!.IsWindowsTerminal = _isWindowsTerminal =
+ Environment.GetEnvironmentVariable ("WT_SESSION") is { }
+ || Environment.GetEnvironmentVariable ("VSAPPIDNAME") != null;
+ }
if (!_isWindowsTerminal)
{
@@ -422,7 +426,7 @@ public override MainLoop Init ()
{
// BUGBUG: The results from GetConsoleOutputWindow are incorrect when called from Init.
// Our thread in WindowsMainLoop.CheckWin will get the correct results. See #if HACK_CHECK_WINCHANGED
- Size winSize = WinConsole.GetConsoleOutputWindow (out Point _);
+ Size winSize = WinConsole.GetConsoleOutputWindow (out _);
Cols = winSize.Width;
Rows = winSize.Height;
OnSizeChanged (new SizeChangedEventArgs (new (Cols, Rows)));
@@ -466,7 +470,7 @@ public override MainLoop Init ()
if (!RunningUnitTests)
{
- WinConsole?.SetInitialCursorVisibility ();
+ WinConsole?.SetInitialCursorVisibility ();
}
return new MainLoop (_mainLoopDriver);
diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs
index 13fcafbd9a..547f5dcd2a 100644
--- a/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs
+++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs
@@ -1,5 +1,7 @@
#nullable enable
+#define HACK_CHECK_WINCHANGED
+
using System.Collections.Concurrent;
namespace Terminal.Gui;