diff --git a/src/.editorconfig b/src/.editorconfig index f4e60e34..b052bd0f 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -39,7 +39,7 @@ csharp_space_between_method_declaration_name_and_open_parenthesis = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_between_square_brackets = false -csharp_style_namespace_declarations = file_scoped:suggestion +csharp_style_namespace_declarations = block_scoped:suggestion csharp_style_var_for_built_in_types = false:suggestion csharp_using_directive_placement = outside_namespace:silent dotnet_diagnostic.bc40000.severity = warning diff --git a/src/Consolonia.Core/ApplicationStartup.cs b/src/Consolonia.Core/ApplicationStartup.cs index 824f446f..41fcb8a4 100644 --- a/src/Consolonia.Core/ApplicationStartup.cs +++ b/src/Consolonia.Core/ApplicationStartup.cs @@ -68,7 +68,7 @@ public static ClassicDesktopStyleApplicationLifetime BuildLifetime(IConsol private static ClassicDesktopStyleApplicationLifetime CreateLifetime(T builder, string[] args) where T : AppBuilderBase, new() { - var lifetime = new ClassicDesktopStyleApplicationLifetime + var lifetime = new ConsoloniaLifetime { Args = args, ShutdownMode = ShutdownMode.OnMainWindowClose diff --git a/src/Consolonia.Core/Infrastructure/ConsoleWindow.cs b/src/Consolonia.Core/Infrastructure/ConsoleWindow.cs index 1900798c..d3c49aed 100644 --- a/src/Consolonia.Core/Infrastructure/ConsoleWindow.cs +++ b/src/Consolonia.Core/Infrastructure/ConsoleWindow.cs @@ -15,8 +15,8 @@ namespace Consolonia.Core.Infrastructure { internal class ConsoleWindow : IWindowImpl { - [NotNull] private readonly IConsole _console; private readonly IKeyboardDevice _myKeyboardDevice; + [NotNull] internal readonly IConsole Console; internal readonly List InvalidatedRects = new(50); private IInputRoot _inputRoot; @@ -24,21 +24,21 @@ public ConsoleWindow() { _myKeyboardDevice = AvaloniaLocator.Current.GetService(); MouseDevice = AvaloniaLocator.Current.GetService(); - _console = AvaloniaLocator.Current.GetService() ?? throw new NotImplementedException(); - _console.Resized += OnConsoleOnResized; - _console.KeyEvent += ConsoleOnKeyEvent; - _console.MouseEvent += ConsoleOnMouseEvent; - _console.FocusEvent += ConsoleOnFocusEvent; + Console = AvaloniaLocator.Current.GetService() ?? throw new NotImplementedException(); + Console.Resized += OnConsoleOnResized; + Console.KeyEvent += ConsoleOnKeyEvent; + Console.MouseEvent += ConsoleOnMouseEvent; + Console.FocusEvent += ConsoleOnFocusEvent; } public void Dispose() { Closed?.Invoke(); - _console.Resized -= OnConsoleOnResized; - _console.KeyEvent -= ConsoleOnKeyEvent; - _console.MouseEvent -= ConsoleOnMouseEvent; - _console.FocusEvent -= ConsoleOnFocusEvent; - _console.Dispose(); + Console.Resized -= OnConsoleOnResized; + Console.KeyEvent -= ConsoleOnKeyEvent; + Console.MouseEvent -= ConsoleOnMouseEvent; + Console.FocusEvent -= ConsoleOnFocusEvent; + Console.Dispose(); } public IRenderer CreateRenderer(IRenderRoot root) @@ -114,7 +114,7 @@ public Size ClientSize { get { - PixelBufferSize pixelBufferSize = _console.Size; + PixelBufferSize pixelBufferSize = Console.Size; return new Size(pixelBufferSize.Width, pixelBufferSize.Height); } } @@ -181,7 +181,7 @@ public void SetTopmost(bool value) public void SetTitle(string title) { - _console.SetTitle(title); + Console.SetTitle(title); } public void SetParent(IWindowImpl parent) @@ -316,7 +316,7 @@ private void OnConsoleOnResized() { Dispatcher.UIThread.Post(() => { - PixelBufferSize pixelBufferSize = _console.Size; + PixelBufferSize pixelBufferSize = Console.Size; var size = new Size(pixelBufferSize.Width, pixelBufferSize.Height); Resized(size, PlatformResizeReason.Unspecified); //todo; Invalidate(new Rect(size)); diff --git a/src/Consolonia.Core/Infrastructure/ConsoloniaLifetime.cs b/src/Consolonia.Core/Infrastructure/ConsoloniaLifetime.cs new file mode 100644 index 00000000..a4b800c0 --- /dev/null +++ b/src/Consolonia.Core/Infrastructure/ConsoloniaLifetime.cs @@ -0,0 +1,35 @@ +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Threading; + +namespace Consolonia.Core.Infrastructure +{ + public class ConsoloniaLifetime : ClassicDesktopStyleApplicationLifetime + { + /// + /// returned task indicates that console is successfully paused + /// + public Task DisconnectFromConsoleAsync(CancellationToken cancellationToken) + { + var taskToWaitFor = new TaskCompletionSource(); + cancellationToken.Register(() => taskToWaitFor.SetResult()); + + var mainWindowPlatformImpl = (ConsoleWindow)MainWindow.PlatformImpl; + IConsole console = mainWindowPlatformImpl.Console; + + Task pauseTask = taskToWaitFor.Task; + + console.PauseIO(pauseTask); + + pauseTask.ContinueWith(_ => + { + mainWindowPlatformImpl.Console.ClearOutput(); + + Dispatcher.UIThread.Post(() => { MainWindow.InvalidateVisual(); }); + }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); + + return Dispatcher.UIThread.InvokeAsync(() => { }); + } + } +} \ No newline at end of file diff --git a/src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs b/src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs index ba9f245d..47cf878a 100644 --- a/src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs +++ b/src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Threading; +using System.Threading.Tasks; using Avalonia.Input; using Consolonia.Core.InternalHelpers; @@ -49,13 +51,32 @@ protected override void Dispose(bool disposing) RaiseFocusEvent(false); } + public override void PauseIO(Task task) + { + base.PauseIO(task); + + TextReader defaultIn = Console.In; + Console.SetIn(new StringReader(string.Empty)); + Console.SetIn(defaultIn); + } + private void StartInputReading() { ThreadPool.QueueUserWorkItem(_ => { while (!Disposed) { - ConsoleKeyInfo consoleKeyInfo = Console.ReadKey(true); + PauseTask?.Wait(); + + ConsoleKeyInfo consoleKeyInfo; + try + { + consoleKeyInfo = Console.ReadKey(true); + } + catch (InvalidOperationException) + { + continue; + } Key key = ConvertToKey(consoleKeyInfo.Key); diff --git a/src/Consolonia.Core/Infrastructure/IConsole.cs b/src/Consolonia.Core/Infrastructure/IConsole.cs index beb16511..48a477e5 100644 --- a/src/Consolonia.Core/Infrastructure/IConsole.cs +++ b/src/Consolonia.Core/Infrastructure/IConsole.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Avalonia; using Avalonia.Input; using Avalonia.Input.Raw; @@ -27,5 +28,7 @@ void Print(PixelBufferCoordinate bufferPoint, ConsoleColor backgroundColor, Cons event Action MouseEvent; event Action FocusEvent; + void PauseIO(Task task); + void ClearOutput(); } } \ No newline at end of file diff --git a/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs b/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs index 91a4a4d0..7f114fc3 100644 --- a/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs +++ b/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs @@ -20,11 +20,13 @@ public class InputLessDefaultNetConsole : IConsole protected InputLessDefaultNetConsole() { Console.CursorVisible = false; - ActualizeTheSize(); + ActualizeSize(); } protected bool Disposed { get; private set; } + protected Task PauseTask { get; private set; } + public bool CaretVisible { get => _caretVisible; @@ -67,6 +69,7 @@ public PixelBufferCoordinate GetCaretPosition() public void Print(PixelBufferCoordinate bufferPoint, ConsoleColor backgroundColor, ConsoleColor foregroundColor, string str) { + PauseTask?.Wait(); SetCaretPosition(bufferPoint); if (_headBackground != backgroundColor) @@ -103,23 +106,35 @@ public void Print(PixelBufferCoordinate bufferPoint, ConsoleColor backgroundColo public event Action MouseEvent; public event Action FocusEvent; + public virtual void PauseIO(Task task) + { + task.ContinueWith(_ => { PauseTask = null; }, TaskScheduler.Default); + PauseTask = task; + } + public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } + public void ClearOutput() + { + // this is hack, but somehow it does not work when just calling ActualizeSize with same size + Size = new PixelBufferSize(1, 1); + Resized?.Invoke(); + } + // ReSharper disable once MemberCanBePrivate.Global protected bool CheckActualizeTheSize() { if (Size.Width == Console.WindowWidth && Size.Height == Console.WindowHeight) return false; - ActualizeTheSize(); + ActualizeSize(); return true; } - protected void ActualizeTheSize() + protected void ActualizeSize() { - Console.Clear(); Size = new PixelBufferSize((ushort)Console.WindowWidth, (ushort)Console.WindowHeight); Resized?.Invoke(); } @@ -151,6 +166,10 @@ protected void StartSizeCheckTimerAsync(uint slowInterval = 1500) { while (!Disposed) { + Task pauseTask = PauseTask; + if (pauseTask != null) + await pauseTask.ConfigureAwait(false); + int timeout = (int)(CheckActualizeTheSize() ? 1 : slowInterval); await Task.Delay(timeout).ConfigureAwait(false); } diff --git a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryAnimatedLines.axaml b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryAnimatedLines.axaml index 0256ee82..b537afbb 100644 --- a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryAnimatedLines.axaml +++ b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryAnimatedLines.axaml @@ -7,129 +7,135 @@ d:DesignWidth="800" d:DesignHeight="450" x:Class="Consolonia.Gallery.Gallery.GalleryViews.GalleryAnimatedLines"> - - - - - - + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + +