diff options
author | Yurii H <gardenapple@posteo.net> | 2021-06-11 20:50:49 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-11 20:50:49 +0300 |
commit | 1a50864b48efeabad79232a3320db10bde7b96e3 (patch) | |
tree | a540ed377ac308a20ef1d48c1ff11ecf3ad02a84 | |
parent | 423b807f2d227ee7052f848bb0ca9029a8ff68f9 (diff) |
Allow manipulating console window size in Xterm (#20886)
Added implementations for `Console.SetWindowSize(int, int)`, `Console.SetBufferSize(int, int)` and associated properties. This is [based on Xterm control sequences](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Miscellaneous) which are supported by a lot of Linux terminals.
The previous API was very hit or miss - e.g. the method `Console.SetWindowSize(int, int)` just does absolutely nothing, while the setter for `Console.WindowWidth` always throws an exception.
The new implementation sends a control sequence if `TERM` starts with "xterm", otherwise throws an exception.
-rw-r--r-- | mcs/class/corlib/System/Console.cs | 12 | ||||
-rw-r--r-- | mcs/class/corlib/System/TermInfoDriver.cs | 59 |
2 files changed, 53 insertions, 18 deletions
diff --git a/mcs/class/corlib/System/Console.cs b/mcs/class/corlib/System/Console.cs index 0830e4ff079..551f5fcd46f 100644 --- a/mcs/class/corlib/System/Console.cs +++ b/mcs/class/corlib/System/Console.cs @@ -548,13 +548,13 @@ namespace System public static int BufferHeight { get { return ConsoleDriver.BufferHeight; } - [MonoLimitation ("Implemented only on Windows")] + [MonoLimitation ("Works only on Windows, or with some Xterm-based terminals")] set { ConsoleDriver.BufferHeight = value; } } public static int BufferWidth { get { return ConsoleDriver.BufferWidth; } - [MonoLimitation ("Implemented only on Windows")] + [MonoLimitation ("Works only on Windows, or with some Xterm-based terminals")] set { ConsoleDriver.BufferWidth = value; } } @@ -616,21 +616,25 @@ namespace System public static int WindowHeight { get { return ConsoleDriver.WindowHeight; } + [MonoLimitation ("Works only on Windows, or with some Xterm-based terminals")] set { ConsoleDriver.WindowHeight = value; } } public static int WindowLeft { get { return ConsoleDriver.WindowLeft; } + [MonoLimitation ("Works only on Windows")] set { ConsoleDriver.WindowLeft = value; } } public static int WindowTop { get { return ConsoleDriver.WindowTop; } + [MonoLimitation ("Works only on Windows")] set { ConsoleDriver.WindowTop = value; } } public static int WindowWidth { get { return ConsoleDriver.WindowWidth; } + [MonoLimitation ("Works only on Windows, or with some Xterm-based terminals")] set { ConsoleDriver.WindowWidth = value; } } @@ -704,7 +708,7 @@ namespace System ConsoleDriver.ResetColor (); } - [MonoLimitation ("Only works on windows")] + [MonoLimitation ("Works only on Windows, or with some Xterm-based terminals")] public static void SetBufferSize (int width, int height) { ConsoleDriver.SetBufferSize (width, height); @@ -715,11 +719,13 @@ namespace System ConsoleDriver.SetCursorPosition (left, top); } + [MonoLimitation ("Works only on Windows")] public static void SetWindowPosition (int left, int top) { ConsoleDriver.SetWindowPosition (left, top); } + [MonoLimitation ("Works only on Windows, or with some Xterm-based terminals")] public static void SetWindowSize (int width, int height) { ConsoleDriver.SetWindowSize (width, height); diff --git a/mcs/class/corlib/System/TermInfoDriver.cs b/mcs/class/corlib/System/TermInfoDriver.cs index c16b7367279..62a33b8e1cc 100644 --- a/mcs/class/corlib/System/TermInfoDriver.cs +++ b/mcs/class/corlib/System/TermInfoDriver.cs @@ -42,6 +42,7 @@ using System.Collections; using System.IO; using System.Text; +using System.Threading; using System.Runtime.InteropServices; namespace System { class TermInfoDriver : IConsoleDriver { @@ -524,7 +525,7 @@ namespace System { Init (); } - throw new NotSupportedException (); + SetBufferSize (BufferWidth, value); } } @@ -542,7 +543,7 @@ namespace System { Init (); } - throw new NotSupportedException (); + SetBufferSize (value, BufferHeight); } } @@ -716,6 +717,29 @@ namespace System { bufferWidth = windowWidth; } + // Should be called after init + // + // Only works on some Xterm-based terminals + void TrySetWindowDimensions (int width, int height) + { + if (width <= 0) + throw new ArgumentOutOfRangeException ("width", "Value must be higher than 0"); + if (height <= 0) + throw new ArgumentOutOfRangeException ("height", "Value must be highet than 0"); + + if (height == WindowHeight && width == WindowWidth) + return; + + if (term.StartsWith ("xterm")) { + WriteConsole ("\x1b[8;" + height.ToString () + ";" + width.ToString () + "t"); + + // Wait for window to get resized + Thread.Sleep (50); + } else { + throw new PlatformNotSupportedException ("Resizing can only work in xterm-based terminals"); + } + } + public int WindowHeight { get { @@ -731,7 +755,7 @@ namespace System { Init (); } - throw new NotSupportedException (); + SetWindowSize (WindowWidth, value); } } @@ -749,7 +773,10 @@ namespace System { Init (); } - throw new NotSupportedException (); + if (value == 0) + return; + + throw new ArgumentOutOfRangeException ("Unix terminals only support window position (0; 0)"); } } @@ -767,7 +794,10 @@ namespace System { Init (); } - throw new NotSupportedException (); + if (value == 0) + return; + + throw new ArgumentOutOfRangeException ("Unix terminals only support window position (0; 0)"); } } @@ -785,7 +815,7 @@ namespace System { Init (); } - throw new NotSupportedException (); + SetWindowSize (value, WindowHeight); } } @@ -817,7 +847,7 @@ namespace System { Init (); } - throw new NotImplementedException (); + throw new PlatformNotSupportedException ("Implemented only on Windows"); } void AddToBuffer (int b) @@ -1191,7 +1221,7 @@ namespace System { Init (); } - throw new NotImplementedException (String.Empty); + TrySetWindowDimensions (width, height); } public void SetCursorPosition (int left, int top) @@ -1202,15 +1232,15 @@ namespace System { CheckWindowDimensions (); if (left < 0 || left >= bufferWidth) - throw new ArgumentOutOfRangeException ("left", "Value must be positive and below the buffer width."); + throw new ArgumentOutOfRangeException ("left", left.ToString (), "Value must be positive and below the buffer width."); if (top < 0 || top >= bufferHeight) - throw new ArgumentOutOfRangeException ("top", "Value must be positive and below the buffer height."); + throw new ArgumentOutOfRangeException ("top", top.ToString (), "Value must be positive and below the buffer height."); // Either CursorAddress or nothing. // We might want to play with up/down/left/right/home when ca is not available. if (cursorAddress == null) - throw new NotSupportedException ("This terminal does not suport setting the cursor position."); + throw new IOException ("This terminal does not suport setting the cursor position."); WriteConsole (ParameterizedStrings.Evaluate (cursorAddress, top, left)); cursorLeft = left; @@ -1223,8 +1253,8 @@ namespace System { Init (); } - // No need to throw exceptions here. - //throw new NotSupportedException (); + if (left != 0 || top != 0) + throw new ArgumentOutOfRangeException ("Unix terminals only support window position (0; 0)"); } public void SetWindowSize (int width, int height) @@ -1233,8 +1263,7 @@ namespace System { Init (); } - // No need to throw exceptions here. - //throw new NotSupportedException (); + TrySetWindowDimensions (width, height); } |