Browse Source

Merge branch 'v2_develop' into v2_develop

Tig 1 year ago
parent
commit
5ef85b6cfb

+ 1 - 3
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -360,7 +360,6 @@ public abstract class ConsoleDriver {
 
 	#region Color Handling
 
-	
 	/// <summary>
 	/// Gets whether the <see cref="ConsoleDriver"/> supports TrueColor output.
 	/// </summary>
@@ -380,7 +379,6 @@ public abstract class ConsoleDriver {
 		get => _force16Colors || !SupportsTrueColor;
 		set {
 			_force16Colors = (value || !SupportsTrueColor);
-			Refresh ();
 		}
 	}
 
@@ -533,7 +531,7 @@ public abstract class ConsoleDriver {
 	/// Ends the execution of the console driver.
 	/// </summary>
 	public abstract void End ();
-	
+
 	/// <summary>
 	/// Returns the name of the driver and relevant library version information.
 	/// </summary>

+ 55 - 22
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -777,21 +777,11 @@ internal class WindowsDriver : ConsoleDriver {
 
 	public WindowsConsole WinConsole { get; private set; }
 
-	public override bool SupportsTrueColor => RunningUnitTests || (Environment.OSVersion.Version.Build >= 14931);
-
-	public override bool Force16Colors {
-		get => base.Force16Colors;
-		set {
-			base.Force16Colors = value;
-			// BUGBUG: This is a hack until we fully support VirtualTerminalSequences
-			if (WinConsole != null) {
-				WinConsole = new WindowsConsole ();
-			}
-			Refresh ();
-		}
-	}
+	public override bool SupportsTrueColor => RunningUnitTests || (Environment.OSVersion.Version.Build >= 14931
+		&& (_isWindowsTerminal || _parentProcessName == "devenv"));
 
 	readonly bool _isWindowsTerminal = false;
+	readonly string _parentProcessName = "WindowsTerminal";
 
 	public WindowsDriver ()
 	{
@@ -803,8 +793,52 @@ internal class WindowsDriver : ConsoleDriver {
 			Clipboard = new FakeDriver.FakeClipboard ();
 		}
 
-		_isWindowsTerminal = Environment.GetEnvironmentVariable ("WT_SESSION") != null;
+		if (!RunningUnitTests) {
+			_parentProcessName = GetParentProcessName ();
+			_isWindowsTerminal = _parentProcessName == "WindowsTerminal";
+			if (!_isWindowsTerminal && _parentProcessName != "devenv") {
+				Force16Colors = true;
+			}
+		}
+	}
 
+	private static string GetParentProcessName ()
+	{
+#pragma warning disable CA1416 // Validate platform compatibility
+		var myId = Process.GetCurrentProcess ().Id;
+		var query = string.Format ($"SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {myId}");
+		var search = new ManagementObjectSearcher ("root\\CIMV2", query);
+		var queryObj = search.Get ().OfType<ManagementBaseObject> ().FirstOrDefault ();
+		if (queryObj == null) {
+			return null;
+		}
+		var parentId = (uint)queryObj ["ParentProcessId"];
+		var parent = Process.GetProcessById ((int)parentId);
+		var prevParent = parent;
+
+		// Check if the parent is from other parent
+		while (queryObj != null) {
+			query = string.Format ($"SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {parentId}");
+			search = new ManagementObjectSearcher ("root\\CIMV2", query);
+			queryObj = search.Get ().OfType<ManagementBaseObject> ().FirstOrDefault ();
+			if (queryObj == null) {
+				return parent.ProcessName;
+			}
+			parentId = (uint)queryObj ["ParentProcessId"];
+			try {
+				parent = Process.GetProcessById ((int)parentId);
+				if (string.Equals (parent.ProcessName, "explorer", StringComparison.InvariantCultureIgnoreCase)) {
+					return prevParent.ProcessName;
+				}
+				prevParent = parent;
+			} catch (ArgumentException) {
+
+				return prevParent.ProcessName;
+			}
+		}
+
+		return parent.ProcessName;
+#pragma warning restore CA1416 // Validate platform compatibility
 	}
 
 	public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
@@ -1454,13 +1488,13 @@ internal class WindowsDriver : ConsoleDriver {
 		if (RunningUnitTests) {
 			return;
 		}
-		
+
 		try {
 			if (WinConsole != null) {
 				var winSize = WinConsole.GetConsoleOutputWindow (out Point pos);
 				Cols = winSize.Width;
 				Rows = winSize.Height;
-			} 
+			}
 			WindowsConsole.SmallRect.MakeEmpty (ref _damageRegion);
 
 			// Needed for Windows Terminal
@@ -1511,8 +1545,7 @@ internal class WindowsDriver : ConsoleDriver {
 
 		WinConsole?.ForceRefreshCursorVisibility ();
 	}
-	
-	
+
 	public override void UpdateScreen ()
 	{
 		var windowSize = WinConsole?.GetConsoleBufferWindow (out _) ?? new Size (Cols, Rows);
@@ -1709,9 +1742,9 @@ internal class WindowsDriver : ConsoleDriver {
 		WinConsole?.Cleanup ();
 		WinConsole = null;
 
-		if (!RunningUnitTests && _isWindowsTerminal) {
+		if (!RunningUnitTests && (_isWindowsTerminal || _parentProcessName == "devenv")) {
 			// Disable alternative screen buffer.
-			Console.Out.Write (EscSeqUtils.CSI_RestoreAltBufferWithBackscroll);
+			Console.Out.Write (EscSeqUtils.CSI_RestoreCursorAndActivateAltBufferWithBackscroll);
 		}
 	}
 
@@ -1797,8 +1830,8 @@ internal class WindowsMainLoop : IMainLoopDriver {
 		while (true) {
 			Task.Delay (500).Wait ();
 			_windowSize = _winConsole.GetConsoleBufferWindow (out _);
-			if (_windowSize != Size.Empty && _windowSize.Width != _consoleDriver.Cols
-			    || _windowSize.Height != _consoleDriver.Rows) {
+			if (_windowSize != Size.Empty && (_windowSize.Width != _consoleDriver.Cols
+			    || _windowSize.Height != _consoleDriver.Rows)) {
 				return;
 			}
 		}

+ 41 - 5
Terminal.Gui/Views/StatusBar.cs

@@ -27,11 +27,13 @@ namespace Terminal.Gui {
 		/// <param name="shortcut">Shortcut to activate the <see cref="StatusItem"/>.</param>
 		/// <param name="title">Title for the <see cref="StatusItem"/>.</param>
 		/// <param name="action">Action to invoke when the <see cref="StatusItem"/> is activated.</param>
-		public StatusItem (Key shortcut, string title, Action action)
+		/// <param name="canExecute">Function to determine if the action can currently be executed.</param>
+		public StatusItem (Key shortcut, string title, Action action, Func<bool> canExecute = null)
 		{
 			Title = title ?? "";
 			Shortcut = shortcut;
 			Action = action;
+			CanExecute = canExecute;
 		}
 
 		/// <summary>
@@ -54,7 +56,22 @@ namespace Terminal.Gui {
 		/// Gets or sets the action to be invoked when the statusbar item is triggered
 		/// </summary>
 		/// <value>Action to invoke.</value>
-		public Action Action { get; }
+		public Action Action { get; set; }
+
+		/// <summary>
+		/// Gets or sets the action to be invoked to determine if the <see cref="StatusItem"/> can be triggered. 
+		/// If <see cref="CanExecute"/> returns <see langword="true"/> the status item will be enabled. Otherwise, it will be disabled.
+		/// </summary>
+		/// <value>Function to determine if the action is can be executed or not.</value>
+		public Func<bool> CanExecute { get; set; }
+
+		/// <summary>
+		/// Returns <see langword="true"/> if the status item is enabled. This method is a wrapper around <see cref="CanExecute"/>.
+		/// </summary>
+		public bool IsEnabled ()
+		{
+			return CanExecute == null ? true : CanExecute ();
+		}
 
 		/// <summary>
 		/// Gets or sets arbitrary data for the status item.
@@ -116,6 +133,17 @@ namespace Terminal.Gui {
 			return result;
 		}
 
+		Attribute DetermineColorSchemeFor (StatusItem item)
+		{
+			if (item != null) {
+				if (item.IsEnabled ()) {
+					return GetNormalColor ();
+				}
+				return ColorScheme.Disabled;
+			}
+			return GetNormalColor ();
+		}
+
 		///<inheritdoc/>
 		public override void OnDrawContent (Rect contentArea)
 		{
@@ -130,9 +158,12 @@ namespace Terminal.Gui {
 			Driver.SetAttribute (scheme);
 			for (int i = 0; i < Items.Length; i++) {
 				var title = Items [i].Title;
+				Driver.SetAttribute (DetermineColorSchemeFor (Items [i]));
 				for (int n = 0; n < Items [i].Title.GetRuneCount (); n++) {
 					if (title [n] == '~') {
-						scheme = ToggleScheme (scheme);
+						if (Items [i].IsEnabled ()) {
+							scheme = ToggleScheme (scheme);
+						}
 						continue;
 					}
 					Driver.AddRune ((Rune)title [n]);
@@ -150,7 +181,9 @@ namespace Terminal.Gui {
 		{
 			foreach (var item in Items) {
 				if (kb.Key == item.Shortcut) {
-					Run (item.Action);
+					if (item.IsEnabled ()) {
+						Run (item.Action);
+					}
 					return true;
 				}
 			}
@@ -166,7 +199,10 @@ namespace Terminal.Gui {
 			int pos = 1;
 			for (int i = 0; i < Items.Length; i++) {
 				if (me.X >= pos && me.X < pos + GetItemTitleLength (Items [i].Title)) {
-					Run (Items [i].Action);
+					var item = Items [i];
+					if (item.IsEnabled ()) {
+						Run (item.Action);
+					}
 					break;
 				}
 				pos += GetItemTitleLength (Items [i].Title) + 3;

+ 39 - 1
UnitTests/Views/StatusBarTests.cs

@@ -23,7 +23,7 @@ namespace Terminal.Gui.ViewsTests {
 		}
 
 		[Fact]
-		public void StatusBar_Contructor_Default ()
+		public void StatusBar_Constructor_Default ()
 		{
 			var sb = new StatusBar ();
 
@@ -160,5 +160,43 @@ CTRL-O Open {CM.Glyphs.VLine} CTRL-Q Quit
 			Assert.Equal ("~^A~ Save As", sb.Items [1].Title);
 			Assert.Equal ("~^Q~ Quit", sb.Items [^1].Title);
 		}
+
+		[Fact, AutoInitShutdown]
+		public void CanExecute_ProcessHotKey ()
+		{
+			Window win = null;
+			var statusBar = new StatusBar (new StatusItem [] {
+				new StatusItem (Key.CtrlMask | Key.N, "~^N~ New", New, CanExecuteNew),
+				new StatusItem (Key.CtrlMask | Key.C, "~^C~ Close", Close, CanExecuteClose)
+			});
+			var top = Application.Top;
+			top.Add (statusBar);
+
+			bool CanExecuteNew () => win == null;
+
+			void New ()
+			{
+				win = new Window ();
+			}
+
+			bool CanExecuteClose () => win != null;
+
+			void Close ()
+			{
+				win = null;
+			}
+
+			Application.Begin (top);
+
+			Assert.Null (win);
+			Assert.True (CanExecuteNew ());
+			Assert.False (CanExecuteClose ());
+
+			Assert.True (top.ProcessHotKey (new KeyEvent (Key.N | Key.CtrlMask, new KeyModifiers () { Alt = true })));
+			Application.MainLoop.RunIteration ();
+			Assert.NotNull (win);
+			Assert.False (CanExecuteNew ());
+			Assert.True (CanExecuteClose ());
+		}
 	}
 }