Trying fixing #518. Almost functions work on both Windows and Unix with the NetDriver.

This commit is contained in:
BDisp
2020-11-17 21:57:45 +00:00
parent 204be65f2a
commit bcc31e0da0
17 changed files with 354 additions and 217 deletions

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@@ -17,9 +17,9 @@ namespace Terminal.Gui {
/// This is the Curses driver for the gui.cs/Terminal framework.
/// </summary>
internal class CursesDriver : ConsoleDriver {
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
public override int Cols => Curses.Cols;
public override int Rows => Curses.Lines;
public override int Top => 0;
// Current row, and current col, tracked by Move/AddRune only
int ccol, crow;
@@ -907,7 +907,5 @@ namespace Terminal.Gui {
killpg (0, signal);
return true;
}
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
}
}

View File

@@ -15,15 +15,11 @@ namespace Terminal.Gui {
/// Implements a mock ConsoleDriver for unit testing
/// </summary>
public class FakeDriver : ConsoleDriver {
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
int cols, rows;
/// <summary>
///
/// </summary>
public override int Cols => cols;
/// <summary>
///
/// </summary>
public override int Rows => rows;
public override int Top => 0;
// The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag
int [,,] contents;
@@ -49,9 +45,6 @@ namespace Terminal.Gui {
static bool sync = false;
/// <summary>
///
/// </summary>
public FakeDriver ()
{
cols = FakeConsole.WindowWidth;
@@ -62,11 +55,6 @@ namespace Terminal.Gui {
bool needMove;
// Current row, and current col, tracked by Move/AddCh only
int ccol, crow;
/// <summary>
///
/// </summary>
/// <param name="col"></param>
/// <param name="row"></param>
public override void Move (int col, int row)
{
ccol = col;
@@ -84,10 +72,6 @@ namespace Terminal.Gui {
}
/// <summary>
///
/// </summary>
/// <param name="rune"></param>
public override void AddRune (Rune rune)
{
rune = MakePrintable (rune);
@@ -113,19 +97,12 @@ namespace Terminal.Gui {
UpdateScreen ();
}
/// <summary>
///
/// </summary>
/// <param name="str"></param>
public override void AddStr (ustring str)
{
foreach (var rune in str)
AddRune (rune);
}
/// <summary>
///
/// </summary>
public override void End ()
{
FakeConsole.ResetColor ();
@@ -138,10 +115,6 @@ namespace Terminal.Gui {
return new Attribute () { value = ((((int)f) & 0xffff) << 16) | (((int)b) & 0xffff) };
}
/// <summary>
///
/// </summary>
/// <param name="terminalResized"></param>
public override void Init (Action terminalResized)
{
Colors.TopLevel = new ColorScheme ();
@@ -185,12 +158,6 @@ namespace Terminal.Gui {
//MockConsole.Clear ();
}
/// <summary>
///
/// </summary>
/// <param name="fore"></param>
/// <param name="back"></param>
/// <returns></returns>
public override Attribute MakeAttribute (Color fore, Color back)
{
return MakeColor ((ConsoleColor)fore, (ConsoleColor)back);
@@ -211,9 +178,6 @@ namespace Terminal.Gui {
}
}
/// <summary>
///
/// </summary>
public override void UpdateScreen ()
{
int rows = Rows;
@@ -233,9 +197,6 @@ namespace Terminal.Gui {
}
}
/// <summary>
///
/// </summary>
public override void Refresh ()
{
int rows = Rows;
@@ -267,40 +228,24 @@ namespace Terminal.Gui {
FakeConsole.CursorLeft = savedCol;
}
/// <summary>
///
/// </summary>
public override void UpdateCursor ()
{
//
}
/// <summary>
///
/// </summary>
public override void StartReportingMouseMoves ()
{
}
/// <summary>
///
/// </summary>
public override void StopReportingMouseMoves ()
{
}
/// <summary>
///
/// </summary>
public override void Suspend ()
{
}
int currentAttribute;
/// <summary>
///
/// </summary>
/// <param name="c"></param>
public override void SetAttribute (Attribute c)
{
currentAttribute = c.value;
@@ -417,18 +362,10 @@ namespace Terminal.Gui {
return keyMod != Key.Null ? keyMod | key : key;
}
/// <summary>
///
/// </summary>
/// <param name="mainLoop"></param>
/// <param name="keyHandler"></param>
/// <param name="keyDownHandler"></param>
/// <param name="keyUpHandler"></param>
/// <param name="mouseHandler"></param>
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
{
// Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
(mainLoop.Driver as NetMainLoop).KeyPressed = delegate (ConsoleKeyInfo consoleKey) {
(mainLoop.Driver as FakeMainLoop).KeyPressed = delegate (ConsoleKeyInfo consoleKey) {
var map = MapKey (consoleKey);
if (map == (Key)0xffffffff)
return;
@@ -452,38 +389,23 @@ namespace Terminal.Gui {
};
}
/// <summary>
///
/// </summary>
/// <param name="foreground"></param>
/// <param name="background"></param>
public override void SetColors (ConsoleColor foreground, ConsoleColor background)
{
throw new NotImplementedException ();
}
/// <summary>
///
/// </summary>
/// <param name="foregroundColorId"></param>
/// <param name="backgroundColorId"></param>
public override void SetColors (short foregroundColorId, short backgroundColorId)
{
throw new NotImplementedException ();
}
/// <summary>
///
/// </summary>
public override void CookMouse ()
{
}
/// <summary>
///
/// </summary>
public override void UncookMouse ()
{
}
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
}
}

View File

@@ -0,0 +1,89 @@
using System;
using System.Threading;
namespace Terminal.Gui {
/// <summary>
/// Mainloop intended to be used with the .NET System.Console API, and can
/// be used on Windows and Unix, it is cross platform but lacks things like
/// file descriptor monitoring.
/// </summary>
/// <remarks>
/// This implementation is used for FakeDriver.
/// </remarks>
public class FakeMainLoop : IMainLoopDriver {
AutoResetEvent keyReady = new AutoResetEvent (false);
AutoResetEvent waitForProbe = new AutoResetEvent (false);
ConsoleKeyInfo? keyResult = null;
MainLoop mainLoop;
Func<ConsoleKeyInfo> consoleKeyReaderFn = null;
/// <summary>
/// Invoked when a Key is pressed.
/// </summary>
public Action<ConsoleKeyInfo> KeyPressed;
/// <summary>
/// Initializes the class.
/// </summary>
/// <remarks>
/// Passing a consoleKeyReaderfn is provided to support unit test scenarios.
/// </remarks>
/// <param name="consoleKeyReaderFn">The method to be called to get a key from the console.</param>
public FakeMainLoop (Func<ConsoleKeyInfo> consoleKeyReaderFn = null)
{
if (consoleKeyReaderFn == null) {
throw new ArgumentNullException ("key reader function must be provided.");
}
this.consoleKeyReaderFn = consoleKeyReaderFn;
}
void WindowsKeyReader ()
{
while (true) {
waitForProbe.WaitOne ();
keyResult = consoleKeyReaderFn ();
keyReady.Set ();
}
}
void IMainLoopDriver.Setup (MainLoop mainLoop)
{
this.mainLoop = mainLoop;
Thread readThread = new Thread (WindowsKeyReader);
readThread.Start ();
}
void IMainLoopDriver.Wakeup ()
{
}
bool IMainLoopDriver.EventsPending (bool wait)
{
long now = DateTime.UtcNow.Ticks;
int waitTimeout;
if (mainLoop.timeouts.Count > 0) {
waitTimeout = (int)((mainLoop.timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond);
if (waitTimeout < 0)
return true;
} else
waitTimeout = -1;
if (!wait)
waitTimeout = 0;
keyResult = null;
waitForProbe.Set ();
keyReady.WaitOne (waitTimeout);
return keyResult.HasValue;
}
void IMainLoopDriver.MainIteration ()
{
if (keyResult.HasValue) {
KeyPressed?.Invoke (keyResult.Value);
keyResult = null;
}
}
}
}

View File

@@ -8,46 +8,46 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NStack;
namespace Terminal.Gui {
internal class NetDriver : ConsoleDriver {
int cols, rows;
int cols, rows, top;
public override int Cols => cols;
public override int Rows => rows;
public override int Top => top;
// The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag
int [,,] contents;
bool [] dirtyLine;
public NetDriver ()
{
ResizeScreen ();
UpdateOffscreen ();
}
void UpdateOffscreen ()
{
int cols = Cols;
int rows = Rows;
contents = new int [rows, cols, 3];
for (int r = 0; r < rows; r++) {
dirtyLine = new bool [rows];
for (int row = 0; row < rows; row++) {
for (int c = 0; c < cols; c++) {
contents [r, c, 0] = ' ';
contents [r, c, 1] = MakeColor (ConsoleColor.Gray, ConsoleColor.Black);
contents [r, c, 2] = 0;
contents [row, c, 0] = ' ';
contents [row, c, 1] = (ushort)Colors.TopLevel.Normal;
contents [row, c, 2] = 0;
dirtyLine [row] = true;
}
}
dirtyLine = new bool [rows];
for (int row = 0; row < rows; row++)
dirtyLine [row] = true;
}
static bool sync = false;
public NetDriver ()
{
cols = Console.WindowWidth;
rows = Console.WindowHeight - 1;
UpdateOffscreen ();
}
bool needMove;
// Current row, and current col, tracked by Move/AddCh only
int ccol, crow;
@@ -57,15 +57,18 @@ namespace Terminal.Gui {
crow = row;
if (Clip.Contains (col, row)) {
Console.CursorTop = row;
Console.CursorLeft = col;
needMove = false;
if (cols == Console.WindowWidth && rows == Console.WindowHeight) {
Console.SetCursorPosition (col, row);
needMove = false;
}
} else {
Console.CursorTop = Clip.Y;
Console.CursorLeft = Clip.X;
needMove = true;
if (cols == Console.WindowWidth && rows == Console.WindowHeight) {
if (Console.WindowHeight > 0) {
Console.SetCursorPosition (Clip.X, Clip.Y);
}
needMove = true;
}
}
}
public override void AddRune (Rune rune)
@@ -73,8 +76,9 @@ namespace Terminal.Gui {
rune = MakePrintable (rune);
if (Clip.Contains (ccol, crow)) {
if (needMove) {
//Console.CursorLeft = ccol;
//Console.CursorTop = crow;
if (cols == Console.WindowWidth && rows == Console.WindowHeight) {
Console.SetCursorPosition (ccol, crow);
}
needMove = false;
}
contents [crow, ccol, 0] = (int)(uint)rune;
@@ -102,7 +106,14 @@ namespace Terminal.Gui {
public override void End ()
{
Console.ResetColor ();
Console.Clear ();
Clear ();
}
void Clear ()
{
if (Rows > 0) {
Console.Clear ();
}
}
static Attribute MakeColor (ConsoleColor f, ConsoleColor b)
@@ -111,15 +122,16 @@ namespace Terminal.Gui {
return new Attribute () { value = ((((int)f) & 0xffff) << 16) | (((int)b) & 0xffff) };
}
public override void Init (Action terminalResized)
{
TerminalResized = terminalResized;
Console.TreatControlCAsInput = true;
Colors.TopLevel = new ColorScheme ();
Colors.Base = new ColorScheme ();
Colors.Dialog = new ColorScheme ();
Colors.Menu = new ColorScheme ();
Colors.Error = new ColorScheme ();
Clip = new Rect (0, 0, Cols, Rows);
Colors.TopLevel.Normal = MakeColor (ConsoleColor.Green, ConsoleColor.Black);
Colors.TopLevel.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkCyan);
@@ -151,7 +163,15 @@ namespace Terminal.Gui {
Colors.Error.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
Colors.Error.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Red);
Colors.Error.HotFocus = Colors.Error.HotNormal;
Console.Clear ();
Clear ();
}
void ResizeScreen ()
{
cols = Console.WindowWidth;
rows = Console.WindowHeight;
Clip = new Rect (0, 0, Cols, Rows);
top = Console.WindowTop;
}
public override Attribute MakeAttribute (Color fore, Color back)
@@ -176,31 +196,14 @@ namespace Terminal.Gui {
public override void UpdateScreen ()
{
int rows = Rows;
int cols = Cols;
Console.CursorTop = 0;
Console.CursorLeft = 0;
for (int row = 0; row < rows; row++) {
dirtyLine [row] = false;
for (int col = 0; col < cols; col++) {
contents [row, col, 2] = 0;
var color = contents [row, col, 1];
if (color != redrawColor)
SetColor (color);
Console.Write ((char)contents [row, col, 0]);
}
if (Rows == 0) {
return;
}
}
public override void Refresh ()
{
int rows = Rows;
int cols = Cols;
var savedRow = Console.CursorTop;
var savedCol = Console.CursorLeft;
for (int row = 0; row < rows; row++) {
for (int row = top; row < rows; row++) {
if (!dirtyLine [row])
continue;
dirtyLine [row] = false;
@@ -208,8 +211,9 @@ namespace Terminal.Gui {
if (contents [row, col, 2] != 1)
continue;
Console.CursorTop = row;
Console.CursorLeft = col;
if (Console.WindowHeight > 0) {
Console.SetCursorPosition (col, row);
}
for (; col < cols && contents [row, col, 2] == 1; col++) {
var color = contents [row, col, 1];
if (color != redrawColor)
@@ -220,13 +224,29 @@ namespace Terminal.Gui {
}
}
}
Console.CursorTop = savedRow;
Console.CursorLeft = savedCol;
UpdateCursor ();
}
public override void Refresh ()
{
if (Console.WindowWidth != Cols || Console.WindowHeight != Rows || Console.WindowTop != Top) {
ResizeScreen ();
UpdateOffscreen ();
TerminalResized.Invoke ();
}
UpdateScreen ();
}
public override void UpdateCursor ()
{
//
// Prevents the exception of size changing during resizing.
try {
if (ccol > 0 && ccol < Console.WindowWidth && crow > 0 && crow < Console.WindowHeight) {
Console.SetCursorPosition (ccol, crow);
}
} catch (ArgumentOutOfRangeException) { }
}
public override void StartReportingMouseMoves ()
@@ -249,6 +269,7 @@ namespace Terminal.Gui {
Key MapKey (ConsoleKeyInfo keyInfo)
{
MapKeyModifiers (keyInfo);
switch (keyInfo.Key) {
case ConsoleKey.Escape:
return Key.Esc;
@@ -298,42 +319,75 @@ namespace Terminal.Gui {
var key = keyInfo.Key;
if (key >= ConsoleKey.A && key <= ConsoleKey.Z) {
var delta = key - ConsoleKey.A;
if (keyInfo.Modifiers == ConsoleModifiers.Control)
return (Key)((uint)Key.A + delta);
if (keyInfo.Modifiers == ConsoleModifiers.Alt)
if (keyInfo.Modifiers == ConsoleModifiers.Control) {
return (Key)(((uint)Key.CtrlMask) | ((uint)Key.A + delta));
}
if (keyInfo.Modifiers == ConsoleModifiers.Alt) {
return (Key)(((uint)Key.AltMask) | ((uint)Key.A + delta));
if (keyInfo.Modifiers == ConsoleModifiers.Shift)
return (Key)((uint)Key.A + delta);
else
return (Key)((uint)'a' + delta);
}
if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
if (keyInfo.KeyChar == 0 || (keyInfo.KeyChar != 0 && keyInfo.KeyChar >= 1 && keyInfo.KeyChar <= 26)) {
return (Key)((uint)Key.A + delta);
}
}
return (Key)((uint)keyInfo.KeyChar);
}
if (key >= ConsoleKey.D0 && key <= ConsoleKey.D9) {
var delta = key - ConsoleKey.D0;
if (keyInfo.Modifiers == ConsoleModifiers.Alt)
if (keyInfo.Modifiers == ConsoleModifiers.Alt) {
return (Key)(((uint)Key.AltMask) | ((uint)Key.D0 + delta));
if (keyInfo.Modifiers == ConsoleModifiers.Shift)
return (Key)((uint)keyInfo.KeyChar);
return (Key)((uint)Key.D0 + delta);
}
if (keyInfo.Modifiers == ConsoleModifiers.Control) {
return (Key)(((uint)Key.CtrlMask) | ((uint)Key.D0 + delta));
}
if ((keyInfo.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
if (keyInfo.KeyChar == 0 || keyInfo.KeyChar == 30) {
return (Key)((uint)Key.D0 + delta);
}
}
return (Key)((uint)keyInfo.KeyChar);
}
if (key >= ConsoleKey.F1 && key <= ConsoleKey.F10) {
if (key >= ConsoleKey.F1 && key <= ConsoleKey.F12) {
var delta = key - ConsoleKey.F1;
if ((keyInfo.Modifiers & (ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0) {
return (Key)((uint)Key.F1 + delta);
}
return (Key)((int)Key.F1 + delta);
return (Key)((uint)Key.F1 + delta);
}
if (keyInfo.KeyChar != 0) {
return (Key)((uint)keyInfo.KeyChar);
}
return (Key)(0xffffffff);
}
KeyModifiers keyModifiers = new KeyModifiers ();
KeyModifiers keyModifiers;
void MapKeyModifiers (ConsoleKeyInfo keyInfo)
{
if (keyModifiers == null)
keyModifiers = new KeyModifiers ();
if ((keyInfo.Modifiers & ConsoleModifiers.Shift) != 0)
keyModifiers.Shift = true;
if ((keyInfo.Modifiers & ConsoleModifiers.Control) != 0)
keyModifiers.Ctrl = true;
if ((keyInfo.Modifiers & ConsoleModifiers.Alt) != 0)
keyModifiers.Alt = true;
}
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
{
// Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
(mainLoop.Driver as NetMainLoop).KeyPressed = delegate (ConsoleKeyInfo consoleKey) {
var map = MapKey (consoleKey);
if (map == (Key)0xffffffff)
if (map == (Key)0xffffffff) {
return;
}
keyHandler (new KeyEvent (map, keyModifiers));
keyUpHandler (new KeyEvent (map, keyModifiers));
keyModifiers = null;
};
}
@@ -368,14 +422,17 @@ namespace Terminal.Gui {
/// file descriptor monitoring.
/// </summary>
/// <remarks>
/// This implementation is used for both NetDriver and FakeDriver.
/// This implementation is used for NetDriver.
/// </remarks>
public class NetMainLoop : IMainLoopDriver {
AutoResetEvent keyReady = new AutoResetEvent (false);
AutoResetEvent waitForProbe = new AutoResetEvent (false);
ManualResetEventSlim keyReady = new ManualResetEventSlim (false);
ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false);
ManualResetEventSlim winChange = new ManualResetEventSlim (false);
ConsoleKeyInfo? keyResult = null;
MainLoop mainLoop;
Func<ConsoleKeyInfo> consoleKeyReaderFn = null;
ConsoleDriver consoleDriver;
bool winChanged;
CancellationTokenSource tokenSource = new CancellationTokenSource ();
/// <summary>
/// Invoked when a Key is pressed.
@@ -383,66 +440,126 @@ namespace Terminal.Gui {
public Action<ConsoleKeyInfo> KeyPressed;
/// <summary>
/// Initializes the class.
/// Initializes the class with the console driver.
/// </summary>
/// <remarks>
/// Passing a consoleKeyReaderfn is provided to support unit test sceanrios.
/// Passing a consoleDriver is provided to capture windows resizing.
/// </remarks>
/// <param name="consoleKeyReaderFn">The method to be called to get a key from the console.</param>
public NetMainLoop (Func<ConsoleKeyInfo> consoleKeyReaderFn = null)
/// <param name="consoleDriver">The console driver used by this Net main loop.</param>
public NetMainLoop (ConsoleDriver consoleDriver = null)
{
if (consoleKeyReaderFn == null) {
throw new ArgumentNullException ("key reader function must be provided.");
if (consoleDriver == null) {
throw new ArgumentNullException ("console driver instance must be provided.");
}
this.consoleKeyReaderFn = consoleKeyReaderFn;
this.consoleDriver = consoleDriver;
}
void WindowsKeyReader ()
void KeyReader ()
{
while (true) {
waitForProbe.WaitOne ();
keyResult = consoleKeyReaderFn();
waitForProbe.Wait ();
waitForProbe.Reset ();
keyResult = Console.ReadKey (true);
keyReady.Set ();
}
}
void CheckWinChange ()
{
while (true) {
winChange.Wait ();
winChange.Reset ();
WaitWinChange ();
winChanged = true;
keyReady.Set ();
}
}
void WaitWinChange ()
{
while (true) {
if (Console.WindowWidth != consoleDriver.Cols || Console.WindowHeight != consoleDriver.Rows
|| Console.WindowTop != consoleDriver.Top) { // Top only working on Windows.
return;
}
}
}
void IMainLoopDriver.Setup (MainLoop mainLoop)
{
this.mainLoop = mainLoop;
Thread readThread = new Thread (WindowsKeyReader);
readThread.Start ();
Task.Run (KeyReader);
Task.Run (CheckWinChange);
}
void IMainLoopDriver.Wakeup ()
{
keyReady.Set ();
}
bool IMainLoopDriver.EventsPending (bool wait)
{
long now = DateTime.UtcNow.Ticks;
int waitTimeout;
waitForProbe.Set ();
winChange.Set ();
if (CheckTimers (wait, out var waitTimeout)) {
return true;
}
try {
if (!tokenSource.IsCancellationRequested) {
keyReady.Wait (waitTimeout, tokenSource.Token);
}
} catch (OperationCanceledException) {
return true;
} finally {
keyReady.Reset ();
}
if (!tokenSource.IsCancellationRequested) {
return keyResult.HasValue || CheckTimers (wait, out _) || winChanged;
}
tokenSource.Dispose ();
tokenSource = new CancellationTokenSource ();
return true;
}
bool CheckTimers (bool wait, out int waitTimeout)
{
long now = DateTime.UtcNow.Ticks;
if (mainLoop.timeouts.Count > 0) {
waitTimeout = (int)((mainLoop.timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond);
if (waitTimeout < 0)
return true;
} else
} else {
waitTimeout = -1;
}
if (!wait)
waitTimeout = 0;
keyResult = null;
waitForProbe.Set ();
keyReady.WaitOne (waitTimeout);
return keyResult.HasValue;
int ic;
lock (mainLoop.idleHandlers) {
ic = mainLoop.idleHandlers.Count;
}
return ic > 0;
}
void IMainLoopDriver.MainIteration ()
{
if (keyResult.HasValue) {
KeyPressed?.Invoke (keyResult.Value);
var kr = keyResult;
keyResult = null;
KeyPressed?.Invoke (kr.Value);
}
if (winChanged) {
winChanged = false;
consoleDriver.Refresh ();
}
}
}

View File

@@ -510,6 +510,7 @@ namespace Terminal.Gui {
public override int Cols => cols;
public override int Rows => rows;
public override int Top => 0;
public WindowsDriver ()
{

View File

@@ -190,8 +190,8 @@ namespace Terminal.Gui {
if (Driver == null) {
var p = Environment.OSVersion.Platform;
if (UseSystemConsole) {
mainLoopDriver = new NetMainLoop (() => Console.ReadKey (true));
Driver = new NetDriver ();
mainLoopDriver = new NetMainLoop (Driver);
} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
var windowsDriver = new WindowsDriver ();
mainLoopDriver = windowsDriver;

View File

@@ -541,6 +541,11 @@ namespace Terminal.Gui {
/// The current number of rows in the terminal.
/// </summary>
public abstract int Rows { get; }
/// <summary>
/// The current top in the terminal.
/// </summary>
public abstract int Top { get; }
/// <summary>
/// Initializes the driver
/// </summary>

View File

@@ -1095,6 +1095,10 @@ namespace Terminal.Gui {
/// <param name="row">Row.</param>
public void Move (int col, int row)
{
if (Driver.Rows == 0) {
return;
}
ViewToScreen (col, row, out var rcol, out var rrow);
Driver.Move (rcol, rrow);
}

View File

@@ -127,6 +127,7 @@ namespace UICatalog {
await Task.Delay (3000);
LogJob ("Returning from task method");
await _itemsList.SetSourceAsync (items);
_itemsList.SetNeedsDisplay ();
}
private CancellationTokenSource cancellationTokenSource;

View File

@@ -28,7 +28,7 @@ namespace Terminal.Gui {
Assert.Null (Application.MainLoop);
Assert.Null (Application.Driver);
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
Assert.NotNull (Application.Current);
Assert.NotNull (Application.CurrentView);
Assert.NotNull (Application.Top);
@@ -66,7 +66,7 @@ namespace Terminal.Gui {
void Init ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey(true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
Assert.NotNull (Application.Driver);
Assert.NotNull (Application.MainLoop);
}

View File

@@ -11,7 +11,7 @@ namespace Terminal.Gui {
public void Init_Inits ()
{
var driver = new FakeDriver ();
Application.Init (driver, new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
driver.Init (() => { });
Assert.Equal (80, Console.BufferWidth);
@@ -27,7 +27,7 @@ namespace Terminal.Gui {
public void End_Cleans_Up ()
{
var driver = new FakeDriver ();
Application.Init (driver, new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
driver.Init (() => { });
FakeConsole.ForegroundColor = ConsoleColor.Red;
@@ -50,7 +50,7 @@ namespace Terminal.Gui {
public void SetColors_Changes_Colors ()
{
var driver = new FakeDriver ();
Application.Init (driver, new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (driver, new FakeMainLoop (() => FakeConsole.ReadKey (true)));
driver.Init (() => { });
Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);

View File

@@ -247,7 +247,7 @@ namespace Terminal.Gui {
[Fact]
public void Dim_Validation_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
@@ -279,7 +279,7 @@ namespace Terminal.Gui {
[Fact]
public void Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Null ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
@@ -300,7 +300,7 @@ namespace Terminal.Gui {
[Fact]
public void Dim_Validation_Do_Not_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
@@ -333,7 +333,7 @@ namespace Terminal.Gui {
{
// Testing with the Button because it properly handles the Dim class.
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;

View File

@@ -18,7 +18,7 @@ namespace Terminal.Gui {
[Fact]
public void Constructor_Setups_Driver ()
{
var ml = new MainLoop (new NetMainLoop(() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
Assert.NotNull (ml.Driver);
}
@@ -26,7 +26,7 @@ namespace Terminal.Gui {
[Fact]
public void AddIdle_Adds_And_Removes ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
Func<bool> fnTrue = () => { return true; };
Func<bool> fnFalse = () => { return false; };
@@ -60,7 +60,7 @@ namespace Terminal.Gui {
[Fact]
public void AddIdle_Function_GetsCalled_OnIteration ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var functionCalled = 0;
Func<bool> fn = () => {
@@ -76,7 +76,7 @@ namespace Terminal.Gui {
[Fact]
public void RemoveIdle_Function_NotCalled ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var functionCalled = 0;
Func<bool> fn = () => {
@@ -93,7 +93,7 @@ namespace Terminal.Gui {
[Fact]
public void AddThenRemoveIdle_Function_NotCalled ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var functionCalled = 0;
Func<bool> fn = () => {
@@ -111,7 +111,7 @@ namespace Terminal.Gui {
[Fact]
public void AddTwice_Function_CalledTwice ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var functionCalled = 0;
Func<bool> fn = () => {
@@ -139,7 +139,7 @@ namespace Terminal.Gui {
[Fact]
public void False_Idle_Stops_It_Being_Called_Again ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var functionCalled = 0;
Func<bool> fn1 = () => {
@@ -172,7 +172,7 @@ namespace Terminal.Gui {
[Fact]
public void AddIdle_Twice_Returns_False_Called_Twice ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var functionCalled = 0;
Func<bool> fn1 = () => {
@@ -204,7 +204,7 @@ namespace Terminal.Gui {
[Fact]
public void Run_Runs_Idle_Stop_Stops_Idle ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var functionCalled = 0;
Func<bool> fn = () => {
@@ -226,7 +226,7 @@ namespace Terminal.Gui {
[Fact]
public void AddTimer_Adds_Removes_NoFaults ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var ms = 100;
var callbackCount = 0;
@@ -246,7 +246,7 @@ namespace Terminal.Gui {
[Fact]
public void AddTimer_Run_Called ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var ms = 100;
var callbackCount = 0;
@@ -274,7 +274,7 @@ namespace Terminal.Gui {
[Fact]
public void AddTimer_Run_CalledAtApproximatelyRightTime ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var ms = TimeSpan.FromMilliseconds (50);
var watch = new System.Diagnostics.Stopwatch ();
@@ -300,7 +300,7 @@ namespace Terminal.Gui {
[Fact]
public void AddTimer_Run_CalledTwiceApproximatelyRightTime ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var ms = TimeSpan.FromMilliseconds (50);
var watch = new System.Diagnostics.Stopwatch ();
@@ -328,7 +328,7 @@ namespace Terminal.Gui {
[Fact]
public void AddTimer_Remove_NotCalled ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var ms = TimeSpan.FromMilliseconds (50);
// Force stop if 10 iterations
@@ -357,7 +357,7 @@ namespace Terminal.Gui {
[Fact]
public void AddTimer_ReturnFalse_StopsBeingCalled ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var ms = TimeSpan.FromMilliseconds (50);
// Force stop if 10 iterations
@@ -390,7 +390,7 @@ namespace Terminal.Gui {
[Fact]
public void Invoke_Adds_Idle ()
{
var ml = new MainLoop (new NetMainLoop (() => FakeConsole.ReadKey (true)));
var ml = new MainLoop (new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var actionCalled = 0;
ml.Invoke (() => { actionCalled++; });

View File

@@ -262,7 +262,7 @@ namespace Terminal.Gui {
// Setup Fake driver
(Window win, Button button) setup ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
Application.Iteration = () => {
Application.RequestStop ();
};
@@ -374,7 +374,7 @@ namespace Terminal.Gui {
[Fact]
public void Pos_Validation_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
@@ -406,7 +406,7 @@ namespace Terminal.Gui {
[Fact]
public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Null ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
@@ -428,7 +428,7 @@ namespace Terminal.Gui {
[Fact]
public void Pos_Validation_Do_Not_Throws_If_NewValue_Is_PosAbsolute_And_OldValue_Is_Another_Type_After_Sets_To_LayoutStyle_Absolute ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;

View File

@@ -55,7 +55,7 @@ namespace Terminal.Gui {
Application.RequestStop ();
}
};
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var ms = 1000;
var abortCount = 0;
@@ -107,7 +107,7 @@ namespace Terminal.Gui {
Application.RequestStop ();
}
};
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var ms = 1000;
var abortCount = 0;

View File

@@ -544,7 +544,7 @@ namespace Terminal.Gui {
[Fact]
public void Initialized_Event_Comparing_With_Added_Event ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = new Toplevel () { Id = "0", };
@@ -643,7 +643,7 @@ namespace Terminal.Gui {
[Fact]
public void Initialized_Event_Will_Be_Invoked_When_Added_Dynamically ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = new Toplevel () { Id = "0", };
@@ -751,7 +751,7 @@ namespace Terminal.Gui {
[Fact]
public void CanFocus_Faced_With_Container_Before_Run ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
@@ -788,7 +788,7 @@ namespace Terminal.Gui {
[Fact]
public void CanFocus_Faced_With_Container_After_Run ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
@@ -831,7 +831,7 @@ namespace Terminal.Gui {
[Fact]
public void CanFocus_Container_ToFalse_Turns_All_Subviews_ToFalse_Too ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
@@ -866,7 +866,7 @@ namespace Terminal.Gui {
[Fact]
public void CanFocus_Container_Toggling_All_Subviews_To_Old_Value_When_Is_True ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
@@ -910,7 +910,7 @@ namespace Terminal.Gui {
{
// Non-regression test for #882 (NullReferenceException during keyboard navigation when Focused is null)
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
Application.Top.Ready += () => {
Assert.Null (Application.Top.Focused);
@@ -928,7 +928,7 @@ namespace Terminal.Gui {
[Fact]
public void Multi_Thread_Toplevels ()
{
Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
var t = Application.Top;
var w = new Window ();