2
0
Эх сурвалжийг харах

Fixes #1446. Added more features to the Border and Toplevel focus. (#1447)

* Fixes #1446. Added more features to the Border and Toplevel focus.

* Prevents throwing exception on negative effect3DOffset values

* Ensures that a view can be focused.

* Only sets focus if it isn't disposing.

* Fixes ViewToScreen and DrawChildBorder Effect3D.

* Unit test for negative coordinates with the ViewToScreen method.

* Added Tab navigation feature to the Editor scenario.

* ComboBox cursonDownKey nullref fix (#1472)

* added null guard to fix null ref when pressing keyDown inside combobox
Improved an error message when view cannot be found

* Added a unit test to ensure combobox can process all key events
Found and fixed a new nullref

* Found a new bug when source is already present and combobox is added to a top view

* searchSet is auto initialized to new List() now to make the code a little bit safer

* Fixes WindowsDriver HeightAsBuffer set to false. (#1466)

* Bump ReportGenerator from 4.8.12 to 4.8.13 (#1473)

Bumps [ReportGenerator](https://github.com/danielpalme/ReportGenerator) from 4.8.12 to 4.8.13.
- [Release notes](https://github.com/danielpalme/ReportGenerator/releases)
- [Commits](https://github.com/danielpalme/ReportGenerator/compare/v4.8.12...v4.8.13)

---
updated-dependencies:
- dependency-name: ReportGenerator
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fixes #1445. Fixing more the Curses and WSL clipboard. (#1448)

* Fixes #1445. Fixing more the Curses and WSL clipboard.

* Fixing unit tests.

* Changing namespace.

* Fixes WSL2 clipboard unit test.

* Upgrades devcontainer with the MainLoop fix.

* Fixes pasting with no selection and with lines break.

* Prevents the event button click being fired after a button pressed with mouse move.

* Fixes the char [ not being processed.

* Added Application.QuitKey property to allow change the quitting application key. (#1450)

* Added Application.QuitKey property to allow change the quitting application key.

* Fixes QuitKey unit test by reseting his value.

* Locks timeouts until is added.

* Fixes #1467. AlternateForward/BackwardKey bypasses dialog modality (#1468)

* Changed namespace.

* Fixing merge conflicts.

* Fixes mouse click issue.

* Removing windows resizing because buffer resizing is enough.

* Fixes #1477. Mouse click and console bottom on Windows Terminal.

Co-authored-by: Igor Bagdamyan <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
BDisp 3 жил өмнө
parent
commit
d55ae77331

+ 27 - 3
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -28,6 +28,9 @@ namespace Terminal.Gui {
 		CursorVisibility? initialCursorVisibility = null;
 		CursorVisibility? currentCursorVisibility = null;
 		IClipboard clipboard;
+		int [,,] contents;
+
+		internal override int [,,] Contents => contents;
 
 		// Current row, and current col, tracked by Move/AddRune only
 		int ccol, crow;
@@ -54,7 +57,11 @@ namespace Terminal.Gui {
 					Curses.move (crow, ccol);
 					needMove = false;
 				}
-				Curses.addch ((int)(uint)MakePrintable (rune));
+				rune = MakePrintable (rune);
+				Curses.addch ((int)(uint)rune);
+				contents [crow, ccol, 0] = (int)(uint)rune;
+				contents [crow, ccol, 1] = currentAttribute;
+				contents [crow, ccol, 2] = 1;
 			} else
 				needMove = true;
 			if (sync)
@@ -80,6 +87,7 @@ namespace Terminal.Gui {
 			Curses.refresh ();
 			if (Curses.CheckWinChange ()) {
 				Clip = new Rect (0, 0, Cols, Rows);
+				UpdateOffScreen ();
 				TerminalResized?.Invoke ();
 			}
 		}
@@ -765,6 +773,7 @@ namespace Terminal.Gui {
 			mLoop.WinChanged += () => {
 				if (Curses.CheckWinChange ()) {
 					Clip = new Rect (0, 0, Cols, Rows);
+					UpdateOffScreen ();
 					TerminalResized?.Invoke ();
 				}
 			};
@@ -854,6 +863,7 @@ namespace Terminal.Gui {
 			Colors.Menu = new ColorScheme ();
 			Colors.Error = new ColorScheme ();
 			Clip = new Rect (0, 0, Cols, Rows);
+			UpdateOffScreen ();
 			if (Curses.HasColors) {
 				Curses.StartColor ();
 				Curses.UseDefaultColors ();
@@ -867,7 +877,7 @@ namespace Terminal.Gui {
 				Colors.Base.Normal = MakeColor (Color.White, Color.Blue);
 				Colors.Base.Focus = MakeColor (Color.Black, Color.Gray);
 				Colors.Base.HotNormal = MakeColor (Color.Cyan, Color.Blue);
-				Colors.Base.HotFocus = MakeColor (Color.Blue, Color.Gray);
+				Colors.Base.HotFocus = MakeColor (Color.BrightBlue, Color.Gray);
 				Colors.Base.Disabled = MakeColor (Color.DarkGray, Color.Blue);
 
 				// Focused,
@@ -921,6 +931,21 @@ namespace Terminal.Gui {
 			}
 		}
 
+		void UpdateOffScreen ()
+		{
+			contents = new int [Rows, Cols, 3];
+			for (int row = 0; row < Rows; row++) {
+				for (int col = 0; col < Cols; col++) {
+					//Curses.move (row, col);
+					//Curses.attrset (Colors.TopLevel.Normal);
+					//Curses.addch ((int)(uint)' ');
+					contents [row, col, 0] = ' ';
+					contents [row, col, 1] = Colors.TopLevel.Normal;
+					contents [row, col, 2] = 0;
+				}
+			}
+		}
+
 		public static bool Is_WSL_Platform ()
 		{
 			var result = BashRunner.Run ("uname -a", runCurses: false);
@@ -1139,7 +1164,6 @@ namespace Terminal.Gui {
 				foreground = MapCursesColor ((value - (back << 12)) >> 8);
 			}
 			return hasColor;
-
 		}
 	}
 

+ 1 - 1
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -35,7 +35,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Assists with testing, the format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag
 		/// </summary>
-		public int [,,] Contents => contents;
+		internal override int [,,] Contents => contents;
 
 		void UpdateOffscreen ()
 		{

+ 1 - 0
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -1155,6 +1155,7 @@ namespace Terminal.Gui {
 		public bool IsWinPlatform { get; }
 		public bool AlwaysSetPosition { get; set; }
 		public override IClipboard Clipboard { get; }
+		internal override int [,,] Contents => contents;
 
 		int largestWindowHeight;
 

+ 30 - 15
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -209,7 +209,9 @@ namespace Terminal.Gui {
 			var csbi = new CONSOLE_SCREEN_BUFFER_INFOEX ();
 			csbi.cbSize = (uint)Marshal.SizeOf (csbi);
 			if (!GetConsoleScreenBufferInfoEx (ScreenBuffer, ref csbi)) {
-				throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
+				//throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
+				position = Point.Empty;
+				return Size.Empty;
 			}
 			var sz = new Size (csbi.srWindow.Right - csbi.srWindow.Left + 1,
 				csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
@@ -239,18 +241,22 @@ namespace Terminal.Gui {
 			if (!GetConsoleScreenBufferInfoEx (ScreenBuffer, ref csbi)) {
 				throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
 			}
-			csbi.dwSize = new Coord (cols, Math.Max (rows, (short)1));
-			csbi.srWindow = new SmallRect (0, 0, cols, rows);
-			csbi.dwMaximumWindowSize = new Coord (cols, rows);
+			var maxWinSize = GetLargestConsoleWindowSize (ScreenBuffer);
+			var newCols = Math.Min (cols, maxWinSize.X);
+			var 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 System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
 			}
-			var winRect = new SmallRect (0, 0, (short)(cols - 1), (short)Math.Max (rows - 1, 0));
+			var winRect = new SmallRect (0, 0, (short)(newCols - 1), (short)Math.Max (newRows - 1, 0));
 			if (!SetConsoleWindowInfo (ScreenBuffer, true, ref winRect)) {
-				throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
+				//throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
+				return new Size (cols, rows);
 			}
 			SetConsoleOutputWindow (csbi);
-			return new Size (winRect.Right + 1, rows - 1 < 0 ? 0 : winRect.Bottom + 1);
+			return new Size (winRect.Right + 1, newRows - 1 < 0 ? 0 : winRect.Bottom + 1);
 		}
 
 		void SetConsoleOutputWindow (CONSOLE_SCREEN_BUFFER_INFOEX csbi)
@@ -706,6 +712,10 @@ namespace Terminal.Gui {
 			IntPtr hConsoleOutput,
 			bool bAbsolute,
 			[In] ref SmallRect lpConsoleWindow);
+
+		[DllImport ("kernel32.dll", SetLastError = true)]
+		static extern Coord GetLargestConsoleWindowSize (
+			IntPtr hConsoleOutput);
 	}
 
 	internal class WindowsDriver : ConsoleDriver {
@@ -714,6 +724,7 @@ namespace Terminal.Gui {
 		int cols, rows, left, top;
 		WindowsConsole.SmallRect damageRegion;
 		IClipboard clipboard;
+		int [,,] contents;
 
 		public override int Cols => cols;
 		public override int Rows => rows;
@@ -721,6 +732,7 @@ namespace Terminal.Gui {
 		public override int Top => top;
 		public override bool HeightAsBuffer { get; set; }
 		public override IClipboard Clipboard => clipboard;
+		internal override int [,,] Contents => contents;
 
 		public WindowsConsole WinConsole { get; private set; }
 
@@ -735,8 +747,6 @@ namespace Terminal.Gui {
 			clipboard = new WindowsClipboard ();
 		}
 
-		bool winChanging;
-
 		public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
 		{
 			this.keyHandler = keyHandler;
@@ -755,7 +765,6 @@ namespace Terminal.Gui {
 
 		private void ChangeWin (Size e)
 		{
-			winChanging = true;
 			if (!HeightAsBuffer) {
 				var w = e.Width;
 				if (w == cols - 3 && e.Height < rows) {
@@ -769,9 +778,7 @@ namespace Terminal.Gui {
 				rows = newSize.Height;
 				ResizeScreen ();
 				UpdateOffScreen ();
-				if (!winChanging) {
-					TerminalResized.Invoke ();
-				}
+				TerminalResized.Invoke ();
 			}
 		}
 
@@ -1044,6 +1051,9 @@ namespace Terminal.Gui {
 				}
 				isButtonPressed = false;
 				isButtonReleased = true;
+				if (point.X == mouseEvent.MousePosition.X && point.Y == mouseEvent.MousePosition.Y) {
+					processButtonClick = true;
+				}
 			} else if (mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved
 				&& !isOneFingerDoubleClicked && isButtonReleased && p == point) {
 
@@ -1436,15 +1446,17 @@ namespace Terminal.Gui {
 
 		void UpdateOffScreen ()
 		{
+			contents = new int [rows, cols, 3];
 			for (int row = 0; row < rows; row++) {
 				for (int col = 0; col < cols; col++) {
 					int position = row * cols + col;
 					OutputBuffer [position].Attributes = (ushort)Colors.TopLevel.Normal;
 					OutputBuffer [position].Char.UnicodeChar = ' ';
+					contents [row, col, 0] = OutputBuffer [position].Char.UnicodeChar;
+					contents [row, col, 1] = OutputBuffer [position].Attributes;
+					contents [row, col, 2] = 0;
 				}
 			}
-
-			winChanging = false;
 		}
 
 		int ccol, crow;
@@ -1462,6 +1474,9 @@ namespace Terminal.Gui {
 			if (Clip.Contains (ccol, crow)) {
 				OutputBuffer [position].Attributes = (ushort)currentAttribute;
 				OutputBuffer [position].Char.UnicodeChar = (char)rune;
+				contents [crow, ccol, 0] = (int)(uint)rune;
+				contents [crow, ccol, 1] = currentAttribute;
+				contents [crow, ccol, 2] = 1;
 				WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow);
 			}
 

+ 20 - 5
Terminal.Gui/Core/Application.cs

@@ -480,12 +480,11 @@ namespace Terminal.Gui {
 
 		static View FindTopFromView (View view)
 		{
-			View top = view?.SuperView != null ? view.SuperView : view;
+			View top = view?.SuperView != null && view?.SuperView != Top
+				? view.SuperView : view;
 
-			while (top?.SuperView != null) {
-				if (top?.SuperView != null) {
-					top = top.SuperView;
-				}
+			while (top?.SuperView != null && top?.SuperView != Top) {
+				top = top.SuperView;
 			}
 			return top;
 		}
@@ -594,6 +593,8 @@ namespace Terminal.Gui {
 
 				// Should we bubbled up the event, if it is not handled?
 				view.OnMouseEvent (nme);
+
+				EnsuresTopOnFront ();
 			}
 		}
 
@@ -1235,5 +1236,19 @@ namespace Terminal.Gui {
 		{
 			MainLoop.Driver.Wakeup ();
 		}
+
+		/// <summary>
+		/// Ensures that the superview of the most focused view is on front.
+		/// </summary>
+		public static void EnsuresTopOnFront ()
+		{
+			if (MdiTop != null) {
+				return;
+			}
+			var top = FindTopFromView (Top?.MostFocused);
+			if (top != null && Top.Subviews.Count > 1 && Top.Subviews [Top.Subviews.Count - 1] != top) {
+				Top.BringSubviewToFront (top);
+			}
+		}
 	}
 }

+ 80 - 65
Terminal.Gui/Core/Border.cs

@@ -357,11 +357,12 @@ namespace Terminal.Gui {
 		/// </summary>
 		public int ActualWidth {
 			get {
+				var driver = Application.Driver;
 				if (Parent?.Border == null) {
-					return Child?.Frame.Width + (2 * marginFrame) + Padding.Right
-						+ BorderThickness.Right + Padding.Left + BorderThickness.Left ?? 0;
+					return Math.Min (Child?.Frame.Width + (2 * marginFrame) + Padding.Right
+						+ BorderThickness.Right + Padding.Left + BorderThickness.Left ?? 0, driver.Cols);
 				}
-				return Parent.Frame.Width;
+				return Math.Min (Parent.Frame.Width, driver.Cols);
 			}
 		}
 		/// <summary>
@@ -369,11 +370,12 @@ namespace Terminal.Gui {
 		/// </summary>
 		public int ActualHeight {
 			get {
+				var driver = Application.Driver;
 				if (Parent?.Border == null) {
-					return Child?.Frame.Height + (2 * marginFrame) + Padding.Bottom
-						+ BorderThickness.Bottom + Padding.Top + BorderThickness.Top ?? 0;
+					return Math.Min (Child?.Frame.Height + (2 * marginFrame) + Padding.Bottom
+						+ BorderThickness.Bottom + Padding.Top + BorderThickness.Top ?? 0, driver.Rows);
 				}
-				return Parent.Frame.Height;
+				return Math.Min (Parent.Frame.Height, driver.Rows);
 			}
 		}
 
@@ -405,7 +407,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Gets or sets the color for the <see cref="Border"/>
 		/// </summary>
-		public Color Effect3DBrush { get; set; } = Color.DarkGray;
+		public Attribute? Effect3DBrush { get; set; }
 
 		/// <summary>
 		/// Calculate the sum of the <see cref="Padding"/> and the <see cref="BorderThickness"/>
@@ -428,9 +430,9 @@ namespace Terminal.Gui {
 		public void DrawContent ()
 		{
 			if (Parent?.Border != null) {
-				DrawParentBorder (Parent.ViewToScreen (new Rect (0, 0, Parent.Frame.Width, Parent.Frame.Height)));
+				DrawParentBorder (Parent.ViewToScreen (Parent.Bounds));
 			} else {
-				DrawChildBorder (Child.ViewToScreen (new Rect (0, 0, Child.Frame.Width, Child.Frame.Height)));
+				DrawChildBorder (Child.ViewToScreen (Child.Bounds));
 			}
 		}
 
@@ -445,9 +447,9 @@ namespace Terminal.Gui {
 			var driver = Application.Driver;
 			Rect scrRect;
 			if (Parent?.Border != null) {
-				scrRect = Parent.ViewToScreen (new Rect (0, 0, Parent.Frame.Width, Parent.Frame.Height));
+				scrRect = Parent.ViewToScreen (Parent.Bounds);
 			} else {
-				scrRect = Child.ViewToScreen (new Rect (0, 0, Child.Frame.Width, Child.Frame.Height));
+				scrRect = Child.ViewToScreen (Child.Bounds);
 			}
 			Rect borderRect;
 			if (Parent?.Border != null) {
@@ -464,14 +466,21 @@ namespace Terminal.Gui {
 
 			// Draw 3D effects
 			if (Effect3D) {
-				driver.SetAttribute (new Attribute (Effect3DBrush));
+				driver.SetAttribute (GetEffect3DBrush ());
+
 				var effectBorder = new Rect () {
 					X = borderRect.X + Effect3DOffset.X,
 					Y = borderRect.Y + Effect3DOffset.Y,
 					Width = ActualWidth,
 					Height = ActualHeight
 				};
-				Child.Clear (effectBorder);
+				//Child.Clear (effectBorder);
+				for (int r = effectBorder.Y; r < Math.Min (effectBorder.Bottom, driver.Rows); r++) {
+					for (int c = effectBorder.X; c < Math.Min (effectBorder.Right, driver.Cols); c++) {
+
+						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
+					}
+				}
 			}
 
 			// Draw border thickness
@@ -530,7 +539,7 @@ namespace Terminal.Gui {
 			for (int r = frame.Y - drawMarginFrame - sumThickness.Top;
 				r < frame.Y - drawMarginFrame - padding.Top; r++) {
 				for (int c = frame.X - drawMarginFrame - sumThickness.Left;
-					c < frame.Right + drawMarginFrame + sumThickness.Right; c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -538,7 +547,7 @@ namespace Terminal.Gui {
 
 			// Draw the left BorderThickness
 			for (int r = frame.Y - drawMarginFrame - padding.Top;
-				r < frame.Bottom + drawMarginFrame + padding.Bottom; r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
 				for (int c = frame.X - drawMarginFrame - sumThickness.Left;
 					c < frame.X - drawMarginFrame - padding.Left; c++) {
 
@@ -548,9 +557,9 @@ namespace Terminal.Gui {
 
 			// Draw the right BorderThickness
 			for (int r = frame.Y - drawMarginFrame - padding.Top;
-				r < frame.Bottom + drawMarginFrame + padding.Bottom; r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
 				for (int c = frame.Right + drawMarginFrame + padding.Right;
-					c < frame.Right + drawMarginFrame + sumThickness.Right; c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -558,9 +567,9 @@ namespace Terminal.Gui {
 
 			// Draw the lower BorderThickness
 			for (int r = frame.Bottom + drawMarginFrame + padding.Bottom;
-				r < frame.Bottom + drawMarginFrame + sumThickness.Bottom; r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom, driver.Rows); r++) {
 				for (int c = frame.X - drawMarginFrame - sumThickness.Left;
-					c < frame.Right + drawMarginFrame + sumThickness.Right; c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -572,7 +581,7 @@ namespace Terminal.Gui {
 			for (int r = frame.Y - drawMarginFrame - padding.Top;
 				r < frame.Y - drawMarginFrame; r++) {
 				for (int c = frame.X - drawMarginFrame - padding.Left;
-					c < frame.Right + drawMarginFrame + padding.Right; c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -580,7 +589,7 @@ namespace Terminal.Gui {
 
 			// Draw the left Padding
 			for (int r = frame.Y - drawMarginFrame;
-				r < frame.Bottom + drawMarginFrame; r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
 				for (int c = frame.X - drawMarginFrame - padding.Left;
 					c < frame.X - drawMarginFrame; c++) {
 
@@ -590,9 +599,9 @@ namespace Terminal.Gui {
 
 			// Draw the right Padding
 			for (int r = frame.Y - drawMarginFrame;
-				r < frame.Bottom + drawMarginFrame; r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
 				for (int c = frame.Right + drawMarginFrame;
-					c < frame.Right + drawMarginFrame + padding.Right; c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -600,9 +609,9 @@ namespace Terminal.Gui {
 
 			// Draw the lower Padding
 			for (int r = frame.Bottom + drawMarginFrame;
-				r < frame.Bottom + drawMarginFrame + padding.Bottom; r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
 				for (int c = frame.X - drawMarginFrame - padding.Left;
-					c < frame.Right + drawMarginFrame + padding.Right; c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -622,45 +631,45 @@ namespace Terminal.Gui {
 			}
 
 			if (Effect3D) {
-				driver.SetAttribute (new Attribute (Effect3DBrush));
+				driver.SetAttribute (GetEffect3DBrush ());
 
 				// Draw the upper Effect3D
 				for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y;
 					r < frame.Y - drawMarginFrame - sumThickness.Top; r++) {
 					for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X;
-						c < frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X; c++) {
+						c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
 
-						AddRuneAt (driver, c, r, ' ');
+						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
 				}
 
 				// Draw the left Effect3D
 				for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y;
-					r < frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y; r++) {
+					r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X;
 						c < frame.X - drawMarginFrame - sumThickness.Left; c++) {
 
-						AddRuneAt (driver, c, r, ' ');
+						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
 				}
 
 				// Draw the right Effect3D
 				for (int r = frame.Y - drawMarginFrame - sumThickness.Top + effect3DOffset.Y;
-					r < frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y; r++) {
+					r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = frame.Right + drawMarginFrame + sumThickness.Right;
-						c < frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X; c++) {
+						c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
 
-						AddRuneAt (driver, c, r, ' ');
+						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
 				}
 
 				// Draw the lower Effect3D
 				for (int r = frame.Bottom + drawMarginFrame + sumThickness.Bottom;
-					r < frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y; r++) {
+					r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = frame.X - drawMarginFrame - sumThickness.Left + effect3DOffset.X;
-						c < frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X; c++) {
+						c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right + effect3DOffset.X, driver.Cols); c++) {
 
-						AddRuneAt (driver, c, r, ' ');
+						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
 				}
 			}
@@ -668,7 +677,6 @@ namespace Terminal.Gui {
 
 		private void DrawParentBorder (Rect frame)
 		{
-			var drawMarginFrame = DrawMarginFrame ? 1 : 0;
 			var sumThickness = GetSumThickness ();
 			var borderThickness = BorderThickness;
 			var effect3DOffset = Effect3DOffset;
@@ -682,7 +690,7 @@ namespace Terminal.Gui {
 			for (int r = frame.Y;
 				r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) {
 				for (int c = frame.X;
-					c < frame.Right; c++) {
+					c < Math.Min (frame.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -690,7 +698,7 @@ namespace Terminal.Gui {
 
 			// Draw the left BorderThickness
 			for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom);
-				r < frame.Bottom - borderThickness.Bottom; r++) {
+				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
 				for (int c = frame.X;
 					c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) {
 
@@ -700,9 +708,9 @@ namespace Terminal.Gui {
 
 			// Draw the right BorderThickness
 			for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom);
-				r < frame.Bottom - borderThickness.Bottom; r++) {
+				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
 				for (int c = Math.Max (frame.Right - borderThickness.Right, frame.X);
-					c < frame.Right; c++) {
+					c < Math.Min (frame.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -710,9 +718,9 @@ namespace Terminal.Gui {
 
 			// Draw the lower BorderThickness
 			for (int r = Math.Max (frame.Bottom - borderThickness.Bottom, frame.Y);
-				r < frame.Bottom; r++) {
+				r < Math.Min (frame.Bottom, driver.Rows); r++) {
 				for (int c = frame.X;
-					c < frame.Right; c++) {
+					c < Math.Min (frame.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -724,7 +732,7 @@ namespace Terminal.Gui {
 			for (int r = frame.Y + borderThickness.Top;
 				r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) {
 				for (int c = frame.X + borderThickness.Left;
-					c < frame.Right - borderThickness.Right; c++) {
+					c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -732,7 +740,7 @@ namespace Terminal.Gui {
 
 			// Draw the left Padding
 			for (int r = frame.Y + sumThickness.Top;
-				r < frame.Bottom - sumThickness.Bottom; r++) {
+				r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
 				for (int c = frame.X + borderThickness.Left;
 					c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) {
 
@@ -742,7 +750,7 @@ namespace Terminal.Gui {
 
 			// Draw the right Padding
 			for (int r = frame.Y + sumThickness.Top;
-				r < frame.Bottom - sumThickness.Bottom; r++) {
+				r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
 				for (int c = Math.Max (frame.Right - sumThickness.Right, frame.X + sumThickness.Left);
 					c < Math.Max (frame.Right - borderThickness.Right, frame.X + sumThickness.Left); c++) {
 
@@ -752,9 +760,9 @@ namespace Terminal.Gui {
 
 			// Draw the lower Padding
 			for (int r = Math.Max (frame.Bottom - sumThickness.Bottom, frame.Y + borderThickness.Top);
-				r < frame.Bottom - borderThickness.Bottom; r++) {
+				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
 				for (int c = frame.X + borderThickness.Left;
-					c < frame.Right - borderThickness.Right; c++) {
+					c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -774,50 +782,57 @@ namespace Terminal.Gui {
 			}
 
 			if (Effect3D) {
-				driver.SetAttribute (new Attribute (Effect3DBrush));
+				driver.SetAttribute (GetEffect3DBrush ());
 
 				// Draw the upper Effect3D
-				for (int r = frame.Y + effect3DOffset.Y;
+				for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0);
 					r < frame.Y; r++) {
-					for (int c = frame.X + effect3DOffset.X;
-						c < frame.Right + effect3DOffset.X; c++) {
+					for (int c = Math.Max (frame.X + effect3DOffset.X, 0);
+						c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
 
-						AddRuneAt (driver, c, r, ' ');
+						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
 				}
 
 				// Draw the left Effect3D
-				for (int r = frame.Y + effect3DOffset.Y;
-					r < frame.Bottom + effect3DOffset.Y; r++) {
-					for (int c = frame.X + effect3DOffset.X;
+				for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0);
+					r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+					for (int c = Math.Max (frame.X + effect3DOffset.X, 0);
 						c < frame.X; c++) {
 
-						AddRuneAt (driver, c, r, ' ');
+						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
 				}
 
 				// Draw the right Effect3D
-				for (int r = frame.Y + effect3DOffset.Y;
-					r < frame.Bottom + effect3DOffset.Y; r++) {
+				for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0);
+					r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = frame.Right;
-						c < frame.Right + effect3DOffset.X; c++) {
+						c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
 
-						AddRuneAt (driver, c, r, ' ');
+						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
 				}
 
 				// Draw the lower Effect3D
 				for (int r = frame.Bottom;
-					r < frame.Bottom + effect3DOffset.Y; r++) {
-					for (int c = frame.X + effect3DOffset.X;
-						c < frame.Right + effect3DOffset.X; c++) {
+					r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+					for (int c = Math.Max (frame.X + effect3DOffset.X, 0);
+						c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
 
-						AddRuneAt (driver, c, r, ' ');
+						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
 				}
 			}
 		}
 
+		private Attribute GetEffect3DBrush ()
+		{
+			return Effect3DBrush == null
+				? new Attribute (Color.Gray, Color.DarkGray)
+				: (Attribute)Effect3DBrush;
+		}
+
 		private void AddRuneAt (ConsoleDriver driver, int col, int row, Rune ch)
 		{
 			driver.Move (col, row);

+ 3 - 0
Terminal.Gui/Core/ConsoleDriver.cs

@@ -665,6 +665,9 @@ namespace Terminal.Gui {
 		/// </summary>
 		public abstract bool HeightAsBuffer { get; set; }
 
+		// The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag
+		internal abstract int [,,] Contents { get; }
+
 		/// <summary>
 		/// Initializes the driver
 		/// </summary>

+ 15 - 4
Terminal.Gui/Core/Toplevel.cs

@@ -213,7 +213,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// <value><c>true</c> if can focus; otherwise, <c>false</c>.</value>
 		public override bool CanFocus {
-			get => true;
+			get => SuperView == null ? true : base.CanFocus;
 		}
 
 		/// <summary>
@@ -348,6 +348,7 @@ namespace Terminal.Gui {
 						top.FocusNext ();
 					}
 					top.SetNeedsDisplay ();
+					Application.EnsuresTopOnFront ();
 				} else {
 					MoveNext ();
 				}
@@ -361,6 +362,7 @@ namespace Terminal.Gui {
 						top.FocusPrev ();
 					}
 					top.SetNeedsDisplay ();
+					Application.EnsuresTopOnFront ();
 				} else {
 					MovePrevious ();
 				}
@@ -656,16 +658,25 @@ namespace Terminal.Gui {
 			// Driver.UncookMouse does not seem to have an effect if there is
 			// a pending mouse event activated.
 
+			if (!CanFocus) {
+				return true;
+			}
+
 			int nx, ny;
-			if (!dragPosition.HasValue && mouseEvent.Flags == (MouseFlags.Button1Pressed)) {
+			if (!dragPosition.HasValue && (mouseEvent.Flags == MouseFlags.Button1Pressed
+				|| mouseEvent.Flags == MouseFlags.Button2Pressed
+				|| mouseEvent.Flags == MouseFlags.Button3Pressed)) {
+
+				SetFocus ();
+				Application.EnsuresTopOnFront ();
+
 				// Only start grabbing if the user clicks on the title bar.
-				if (mouseEvent.Y == 0) {
+				if (mouseEvent.Y == 0 && mouseEvent.Flags == MouseFlags.Button1Pressed) {
 					start = new Point (mouseEvent.X, mouseEvent.Y);
 					dragPosition = new Point ();
 					nx = mouseEvent.X - mouseEvent.OfX;
 					ny = mouseEvent.Y - mouseEvent.OfY;
 					dragPosition = new Point (nx, ny);
-					SuperView?.BringSubviewToFront (this);
 					Application.GrabMouse (this);
 				}
 

+ 12 - 7
Terminal.Gui/Core/View.cs

@@ -344,11 +344,6 @@ namespace Terminal.Gui {
 						TabIndex = SuperView != null ? SuperView.tabIndexes.IndexOf (this) : -1;
 					}
 					TabStop = value;
-					if (!value && HasFocus) {
-						SetHasFocus (false, this);
-					}
-					OnCanFocusChanged ();
-					SetNeedsDisplay ();
 				}
 				if (subviews != null && IsInitialized) {
 					foreach (var view in subviews) {
@@ -369,6 +364,16 @@ namespace Terminal.Gui {
 						}
 					}
 				}
+				if (!value && HasFocus) {
+					SetHasFocus (false, this);
+					EnsureFocus ();
+					if (Focused == null) {
+						Application.Top.FocusNext ();
+						Application.EnsuresTopOnFront ();
+					}
+				}
+				OnCanFocusChanged ();
+				SetNeedsDisplay ();
 			}
 		}
 
@@ -1013,8 +1018,8 @@ namespace Terminal.Gui {
 		internal void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
 		{
 			// Computes the real row, col relative to the screen.
-			rrow = Math.Max (row + frame.Y, 0);
-			rcol = Math.Max (col + frame.X, 0);
+			rrow = row + frame.Y;
+			rcol = col + frame.X;
 			var ccontainer = container;
 			while (ccontainer != null) {
 				rrow += ccontainer.frame.Y;

+ 4 - 1
Terminal.Gui/Core/Window.cs

@@ -159,6 +159,7 @@ namespace Terminal.Gui {
 
 		void Initialize (ustring title, Rect frame, int padding = 0, Border border = null)
 		{
+			CanFocus = true;
 			ColorScheme = Colors.Base;
 			Title = title;
 			if (border == null) {
@@ -235,13 +236,15 @@ namespace Terminal.Gui {
 			}
 
 			SetNeedsDisplay ();
-			var touched = view.Frame;
 			contentView.Remove (view);
 
 			if (contentView.InternalSubviews.Count < 1) {
 				CanFocus = false;
 			}
 			RemoveMenuStatusBar (view);
+			if (view != contentView && Focused == null) {
+				FocusFirst ();
+			}
 		}
 
 		/// <inheritdoc/>

+ 3 - 0
Terminal.Gui/Views/Label.cs

@@ -101,6 +101,9 @@ namespace Terminal.Gui {
 
 			if (mouseEvent.Flags == MouseFlags.Button1Clicked) {
 				if (!HasFocus && SuperView != null) {
+					if (!SuperView.HasFocus) {
+						SuperView.SetFocus ();
+					}
 					SetFocus ();
 					SetNeedsDisplay ();
 				}

+ 37 - 16
UICatalog/Scenarios/Editor.cs

@@ -23,6 +23,7 @@ namespace UICatalog {
 		private bool _matchCase;
 		private bool _matchWholeWord;
 		private Window winDialog;
+		private TabView _tabView;
 
 		public override void Init (Toplevel top, ColorScheme colorScheme)
 		{
@@ -97,7 +98,7 @@ namespace UICatalog {
 				}),
 				new MenuBarItem ("Forma_t", new MenuItem [] {
 					CreateWrapChecked (),
-          CreateAutocomplete(),
+					CreateAutocomplete(),
 					CreateAllowsTabChecked ()
 				}),
 				new MenuBarItem ("_Responder", new MenuItem [] {
@@ -163,12 +164,27 @@ namespace UICatalog {
 			};
 
 			Win.KeyPress += (e) => {
+				var keys = ShortcutHelper.GetModifiersKey (e.KeyEvent);
 				if (winDialog != null && (e.KeyEvent.Key == Key.Esc
 					|| e.KeyEvent.Key == (Key.Q | Key.CtrlMask))) {
 					DisposeWinDialog ();
 				} else if (e.KeyEvent.Key == (Key.Q | Key.CtrlMask)) {
 					Quit ();
 					e.Handled = true;
+				} else if (keys == (Key.Tab | Key.CtrlMask)) {
+					if (_tabView.SelectedTab == _tabView.Tabs.ElementAt (_tabView.Tabs.Count - 1)) {
+						_tabView.SelectedTab = _tabView.Tabs.ElementAt (0);
+					} else {
+						_tabView.SwitchTabBy (1);
+					}
+					e.Handled = true;
+				} else if (keys == (Key.Tab | Key.CtrlMask | Key.ShiftMask)) {
+					if (_tabView.SelectedTab == _tabView.Tabs.ElementAt (0)) {
+						_tabView.SelectedTab = _tabView.Tabs.ElementAt (_tabView.Tabs.Count - 1);
+					} else {
+						_tabView.SwitchTabBy (-1);
+					}
+					e.Handled = true;
 				}
 			};
 		}
@@ -364,7 +380,7 @@ namespace UICatalog {
 
 		private bool SaveAs ()
 		{
-		var aTypes = new List<string> () { ".txt", ".bin", ".xml", ".*" };
+			var aTypes = new List<string> () { ".txt", ".bin", ".xml", ".*" };
 			var sd = new SaveDialog ("Save file", "Choose the path where to save the file.", aTypes);
 			sd.FilePath = System.IO.Path.Combine (sd.FilePath.ToString (), Win.Title.ToString ());
 			Application.Run (sd);
@@ -476,22 +492,21 @@ namespace UICatalog {
 			return item;
 		}
 
-		private MenuItem CreateAutocomplete()
+		private MenuItem CreateAutocomplete ()
 		{
 			var auto = new MenuItem ();
 			auto.Title = "Autocomplete";
 			auto.CheckType |= MenuItemCheckStyle.Checked;
 			auto.Checked = false;
 			auto.Action += () => {
-				if(auto.Checked = !auto.Checked) {
+				if (auto.Checked = !auto.Checked) {
 					// setup autocomplete with all words currently in the editor
-					_textView.Autocomplete.AllSuggestions = 
-					
-					Regex.Matches(_textView.Text.ToString(),"\\w+")
-					.Select(s=>s.Value)
+					_textView.Autocomplete.AllSuggestions =
+
+					Regex.Matches (_textView.Text.ToString (), "\\w+")
+					.Select (s => s.Value)
 					.Distinct ().ToList ();
-				}
-				else {
+				} else {
 					_textView.Autocomplete.AllSuggestions.Clear ();
 
 				}
@@ -567,24 +582,30 @@ namespace UICatalog {
 
 		private void CreateFindReplace (bool isFind = true)
 		{
+			if (winDialog != null) {
+				winDialog.SetFocus ();
+				return;
+			}
+
 			winDialog = new Window (isFind ? "Find" : "Replace") {
 				X = Win.Bounds.Width / 2 - 30,
 				Y = Win.Bounds.Height / 2 - 10,
-				ColorScheme = Colors.Menu
+				ColorScheme = Colors.TopLevel
 			};
+			winDialog.Border.Effect3D = true;
 
-			var tabView = new TabView () {
+			_tabView = new TabView () {
 				X = 0,
 				Y = 0,
 				Width = Dim.Fill (),
 				Height = Dim.Fill ()
 			};
 
-			tabView.AddTab (new TabView.Tab ("Find", FindTab ()), isFind);
+			_tabView.AddTab (new TabView.Tab ("Find", FindTab ()), isFind);
 			var replace = ReplaceTab ();
-			tabView.AddTab (new TabView.Tab ("Replace", replace), !isFind);
-			tabView.SelectedTabChanged += (s, e) => tabView.SelectedTab.View.FocusFirst ();
-			winDialog.Add (tabView);
+			_tabView.AddTab (new TabView.Tab ("Replace", replace), !isFind);
+			_tabView.SelectedTabChanged += (s, e) => _tabView.SelectedTab.View.FocusFirst ();
+			winDialog.Add (_tabView);
 
 			Win.Add (winDialog);
 

+ 91 - 0
UnitTests/ApplicationTests.cs

@@ -1173,5 +1173,96 @@ namespace Terminal.Gui.Core {
 			// Reset the QuitKey to avoid throws errors on another tests
 			Application.QuitKey = Key.Q | Key.CtrlMask;
 		}
+
+		[Fact]
+		[AutoInitShutdown]
+		public void EnsuresTopOnFront_CanFocus_True_By_Keyboard_And_Mouse ()
+		{
+			var top = Application.Top;
+			var win = new Window ("win") { X = 0, Y = 0, Width = 20, Height = 10 };
+			var tf = new TextField () { Width = 10 };
+			win.Add (tf);
+			var win2 = new Window ("win2") { X = 22, Y = 0, Width = 20, Height = 10 };
+			var tf2 = new TextField () { Width = 10 };
+			win2.Add (tf2);
+			top.Add (win, win2);
+
+			Application.Begin (top);
+
+			Assert.True (win.CanFocus);
+			Assert.True (win.HasFocus);
+			Assert.True (win2.CanFocus);
+			Assert.False (win2.HasFocus);
+			Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+
+			top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
+			Assert.True (win.CanFocus);
+			Assert.False (win.HasFocus);
+			Assert.True (win2.CanFocus);
+			Assert.True (win2.HasFocus);
+			Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+
+			top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
+			Assert.True (win.CanFocus);
+			Assert.True (win.HasFocus);
+			Assert.True (win2.CanFocus);
+			Assert.False (win2.HasFocus);
+			Assert.Equal ("win", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+
+			win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed });
+			Assert.True (win.CanFocus);
+			Assert.False (win.HasFocus);
+			Assert.True (win2.CanFocus);
+			Assert.True (win2.HasFocus);
+			Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+			win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released });
+			Assert.Null (Toplevel.dragPosition);
+		}
+
+		[Fact]
+		[AutoInitShutdown]
+		public void EnsuresTopOnFront_CanFocus_False_By_Keyboard_And_Mouse ()
+		{
+			var top = Application.Top;
+			var win = new Window ("win") { X = 0, Y = 0, Width = 20, Height = 10 };
+			var tf = new TextField () { Width = 10 };
+			win.Add (tf);
+			var win2 = new Window ("win2") { X = 22, Y = 0, Width = 20, Height = 10 };
+			var tf2 = new TextField () { Width = 10 };
+			win2.Add (tf2);
+			top.Add (win, win2);
+
+			Application.Begin (top);
+
+			win.CanFocus = false;
+			Assert.False (win.CanFocus);
+			Assert.False (win.HasFocus);
+			Assert.True (win2.CanFocus);
+			Assert.True (win2.HasFocus);
+			Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+
+			top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
+			Assert.True (win2.CanFocus);
+			Assert.False (win.HasFocus);
+			Assert.True (win2.CanFocus);
+			Assert.True (win2.HasFocus);
+			Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+
+			top.ProcessKey (new KeyEvent (Key.CtrlMask | Key.Tab, new KeyModifiers ()));
+			Assert.False (win.CanFocus);
+			Assert.False (win.HasFocus);
+			Assert.True (win2.CanFocus);
+			Assert.True (win2.HasFocus);
+			Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+
+			win.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Pressed });
+			Assert.False (win.CanFocus);
+			Assert.False (win.HasFocus);
+			Assert.True (win2.CanFocus);
+			Assert.True (win2.HasFocus);
+			Assert.Equal ("win2", ((Window)top.Subviews [top.Subviews.Count - 1]).Title);
+			win2.MouseEvent (new MouseEvent () { Flags = MouseFlags.Button1Released });
+			Assert.Null (Toplevel.dragPosition);
+		}
 	}
 }

+ 3 - 1
UnitTests/BorderTests.cs

@@ -9,6 +9,7 @@ using Rune = System.Rune;
 namespace Terminal.Gui.Core {
 	public class BorderTests {
 		[Fact]
+		[AutoInitShutdown]
 		public void Constructor_Defaults ()
 		{
 			var b = new Border ();
@@ -24,7 +25,7 @@ namespace Terminal.Gui.Core {
 			Assert.Null (b.ChildContainer);
 			Assert.False (b.Effect3D);
 			Assert.Equal (new Point (1, 1), b.Effect3DOffset);
-			Assert.Equal (Color.DarkGray, b.Effect3DBrush);
+			Assert.Null (b.Effect3DBrush);
 		}
 
 		[Fact]
@@ -44,6 +45,7 @@ namespace Terminal.Gui.Core {
 		}
 
 		[Fact]
+		[AutoInitShutdown]
 		public void ActualWidth_ActualHeight ()
 		{
 			var v = new View (new Rect (5, 10, 60, 20), "", new Border ());

+ 1 - 1
UnitTests/ComboBoxTests.cs

@@ -3,7 +3,7 @@ using System.Linq;
 using Terminal.Gui;
 using Xunit;
 
-namespace UnitTests {
+namespace Terminal.Gui.Views {
     public class ComboBoxTests {
         [Fact]
         [AutoInitShutdown]

+ 5 - 0
UnitTests/ToplevelTests.cs

@@ -310,6 +310,11 @@ namespace Terminal.Gui.Core {
 			Assert.Null (Toplevel.dragPosition);
 			win.MouseEvent (new MouseEvent () { X = 6, Y = 0, Flags = MouseFlags.Button1Pressed });
 			Assert.Equal (new Point (6, 0), Toplevel.dragPosition);
+			win.MouseEvent (new MouseEvent () { X = 6, Y = 0, Flags = MouseFlags.Button1Released });
+			Assert.Null (Toplevel.dragPosition);
+			win.CanFocus = false;
+			win.MouseEvent (new MouseEvent () { X = 6, Y = 0, Flags = MouseFlags.Button1Pressed });
+			Assert.Null (Toplevel.dragPosition);
 		}
 	}
 }

+ 8 - 2
UnitTests/ViewTests.cs

@@ -878,7 +878,7 @@ namespace Terminal.Gui.Views {
 				Assert.True (v2.CanFocus);
 
 				w.CanFocus = false;
-				Assert.True (w.CanFocus);
+				Assert.False (w.CanFocus);
 				Assert.False (f.CanFocus);
 				Assert.False (v1.CanFocus);
 				Assert.False (v2.CanFocus);
@@ -913,7 +913,7 @@ namespace Terminal.Gui.Views {
 				Assert.True (v2.CanFocus);
 
 				w.CanFocus = false;
-				Assert.True (w.CanFocus);
+				Assert.False (w.CanFocus);
 				Assert.False (f.CanFocus);
 				Assert.False (v1.CanFocus);
 				Assert.False (v2.CanFocus);
@@ -1411,6 +1411,12 @@ namespace Terminal.Gui.Views {
 			view.LayoutComplete += (_) => { layoutStarted = false; };
 			view.OnLayoutComplete (null);
 			Assert.False (layoutStarted);
+			view.X = Pos.Center () - 41;
+			view.Y = Pos.Center () - 13;
+			view.SetRelativeLayout (top.Bounds);
+			view.ViewToScreen (0, 0, out rcol, out rrow);
+			Assert.Equal (-1, rcol);
+			Assert.Equal (-1, rrow);
 		}
 
 		[Fact]