浏览代码

Merge branch 'develop'

Tigger Kindel 1 年之前
父节点
当前提交
3eb585d839
共有 46 个文件被更改,包括 1627 次插入629 次删除
  1. 3 2
      .github/CODEOWNERS
  2. 5 3
      .github/workflows/dotnet-core.yml
  3. 33 36
      .github/workflows/publish.yml
  4. 2 5
      Example/Example.csproj
  5. 4 4
      FSharpExample/FSharpExample.fsproj
  6. 28 0
      GitVersion.yml
  7. 4 5
      ReactiveExample/ReactiveExample.csproj
  8. 49 8
      Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
  9. 2 2
      Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs
  10. 4 1
      Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs
  11. 18 38
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
  12. 29 98
      Terminal.Gui/ConsoleDrivers/NetDriver.cs
  13. 17 13
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  14. 8 26
      Terminal.Gui/Core/Application.cs
  15. 17 15
      Terminal.Gui/Core/Border.cs
  16. 5 5
      Terminal.Gui/Core/ConsoleDriver.cs
  17. 8 6
      Terminal.Gui/Core/Toplevel.cs
  18. 6 9
      Terminal.Gui/Core/View.cs
  19. 8 4
      Terminal.Gui/Core/Window.cs
  20. 49 29
      Terminal.Gui/Terminal.Gui.csproj
  21. 1 1
      Terminal.Gui/Views/ContextMenu.cs
  22. 64 14
      Terminal.Gui/Views/Menu.cs
  23. 7 7
      Terminal.Gui/Views/ScrollBarView.cs
  24. 41 5
      Terminal.Gui/Views/StatusBar.cs
  25. 37 8
      Terminal.Gui/Views/TextView.cs
  26. 20 18
      Terminal.sln
  27. 6 1
      UICatalog/Properties/launchSettings.json
  28. 0 22
      UICatalog/UICatalog.cs
  29. 6 9
      UICatalog/UICatalog.csproj
  30. 0 2
      UnitTests/Application/ApplicationTests.cs
  31. 0 9
      UnitTests/AssemblyInfo.cs
  32. 24 0
      UnitTests/Core/BorderTests.cs
  33. 32 160
      UnitTests/Drivers/ConsoleDriverTests.cs
  34. 69 4
      UnitTests/Menus/ContextMenuTests.cs
  35. 65 2
      UnitTests/Menus/MenuTests.cs
  36. 8 0
      UnitTests/ReflectionTools.cs
  37. 109 1
      UnitTests/TopLevels/ToplevelTests.cs
  38. 16 0
      UnitTests/TopLevels/WindowTests.cs
  39. 10 8
      UnitTests/UnitTests.csproj
  40. 682 43
      UnitTests/Views/ScrollBarViewTests.cs
  41. 40 1
      UnitTests/Views/StatusBarTests.cs
  42. 32 2
      UnitTests/Views/TextViewTests.cs
  43. 43 0
      UnitTests/Views/ViewTests.cs
  44. 2 1
      UnitTests/xunit.runner.json
  45. 2 2
      global.json
  46. 12 0
      nuget.config

+ 3 - 2
.github/CODEOWNERS

@@ -2,7 +2,9 @@
 # the repo. Unless a later match takes precedence,
 # the repo. Unless a later match takes precedence,
 # @global-owner1 and @global-owner2 will be requested for
 # @global-owner1 and @global-owner2 will be requested for
 # review when someone opens a pull request.
 # review when someone opens a pull request.
-*       @migueldeicaza @tig
+* @tig
+
+/docfx/ @tig @tznind @bdisp
 
 
 # Order is important; the last matching pattern takes the most
 # Order is important; the last matching pattern takes the most
 # precedence. When someone opens a pull request that only
 # precedence. When someone opens a pull request that only
@@ -29,7 +31,6 @@
 # The `docs/*` pattern will match files like
 # The `docs/*` pattern will match files like
 # `docs/getting-started.md` but not further nested files like
 # `docs/getting-started.md` but not further nested files like
 # `docs/build-app/troubleshooting.md`.
 # `docs/build-app/troubleshooting.md`.
-#docs/*  [email protected]
 
 
 # In this example, @octocat owns any file in an apps directory
 # In this example, @octocat owns any file in an apps directory
 # anywhere in your repository.
 # anywhere in your repository.

+ 5 - 3
.github/workflows/dotnet-core.yml

@@ -12,7 +12,6 @@ on:
       
       
 jobs:
 jobs:
   build:
   build:
-
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
 
 
     steps:
     steps:
@@ -22,16 +21,19 @@ jobs:
       uses: actions/setup-dotnet@v3
       uses: actions/setup-dotnet@v3
       with:
       with:
         dotnet-version: 7.0
         dotnet-version: 7.0
+        dotnet-quality: 'ga'
 
 
     - name: Install dependencies
     - name: Install dependencies
       run: |
       run: |
         dotnet restore
         dotnet restore
 
 
     - name: Build Debug
     - name: Build Debug
-      run: dotnet build --configuration Debug --no-restore
-
+      run: |
+        dotnet build --configuration Debug --no-restore
+        
     - name: Test
     - name: Test
       run: |
       run: |
+        sed -i 's/"stopOnFail": false/"stopOnFail": true/g' UnitTests/xunit.runner.json
         dotnet test --no-restore --verbosity normal --collect:"XPlat Code Coverage"  --settings UnitTests/coverlet.runsettings
         dotnet test --no-restore --verbosity normal --collect:"XPlat Code Coverage"  --settings UnitTests/coverlet.runsettings
         mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
         mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
 
 

+ 33 - 36
.github/workflows/publish.yml

@@ -1,11 +1,14 @@
 name: Publish Terminal.Gui
 name: Publish Terminal.Gui
+
 on:
 on:
   push:
   push:
+    branches: [ main, develop, v2_release, v2_develop ]
     tags:
     tags:
       - v*
       - v*
+    paths-ignore:
+      - '**.md'
 
 
 jobs:
 jobs:
-
   publish:
   publish:
     name: Build and Publish to Nuget.org
     name: Build and Publish to Nuget.org
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
@@ -13,27 +16,27 @@ jobs:
     steps:
     steps:
     - uses: actions/checkout@v3
     - uses: actions/checkout@v3
       with:
       with:
-        fetch-depth: 0 #fetch-depth is needed for GitVersion
+        fetch-depth: 0 # fetch-depth is needed for GitVersion
 
 
-    - name: Install and calculate the new version with GitVersion 
+    - name: Install GitVersion 
       uses: gittools/actions/gitversion/setup@v0
       uses: gittools/actions/gitversion/setup@v0
       with:
       with:
-        versionSpec: 5.x
+          versionSpec: '5.x'
+          includePrerelease: true
 
 
     - name: Determine Version
     - name: Determine Version
       uses: gittools/actions/gitversion/execute@v0
       uses: gittools/actions/gitversion/execute@v0
+      with:
+        useConfigFile: true
+        #additionalArguments: /b develop
       id: gitversion # step id used as reference for output values
       id: gitversion # step id used as reference for output values
 
 
-    - name: Display GitVersion outputs
-      run: |
-        echo "Version: ${{ steps.gitversion.outputs.SemVer }}"
-        echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.CommitsSinceVersionSource }}"
-
     - name: Setup dotnet
     - name: Setup dotnet
       uses: actions/setup-dotnet@v3
       uses: actions/setup-dotnet@v3
       with:
       with:
         dotnet-version: 7.0
         dotnet-version: 7.0
-
+        dotnet-quality: 'ga'
+        
     - name: Install dependencies
     - name: Install dependencies
       run: dotnet restore
       run: dotnet restore
 
 
@@ -45,33 +48,27 @@ jobs:
     - name: Pack
     - name: Pack
       run: dotnet pack -c Release --include-symbols -p:Version='${{ steps.gitversion.outputs.SemVer }}' 
       run: dotnet pack -c Release --include-symbols -p:Version='${{ steps.gitversion.outputs.SemVer }}' 
 
 
-    - name: Test to generate Code Coverage Report
-      run: |
-        dotnet test --verbosity normal --collect:"XPlat Code Coverage" --settings UnitTests/coverlet.runsettings
-        mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
+    # - name: Test to generate Code Coverage Report
+    #   run: |
+    #     sed -i 's/"stopOnFail": false/"stopOnFail": true/g' UnitTests/xunit.runner.json
+    #     dotnet test --verbosity normal --collect:"XPlat Code Coverage" --settings UnitTests/coverlet.runsettings
+    #     mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
 
 
-    - name: Create Test Coverage Badge
-      uses: simon-k/[email protected]
-      id: create_coverage_badge
-      with:
-        label: Unit Test Coverage
-        color: brightgreen
-        path: UnitTests/TestResults/coverage.opencover.xml
-        gist-filename: code-coverage.json
-        # https://gist.github.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27
-        gist-id: 90ef67a684cb71db1817921a970f8d27
-        gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}   
+    # - name: Create Test Coverage Badge
+    #   uses: simon-k/[email protected]
+    #   id: create_coverage_badge
+    #   with:
+    #     label: Unit Test Coverage
+    #     color: brightgreen
+    #     path: UnitTests/TestResults/coverage.opencover.xml
+    #     gist-filename: code-coverage.json
+    #     gist-id: 90ef67a684cb71db1817921a970f8d27
+    #     gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}   
 
 
-    - name: Print Code Coverage
-      run: |
-        echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
-        echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"
+    # - name: Print Code Coverage
+    #   run: |
+    #     echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
+    #     echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"
         
         
-    #- name: Prep GitHub Packages
-    #  run: dotnet nuget add source --username tig --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/tig/index.json"
-
-    #- name: Publish to GitHub packages 
-    #  run: dotnet nuget push NStack/bin/Release/*.nupkg --api-key ${{ secrets.GITHUB_TOKEN }}  --source "github"
-
     - name: Publish to NuGet.org
     - name: Publish to NuGet.org
-      run: dotnet nuget push Terminal.Gui/bin/Release/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json
+      run: dotnet nuget push Terminal.Gui/bin/Release/Terminal.Gui.${{ steps.gitversion.outputs.SemVer }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} 

+ 2 - 5
Example/Example.csproj

@@ -3,12 +3,9 @@
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
     <TargetFramework>net7.0</TargetFramework>
     <TargetFramework>net7.0</TargetFramework>
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
-    <!-- In the source tree the version will always be 1.0 for all projects. -->
     <!-- Do not modify these. -->
     <!-- Do not modify these. -->
-    <AssemblyVersion>1.10.1.0</AssemblyVersion>
-    <FileVersion>1.10.1.0</FileVersion>
-    <Version>1.10.1</Version>
-    <InformationalVersion>1.10.1+6.Branch.main.Sha.f7ee66ddbf8dbcfb0d96af7d63789879091670ec</InformationalVersion>
+    <FileVersion>1.0.0.0</FileVersion>
+    <Version>1.0.0</Version>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />

+ 4 - 4
FSharpExample/FSharpExample.fsproj

@@ -2,10 +2,10 @@
   <PropertyGroup>
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
     <TargetFramework>net6.0</TargetFramework>
     <TargetFramework>net6.0</TargetFramework>
-    <AssemblyVersion>1.10.1.0</AssemblyVersion>
-    <FileVersion>1.10.1.0</FileVersion>
-    <InformationalVersion>1.10.1+6.Branch.main.Sha.f7ee66ddbf8dbcfb0d96af7d63789879091670ec</InformationalVersion>
-    <Version>1.10.1</Version>
+    <AssemblyVersion>1.14.0.0</AssemblyVersion>
+    <FileVersion>1.14.0.0</FileVersion>
+    <InformationalVersion>1.14.0-pre.1+Branch.develop.Sha.e0b7464669ef87b96b57f2285200e02bcf85d0e7</InformationalVersion>
+    <Version>1.14.0-pre0001</Version>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="Program.fs" />
     <Compile Include="Program.fs" />

+ 28 - 0
GitVersion.yml

@@ -0,0 +1,28 @@
+mode: ContinuousDeployment
+tag-prefix: '[vV]'
+continuous-delivery-fallback-tag: pre
+branches:
+  develop:
+    mode: ContinuousDeployment
+    tag: pre
+    regex: develop
+    source-branches:
+    - main
+    pre-release-weight: 100
+  main:
+    tag: rc
+    increment: Patch
+    source-branches:
+    - develop
+    - main
+  feature:
+    tag: useBranchName
+    regex: ^features?[/-]
+    source-branches:
+    - develop
+    - main
+  pull-request:
+    tag: PullRequest.{BranchName}
+    increment: Inherit
+ignore:
+  sha: []

+ 4 - 5
ReactiveExample/ReactiveExample.csproj

@@ -3,12 +3,11 @@
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
     <TargetFramework>net7.0</TargetFramework>
     <TargetFramework>net7.0</TargetFramework>
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
-    <!-- In the source tree the version will always be 2.0 for all projects. -->
     <!-- Do not modify these. -->
     <!-- Do not modify these. -->
-    <AssemblyVersion>1.10.1.0</AssemblyVersion>
-    <FileVersion>1.10.1.0</FileVersion>
-    <Version>1.10.1</Version>
-    <InformationalVersion>1.10.1+6.Branch.main.Sha.f7ee66ddbf8dbcfb0d96af7d63789879091670ec</InformationalVersion>
+    <!--<AssemblyVersion>1.14.0.0</AssemblyVersion>
+    <FileVersion>1.14.0.0</FileVersion>
+    <Version>1.14.0-pre0001</Version>
+    <InformationalVersion>1.14.0-pre.1+Branch.develop.Sha.e0b7464669ef87b96b57f2285200e02bcf85d0e7</InformationalVersion>-->
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="ReactiveUI.Fody" Version="19.4.1" />
     <PackageReference Include="ReactiveUI.Fody" Version="19.4.1" />

+ 49 - 8
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -20,12 +20,10 @@ namespace Terminal.Gui {
 		public override int Rows => Curses.Lines;
 		public override int Rows => Curses.Lines;
 		public override int Left => 0;
 		public override int Left => 0;
 		public override int Top => 0;
 		public override int Top => 0;
+		[Obsolete ("This API is deprecated", false)]
 		public override bool EnableConsoleScrolling { get; set; }
 		public override bool EnableConsoleScrolling { get; set; }
-		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
-		public override bool HeightAsBuffer {
-			get => EnableConsoleScrolling;
-			set => EnableConsoleScrolling = value;
-		}
+		[Obsolete ("This API is deprecated", false)]
+		public override bool HeightAsBuffer { get; set; }
 		public override IClipboard Clipboard { get => clipboard; }
 		public override IClipboard Clipboard { get => clipboard; }
 
 
 		CursorVisibility? initialCursorVisibility = null;
 		CursorVisibility? initialCursorVisibility = null;
@@ -144,7 +142,6 @@ namespace Terminal.Gui {
 			Curses.raw ();
 			Curses.raw ();
 			Curses.noecho ();
 			Curses.noecho ();
 			Curses.refresh ();
 			Curses.refresh ();
-			ProcessWinChange ();
 		}
 		}
 
 
 		private void ProcessWinChange ()
 		private void ProcessWinChange ()
@@ -163,6 +160,10 @@ namespace Terminal.Gui {
 			StopReportingMouseMoves ();
 			StopReportingMouseMoves ();
 			SetCursorVisibility (CursorVisibility.Default);
 			SetCursorVisibility (CursorVisibility.Default);
 
 
+			// throws away any typeahead that has been typed by
+			// the user and has not yet been read by the program.
+			Curses.flushinp ();
+
 			Curses.endwin ();
 			Curses.endwin ();
 		}
 		}
 
 
@@ -339,8 +340,12 @@ namespace Terminal.Gui {
 			Key k = Key.Null;
 			Key k = Key.Null;
 
 
 			if (code == Curses.KEY_CODE_YES) {
 			if (code == Curses.KEY_CODE_YES) {
-				if (wch == Curses.KeyResize) {
+				while (code == Curses.KEY_CODE_YES && wch == Curses.KeyResize) {
 					ProcessWinChange ();
 					ProcessWinChange ();
+					code = Curses.get_wch (out wch);
+				}
+				if (wch == 0) {
+					return;
 				}
 				}
 				if (wch == Curses.KeyMouse) {
 				if (wch == Curses.KeyMouse) {
 					int wch2 = wch;
 					int wch2 = wch;
@@ -494,8 +499,44 @@ namespace Terminal.Gui {
 			}
 			}
 		}
 		}
 
 
+		MouseFlags lastMouseFlags;
+
 		void ProcessMouseEvent (MouseFlags mouseFlag, Point pos)
 		void ProcessMouseEvent (MouseFlags mouseFlag, Point pos)
 		{
 		{
+			bool WasButtonReleased (MouseFlags flag)
+			{
+				return flag.HasFlag (MouseFlags.Button1Released) ||
+					flag.HasFlag (MouseFlags.Button2Released) ||
+					flag.HasFlag (MouseFlags.Button3Released) ||
+					flag.HasFlag (MouseFlags.Button4Released);
+			}
+
+			bool IsButtonNotPressed (MouseFlags flag)
+			{
+				return !flag.HasFlag (MouseFlags.Button1Pressed) &&
+					!flag.HasFlag (MouseFlags.Button2Pressed) &&
+					!flag.HasFlag (MouseFlags.Button3Pressed) &&
+					!flag.HasFlag (MouseFlags.Button4Pressed);
+			}
+
+			bool IsButtonClickedOrDoubleClicked (MouseFlags flag)
+			{
+				return flag.HasFlag (MouseFlags.Button1Clicked) ||
+					flag.HasFlag (MouseFlags.Button2Clicked) ||
+					flag.HasFlag (MouseFlags.Button3Clicked) ||
+					flag.HasFlag (MouseFlags.Button4Clicked) ||
+					flag.HasFlag (MouseFlags.Button1DoubleClicked) ||
+					flag.HasFlag (MouseFlags.Button2DoubleClicked) ||
+					flag.HasFlag (MouseFlags.Button3DoubleClicked) ||
+					flag.HasFlag (MouseFlags.Button4DoubleClicked);
+			}
+
+			if ((WasButtonReleased (mouseFlag) && IsButtonNotPressed (lastMouseFlags)) ||
+				(IsButtonClickedOrDoubleClicked (mouseFlag) && lastMouseFlags == 0)) {
+				return;
+			}
+
+			lastMouseFlags = mouseFlag;
 			var me = new MouseEvent () {
 			var me = new MouseEvent () {
 				Flags = mouseFlag,
 				Flags = mouseFlag,
 				X = pos.X,
 				X = pos.X,
@@ -531,7 +572,7 @@ namespace Terminal.Gui {
 			});
 			});
 
 
 			mLoop.WinChanged += () => {
 			mLoop.WinChanged += () => {
-				ProcessWinChange ();
+				ProcessInput ();
 			};
 			};
 		}
 		}
 
 

+ 2 - 2
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -97,8 +97,8 @@ namespace Terminal.Gui {
 		{
 		{
 			this.mainLoop = mainLoop;
 			this.mainLoop = mainLoop;
 			pipe (wakeupPipes);
 			pipe (wakeupPipes);
-			AddWatch (wakeupPipes [0], Condition.PollIn, ml => {
-				read (wakeupPipes [0], ignore, readHandle);
+			AddWatch (wakeupPipes [1], Condition.PollIn, ml => {
+				read (wakeupPipes [1], ignore, readHandle);
 				return true;
 				return true;
 			});
 			});
 		}
 		}

+ 4 - 1
Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs

@@ -160,7 +160,10 @@ namespace Unix.Terminal {
 
 
 			console_sharp_get_dims (out l, out c);
 			console_sharp_get_dims (out l, out c);
 
 
-			if (l == 1 || l != lines || c != cols) {
+			if (l < 1) {
+				l = 1;
+			}
+			if (l != lines || c != cols) {
 				lines = l;
 				lines = l;
 				cols = c;
 				cols = c;
 				return true;
 				return true;

+ 18 - 38
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -45,12 +45,10 @@ namespace Terminal.Gui {
 		// Only handling left here because not all terminals has a horizontal scroll bar.
 		// Only handling left here because not all terminals has a horizontal scroll bar.
 		public override int Left => 0;
 		public override int Left => 0;
 		public override int Top => 0;
 		public override int Top => 0;
+		[Obsolete ("This API is deprecated", false)]
 		public override bool EnableConsoleScrolling { get; set; }
 		public override bool EnableConsoleScrolling { get; set; }
-		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
-		public override bool HeightAsBuffer {
-			get => EnableConsoleScrolling;
-			set => EnableConsoleScrolling = value;
-		}
+		[Obsolete ("This API is deprecated", false)]
+		public override bool HeightAsBuffer { get; set; }
 		private IClipboard clipboard = null;
 		private IClipboard clipboard = null;
 		public override IClipboard Clipboard => clipboard;
 		public override IClipboard Clipboard => clipboard;
 
 
@@ -537,31 +535,24 @@ namespace Terminal.Gui {
 			FakeConsole.SetBufferSize (width, height);
 			FakeConsole.SetBufferSize (width, height);
 			cols = width;
 			cols = width;
 			rows = height;
 			rows = height;
-			if (!EnableConsoleScrolling) {
-				SetWindowSize (width, height);
-			}
+			SetWindowSize (width, height);
 			ProcessResize ();
 			ProcessResize ();
 		}
 		}
 
 
 		public void SetWindowSize (int width, int height)
 		public void SetWindowSize (int width, int height)
 		{
 		{
 			FakeConsole.SetWindowSize (width, height);
 			FakeConsole.SetWindowSize (width, height);
-			if (!EnableConsoleScrolling) {
-				if (width != cols || height != rows) {
-					SetBufferSize (width, height);
-					cols = width;
-					rows = height;
-				}
+			if (width != cols || height != rows) {
+				SetBufferSize (width, height);
+				cols = width;
+				rows = height;
 			}
 			}
 			ProcessResize ();
 			ProcessResize ();
 		}
 		}
 
 
 		public void SetWindowPosition (int left, int top)
 		public void SetWindowPosition (int left, int top)
 		{
 		{
-			if (EnableConsoleScrolling) {
-				this.left = Math.Max (Math.Min (left, Cols - FakeConsole.WindowWidth), 0);
-				this.top = Math.Max (Math.Min (top, Rows - FakeConsole.WindowHeight), 0);
-			} else if (this.left > 0 || this.top > 0) {
+			if (this.left > 0 || this.top > 0) {
 				this.left = 0;
 				this.left = 0;
 				this.top = 0;
 				this.top = 0;
 			}
 			}
@@ -577,29 +568,18 @@ namespace Terminal.Gui {
 
 
 		public override void ResizeScreen ()
 		public override void ResizeScreen ()
 		{
 		{
-			if (!EnableConsoleScrolling) {
-				if (FakeConsole.WindowHeight > 0) {
-					// Can raise an exception while is still resizing.
-					try {
-#pragma warning disable CA1416
-						FakeConsole.CursorTop = 0;
-						FakeConsole.CursorLeft = 0;
-						FakeConsole.WindowTop = 0;
-						FakeConsole.WindowLeft = 0;
-#pragma warning restore CA1416
-					} catch (System.IO.IOException) {
-						return;
-					} catch (ArgumentOutOfRangeException) {
-						return;
-					}
-				}
-			} else {
+			if (FakeConsole.WindowHeight > 0) {
+				// Can raise an exception while is still resizing.
 				try {
 				try {
 #pragma warning disable CA1416
 #pragma warning disable CA1416
-					FakeConsole.WindowLeft = Math.Max (Math.Min (left, Cols - FakeConsole.WindowWidth), 0);
-					FakeConsole.WindowTop = Math.Max (Math.Min (top, Rows - FakeConsole.WindowHeight), 0);
+					FakeConsole.CursorTop = 0;
+					FakeConsole.CursorLeft = 0;
+					FakeConsole.WindowTop = 0;
+					FakeConsole.WindowLeft = 0;
 #pragma warning restore CA1416
 #pragma warning restore CA1416
-				} catch (Exception) {
+				} catch (System.IO.IOException) {
+					return;
+				} catch (ArgumentOutOfRangeException) {
 					return;
 					return;
 				}
 				}
 			}
 			}

+ 29 - 98
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -113,7 +113,6 @@ namespace Terminal.Gui {
 		ConsoleDriver consoleDriver;
 		ConsoleDriver consoleDriver;
 		volatile ConsoleKeyInfo [] cki = null;
 		volatile ConsoleKeyInfo [] cki = null;
 		static volatile bool isEscSeq;
 		static volatile bool isEscSeq;
-		int lastWindowHeight;
 		bool stopTasks;
 		bool stopTasks;
 #if PROCESS_REQUEST
 #if PROCESS_REQUEST
 		bool neededProcessRequest;
 		bool neededProcessRequest;
@@ -251,21 +250,11 @@ namespace Terminal.Gui {
 
 
 		bool IsWinChanged (int winHeight, int winWidth, int buffHeight, int buffWidth)
 		bool IsWinChanged (int winHeight, int winWidth, int buffHeight, int buffWidth)
 		{
 		{
-			if (!consoleDriver.EnableConsoleScrolling) {
-				if (winWidth != consoleDriver.Cols || winHeight != consoleDriver.Rows) {
-					var w = Math.Max (winWidth, 0);
-					var h = Math.Max (winHeight, 0);
-					GetWindowSizeEvent (new Size (w, h));
-					return true;
-				}
-			} else {
-				if (winWidth != consoleDriver.Cols || winHeight != lastWindowHeight
-					|| buffWidth != consoleDriver.Cols || buffHeight != consoleDriver.Rows) {
-
-					lastWindowHeight = Math.Max (winHeight, 0);
-					GetWindowSizeEvent (new Size (winWidth, lastWindowHeight));
-					return true;
-				}
+			if (winWidth != consoleDriver.Cols || winHeight != consoleDriver.Rows) {
+				var w = Math.Max (winWidth, 0);
+				var h = Math.Max (winHeight, 0);
+				GetWindowSizeEvent (new Size (w, h));
+				return true;
 			}
 			}
 			return false;
 			return false;
 		}
 		}
@@ -584,20 +573,15 @@ namespace Terminal.Gui {
 		public override int Rows => rows;
 		public override int Rows => rows;
 		public override int Left => left;
 		public override int Left => left;
 		public override int Top => top;
 		public override int Top => top;
+		[Obsolete ("This API is deprecated", false)]
 		public override bool EnableConsoleScrolling { get; set; }
 		public override bool EnableConsoleScrolling { get; set; }
-		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
-		public override bool HeightAsBuffer {
-			get => EnableConsoleScrolling;
-			set => EnableConsoleScrolling = value;
-		}
-
+		[Obsolete ("This API is deprecated", false)]
+		public override bool HeightAsBuffer { get; set; }
 		public NetWinVTConsole NetWinConsole { get; }
 		public NetWinVTConsole NetWinConsole { get; }
 		public bool IsWinPlatform { get; }
 		public bool IsWinPlatform { get; }
 		public override IClipboard Clipboard { get; }
 		public override IClipboard Clipboard { get; }
 		public override int [,,] Contents => contents;
 		public override int [,,] Contents => contents;
 
 
-		int largestBufferHeight;
-
 		public NetDriver ()
 		public NetDriver ()
 		{
 		{
 			var p = Environment.OSVersion.Platform;
 			var p = Environment.OSVersion.Platform;
@@ -752,14 +736,8 @@ namespace Terminal.Gui {
 
 
 			Console.TreatControlCAsInput = true;
 			Console.TreatControlCAsInput = true;
 
 
-			if (EnableConsoleScrolling) {
-				largestBufferHeight = Console.BufferHeight;
-			} else {
-				largestBufferHeight = Console.WindowHeight;
-			}
-
 			cols = Console.WindowWidth;
 			cols = Console.WindowWidth;
-			rows = largestBufferHeight;
+			rows = Console.WindowHeight; 
 
 
 			CurrentAttribute = MakeColor (Color.White, Color.Black);
 			CurrentAttribute = MakeColor (Color.White, Color.Black);
 			InitalizeColorSchemes ();
 			InitalizeColorSchemes ();
@@ -775,54 +753,31 @@ namespace Terminal.Gui {
 
 
 		public override void ResizeScreen ()
 		public override void ResizeScreen ()
 		{
 		{
-			if (!EnableConsoleScrolling) {
-				if (Console.WindowHeight > 0) {
-					// Not supported on Unix.
-					if (IsWinPlatform) {
-						// Can raise an exception while is still resizing.
-						try {
-#pragma warning disable CA1416
-							Console.CursorTop = 0;
-							Console.CursorLeft = 0;
-							Console.WindowTop = 0;
-							Console.WindowLeft = 0;
-							if (Console.WindowHeight > Rows) {
-								Console.SetWindowSize (Cols, Rows);
-							}
-							Console.SetBufferSize (Cols, Rows);
-#pragma warning restore CA1416
-						} catch (System.IO.IOException) {
-							setClip ();
-						} catch (ArgumentOutOfRangeException) {
-							setClip ();
-						}
-					} else {
-						Console.Out.Write ($"\x1b[8;{Rows};{Cols}t");
-					}
-				}
-			} else {
+			if (Console.WindowHeight > 0) {
+				// Not supported on Unix.
 				if (IsWinPlatform) {
 				if (IsWinPlatform) {
-					if (Console.WindowHeight > 0) {
-						// Can raise an exception while is still resizing.
-						try {
+					// Can raise an exception while is still resizing.
+					try {
 #pragma warning disable CA1416
 #pragma warning disable CA1416
-							Console.CursorTop = 0;
-							Console.CursorLeft = 0;
-							if (Console.WindowHeight > Rows) {
-								Console.SetWindowSize (Cols, Rows);
-							}
-							Console.SetBufferSize (Cols, Rows);
-#pragma warning restore CA1416
-						} catch (System.IO.IOException) {
-							setClip ();
-						} catch (ArgumentOutOfRangeException) {
-							setClip ();
+						Console.CursorTop = 0;
+						Console.CursorLeft = 0;
+						Console.WindowTop = 0;
+						Console.WindowLeft = 0;
+						if (Console.WindowHeight > Rows) {
+							Console.SetWindowSize (Cols, Rows);
 						}
 						}
+						Console.SetBufferSize (Cols, Rows);
+#pragma warning restore CA1416
+					} catch (System.IO.IOException) {
+						setClip ();
+					} catch (ArgumentOutOfRangeException) {
+						setClip ();
 					}
 					}
 				} else {
 				} else {
-					Console.Out.Write ($"\x1b[30;{Rows};{Cols}t");
+					Console.Out.Write ($"\x1b[8;{Rows};{Cols}t");
 				}
 				}
 			}
 			}
+
 			setClip ();
 			setClip ();
 
 
 			void setClip ()
 			void setClip ()
@@ -864,9 +819,7 @@ namespace Terminal.Gui {
 
 
 		public override void UpdateScreen ()
 		public override void UpdateScreen ()
 		{
 		{
-			if (winChanging || Console.WindowHeight < 1 || contents.Length != Rows * Cols * 3
-				|| (!EnableConsoleScrolling && Rows != Console.WindowHeight)
-				|| (EnableConsoleScrolling && Rows != largestBufferHeight)) {
+			if (winChanging || Console.WindowHeight < 1 || contents.Length != Rows * Cols * 3 || Rows != Console.WindowHeight) {
 				return;
 				return;
 			}
 			}
 
 
@@ -1021,23 +974,6 @@ namespace Terminal.Gui {
 
 
 		private void SetWindowPosition (int col, int row)
 		private void SetWindowPosition (int col, int row)
 		{
 		{
-			if (IsWinPlatform && EnableConsoleScrolling) {
-				var winTop = Math.Max (Rows - Console.WindowHeight - row, 0);
-				winTop = Math.Min (winTop, Rows - Console.WindowHeight + 1);
-				winTop = Math.Max (winTop, 0);
-				if (winTop != Console.WindowTop) {
-					try {
-						if (!EnsureBufferSize ()) {
-							return;
-						}
-#pragma warning disable CA1416
-						Console.SetWindowPosition (col, winTop);
-#pragma warning restore CA1416
-					} catch (System.IO.IOException) {
-
-					} catch (System.ArgumentOutOfRangeException) { }
-				}
-			}
 			top = Console.WindowTop;
 			top = Console.WindowTop;
 			left = Console.WindowLeft;
 			left = Console.WindowLeft;
 		}
 		}
@@ -1287,15 +1223,10 @@ namespace Terminal.Gui {
 		void ChangeWin (Size size)
 		void ChangeWin (Size size)
 		{
 		{
 			winChanging = true;
 			winChanging = true;
-			if (!EnableConsoleScrolling) {
-				largestBufferHeight = Math.Max (size.Height, 0);
-			} else {
-				largestBufferHeight = Math.Max (size.Height, largestBufferHeight);
-			}
 			top = 0;
 			top = 0;
 			left = 0;
 			left = 0;
 			cols = size.Width;
 			cols = size.Width;
-			rows = largestBufferHeight;
+			rows = Math.Max (size.Height, 0); 
 			ResizeScreen ();
 			ResizeScreen ();
 			UpdateOffScreen ();
 			UpdateOffScreen ();
 			winChanging = false;
 			winChanging = false;

+ 17 - 13
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -709,17 +709,16 @@ namespace Terminal.Gui {
 		WindowsConsole.SmallRect damageRegion;
 		WindowsConsole.SmallRect damageRegion;
 		IClipboard clipboard;
 		IClipboard clipboard;
 		int [,,] contents;
 		int [,,] contents;
+		readonly bool isWindowsTerminal;
 
 
 		public override int Cols => cols;
 		public override int Cols => cols;
 		public override int Rows => rows;
 		public override int Rows => rows;
 		public override int Left => left;
 		public override int Left => left;
 		public override int Top => top;
 		public override int Top => top;
+		[Obsolete ("This API is deprecated", false)]
 		public override bool EnableConsoleScrolling { get; set; }
 		public override bool EnableConsoleScrolling { get; set; }
-		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
-		public override bool HeightAsBuffer {
-			get => EnableConsoleScrolling;
-			set => EnableConsoleScrolling = value;
-		}
+		[Obsolete ("This API is deprecated", false)]
+		public override bool HeightAsBuffer { get; set; }
 		public override IClipboard Clipboard => clipboard;
 		public override IClipboard Clipboard => clipboard;
 		public override int [,,] Contents => contents;
 		public override int [,,] Contents => contents;
 
 
@@ -734,6 +733,8 @@ namespace Terminal.Gui {
 		{
 		{
 			WinConsole = new WindowsConsole ();
 			WinConsole = new WindowsConsole ();
 			clipboard = new WindowsClipboard ();
 			clipboard = new WindowsClipboard ();
+
+			isWindowsTerminal = Environment.GetEnvironmentVariable ("WT_SESSION") != null;
 		}
 		}
 
 
 		public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
 		public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
@@ -1428,15 +1429,17 @@ namespace Terminal.Gui {
 
 
 			try {
 			try {
 				// Needed for Windows Terminal
 				// Needed for Windows Terminal
-				// ESC [ ? 1047 h  Activate xterm alternative buffer (no backscroll)
-				// ESC [ ? 1047 l  Restore xterm working buffer (with backscroll)
+				// ESC [ ? 1047 h  Save cursor position and activate xterm alternative buffer (no backscroll)
+				// ESC [ ? 1047 l  Restore cursor position and restore xterm working buffer (with backscroll)
 				// ESC [ ? 1048 h  Save cursor position
 				// ESC [ ? 1048 h  Save cursor position
 				// ESC [ ? 1048 l  Restore cursor position
 				// ESC [ ? 1048 l  Restore cursor position
-				// ESC [ ? 1049 h  Save cursor position and activate xterm alternative buffer (no backscroll)
-				// ESC [ ? 1049 l  Restore cursor position and restore xterm working buffer (with backscroll)
-				// Per Issue #2264 using the alterantive screen buffer is required for Windows Terminal to not 
+				// ESC [ ? 1049 h  Activate xterm alternative buffer (no backscroll)
+				// ESC [ ? 1049 l  Restore xterm working buffer (with backscroll)
+				// Per Issue #2264 using the alternative screen buffer is required for Windows Terminal to not 
 				// wipe out the backscroll buffer when the application exits.
 				// wipe out the backscroll buffer when the application exits.
-				Console.Out.Write ("\x1b[?1047h");
+				if (isWindowsTerminal) {
+					Console.Out.Write ("\x1b[?1049h");
+				}
 
 
 				var winSize = WinConsole.GetConsoleOutputWindow (out Point pos);
 				var winSize = WinConsole.GetConsoleOutputWindow (out Point pos);
 				cols = winSize.Width;
 				cols = winSize.Width;
@@ -1678,12 +1681,13 @@ namespace Terminal.Gui {
 
 
 		public override void End ()
 		public override void End ()
 		{
 		{
-
 			WinConsole.Cleanup ();
 			WinConsole.Cleanup ();
 			WinConsole = null;
 			WinConsole = null;
 
 
 			// Disable alternative screen buffer.
 			// Disable alternative screen buffer.
-			Console.Out.Write ("\x1b[?1047l");
+			if (isWindowsTerminal) {
+				Console.Out.Write ("\x1b[?1049l");
+			}
 		}
 		}
 
 
 		/// <inheritdoc/>
 		/// <inheritdoc/>

+ 8 - 26
Terminal.Gui/Core/Application.cs

@@ -111,8 +111,6 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public static View WantContinuousButtonPressedView { get; private set; }
 		public static View WantContinuousButtonPressedView { get; private set; }
 
 
-		private static bool? _enableConsoleScrolling;
-
 		/// <summary>
 		/// <summary>
 		/// The current <see cref="ConsoleDriver.EnableConsoleScrolling"/> used in the terminal.
 		/// The current <see cref="ConsoleDriver.EnableConsoleScrolling"/> used in the terminal.
 		/// </summary>
 		/// </summary>
@@ -128,32 +126,17 @@ namespace Terminal.Gui {
 		/// In this case console scrolling is enabled and the contents (<see cref="ConsoleDriver.Rows"/> high) will scroll
 		/// In this case console scrolling is enabled and the contents (<see cref="ConsoleDriver.Rows"/> high) will scroll
 		/// as the console scrolls. 
 		/// as the console scrolls. 
 		/// </para>
 		/// </para>
-		/// This API was previously named 'HeightAsBuffer` but was renamed to make its purpose more clear.
+		/// <para>This API is deprecated and has no impact when enabled.</para>
+		/// <para>This API was previously named 'HeightAsBuffer` but was renamed to make its purpose more clear.</para>
 		/// </remarks>
 		/// </remarks>
-		public static bool EnableConsoleScrolling {
-			get {
-				if (Driver == null) {
-					return _enableConsoleScrolling.HasValue && _enableConsoleScrolling.Value;
-				}
-				return Driver.EnableConsoleScrolling;
-			}
-			set {
-				_enableConsoleScrolling = value;
-				if (Driver == null) {
-					return;
-				}
-				Driver.EnableConsoleScrolling = value;
-			}
-		}
+		[Obsolete ("This API is deprecated and has no impact when enabled.", false)]
+		public static bool EnableConsoleScrolling { get; set; }
 
 
 		/// <summary>
 		/// <summary>
 		/// This API is deprecated; use <see cref="EnableConsoleScrolling"/> instead.
 		/// This API is deprecated; use <see cref="EnableConsoleScrolling"/> instead.
 		/// </summary>
 		/// </summary>
-		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
-		public static bool HeightAsBuffer {
-			get => EnableConsoleScrolling;
-			set => EnableConsoleScrolling = value;
-		}
+		[Obsolete ("This API is deprecated and has no impact when enabled.", false)]
+		public static bool HeightAsBuffer { get; set; }
 
 
 		static Key alternateForwardKey = Key.PageDown | Key.CtrlMask;
 		static Key alternateForwardKey = Key.PageDown | Key.CtrlMask;
 
 
@@ -449,7 +432,6 @@ namespace Terminal.Gui {
 			MainLoop = new MainLoop (mainLoopDriver);
 			MainLoop = new MainLoop (mainLoopDriver);
 
 
 			try {
 			try {
-				Driver.EnableConsoleScrolling = EnableConsoleScrolling;
 				Driver.Init (TerminalResized);
 				Driver.Init (TerminalResized);
 			} catch (InvalidOperationException ex) {
 			} catch (InvalidOperationException ex) {
 				// This is a case where the driver is unable to initialize the console.
 				// This is a case where the driver is unable to initialize the console.
@@ -1071,7 +1053,8 @@ namespace Terminal.Gui {
 					MdiTop.OnAllChildClosed ();
 					MdiTop.OnAllChildClosed ();
 				} else {
 				} else {
 					SetCurrentAsTop ();
 					SetCurrentAsTop ();
-					Current.OnEnter (Current);
+					runState.Toplevel.OnLeave (Current);
+					Current.OnEnter (runState.Toplevel);
 				}
 				}
 				Refresh ();
 				Refresh ();
 			}
 			}
@@ -1125,7 +1108,6 @@ namespace Terminal.Gui {
 			NotifyStopRunState = null;
 			NotifyStopRunState = null;
 			_initialized = false;
 			_initialized = false;
 			mouseGrabView = null;
 			mouseGrabView = null;
-			_enableConsoleScrolling = false;
 
 
 			// Reset synchronization context to allow the user to run async/await,
 			// Reset synchronization context to allow the user to run async/await,
 			// as the main loop has been ended, the synchronization context from 
 			// as the main loop has been ended, the synchronization context from 

+ 17 - 15
Terminal.Gui/Core/Border.cs

@@ -284,7 +284,7 @@ namespace Terminal.Gui {
 			/// <inheritdoc/>
 			/// <inheritdoc/>
 			public override void OnCanFocusChanged ()
 			public override void OnCanFocusChanged ()
 			{
 			{
-				if (Border.Child != null) {
+				if (Border?.Child != null) {
 					Border.Child.CanFocus = CanFocus;
 					Border.Child.CanFocus = CanFocus;
 				}
 				}
 				base.OnCanFocusChanged ();
 				base.OnCanFocusChanged ();
@@ -375,8 +375,10 @@ namespace Terminal.Gui {
 		public Color BorderBrush {
 		public Color BorderBrush {
 			get => borderBrush != null ? (Color)borderBrush : (Color)(-1);
 			get => borderBrush != null ? (Color)borderBrush : (Color)(-1);
 			set {
 			set {
-				borderBrush = value;
-				OnBorderChanged ();
+				if (Enum.IsDefined (typeof (Color), value)) {
+					borderBrush = value;
+					OnBorderChanged ();
+				}
 			}
 			}
 		}
 		}
 
 
@@ -386,8 +388,10 @@ namespace Terminal.Gui {
 		public Color Background {
 		public Color Background {
 			get => background != null ? (Color)background : (Color)(-1);
 			get => background != null ? (Color)background : (Color)(-1);
 			set {
 			set {
-				background = value;
-				OnBorderChanged ();
+				if (Enum.IsDefined (typeof (Color), value)) {
+					background = value;
+					OnBorderChanged ();
+				}
 			}
 			}
 		}
 		}
 
 
@@ -445,12 +449,10 @@ namespace Terminal.Gui {
 
 
 		private void Parent_Removed (View obj)
 		private void Parent_Removed (View obj)
 		{
 		{
-			if (borderBrush != null)
-			{
+			if (borderBrush != null) {
 				BorderBrush = default;
 				BorderBrush = default;
 			}
 			}
-			if (background != null)
-			{
+			if (background != null) {
 				Background = default;
 				Background = default;
 			}
 			}
 			child.Removed -= Parent_Removed;
 			child.Removed -= Parent_Removed;
@@ -800,7 +802,7 @@ namespace Terminal.Gui {
 			SetBorderBrush (driver);
 			SetBorderBrush (driver);
 
 
 			// Draw the upper BorderThickness
 			// Draw the upper BorderThickness
-			for (int r = frame.Y;
+			for (int r = Math.Max (frame.Y, 0);
 				r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) {
 				r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) {
 				for (int c = frame.X;
 				for (int c = frame.X;
 					c < Math.Min (frame.Right, driver.Cols); c++) {
 					c < Math.Min (frame.Right, driver.Cols); c++) {
@@ -810,7 +812,7 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			// Draw the left BorderThickness
 			// Draw the left BorderThickness
-			for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom);
+			for (int r = Math.Max (Math.Min (frame.Y + borderThickness.Top, frame.Bottom), 0);
 				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
 				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
 				for (int c = frame.X;
 				for (int c = frame.X;
 					c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) {
 					c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) {
@@ -820,7 +822,7 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			// Draw the right BorderThickness
 			// Draw the right BorderThickness
-			for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom);
+			for (int r = Math.Max (Math.Min (frame.Y + borderThickness.Top, frame.Bottom), 0);
 				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
 				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
 				for (int c = Math.Max (frame.Right - borderThickness.Right, frame.X);
 				for (int c = Math.Max (frame.Right - borderThickness.Right, frame.X);
 					c < Math.Min (frame.Right, driver.Cols); c++) {
 					c < Math.Min (frame.Right, driver.Cols); c++) {
@@ -842,7 +844,7 @@ namespace Terminal.Gui {
 			SetBackground (driver);
 			SetBackground (driver);
 
 
 			// Draw the upper Padding
 			// Draw the upper Padding
-			for (int r = frame.Y + borderThickness.Top;
+			for (int r = Math.Max (frame.Y + borderThickness.Top, 0);
 				r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) {
 				r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) {
 				for (int c = frame.X + borderThickness.Left;
 				for (int c = frame.X + borderThickness.Left;
 					c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
 					c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
@@ -852,7 +854,7 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			// Draw the left Padding
 			// Draw the left Padding
-			for (int r = frame.Y + sumThickness.Top;
+			for (int r = Math.Max (frame.Y + sumThickness.Top, 0);
 				r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
 				r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
 				for (int c = frame.X + borderThickness.Left;
 				for (int c = frame.X + borderThickness.Left;
 					c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) {
 					c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) {
@@ -862,7 +864,7 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			// Draw the right Padding
 			// Draw the right Padding
-			for (int r = frame.Y + sumThickness.Top;
+			for (int r = Math.Max (frame.Y + sumThickness.Top, 0);
 				r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
 				r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
 				for (int c = Math.Max (frame.Right - sumThickness.Right, frame.X + sumThickness.Left);
 				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++) {
 					c < Math.Max (frame.Right - borderThickness.Right, frame.X + sumThickness.Left); c++) {

+ 5 - 5
Terminal.Gui/Core/ConsoleDriver.cs

@@ -696,16 +696,16 @@ namespace Terminal.Gui {
 		/// </para>
 		/// </para>
 		/// </summary>
 		/// </summary>
 		/// <remarks>
 		/// <remarks>
-		/// NOTE: This functionaliy is currently broken on Windows Terminal.
+		/// NOTE: Changes to Windows Terminal prevents this functionality from working. It only really worked on Windows 'conhost' previously.
 		/// </remarks>
 		/// </remarks>
+		[Obsolete ("This API is deprecated and has no impact when enabled.", false)]
 		public abstract bool EnableConsoleScrolling { get; set; }
 		public abstract bool EnableConsoleScrolling { get; set; }
-
 		/// <summary>
 		/// <summary>
-		/// This API is deprecated; use <see cref="EnableConsoleScrolling"/> instead.
+		/// This API is deprecated and has no impact when enabled.
 		/// </summary>
 		/// </summary>
-		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
+		[Obsolete ("This API is deprecated and has no impact when enabled.", false)]
 		public abstract bool HeightAsBuffer { get; set; }
 		public abstract bool HeightAsBuffer { get; set; }
-
+		
 		/// <summary>
 		/// <summary>
 		/// The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag
 		/// The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag
 		/// </summary>
 		/// </summary>

+ 8 - 6
Terminal.Gui/Core/Toplevel.cs

@@ -552,6 +552,7 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override void Add (View view)
 		public override void Add (View view)
 		{
 		{
+			CanFocus = true;
 			AddMenuStatusBar (view);
 			AddMenuStatusBar (view);
 			base.Add (view);
 			base.Add (view);
 		}
 		}
@@ -603,7 +604,7 @@ namespace Terminal.Gui {
 			out int nx, out int ny, out View mb, out View sb)
 			out int nx, out int ny, out View mb, out View sb)
 		{
 		{
 			int l;
 			int l;
-			View superView;
+			View superView = null;
 			if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
 			if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
 				l = Driver.Cols;
 				l = Driver.Cols;
 				superView = Application.Top;
 				superView = Application.Top;
@@ -618,11 +619,12 @@ namespace Terminal.Gui {
 				nx = Math.Max (top.Frame.Right - mfLength, 0);
 				nx = Math.Max (top.Frame.Right - mfLength, 0);
 			}
 			}
 			//System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
 			//System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
-			bool m, s;
-			if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
+			bool m = false, s = false;
+			mb = null; sb = null;
+			if (!(top is Window && top == Application.Top) && (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top)) {
 				m = Application.Top.MenuBar?.Visible == true;
 				m = Application.Top.MenuBar?.Visible == true;
 				mb = Application.Top.MenuBar;
 				mb = Application.Top.MenuBar;
-			} else {
+			} else if (!(top is Window && top == Application.Top)) {
 				var t = top.SuperView;
 				var t = top.SuperView;
 				while (!(t is Toplevel)) {
 				while (!(t is Toplevel)) {
 					t = t.SuperView;
 					t = t.SuperView;
@@ -636,10 +638,10 @@ namespace Terminal.Gui {
 				l = 0;
 				l = 0;
 			}
 			}
 			ny = Math.Max (y, l);
 			ny = Math.Max (y, l);
-			if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
+			if (!(top is Window && top == Application.Top) && (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top)) {
 				s = Application.Top.StatusBar?.Visible == true;
 				s = Application.Top.StatusBar?.Visible == true;
 				sb = Application.Top.StatusBar;
 				sb = Application.Top.StatusBar;
-			} else {
+			} else if (!(top is Window && top == Application.Top)) {
 				var t = top.SuperView;
 				var t = top.SuperView;
 				while (!(t is Toplevel)) {
 				while (!(t is Toplevel)) {
 					t = t.SuperView;
 					t = t.SuperView;

+ 6 - 9
Terminal.Gui/Core/View.cs

@@ -371,7 +371,7 @@ namespace Terminal.Gui {
 						SuperView?.EnsureFocus ();
 						SuperView?.EnsureFocus ();
 						if (SuperView != null && SuperView.Focused == null) {
 						if (SuperView != null && SuperView.Focused == null) {
 							SuperView.FocusNext ();
 							SuperView.FocusNext ();
-							if (SuperView.Focused == null) {
+							if (SuperView.Focused == null && Application.Current != null) {
 								Application.Current.FocusNext ();
 								Application.Current.FocusNext ();
 							}
 							}
 							Application.EnsuresTopOnFront ();
 							Application.EnsuresTopOnFront ();
@@ -995,9 +995,6 @@ namespace Terminal.Gui {
 			view.tabIndex = -1;
 			view.tabIndex = -1;
 			SetNeedsLayout ();
 			SetNeedsLayout ();
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
-			if (subviews.Count < 1) {
-				CanFocus = false;
-			}
 			foreach (var v in subviews) {
 			foreach (var v in subviews) {
 				if (v.Frame.IntersectsWith (touched))
 				if (v.Frame.IntersectsWith (touched))
 					view.SetNeedsDisplay ();
 					view.SetNeedsDisplay ();
@@ -2199,7 +2196,7 @@ namespace Terminal.Gui {
 			} else {
 			} else {
 				actY = y?.Anchor (hostFrame.Height) ?? 0;
 				actY = y?.Anchor (hostFrame.Height) ?? 0;
 
 
-				actH = Math.Max (CalculateActualHight (height, hostFrame, actY, s), 0);
+				actH = Math.Max (CalculateActualHeight (height, hostFrame, actY, s), 0);
 			}
 			}
 
 
 			var r = new Rect (actX, actY, actW, actH);
 			var r = new Rect (actX, actY, actW, actH);
@@ -2240,7 +2237,7 @@ namespace Terminal.Gui {
 			return actW;
 			return actW;
 		}
 		}
 
 
-		private int CalculateActualHight (Dim height, Rect hostFrame, int actY, Size s)
+		private int CalculateActualHeight (Dim height, Rect hostFrame, int actY, Size s)
 		{
 		{
 			int actH;
 			int actH;
 			switch (height) {
 			switch (height) {
@@ -2248,8 +2245,8 @@ namespace Terminal.Gui {
 				actH = AutoSize ? s.Height : hostFrame.Height;
 				actH = AutoSize ? s.Height : hostFrame.Height;
 				break;
 				break;
 			case Dim.DimCombine combine:
 			case Dim.DimCombine combine:
-				int leftActH = CalculateActualHight (combine.left, hostFrame, actY, s);
-				int rightActH = CalculateActualHight (combine.right, hostFrame, actY, s);
+				int leftActH = CalculateActualHeight (combine.left, hostFrame, actY, s);
+				int rightActH = CalculateActualHeight (combine.right, hostFrame, actY, s);
 				if (combine.add) {
 				if (combine.add) {
 					actH = leftActH + rightActH;
 					actH = leftActH + rightActH;
 				} else {
 				} else {
@@ -2449,7 +2446,7 @@ namespace Terminal.Gui {
 
 
 			foreach (var v in ordered) {
 			foreach (var v in ordered) {
 				if (v.LayoutStyle == LayoutStyle.Computed) {
 				if (v.LayoutStyle == LayoutStyle.Computed) {
-					v.SetRelativeLayout (Frame);
+					v.SetRelativeLayout (v?.SuperView.Frame ?? Frame);
 				}
 				}
 
 
 				v.LayoutSubviews ();
 				v.LayoutSubviews ();

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

@@ -88,11 +88,18 @@ namespace Terminal.Gui {
 
 
 			public ContentView (Rect frame, Window instance) : base (frame)
 			public ContentView (Rect frame, Window instance) : base (frame)
 			{
 			{
-				this.instance = instance;
+				Initialize (instance);
 			}
 			}
 			public ContentView (Window instance) : base ()
 			public ContentView (Window instance) : base ()
+			{
+				Initialize (instance);
+			}
+
+			private void Initialize (Window instance)
 			{
 			{
 				this.instance = instance;
 				this.instance = instance;
+				CanFocus = this.instance.CanFocus;
+				Driver?.SetCursorVisibility (CursorVisibility.Invisible);
 			}
 			}
 
 
 			public override void OnCanFocusChanged ()
 			public override void OnCanFocusChanged ()
@@ -263,9 +270,6 @@ namespace Terminal.Gui {
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 			contentView.Remove (view);
 			contentView.Remove (view);
 
 
-			if (contentView.InternalSubviews.Count < 1) {
-				CanFocus = false;
-			}
 			RemoveMenuStatusBar (view);
 			RemoveMenuStatusBar (view);
 			if (view != contentView && Focused == null) {
 			if (view != contentView && Focused == null) {
 				FocusFirst ();
 				FocusFirst ();

+ 49 - 29
Terminal.Gui/Terminal.Gui.csproj

@@ -1,30 +1,48 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
+  <!-- =================================================================== -->
+  <!-- Version numbers -->
+  <!-- Automatically updated by gitversion (run `dotnet-gitversion /updateprojectfiles`)  -->
+  <!-- GitVersion.xml controls settings  -->
+  <!-- =================================================================== -->
+  <PropertyGroup>
+    <FileVersion>1.0.0.0</FileVersion>
+    <Version>1.0.0</Version>
+  </PropertyGroup>
+  <!-- =================================================================== -->
+  <!-- .NET Build Settings -->
+  <!-- =================================================================== -->
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>portable</DebugType>
     <DebugType>portable</DebugType>
+    <VersionSuffix></VersionSuffix>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DefineConstants>TRACE;DEBUG_IDISPOSABLE</DefineConstants>
     <DefineConstants>TRACE;DEBUG_IDISPOSABLE</DefineConstants>
     <DebugType>portable</DebugType>
     <DebugType>portable</DebugType>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup>
   <PropertyGroup>
-    <!-- Version numbers are automatically updated by gitversion when a release is released -->
-    <!-- In the source tree the version will always be 1.0 for all projects. -->
-    <!-- Do not modify these. Do NOT commit after manually running `dotnet-gitversion /updateprojectfiles` -->
-    <AssemblyVersion>1.0</AssemblyVersion>
-    <FileVersion>1.0</FileVersion>
-    <Version>1.0</Version>
-    <InformationalVersion>1.0</InformationalVersion>
+    <TargetFrameworks>net472;netstandard2.1;net7.0</TargetFrameworks>
+    <RootNamespace>Terminal.Gui</RootNamespace>
+    <AssemblyName>Terminal.Gui</AssemblyName>
+    <SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
   </PropertyGroup>
   </PropertyGroup>
+  <!-- =================================================================== -->
+  <!-- Dependencies -->
+  <!-- =================================================================== -->
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="NStack.Core" Version="1.0.7" />
     <PackageReference Include="NStack.Core" Version="1.0.7" />
+    <PackageReference Include="System.Management" Version="7.0.2" />
+    <!-- Enable Nuget Source Link for github -->
+    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
     <InternalsVisibleTo Include="UnitTests" />
     <InternalsVisibleTo Include="UnitTests" />
   </ItemGroup>
   </ItemGroup>
-  <!-- Uncomment the RestoreSources element to have dotnet restore pull NStack from a local dir for testing -->
   <PropertyGroup>
   <PropertyGroup>
+    <!-- Uncomment the RestoreSources element to have dotnet restore pull NStack from a local dir for testing -->
     <!-- See https://stackoverflow.com/a/44463578/297526 -->
     <!-- See https://stackoverflow.com/a/44463578/297526 -->
     <!--<RestoreSources>$(RestoreSources);..\..\NStack\NStack\bin\Debug;https://api.nuget.org/v3/index.json</RestoreSources>-->
     <!--<RestoreSources>$(RestoreSources);..\..\NStack\NStack\bin\Debug;https://api.nuget.org/v3/index.json</RestoreSources>-->
   </PropertyGroup>
   </PropertyGroup>
+  <!-- =================================================================== -->
   <!-- API Documentation -->
   <!-- API Documentation -->
+  <!-- =================================================================== -->
   <ItemGroup>
   <ItemGroup>
     <None Include="..\docfx\images\logo.png">
     <None Include="..\docfx\images\logo.png">
       <Pack>True</Pack>
       <Pack>True</Pack>
@@ -35,6 +53,9 @@
       <PackagePath>\</PackagePath>
       <PackagePath>\</PackagePath>
     </None>
     </None>
   </ItemGroup>
   </ItemGroup>
+  <!-- =================================================================== -->
+  <!-- i18 -->
+  <!-- =================================================================== -->
   <ItemGroup>
   <ItemGroup>
     <Compile Update="Resources\Strings.Designer.cs">
     <Compile Update="Resources\Strings.Designer.cs">
       <DesignTime>True</DesignTime>
       <DesignTime>True</DesignTime>
@@ -48,38 +69,37 @@
       <LastGenOutput>Strings.Designer.cs</LastGenOutput>
       <LastGenOutput>Strings.Designer.cs</LastGenOutput>
     </EmbeddedResource>
     </EmbeddedResource>
   </ItemGroup>
   </ItemGroup>
-  <!-- Enable Nuget Source Link for github -->
-  <ItemGroup>
-    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
-    <PackageReference Include="System.Management" Version="7.0.2" />
-  </ItemGroup>
+  <!-- =================================================================== -->
+  <!-- Nuget  -->
+  <!-- =================================================================== -->
   <PropertyGroup>
   <PropertyGroup>
-    <TargetFrameworks>net472;netstandard2.1;net7.0</TargetFrameworks>
-    <RootNamespace>Terminal.Gui</RootNamespace>
-    <AssemblyName>Terminal.Gui</AssemblyName>
-    <DocumentationFile>bin\Release\Terminal.Gui.xml</DocumentationFile>
-    <GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
-    <!--<GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' ">true</GeneratePackageOnBuild>-->
     <PackageId>Terminal.Gui</PackageId>
     <PackageId>Terminal.Gui</PackageId>
     <PackageLicenseExpression>MIT</PackageLicenseExpression>
     <PackageLicenseExpression>MIT</PackageLicenseExpression>
     <PackageProjectUrl>https://github.com/gui-cs/Terminal.Gui/</PackageProjectUrl>
     <PackageProjectUrl>https://github.com/gui-cs/Terminal.Gui/</PackageProjectUrl>
-    <RepositoryUrl>https://github.com/gui-cs/Terminal.Gui.git</RepositoryUrl>
-    <RepositoryType>git</RepositoryType>
-    <IncludeSymbols>true</IncludeSymbols>
-    <SymbolPackageFormat>snupkg</SymbolPackageFormat>
-    <!-- Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
-    <PublishRepositoryUrl>true</PublishRepositoryUrl>
-    <!-- Embed source files that are not tracked by the source control manager in the PDB -->
-    <EmbedUntrackedSources>true</EmbedUntrackedSources>
     <PackageIcon>logo.png</PackageIcon>
     <PackageIcon>logo.png</PackageIcon>
     <PackageReadmeFile>README.md</PackageReadmeFile>
     <PackageReadmeFile>README.md</PackageReadmeFile>
     <PackageTags>csharp, terminal, c#, f#, gui, toolkit, console, tui</PackageTags>
     <PackageTags>csharp, terminal, c#, f#, gui, toolkit, console, tui</PackageTags>
     <Description>Cross platform Terminal UI toolkit for .NET</Description>
     <Description>Cross platform Terminal UI toolkit for .NET</Description>
-    <Owners>Miguel de Icaza, Charlie Kindel</Owners>
+    <Owners>Miguel de Icaza, Tig Kindel</Owners>
     <Summary>A toolkit for building rich console apps for .NET that works on Windows, Mac, and Linux/Unix.</Summary>
     <Summary>A toolkit for building rich console apps for .NET that works on Windows, Mac, and Linux/Unix.</Summary>
     <Title>Terminal.Gui - Cross platform Terminal User Interface (TUI) toolkit for .NET</Title>
     <Title>Terminal.Gui - Cross platform Terminal User Interface (TUI) toolkit for .NET</Title>
     <PackageReleaseNotes>
     <PackageReleaseNotes>
       See: https://github.com/gui-cs/Terminal.Gui/releases
       See: https://github.com/gui-cs/Terminal.Gui/releases
     </PackageReleaseNotes>
     </PackageReleaseNotes>
+    <DocumentationFile>bin\Release\Terminal.Gui.xml</DocumentationFile>
+    <GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Debug' ">true</GeneratePackageOnBuild>
+    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+    <RepositoryUrl>https://github.com/gui-cs/Terminal.Gui.git</RepositoryUrl>
+    <RepositoryType>git</RepositoryType>
+    <IncludeSymbols>true</IncludeSymbols>
+    <SymbolPackageFormat>snupkg</SymbolPackageFormat>
+    <!-- Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
+    <PublishRepositoryUrl>true</PublishRepositoryUrl>
+    <!-- Embed source files that are not tracked by the source control manager in the PDB -->
+    <GitRepositoryRemoteName>upstream</GitRepositoryRemoteName>
+    <EmbedUntrackedSources>true</EmbedUntrackedSources>
+    <EnableSourceLink>true</EnableSourceLink>
+    <!--<DebugType>Embedded</DebugType>-->
+    <Authors>Miguel de Icaza, Tig Kindel (@tig), @BDisp</Authors>
   </PropertyGroup>
   </PropertyGroup>
 </Project>
 </Project>

+ 1 - 1
Terminal.Gui/Views/ContextMenu.cs

@@ -162,7 +162,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public void Hide ()
 		public void Hide ()
 		{
 		{
-			menuBar.CleanUp ();
+			menuBar?.CleanUp ();
 			Dispose ();
 			Dispose ();
 		}
 		}
 
 

+ 64 - 14
Terminal.Gui/Views/Menu.cs

@@ -414,7 +414,7 @@ namespace Terminal.Gui {
 
 
 				current = -1;
 				current = -1;
 				for (int i = 0; i < barItems.Children?.Length; i++) {
 				for (int i = 0; i < barItems.Children?.Length; i++) {
-					if (barItems.Children [i] != null) {
+					if (barItems.Children [i]?.IsEnabled () == true) {
 						current = i;
 						current = i;
 						break;
 						break;
 					}
 					}
@@ -572,17 +572,14 @@ namespace Terminal.Gui {
 
 
 		public void Run (Action action)
 		public void Run (Action action)
 		{
 		{
-			if (action == null)
+			if (action == null || host == null)
 				return;
 				return;
 
 
 			Application.UngrabMouse ();
 			Application.UngrabMouse ();
 			host.CloseAllMenus ();
 			host.CloseAllMenus ();
 			Application.Refresh ();
 			Application.Refresh ();
 
 
-			Application.MainLoop.AddIdle (() => {
-				action ();
-				return false;
-			});
+			host.Run (action);
 		}
 		}
 
 
 		public override bool OnLeave (View view)
 		public override bool OnLeave (View view)
@@ -946,6 +943,17 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public Key Key { get; set; } = Key.F9;
 		public Key Key { get; set; } = Key.F9;
 
 
+		///<inheritdoc/>
+		public override bool Visible {
+			get => base.Visible;
+			set {
+				base.Visible = value;
+				if (!value) {
+					CloseAllMenus ();
+				}
+			}
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Initializes a new instance of the <see cref="MenuBar"/>.
 		/// Initializes a new instance of the <see cref="MenuBar"/>.
 		/// </summary>
 		/// </summary>
@@ -1130,7 +1138,11 @@ namespace Terminal.Gui {
 			Application.UngrabMouse ();
 			Application.UngrabMouse ();
 			CloseAllMenus ();
 			CloseAllMenus ();
 			Application.Refresh ();
 			Application.Refresh ();
+			Run (action);
+		}
 
 
+		internal void Run (Action action)
+		{
 			Application.MainLoop.AddIdle (() => {
 			Application.MainLoop.AddIdle (() => {
 				action ();
 				action ();
 				return false;
 				return false;
@@ -1641,6 +1653,44 @@ namespace Terminal.Gui {
 					if (Char.ToUpperInvariant ((char)mi.Title [p + 1]) == c) {
 					if (Char.ToUpperInvariant ((char)mi.Title [p + 1]) == c) {
 						ProcessMenu (i, mi);
 						ProcessMenu (i, mi);
 						return true;
 						return true;
+					} else if (mi.Children?.Length > 0) {
+						if (FindAndOpenChildrenMenuByHotkey (kb, mi.Children)) {
+							return true;
+						}
+					}
+				} else if (mi.Children?.Length > 0) {
+					if (FindAndOpenChildrenMenuByHotkey (kb, mi.Children)) {
+						return true;
+					}
+				}
+			}
+
+			return false;
+		}
+
+		bool FindAndOpenChildrenMenuByHotkey (KeyEvent kb, MenuItem [] children)
+		{
+			var c = ((uint)kb.Key & (uint)Key.CharMask);
+			for (int i = 0; i < children.Length; i++) {
+				var mi = children [i];
+				int p = mi.Title.IndexOf (MenuBar.HotKeySpecifier);
+				if (p != -1 && p + 1 < mi.Title.RuneCount) {
+					if (Char.ToUpperInvariant ((char)mi.Title [p + 1]) == c) {
+						if (mi.IsEnabled ()) {
+							var action = mi.Action;
+							if (action != null) {
+								Run (action);
+							}
+						}
+						return true;
+					} else if (mi is MenuBarItem menuBarItem && menuBarItem?.Children.Length > 0) {
+						if (FindAndOpenChildrenMenuByHotkey (kb, menuBarItem.Children)) {
+							return true;
+						}
+					}
+				} else if (mi is MenuBarItem menuBarItem && menuBarItem?.Children.Length > 0) {
+					if (FindAndOpenChildrenMenuByHotkey (kb, menuBarItem.Children)) {
+						return true;
 					}
 					}
 				}
 				}
 			}
 			}
@@ -1662,12 +1712,11 @@ namespace Terminal.Gui {
 					continue;
 					continue;
 				}
 				}
 				if ((!(mi is MenuBarItem mbiTopLevel) || mbiTopLevel.IsTopLevel) && mi.Shortcut != Key.Null && mi.Shortcut == (Key)key) {
 				if ((!(mi is MenuBarItem mbiTopLevel) || mbiTopLevel.IsTopLevel) && mi.Shortcut != Key.Null && mi.Shortcut == (Key)key) {
-					var action = mi.Action;
-					if (action != null) {
-						Application.MainLoop.AddIdle (() => {
-							action ();
-							return false;
-						});
+					if (mi.IsEnabled ()) {
+						var action = mi.Action;
+						if (action != null) {
+							Run (action);
+						}
 					}
 					}
 					return true;
 					return true;
 				}
 				}
@@ -1707,10 +1756,11 @@ namespace Terminal.Gui {
 		public override bool ProcessHotKey (KeyEvent kb)
 		public override bool ProcessHotKey (KeyEvent kb)
 		{
 		{
 			if (kb.Key == Key) {
 			if (kb.Key == Key) {
-				if (!IsMenuOpen)
+				if (Visible && !IsMenuOpen) {
 					OpenMenu ();
 					OpenMenu ();
-				else
+				} else {
 					CloseAllMenus ();
 					CloseAllMenus ();
+				}
 				return true;
 				return true;
 			}
 			}
 
 

+ 7 - 7
Terminal.Gui/Views/ScrollBarView.cs

@@ -109,7 +109,7 @@ namespace Terminal.Gui {
 				OtherScrollBarView.ShowScrollIndicator = true;
 				OtherScrollBarView.ShowScrollIndicator = true;
 			}
 			}
 			ShowScrollIndicator = true;
 			ShowScrollIndicator = true;
-			contentBottomRightCorner = new View (" ") { Visible = host.Visible };
+			contentBottomRightCorner = new View (" ") { Visible = host.Visible, ColorScheme = host.ColorScheme };
 			Host.SuperView.Add (contentBottomRightCorner);
 			Host.SuperView.Add (contentBottomRightCorner);
 			contentBottomRightCorner.X = Pos.Right (host) - 1;
 			contentBottomRightCorner.X = Pos.Right (host) - 1;
 			contentBottomRightCorner.Y = Pos.Bottom (host) - 1;
 			contentBottomRightCorner.Y = Pos.Bottom (host) - 1;
@@ -346,23 +346,23 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			if (showBothScrollIndicator) {
 			if (showBothScrollIndicator) {
-				if (contentBottomRightCorner != null) {
+				if (contentBottomRightCorner != null && !contentBottomRightCorner.Visible) {
 					contentBottomRightCorner.Visible = true;
 					contentBottomRightCorner.Visible = true;
-				} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null) {
+				} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null && !otherScrollBarView.contentBottomRightCorner.Visible) {
 					otherScrollBarView.contentBottomRightCorner.Visible = true;
 					otherScrollBarView.contentBottomRightCorner.Visible = true;
 				}
 				}
 			} else if (!showScrollIndicator) {
 			} else if (!showScrollIndicator) {
-				if (contentBottomRightCorner != null) {
+				if (contentBottomRightCorner != null && contentBottomRightCorner.Visible) {
 					contentBottomRightCorner.Visible = false;
 					contentBottomRightCorner.Visible = false;
-				} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null) {
+				} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null && otherScrollBarView.contentBottomRightCorner.Visible) {
 					otherScrollBarView.contentBottomRightCorner.Visible = false;
 					otherScrollBarView.contentBottomRightCorner.Visible = false;
 				}
 				}
 				if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
 				if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
 					Application.UngrabMouse ();
 					Application.UngrabMouse ();
 				}
 				}
-			} else if (contentBottomRightCorner != null) {
+			} else if (contentBottomRightCorner != null && contentBottomRightCorner.Visible) {
 				contentBottomRightCorner.Visible = false;
 				contentBottomRightCorner.Visible = false;
-			} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null) {
+			} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null && otherScrollBarView.contentBottomRightCorner.Visible) {
 				otherScrollBarView.contentBottomRightCorner.Visible = false;
 				otherScrollBarView.contentBottomRightCorner.Visible = false;
 			}
 			}
 			if (Host?.Visible == true && showScrollIndicator && !Visible) {
 			if (Host?.Visible == true && showScrollIndicator && !Visible) {

+ 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="shortcut">Shortcut to activate the <see cref="StatusItem"/>.</param>
 		/// <param name="title">Title for 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>
 		/// <param name="action">Action to invoke when the <see cref="StatusItem"/> is activated.</param>
-		public StatusItem (Key shortcut, ustring title, Action action)
+		/// <param name="canExecute">Function to determine if the action can currently be executed.</param>
+		public StatusItem (Key shortcut, ustring title, Action action, Func<bool> canExecute = null)
 		{
 		{
 			Title = title ?? "";
 			Title = title ?? "";
 			Shortcut = shortcut;
 			Shortcut = shortcut;
 			Action = action;
 			Action = action;
+			CanExecute = canExecute;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -54,7 +56,22 @@ namespace Terminal.Gui {
 		/// Gets or sets the action to be invoked when the statusbar item is triggered
 		/// Gets or sets the action to be invoked when the statusbar item is triggered
 		/// </summary>
 		/// </summary>
 		/// <value>Action to invoke.</value>
 		/// <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>
 		/// <summary>
 		/// Gets or sets arbitrary data for the status item.
 		/// Gets or sets arbitrary data for the status item.
@@ -116,6 +133,17 @@ namespace Terminal.Gui {
 			return result;
 			return result;
 		}
 		}
 
 
+		Attribute DetermineColorSchemeFor (StatusItem item)
+		{
+			if (item != null) {
+				if (item.IsEnabled ()) {
+					return GetNormalColor ();
+				}
+				return ColorScheme.Disabled;
+			}
+			return GetNormalColor ();
+		}
+
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override void Redraw (Rect bounds)
 		public override void Redraw (Rect bounds)
 		{
 		{
@@ -129,9 +157,12 @@ namespace Terminal.Gui {
 			Driver.SetAttribute (scheme);
 			Driver.SetAttribute (scheme);
 			for (int i = 0; i < Items.Length; i++) {
 			for (int i = 0; i < Items.Length; i++) {
 				var title = Items [i].Title.ToString ();
 				var title = Items [i].Title.ToString ();
+				Driver.SetAttribute (DetermineColorSchemeFor (Items [i]));
 				for (int n = 0; n < Items [i].Title.RuneCount; n++) {
 				for (int n = 0; n < Items [i].Title.RuneCount; n++) {
 					if (title [n] == '~') {
 					if (title [n] == '~') {
-						scheme = ToggleScheme (scheme);
+						if (Items [i].IsEnabled ()) {
+							scheme = ToggleScheme (scheme);
+						}
 						continue;
 						continue;
 					}
 					}
 					Driver.AddRune (title [n]);
 					Driver.AddRune (title [n]);
@@ -149,7 +180,9 @@ namespace Terminal.Gui {
 		{
 		{
 			foreach (var item in Items) {
 			foreach (var item in Items) {
 				if (kb.Key == item.Shortcut) {
 				if (kb.Key == item.Shortcut) {
-					Run (item.Action);
+					if (item.IsEnabled ()) {
+						Run (item.Action);
+					}
 					return true;
 					return true;
 				}
 				}
 			}
 			}
@@ -165,7 +198,10 @@ namespace Terminal.Gui {
 			int pos = 1;
 			int pos = 1;
 			for (int i = 0; i < Items.Length; i++) {
 			for (int i = 0; i < Items.Length; i++) {
 				if (me.X >= pos && me.X < pos + GetItemTitleLength (Items [i].Title)) {
 				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;
 					break;
 				}
 				}
 				pos += GetItemTitleLength (Items [i].Title) + 3;
 				pos += GetItemTitleLength (Items [i].Title) + 3;

+ 37 - 8
Terminal.Gui/Views/TextView.cs

@@ -1654,11 +1654,8 @@ namespace Terminal.Gui {
 		public int BottomOffset {
 		public int BottomOffset {
 			get => bottomOffset;
 			get => bottomOffset;
 			set {
 			set {
-				if (currentRow == Lines - 1 && bottomOffset > 0 && value == 0) {
-					topRow = Math.Max (topRow - bottomOffset, 0);
-				}
+				topRow = AdjustOffset (value);
 				bottomOffset = value;
 				bottomOffset = value;
-				Adjust ();
 			}
 			}
 		}
 		}
 
 
@@ -1669,11 +1666,8 @@ namespace Terminal.Gui {
 		public int RightOffset {
 		public int RightOffset {
 			get => rightOffset;
 			get => rightOffset;
 			set {
 			set {
-				if (!wordWrap && currentColumn == GetCurrentLine ().Count && rightOffset > 0 && value == 0) {
-					leftColumn = Math.Max (leftColumn - rightOffset, 0);
-				}
+				leftColumn = AdjustOffset (value, false);
 				rightOffset = value;
 				rightOffset = value;
-				Adjust ();
 			}
 			}
 		}
 		}
 
 
@@ -2645,6 +2639,7 @@ namespace Terminal.Gui {
 				HistoryText.LineStatus.Replaced);
 				HistoryText.LineStatus.Replaced);
 
 
 			UpdateWrapModel ();
 			UpdateWrapModel ();
+			OnContentsChanged ();
 		}
 		}
 
 
 		// The column we are tracking, or -1 if we are not tracking any column
 		// The column we are tracking, or -1 if we are not tracking any column
@@ -2710,6 +2705,30 @@ namespace Terminal.Gui {
 			OnUnwrappedCursorPosition ();
 			OnUnwrappedCursorPosition ();
 		}
 		}
 
 
+		int AdjustOffset (int valueOffset, bool isRow = true)
+		{
+			var curWrap = isRow ? false : wordWrap;
+			var curLength = isRow ? Lines - 1 : GetCurrentLine ().Count;
+			var curStart = isRow ? topRow : leftColumn;
+			var curOffset = isRow ? bottomOffset : rightOffset;
+			var curSize = isRow ? Frame.Height - valueOffset : Frame.Width - valueOffset;
+			var newStart = curStart;
+
+			if (!curWrap) {
+				if (curStart > 0 && curOffset > 0 && valueOffset == 0) {
+					newStart = Math.Max (curStart - curOffset, 0);
+				} else if (curStart > 0 && curOffset == 0 && valueOffset > 0) {
+					newStart = Math.Max (Math.Min (curStart + valueOffset, curLength - curSize + 1), 0);
+				}
+
+				if (newStart != curStart) {
+					Application.MainLoop.Invoke (() => SetNeedsDisplay ());
+				}
+			}
+
+			return newStart;
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Event arguments for events for when the contents of the TextView change. E.g. the <see cref="ContentsChanged"/> event.
 		/// Event arguments for events for when the contents of the TextView change. E.g. the <see cref="ContentsChanged"/> event.
 		/// </summary>
 		/// </summary>
@@ -3550,6 +3569,7 @@ namespace Terminal.Gui {
 			}
 			}
 			if (DeleteTextForwards ()) {
 			if (DeleteTextForwards ()) {
 				UpdateWrapModel ();
 				UpdateWrapModel ();
+				OnContentsChanged ();
 
 
 				return;
 				return;
 			}
 			}
@@ -3557,6 +3577,7 @@ namespace Terminal.Gui {
 			UpdateWrapModel ();
 			UpdateWrapModel ();
 
 
 			DoNeededAction ();
 			DoNeededAction ();
+			OnContentsChanged ();
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -3581,11 +3602,13 @@ namespace Terminal.Gui {
 					HistoryText.LineStatus.Replaced);
 					HistoryText.LineStatus.Replaced);
 
 
 				UpdateWrapModel ();
 				UpdateWrapModel ();
+				OnContentsChanged ();
 
 
 				return;
 				return;
 			}
 			}
 			if (DeleteTextBackwards ()) {
 			if (DeleteTextBackwards ()) {
 				UpdateWrapModel ();
 				UpdateWrapModel ();
+				OnContentsChanged ();
 
 
 				return;
 				return;
 			}
 			}
@@ -3593,6 +3616,7 @@ namespace Terminal.Gui {
 			UpdateWrapModel ();
 			UpdateWrapModel ();
 
 
 			DoNeededAction ();
 			DoNeededAction ();
+			OnContentsChanged ();
 		}
 		}
 
 
 		void MoveLeft ()
 		void MoveLeft ()
@@ -3972,6 +3996,8 @@ namespace Terminal.Gui {
 
 
 				historyText.Add (new List<List<Rune>> () { new List<Rune> (GetCurrentLine ()) }, CursorPosition,
 				historyText.Add (new List<List<Rune>> () { new List<Rune> (GetCurrentLine ()) }, CursorPosition,
 					HistoryText.LineStatus.Replaced);
 					HistoryText.LineStatus.Replaced);
+
+				SetNeedsDisplay ();
 				OnContentsChanged ();
 				OnContentsChanged ();
 			} else {
 			} else {
 				if (selecting) {
 				if (selecting) {
@@ -3984,6 +4010,8 @@ namespace Terminal.Gui {
 					historyText.ReplaceLast (new List<List<Rune>> () { new List<Rune> (GetCurrentLine ()) }, CursorPosition,
 					historyText.ReplaceLast (new List<List<Rune>> () { new List<Rune> (GetCurrentLine ()) }, CursorPosition,
 						HistoryText.LineStatus.Original);
 						HistoryText.LineStatus.Original);
 				}
 				}
+
+				SetNeedsDisplay ();
 			}
 			}
 			UpdateWrapModel ();
 			UpdateWrapModel ();
 			selecting = false;
 			selecting = false;
@@ -4095,6 +4123,7 @@ namespace Terminal.Gui {
 			currentColumn = line.Count;
 			currentColumn = line.Count;
 			TrackColumn ();
 			TrackColumn ();
 			PositionCursor ();
 			PositionCursor ();
+			SetNeedsDisplay ();
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>

+ 20 - 18
Terminal.sln

@@ -15,9 +15,13 @@ EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E143FB1F-0B88-48CB-9086-72CDCECFCD22}"
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E143FB1F-0B88-48CB-9086-72CDCECFCD22}"
 	ProjectSection(SolutionItems) = preProject
 	ProjectSection(SolutionItems) = preProject
 		.gitignore = .gitignore
 		.gitignore = .gitignore
+		.github\CODEOWNERS = .github\CODEOWNERS
 		CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
 		CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
 		CONTRIBUTING.md = CONTRIBUTING.md
 		CONTRIBUTING.md = CONTRIBUTING.md
 		.github\workflows\dotnet-core.yml = .github\workflows\dotnet-core.yml
 		.github\workflows\dotnet-core.yml = .github\workflows\dotnet-core.yml
+		GitVersion.yml = GitVersion.yml
+		global.json = global.json
+		nuget.config = nuget.config
 		.github\workflows\publish.yml = .github\workflows\publish.yml
 		.github\workflows\publish.yml = .github\workflows\publish.yml
 		README.md = README.md
 		README.md = README.md
 		testenvironments.json = testenvironments.json
 		testenvironments.json = testenvironments.json
@@ -31,23 +35,6 @@ Global
 		Release|x86 = Release|x86
 		Release|x86 = Release|x86
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.Build.0 = Debug|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.Build.0 = Release|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.ActiveCfg = Release|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.Build.0 = Release|Any CPU
-
-		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.Build.0 = Debug|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.ActiveCfg = Release|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.Build.0 = Release|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.ActiveCfg = Debug|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.ActiveCfg = Debug|Any CPU
@@ -56,7 +43,14 @@ Global
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|Any CPU.Build.0 = Release|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|Any CPU.Build.0 = Release|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.ActiveCfg = Release|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.ActiveCfg = Release|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.Build.0 = Release|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.Build.0 = Release|Any CPU
-
+		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.Build.0 = Debug|Any CPU
+		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.Build.0 = Release|Any CPU
+		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.ActiveCfg = Release|Any CPU
+		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.Build.0 = Release|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|x86.ActiveCfg = Debug|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|x86.ActiveCfg = Debug|Any CPU
@@ -73,6 +67,14 @@ Global
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|Any CPU.Build.0 = Release|Any CPU
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|Any CPU.Build.0 = Release|Any CPU
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|x86.ActiveCfg = Release|Any CPU
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|x86.ActiveCfg = Release|Any CPU
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|x86.Build.0 = Release|Any CPU
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|x86.Build.0 = Release|Any CPU
+		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.Build.0 = Debug|Any CPU
+		{B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.ActiveCfg = Release|Any CPU
+		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE

+ 6 - 1
UICatalog/Properties/launchSettings.json

@@ -52,7 +52,12 @@
       "commandLineArgs": "\"Windows & FrameViews\""
       "commandLineArgs": "\"Windows & FrameViews\""
     },
     },
     "Docker": {
     "Docker": {
-      "commandName": "Docker"      
+      "commandName": "Docker"
+    },
+    "UICatalog WT": {
+      "commandName": "Executable",
+      "executablePath": "wt",
+      "commandLineArgs": "UICatalog.exe"
     }
     }
   }
   }
 }
 }

+ 0 - 22
UICatalog/UICatalog.cs

@@ -121,8 +121,6 @@ namespace UICatalog {
 			// a Scenario was selected. Otherwise, the user wants to exit UI Catalog.
 			// a Scenario was selected. Otherwise, the user wants to exit UI Catalog.
 			Application.Init ();
 			Application.Init ();
 			
 			
-			Application.EnableConsoleScrolling = _enableConsoleScrolling;
-			
 			Application.Run<UICatalogTopLevel> ();
 			Application.Run<UICatalogTopLevel> ();
 			Application.Shutdown ();
 			Application.Shutdown ();
 
 
@@ -144,7 +142,6 @@ namespace UICatalog {
 
 
 		static bool _useSystemConsole = false;
 		static bool _useSystemConsole = false;
 		static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
 		static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
-		static bool _enableConsoleScrolling = false;
 		static bool _isFirstRunning = true;
 		static bool _isFirstRunning = true;
 		static ColorScheme _colorScheme;
 		static ColorScheme _colorScheme;
 
 
@@ -154,7 +151,6 @@ namespace UICatalog {
 		/// </summary>
 		/// </summary>
 		class UICatalogTopLevel : Toplevel {
 		class UICatalogTopLevel : Toplevel {
 			public MenuItem miIsMouseDisabled;
 			public MenuItem miIsMouseDisabled;
-			public MenuItem miEnableConsoleScrolling;
 
 
 			public FrameView LeftPane;
 			public FrameView LeftPane;
 			public ListView CategoryListView;
 			public ListView CategoryListView;
@@ -282,7 +278,6 @@ namespace UICatalog {
 				}
 				}
 
 
 				miIsMouseDisabled.Checked = Application.IsMouseDisabled;
 				miIsMouseDisabled.Checked = Application.IsMouseDisabled;
-				miEnableConsoleScrolling.Checked = Application.EnableConsoleScrolling;
 				DriverName.Title = $"Driver: {Driver.GetType ().Name}";
 				DriverName.Title = $"Driver: {Driver.GetType ().Name}";
 				OS.Title = $"OS: {Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystem} {Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystemVersion}";
 				OS.Title = $"OS: {Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystem} {Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystemVersion}";
 
 
@@ -319,7 +314,6 @@ namespace UICatalog {
 				List<MenuItem []> menuItems = new List<MenuItem []> ();
 				List<MenuItem []> menuItems = new List<MenuItem []> ();
 				menuItems.Add (CreateDiagnosticFlagsMenuItems ());
 				menuItems.Add (CreateDiagnosticFlagsMenuItems ());
 				menuItems.Add (new MenuItem [] { null });
 				menuItems.Add (new MenuItem [] { null });
-				menuItems.Add (CreateEnableConsoleScrollingMenuItems ());
 				menuItems.Add (CreateDisabledEnabledMouseItems ());
 				menuItems.Add (CreateDisabledEnabledMouseItems ());
 				menuItems.Add (CreateKeybindingsMenuItems ());
 				menuItems.Add (CreateKeybindingsMenuItems ());
 				return menuItems;
 				return menuItems;
@@ -357,22 +351,6 @@ namespace UICatalog {
 				return menuItems.ToArray ();
 				return menuItems.ToArray ();
 			}
 			}
 
 
-			MenuItem [] CreateEnableConsoleScrollingMenuItems ()
-			{
-				List<MenuItem> menuItems = new List<MenuItem> ();
-				miEnableConsoleScrolling = new MenuItem ();
-				miEnableConsoleScrolling.Title = "_Enable Console Scrolling";
-				miEnableConsoleScrolling.Shortcut = Key.CtrlMask | Key.AltMask | (Key)miEnableConsoleScrolling.Title.ToString ().Substring (1, 1) [0];
-				miEnableConsoleScrolling.CheckType |= MenuItemCheckStyle.Checked;
-				miEnableConsoleScrolling.Action += () => {
-					miEnableConsoleScrolling.Checked = !miEnableConsoleScrolling.Checked;
-					Application.EnableConsoleScrolling = miEnableConsoleScrolling.Checked;
-				};
-				menuItems.Add (miEnableConsoleScrolling);
-
-				return menuItems.ToArray ();
-			}
-
 			MenuItem [] CreateDiagnosticFlagsMenuItems ()
 			MenuItem [] CreateDiagnosticFlagsMenuItems ()
 			{
 			{
 				const string OFF = "Diagnostics: _Off";
 				const string OFF = "Diagnostics: _Off";

+ 6 - 9
UICatalog/UICatalog.csproj

@@ -2,16 +2,13 @@
   <PropertyGroup>
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
     <TargetFramework>net7.0</TargetFramework>
     <TargetFramework>net7.0</TargetFramework>
-    <LangVersion>8.0</LangVersion>
+    <LangVersion>9.0</LangVersion>
     <StartupObject>UICatalog.UICatalogApp</StartupObject>
     <StartupObject>UICatalog.UICatalogApp</StartupObject>
+    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
-    <!-- In the source tree the version will always be 2.0 for all projects. -->
     <!-- Do not modify these. -->
     <!-- Do not modify these. -->
-    <AssemblyVersion>1.10.1.0</AssemblyVersion>
-    <FileVersion>1.10.1.0</FileVersion>
-    <Version>1.10.1</Version>
-    <InformationalVersion>1.10.1+6.Branch.main.Sha.f7ee66ddbf8dbcfb0d96af7d63789879091670ec</InformationalVersion>
-    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
+    <FileVersion>1.0.0.0</FileVersion>
+    <Version>1.0.0</Version>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
     <DefineConstants>TRACE</DefineConstants>
     <DefineConstants>TRACE</DefineConstants>
@@ -23,8 +20,8 @@
     <None Update="./Scenarios/Spinning_globe_dark_small.gif" CopyToOutputDirectory="PreserveNewest" />
     <None Update="./Scenarios/Spinning_globe_dark_small.gif" CopyToOutputDirectory="PreserveNewest" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
-    <PackageReference Include="SixLabors.ImageSharp" Version="3.0.1" />
+    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
+    <PackageReference Include="SixLabors.ImageSharp" Version="3.0.2" />
     <PackageReference Include="CsvHelper" Version="30.0.1" />
     <PackageReference Include="CsvHelper" Version="30.0.1" />
     <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
     <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
   </ItemGroup>
   </ItemGroup>

+ 0 - 2
UnitTests/Application/ApplicationTests.cs

@@ -24,7 +24,6 @@ namespace Terminal.Gui.ApplicationTests {
 			Assert.Null (Application.Driver);
 			Assert.Null (Application.Driver);
 			Assert.Null (Application.Top);
 			Assert.Null (Application.Top);
 			Assert.Null (Application.Current);
 			Assert.Null (Application.Current);
-			Assert.False (Application.EnableConsoleScrolling);
 			Assert.Null (Application.MainLoop);
 			Assert.Null (Application.MainLoop);
 			Assert.Null (Application.Iteration);
 			Assert.Null (Application.Iteration);
 			Assert.Null (Application.RootMouseEvent);
 			Assert.Null (Application.RootMouseEvent);
@@ -36,7 +35,6 @@ namespace Terminal.Gui.ApplicationTests {
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.Top);
 			Assert.NotNull (Application.Top);
 			Assert.NotNull (Application.Current);
 			Assert.NotNull (Application.Current);
-			Assert.False (Application.EnableConsoleScrolling);
 			Assert.NotNull (Application.MainLoop);
 			Assert.NotNull (Application.MainLoop);
 			Assert.Null (Application.Iteration);
 			Assert.Null (Application.Iteration);
 			Assert.Null (Application.RootMouseEvent);
 			Assert.Null (Application.RootMouseEvent);

+ 0 - 9
UnitTests/AssemblyInfo.cs

@@ -1,9 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Reflection;
-using Terminal.Gui;
-using Xunit;
-
-// Since Application is a singleton we can't run tests in parallel
-[assembly: CollectionBehavior (DisableTestParallelization = true)]
-

+ 24 - 0
UnitTests/Core/BorderTests.cs

@@ -619,5 +619,29 @@ At 0,0
 ████████████████████
 ████████████████████
 At 0,4              ", output);
 At 0,4              ", output);
 		}
 		}
+
+		[Fact]
+		public void BorderBrush_Background_Only_Is_Set_To_Valid_Color_Enum ()
+		{
+			var border = new Border ();
+			Assert.Equal ((Color)(-1), border.BorderBrush);
+			Assert.Equal ((Color)(-1), border.Background);
+			Assert.Null (border.GetFieldValue<string> ("borderBrush"));
+			Assert.Null (border.GetFieldValue<string> ("background"));
+
+			border.BorderBrush = (Color)(-1);
+			border.Background = (Color)(-1);
+			Assert.Equal ((Color)(-1), border.BorderBrush);
+			Assert.Equal ((Color)(-1), border.Background);
+			Assert.Null (border.GetFieldValue<Color?> ("borderBrush"));
+			Assert.Null (border.GetFieldValue<Color?> ("background"));
+
+			border.BorderBrush = Color.Blue;
+			border.Background = Color.White;
+			Assert.Equal (Color.Blue, border.BorderBrush);
+			Assert.Equal (Color.White, border.Background);
+			Assert.Equal (Color.Blue, border.GetFieldValue<Color> ("borderBrush"));
+			Assert.Equal (Color.White, border.GetFieldValue<Color?> ("background"));
+		}
 	}
 	}
 }
 }

+ 32 - 160
UnitTests/Drivers/ConsoleDriverTests.cs

@@ -169,29 +169,16 @@ namespace Terminal.Gui.DriverTests {
 			Assert.Equal (40, Application.Driver.Rows);
 			Assert.Equal (40, Application.Driver.Rows);
 			Assert.True (wasTerminalResized);
 			Assert.True (wasTerminalResized);
 
 
-			// MockDriver will still be 120x40
-			wasTerminalResized = false;
-			Application.EnableConsoleScrolling = true;
-			driver.SetWindowSize (40, 20);
-			Assert.Equal (120, Application.Driver.Cols);
-			Assert.Equal (40, Application.Driver.Rows);
-			Assert.Equal (120, Console.BufferWidth);
-			Assert.Equal (40, Console.BufferHeight);
-			Assert.Equal (40, Console.WindowWidth);
-			Assert.Equal (20, Console.WindowHeight);
-			Assert.True (wasTerminalResized);
-
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
 		[Theory]
 		[Theory]
 		[InlineData (typeof (FakeDriver))]
 		[InlineData (typeof (FakeDriver))]
-		public void EnableConsoleScrolling_Is_False_Left_And_Top_Is_Always_Zero (Type driverType)
+		public void Left_And_Top_Is_Always_Zero (Type driverType)
 		{
 		{
 			var driver = (FakeDriver)Activator.CreateInstance (driverType);
 			var driver = (FakeDriver)Activator.CreateInstance (driverType);
 			Application.Init (driver);
 			Application.Init (driver);
 
 
-			Assert.False (Application.EnableConsoleScrolling);
 			Assert.Equal (0, Console.WindowLeft);
 			Assert.Equal (0, Console.WindowLeft);
 			Assert.Equal (0, Console.WindowTop);
 			Assert.Equal (0, Console.WindowTop);
 
 
@@ -202,124 +189,7 @@ namespace Terminal.Gui.DriverTests {
 			Application.Shutdown ();
 			Application.Shutdown ();
 		}
 		}
 
 
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void EnableConsoleScrolling_Is_True_Left_Cannot_Be_Greater_Than_WindowWidth (Type driverType)
-		{
-			var driver = (FakeDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
-
-			Application.EnableConsoleScrolling = true;
-			Assert.True (Application.EnableConsoleScrolling);
-
-			driver.SetWindowPosition (81, 25);
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (0, Console.WindowTop);
-
-			Application.Shutdown ();
-		}
-
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void EnableConsoleScrolling_Is_True_Left_Cannot_Be_Greater_Than_BufferWidth_Minus_WindowWidth (Type driverType)
-		{
-			var driver = (FakeDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
-
-			Application.EnableConsoleScrolling = true;
-			Assert.True (Application.EnableConsoleScrolling);
-
-			driver.SetWindowPosition (81, 25);
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (0, Console.WindowTop);
-
-			// MockDriver will now be sets to 120x25
-			driver.SetBufferSize (120, 25);
-			Assert.Equal (120, Application.Driver.Cols);
-			Assert.Equal (25, Application.Driver.Rows);
-			Assert.Equal (120, Console.BufferWidth);
-			Assert.Equal (25, Console.BufferHeight);
-			Assert.Equal (80, Console.WindowWidth);
-			Assert.Equal (25, Console.WindowHeight);
-			driver.SetWindowPosition (121, 25);
-			Assert.Equal (40, Console.WindowLeft);
-			Assert.Equal (0, Console.WindowTop);
-
-			driver.SetWindowSize (90, 25);
-			Assert.Equal (120, Application.Driver.Cols);
-			Assert.Equal (25, Application.Driver.Rows);
-			Assert.Equal (120, Console.BufferWidth);
-			Assert.Equal (25, Console.BufferHeight);
-			Assert.Equal (90, Console.WindowWidth);
-			Assert.Equal (25, Console.WindowHeight);
-			driver.SetWindowPosition (121, 25);
-			Assert.Equal (30, Console.WindowLeft);
-			Assert.Equal (0, Console.WindowTop);
-
-			Application.Shutdown ();
-		}
-
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void EnableConsoleScrolling_Is_True_Top_Cannot_Be_Greater_Than_WindowHeight (Type driverType)
-		{
-			var driver = (FakeDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
-
-			Application.EnableConsoleScrolling = true;
-			Assert.True (Application.EnableConsoleScrolling);
-
-			driver.SetWindowPosition (80, 26);
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (0, Console.WindowTop);
-
-			Application.Shutdown ();
-		}
-
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void EnableConsoleScrolling_Is_True_Top_Cannot_Be_Greater_Than_BufferHeight_Minus_WindowHeight (Type driverType)
-		{
-			var driver = (FakeDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
-
-			Application.EnableConsoleScrolling = true;
-			Assert.True (Application.EnableConsoleScrolling);
 
 
-			driver.SetWindowPosition (80, 26);
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (0, Console.WindowTop);
-
-			// MockDriver will now be sets to 80x40
-			driver.SetBufferSize (80, 40);
-			Assert.Equal (80, Application.Driver.Cols);
-			Assert.Equal (40, Application.Driver.Rows);
-			Assert.Equal (80, Console.BufferWidth);
-			Assert.Equal (40, Console.BufferHeight);
-			Assert.Equal (80, Console.WindowWidth);
-			Assert.Equal (25, Console.WindowHeight);
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (0, Console.WindowTop);
-			driver.SetWindowPosition (80, 40);
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (15, Console.WindowTop);
-
-			driver.SetWindowSize (80, 20);
-			Assert.Equal (80, Application.Driver.Cols);
-			Assert.Equal (40, Application.Driver.Rows);
-			Assert.Equal (80, Console.BufferWidth);
-			Assert.Equal (40, Console.BufferHeight);
-			Assert.Equal (80, Console.WindowWidth);
-			Assert.Equal (20, Console.WindowHeight);
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (15, Console.WindowTop);
-			driver.SetWindowPosition (80, 41);
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (20, Console.WindowTop);
-
-			Application.Shutdown ();
-		}
-		
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void AddRune_On_Clip_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
 		public void AddRune_On_Clip_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
 		{
 		{
@@ -441,7 +311,7 @@ namespace Terminal.Gui.DriverTests {
 		}
 		}
 
 
 		private static object packetLock = new object ();
 		private static object packetLock = new object ();
-		
+
 		/// <summary>
 		/// <summary>
 		/// Sometimes when using remote tools EventKeyRecord sends 'virtual keystrokes'.
 		/// Sometimes when using remote tools EventKeyRecord sends 'virtual keystrokes'.
 		/// These are indicated with the wVirtualKeyCode of 231. When we see this code
 		/// These are indicated with the wVirtualKeyCode of 231. When we see this code
@@ -449,46 +319,48 @@ namespace Terminal.Gui.DriverTests {
 		/// when telling the rest of the framework what button was pressed. For full details
 		/// when telling the rest of the framework what button was pressed. For full details
 		/// see: https://github.com/gui-cs/Terminal.Gui/issues/2008
 		/// see: https://github.com/gui-cs/Terminal.Gui/issues/2008
 		/// </summary>
 		/// </summary>
-		[Theory, AutoInitShutdown]
+		[Theory]
 		[ClassData (typeof (PacketTest))]
 		[ClassData (typeof (PacketTest))]
 		public void TestVKPacket (uint unicodeCharacter, bool shift, bool alt, bool control, uint initialVirtualKey, uint initialScanCode, Key expectedRemapping, uint expectedVirtualKey, uint expectedScanCode)
 		public void TestVKPacket (uint unicodeCharacter, bool shift, bool alt, bool control, uint initialVirtualKey, uint initialScanCode, Key expectedRemapping, uint expectedVirtualKey, uint expectedScanCode)
 		{
 		{
-			var modifiers = new ConsoleModifiers ();
-			if (shift) modifiers |= ConsoleModifiers.Shift;
-			if (alt) modifiers |= ConsoleModifiers.Alt;
-			if (control) modifiers |= ConsoleModifiers.Control;
-			var mappedConsoleKey = ConsoleKeyMapping.GetConsoleKeyFromKey (unicodeCharacter, modifiers, out uint scanCode, out uint outputChar);
+			lock (packetLock) {
+				Application.ForceFakeConsole = true;
+				Application.Init ();
 
 
-			if ((scanCode > 0 || mappedConsoleKey == 0) && mappedConsoleKey == initialVirtualKey) Assert.Equal (mappedConsoleKey, initialVirtualKey);
-			else Assert.Equal (mappedConsoleKey, outputChar < 0xff ? outputChar & 0xff | 0xff << 8 : outputChar);
-			Assert.Equal (scanCode, initialScanCode);
+				var modifiers = new ConsoleModifiers ();
+				if (shift) modifiers |= ConsoleModifiers.Shift;
+				if (alt) modifiers |= ConsoleModifiers.Alt;
+				if (control) modifiers |= ConsoleModifiers.Control;
+				var mappedConsoleKey = ConsoleKeyMapping.GetConsoleKeyFromKey (unicodeCharacter, modifiers, out uint scanCode, out uint outputChar);
 
 
-			var keyChar = ConsoleKeyMapping.GetKeyCharFromConsoleKey (mappedConsoleKey, modifiers, out uint consoleKey, out scanCode);
+				if ((scanCode > 0 || mappedConsoleKey == 0) && mappedConsoleKey == initialVirtualKey) Assert.Equal (mappedConsoleKey, initialVirtualKey);
+				else Assert.Equal (mappedConsoleKey, outputChar < 0xff ? outputChar & 0xff | 0xff << 8 : outputChar);
+				Assert.Equal (scanCode, initialScanCode);
 
 
-			//if (scanCode > 0 && consoleKey == keyChar && consoleKey > 48 && consoleKey > 57 && consoleKey < 65 && consoleKey > 91) {
-			if (scanCode > 0 && keyChar == 0 && consoleKey == mappedConsoleKey) Assert.Equal (0, (double)keyChar);
-			else Assert.Equal (keyChar, unicodeCharacter);
-			Assert.Equal (consoleKey, expectedVirtualKey);
-			Assert.Equal (scanCode, expectedScanCode);
+				var keyChar = ConsoleKeyMapping.GetKeyCharFromConsoleKey (mappedConsoleKey, modifiers, out uint consoleKey, out scanCode);
 
 
-			var top = Application.Top;
+				//if (scanCode > 0 && consoleKey == keyChar && consoleKey > 48 && consoleKey > 57 && consoleKey < 65 && consoleKey > 91) {
+				if (scanCode > 0 && keyChar == 0 && consoleKey == mappedConsoleKey) Assert.Equal (0, (double)keyChar);
+				else Assert.Equal (keyChar, unicodeCharacter);
+				Assert.Equal (consoleKey, expectedVirtualKey);
+				Assert.Equal (scanCode, expectedScanCode);
 
 
-			top.KeyPress += (e) => {
-				var after = ShortcutHelper.GetModifiersKey (e.KeyEvent);
-				Assert.Equal (expectedRemapping, after);
-				e.Handled = true;
-				Application.RequestStop ();
-			};
+				var top = Application.Top;
 
 
-			var iterations = -1;
+				top.KeyPress += (e) => {
+					var after = ShortcutHelper.GetModifiersKey (e.KeyEvent);
+					Assert.Equal (expectedRemapping, after);
+					e.Handled = true;
+					Application.RequestStop ();
+				};
 
 
-			Application.Iteration += () => {
-				iterations++;
-				if (iterations == 0) Application.Driver.SendKeys ((char)mappedConsoleKey, ConsoleKey.Packet, shift, alt, control);
-			};
+				var iterations = -1;
 
 
+				Application.Iteration += () => {
+					iterations++;
+					if (iterations == 0) Application.Driver.SendKeys ((char)mappedConsoleKey, ConsoleKey.Packet, shift, alt, control);
+				};
 
 
-			lock (packetLock) {
 				Application.Run ();
 				Application.Run ();
 				Application.Shutdown ();
 				Application.Shutdown ();
 			}
 			}

+ 69 - 4
UnitTests/Menus/ContextMenuTests.cs

@@ -49,16 +49,21 @@ namespace Terminal.Gui.MenuTests {
 			Assert.NotNull (cm.Host);
 			Assert.NotNull (cm.Host);
 		}
 		}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Show_Hide_IsShow ()
+		private ContextMenu Create_ContextMenu_With_Two_MenuItem (int x, int y)
 		{
 		{
-			var cm = new ContextMenu (10, 5,
+			return new ContextMenu (x, y,
 				new MenuBarItem (new MenuItem [] {
 				new MenuBarItem (new MenuItem [] {
 					new MenuItem ("One", "", null),
 					new MenuItem ("One", "", null),
 					new MenuItem ("Two", "", null)
 					new MenuItem ("Two", "", null)
 				})
 				})
 			);
 			);
+		}
+
+		[Fact]
+		[AutoInitShutdown]
+		public void Show_Hide_IsShow ()
+		{
+			var cm = Create_ContextMenu_With_Two_MenuItem (10, 5);
 
 
 			cm.Show ();
 			cm.Show ();
 			Assert.True (ContextMenu.IsShow);
 			Assert.True (ContextMenu.IsShow);
@@ -902,5 +907,65 @@ namespace Terminal.Gui.MenuTests {
 			Assert.True (top.Subviews [1].ProcessKey (new KeyEvent (Key.F10 | Key.ShiftMask, new KeyModifiers ())));
 			Assert.True (top.Subviews [1].ProcessKey (new KeyEvent (Key.F10 | Key.ShiftMask, new KeyModifiers ())));
 			Assert.Null (tf.ContextMenu.MenuBar);
 			Assert.Null (tf.ContextMenu.MenuBar);
 		}
 		}
+
+		[Fact, AutoInitShutdown]
+		public void RequestStop_While_ContextMenu_Is_Open_Does_Not_Throws ()
+		{
+			var cm = Create_ContextMenu_With_Two_MenuItem (10, 5);
+			var top = Application.Top;
+			var isMenuAllClosed = false;
+			MenuBarItem mi = null;
+			var iterations = -1;
+			Application.Iteration += () => {
+				iterations++;
+				if (iterations == 0) {
+					cm.Show ();
+					Assert.True (ContextMenu.IsShow);
+					mi = cm.MenuBar.Menus [0];
+					mi.Action = () => {
+						var dialog1 = new Dialog ();
+						Application.Run (dialog1);
+
+						Assert.False (ContextMenu.IsShow);
+						Assert.True (isMenuAllClosed);
+					};
+
+					cm.MenuBar.MenuAllClosed += () => isMenuAllClosed = true;
+
+				} else if (iterations == 1) {
+					mi.Action ();
+				} else if (iterations == 2) {
+					Application.RequestStop ();
+				} else if (iterations == 3) {
+					isMenuAllClosed = false;
+					cm.Show ();
+					Assert.True (ContextMenu.IsShow);
+
+					cm.MenuBar.MenuAllClosed += () => isMenuAllClosed = true;
+				} else if (iterations == 4) {
+					var exception = Record.Exception (() => Application.RequestStop ());
+					Assert.Null (exception);
+				} else {
+					Application.RequestStop ();
+				}
+			};
+
+			var isTopClosed = false;
+			top.Closing += (_) => {
+				var dialog2 = new Dialog ();
+				Application.Run (dialog2);
+
+				Assert.False (ContextMenu.IsShow);
+				Assert.True (isMenuAllClosed);
+
+				isTopClosed = true;
+			};
+
+			Application.Run ();
+
+			Assert.True (isTopClosed);
+			Assert.False (ContextMenu.IsShow);
+			Assert.True (isMenuAllClosed);
+		}
 	}
 	}
 }
 }

+ 65 - 2
UnitTests/Menus/MenuTests.cs

@@ -254,8 +254,9 @@ Edit
 			// open the menu
 			// open the menu
 			Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ())));
 			Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ())));
 			Assert.True (menu.IsMenuOpen);
 			Assert.True (menu.IsMenuOpen);
-			Assert.Equal ("_New", miCurrent.Parent.Title);
-			Assert.Equal ("_New doc", miCurrent.Title);
+			// The _New doc isn't enabled because it can't execute and so can't be selected
+			Assert.Equal ("_File", miCurrent.Parent.Title);
+			Assert.Equal ("_New", miCurrent.Title);
 
 
 			Assert.True (mCurrent.ProcessKey (new KeyEvent (Key.CursorDown, new KeyModifiers ())));
 			Assert.True (mCurrent.ProcessKey (new KeyEvent (Key.CursorDown, new KeyModifiers ())));
 			Assert.True (menu.IsMenuOpen);
 			Assert.True (menu.IsMenuOpen);
@@ -1746,5 +1747,67 @@ Edit
 			var exception = Record.Exception (() => menu.ProcessColdKey (new KeyEvent (Key.Space, new KeyModifiers ())));
 			var exception = Record.Exception (() => menu.ProcessColdKey (new KeyEvent (Key.Space, new KeyModifiers ())));
 			Assert.Null (exception);
 			Assert.Null (exception);
 		}
 		}
+
+		[Fact, AutoInitShutdown]
+		public void CanExecute_ProcessHotKey ()
+		{
+			Window win = null;
+			var menu = new MenuBar (new MenuBarItem [] {
+				new MenuBarItem ("File", new MenuItem [] {
+					new MenuItem ("_New", "", New, CanExecuteNew),
+					new MenuItem ("_Close", "", Close, CanExecuteClose)
+				}),
+			});
+			var top = Application.Top;
+			top.Add (menu);
+
+			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.AltMask, new KeyModifiers () { Alt = true })));
+			Application.MainLoop.MainIteration ();
+			Assert.NotNull (win);
+			Assert.False (CanExecuteNew ());
+			Assert.True (CanExecuteClose ());
+		}
+
+		[Fact, AutoInitShutdown]
+		public void Visible_False_Key_Does_Not_Open_And_Close_All_Opened_Menus ()
+		{
+			var menu = new MenuBar (new MenuBarItem [] {
+				new MenuBarItem ("File", new MenuItem [] {
+					new MenuItem ("New", "", null)
+				})
+			});
+			Application.Top.Add (menu);
+			Application.Begin (Application.Top);
+
+			Assert.True (menu.Visible);
+			Assert.True (menu.ProcessHotKey (new KeyEvent (menu.Key, new KeyModifiers ())));
+			Assert.True (menu.IsMenuOpen);
+
+			menu.Visible = false;
+			Assert.False (menu.IsMenuOpen);
+
+			Assert.True (menu.ProcessHotKey (new KeyEvent (menu.Key, new KeyModifiers ())));
+			Assert.False (menu.IsMenuOpen);
+		}
 	}
 	}
 }
 }

+ 8 - 0
UnitTests/ReflectionTools.cs

@@ -32,4 +32,12 @@ public static class ReflectionTools {
 		}
 		}
 		return null;
 		return null;
 	}
 	}
+
+	public static T GetFieldValue<T> (this object obj, string name)
+	{
+		// Set the flags so that private and public fields from instances will be found
+		var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+		var field = obj.GetType ().GetField (name, bindingFlags);
+		return (T)field?.GetValue (obj);
+	}
 }
 }

+ 109 - 1
UnitTests/TopLevels/ToplevelTests.cs

@@ -1009,7 +1009,98 @@ namespace Terminal.Gui.TopLevelTests {
 			Application.End (rs);
 			Application.End (rs);
 
 
 			Assert.True (isEnter);
 			Assert.True (isEnter);
-			Assert.False (isLeave);
+			Assert.False (isLeave);  // Leave event cannot be trigger because it v.Enter was performed and v is focused
+			Assert.True (v.HasFocus);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void OnEnter_OnLeave_Triggered_On_Application_Begin_End_With_More_Toplevels ()
+		{
+			var iterations = 0;
+			var steps = new int [5];
+			var isEnterTop = false;
+			var isLeaveTop = false;
+			var vt = new View ();
+			var top = Application.Top;
+			var diag = new Dialog ();
+
+			vt.Enter += (e) => {
+				iterations++;
+				isEnterTop = true;
+				if (iterations == 1) {
+					steps [0] = iterations;
+					Assert.Null (e.View);
+				} else {
+					steps [4] = iterations;
+					Assert.Equal (diag, e.View);
+				}
+			};
+			vt.Leave += (e) => {
+				iterations++;
+				steps [1] = iterations;
+				isLeaveTop = true;
+				Assert.Equal (diag, e.View);
+			};
+			top.Add (vt);
+
+			Assert.False (vt.CanFocus);
+			var exception = Record.Exception (() => top.OnEnter (top));
+			Assert.Null (exception);
+			exception = Record.Exception (() => top.OnLeave (top));
+			Assert.Null (exception);
+
+			vt.CanFocus = true;
+			Application.Begin (top);
+
+			Assert.True (isEnterTop);
+			Assert.False (isLeaveTop);
+
+			isEnterTop = false;
+			var isEnterDiag = false;
+			var isLeaveDiag = false;
+			var vd = new View ();
+			vd.Enter += (e) => {
+				iterations++;
+				steps [2] = iterations;
+				isEnterDiag = true;
+				Assert.Null (e.View);
+			};
+			vd.Leave += (e) => {
+				iterations++;
+				steps [3] = iterations;
+				isLeaveDiag = true;
+				Assert.Equal (top, e.View);
+			};
+			diag.Add (vd);
+
+			Assert.False (vd.CanFocus);
+			exception = Record.Exception (() => diag.OnEnter (diag));
+			Assert.Null (exception);
+			exception = Record.Exception (() => diag.OnLeave (diag));
+			Assert.Null (exception);
+
+			vd.CanFocus = true;
+			var rs = Application.Begin (diag);
+
+			Assert.True (isEnterDiag);
+			Assert.False (isLeaveDiag);
+			Assert.False (isEnterTop);
+			Assert.True (isLeaveTop);
+
+			isEnterDiag = false;
+			isLeaveTop = false;
+			Application.End (rs);
+
+			Assert.False (isEnterDiag);
+			Assert.True (isLeaveDiag);
+			Assert.True (isEnterTop);
+			Assert.False (isLeaveTop);  // Leave event cannot be trigger because it v.Enter was performed and v is focused
+			Assert.True (vt.HasFocus);
+			Assert.Equal (1, steps [0]);
+			Assert.Equal (2, steps [1]);
+			Assert.Equal (3, steps [2]);
+			Assert.Equal (4, steps [3]);
+			Assert.Equal (5, steps [^1]);
 		}
 		}
 
 
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
@@ -1031,5 +1122,22 @@ namespace Terminal.Gui.TopLevelTests {
 			Application.Driver.GetCursorVisibility (out cursor);
 			Application.Driver.GetCursorVisibility (out cursor);
 			Assert.Equal (CursorVisibility.Invisible, cursor);
 			Assert.Equal (CursorVisibility.Invisible, cursor);
 		}
 		}
+
+		[Fact, AutoInitShutdown]
+		public void Activating_MenuBar_By_Alt_Key_Does_Not_Throw ()
+		{
+			var menu = new MenuBar (new MenuBarItem [] {
+				new MenuBarItem ("Child", new MenuItem [] {
+					new MenuItem ("_Create Child", "", null)
+				})
+			});
+			var topChild = new Toplevel ();
+			topChild.Add (menu);
+			Application.Top.Add (topChild);
+			Application.Begin (Application.Top);
+
+			var exception = Record.Exception (() => topChild.ProcessHotKey (new KeyEvent (Key.AltMask, new KeyModifiers { Alt = true })));
+			Assert.Null (exception);
+		}
 	}
 	}
 }
 }

+ 16 - 0
UnitTests/TopLevels/WindowTests.cs

@@ -235,7 +235,23 @@ namespace Terminal.Gui.TopLevelTests {
 │└────────────────┘│
 │└────────────────┘│
 │ ^Q Quit │ ^O Open│
 │ ^Q Quit │ ^O Open│
 └──────────────────┘", output);
 └──────────────────┘", output);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void Activating_MenuBar_By_Alt_Key_Does_Not_Throw ()
+		{
+			var menu = new MenuBar (new MenuBarItem [] {
+				new MenuBarItem ("Child", new MenuItem [] {
+					new MenuItem ("_Create Child", "", null)
+				})
+			});
+			var win = new Window ();
+			win.Add (menu);
+			Application.Top.Add (win);
+			Application.Begin (Application.Top);
 
 
+			var exception = Record.Exception (() => win.ProcessHotKey (new KeyEvent (Key.AltMask, new KeyModifiers { Alt = true })));
+			Assert.Null (exception);
 		}
 		}
 	}
 	}
 }
 }

+ 10 - 8
UnitTests/UnitTests.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
   <PropertyGroup>
     <TargetFramework>net7.0</TargetFramework>
     <TargetFramework>net7.0</TargetFramework>
     <!-- https://stackoverflow.com/questions/294216/why-does-c-sharp-forbid-generic-attribute-types -->
     <!-- https://stackoverflow.com/questions/294216/why-does-c-sharp-forbid-generic-attribute-types -->
@@ -7,12 +7,9 @@
     <IsPackable>false</IsPackable>
     <IsPackable>false</IsPackable>
     <UseDataCollector />
     <UseDataCollector />
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
-    <!-- In the source tree the version will always be 2.0 for all projects. -->
     <!-- Do not modify these. -->
     <!-- Do not modify these. -->
-    <AssemblyVersion>1.10.1.0</AssemblyVersion>
-    <FileVersion>1.10.1.0</FileVersion>
-    <Version>1.10.1</Version>
-    <InformationalVersion>1.10.1+6.Branch.main.Sha.f7ee66ddbf8dbcfb0d96af7d63789879091670ec</InformationalVersion>
+    <FileVersion>1.0.0.0</FileVersion>
+    <Version>1.0.0</Version>
   </PropertyGroup>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
     <DefineConstants>TRACE</DefineConstants>
     <DefineConstants>TRACE</DefineConstants>
@@ -21,8 +18,8 @@
     <DefineConstants>TRACE;DEBUG_IDISPOSABLE</DefineConstants>
     <DefineConstants>TRACE;DEBUG_IDISPOSABLE</DefineConstants>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
-    <PackageReference Include="ReportGenerator" Version="5.1.23" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
+    <PackageReference Include="ReportGenerator" Version="5.1.24" />
     <PackageReference Include="System.Collections" Version="4.3.0" />
     <PackageReference Include="System.Collections" Version="4.3.0" />
     <PackageReference Include="xunit" Version="2.5.0" />
     <PackageReference Include="xunit" Version="2.5.0" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.5.0">
     <PackageReference Include="xunit.runner.visualstudio" Version="2.5.0">
@@ -38,6 +35,11 @@
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
     <ProjectReference Include="..\UICatalog\UICatalog.csproj" />
     <ProjectReference Include="..\UICatalog\UICatalog.csproj" />
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <None Update="xunit.runner.json">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
   <PropertyGroup Label="FineCodeCoverage">
   <PropertyGroup Label="FineCodeCoverage">
     <Enabled>
     <Enabled>
       True
       True

+ 682 - 43
UnitTests/Views/ScrollBarViewTests.cs

@@ -636,6 +636,81 @@ namespace Terminal.Gui.ViewTests {
 			Assert.True (sbv.OtherScrollBarView.Visible);
 			Assert.True (sbv.OtherScrollBarView.Visible);
 		}
 		}
 
 
+		private class TextViewScrollBarView : ScrollBarView {
+			private TextView _textView;
+
+			public TextViewScrollBarView (TextView textView) : base (textView, true)
+			{
+				_textView = textView;
+
+				ChangedPosition += TextViewScrollBarView_ChangedPosition;
+				OtherScrollBarView.ChangedPosition += OtherScrollBarView_ChangedPosition;
+				VisibleChanged += TextViewScrollBarView_VisibleChanged;
+				OtherScrollBarView.VisibleChanged += OtherScrollBarView_VisibleChanged;
+				_textView.DrawContent += TextView_DrawContent;
+				Initialized += TextViewScrollBarView_Initialized;
+				OtherScrollBarView.Initialized += OtherScrollBarView_Initialized;
+			}
+
+			private void OtherScrollBarView_Initialized (object sender, EventArgs e)
+			{
+				OtherScrollBarView_VisibleChanged ();
+			}
+
+			private void TextViewScrollBarView_Initialized (object sender, EventArgs e)
+			{
+				TextViewScrollBarView_VisibleChanged ();
+			}
+
+			private void TextView_DrawContent (Rect obj)
+			{
+				Size = _textView.Lines;
+				Position = _textView.TopRow;
+				if (OtherScrollBarView != null) {
+					OtherScrollBarView.Size = _textView.Maxlength;
+					OtherScrollBarView.Position = _textView.LeftColumn;
+				}
+				LayoutSubviews ();
+				Refresh ();
+			}
+
+			private void OtherScrollBarView_VisibleChanged ()
+			{
+				if (OtherScrollBarView.Visible && _textView.BottomOffset == 0) {
+					_textView.BottomOffset = 1;
+				} else if (!OtherScrollBarView.Visible && _textView.BottomOffset == 1) {
+					_textView.BottomOffset = 0;
+				}
+			}
+
+			private void TextViewScrollBarView_VisibleChanged ()
+			{
+				if (Visible && _textView.RightOffset == 0) {
+					_textView.RightOffset = 1;
+				} else if (!Visible && _textView.RightOffset == 1) {
+					_textView.RightOffset = 0;
+				}
+			}
+
+			private void OtherScrollBarView_ChangedPosition ()
+			{
+				_textView.LeftColumn = OtherScrollBarView.Position;
+				if (_textView.LeftColumn != OtherScrollBarView.Position) {
+					OtherScrollBarView.Position = _textView.LeftColumn;
+				}
+				_textView.SetNeedsDisplay ();
+			}
+
+			private void TextViewScrollBarView_ChangedPosition ()
+			{
+				_textView.TopRow = Position;
+				if (_textView.TopRow != Position) {
+					Position = _textView.TopRow;
+				}
+				_textView.SetNeedsDisplay ();
+			}
+		}
+
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void Hosting_ShowBothScrollIndicator_Invisible ()
 		public void Hosting_ShowBothScrollIndicator_Invisible ()
 		{
 		{
@@ -650,50 +725,8 @@ namespace Terminal.Gui.ViewTests {
 			};
 			};
 			win.Add (textView);
 			win.Add (textView);
 
 
-			var scrollBar = new ScrollBarView (textView, true);
-
-			scrollBar.ChangedPosition += () => {
-				textView.TopRow = scrollBar.Position;
-				if (textView.TopRow != scrollBar.Position) {
-					scrollBar.Position = textView.TopRow;
-				}
-				textView.SetNeedsDisplay ();
-			};
-
-			scrollBar.OtherScrollBarView.ChangedPosition += () => {
-				textView.LeftColumn = scrollBar.OtherScrollBarView.Position;
-				if (textView.LeftColumn != scrollBar.OtherScrollBarView.Position) {
-					scrollBar.OtherScrollBarView.Position = textView.LeftColumn;
-				}
-				textView.SetNeedsDisplay ();
-			};
-
-			scrollBar.VisibleChanged += () => {
-				if (scrollBar.Visible && textView.RightOffset == 0) {
-					textView.RightOffset = 1;
-				} else if (!scrollBar.Visible && textView.RightOffset == 1) {
-					textView.RightOffset = 0;
-				}
-			};
+			var scrollBar = new TextViewScrollBarView (textView);
 
 
-			scrollBar.OtherScrollBarView.VisibleChanged += () => {
-				if (scrollBar.OtherScrollBarView.Visible && textView.BottomOffset == 0) {
-					textView.BottomOffset = 1;
-				} else if (!scrollBar.OtherScrollBarView.Visible && textView.BottomOffset == 1) {
-					textView.BottomOffset = 0;
-				}
-			};
-
-			textView.DrawContent += (e) => {
-				scrollBar.Size = textView.Lines;
-				scrollBar.Position = textView.TopRow;
-				if (scrollBar.OtherScrollBarView != null) {
-					scrollBar.OtherScrollBarView.Size = textView.Maxlength;
-					scrollBar.OtherScrollBarView.Position = textView.LeftColumn;
-				}
-				scrollBar.LayoutSubviews ();
-				scrollBar.Refresh ();
-			};
 			Application.Top.Add (win);
 			Application.Top.Add (win);
 
 
 			Application.Begin (Application.Top);
 			Application.Begin (Application.Top);
@@ -971,5 +1004,611 @@ This is a test
 			Assert.False (sbv.ShowScrollIndicator);
 			Assert.False (sbv.ShowScrollIndicator);
 			Assert.False (sbv.Visible);
 			Assert.False (sbv.Visible);
 		}
 		}
+
+		[Fact, AutoInitShutdown]
+		public void ScrollBarView_Inside_TextView_Always_Scroll ()
+		{
+			var text = "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n1234567890\n";
+			var tv1 = new TextView () {
+				Id = "tv1",
+				Width = Dim.Fill (),
+				Height = Dim.Fill (),
+				Text = text
+			};
+			var f1 = new FrameView () {
+				Width = Dim.Fill (),
+				Height = Dim.Percent (70)
+			};
+			f1.Add (tv1);
+			var sBar1 = new TextViewScrollBarView (tv1);
+			var tv2 = new TextView () {
+				Id = "tv2",
+				Width = Dim.Fill (),
+				Height = Dim.Fill (),
+				Text = text,
+				ReadOnly = true
+			};
+			var f2 = new FrameView () {
+				Y = Pos.Bottom (f1),
+				Width = Dim.Fill (),
+				Height = Dim.Fill ()
+			};
+			f2.Add (tv2);
+			var sBar2 = new TextViewScrollBarView (tv2);
+			var win = new Window () {
+				Width = Dim.Fill (),
+				Height = Dim.Fill ()
+			};
+			win.Add (f1, f2);
+
+			Application.Top.Add (win);
+
+			Application.Begin (Application.Top);
+			((FakeDriver)Application.Driver).SetBufferSize (10, 20);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (0, sBar1.Position);
+			Assert.Equal (0, tv1.TopRow);
+			Assert.False (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (0, tv1.LeftColumn);
+			Assert.Equal (0, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (0, sBar2.Position);
+			Assert.Equal (0, tv2.TopRow);
+			Assert.False (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (0, tv2.LeftColumn);
+			Assert.Equal (0, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││1    ▲││
+││2    ┬││
+││3    │││
+││4    │││
+││5    │││
+││6    │││
+││7    │││
+││8    ┴││
+││9    ░││
+││10   ▼││
+│└──────┘│
+│┌──────┐│
+││1    ▲││
+││2    ┬││
+││3    ┴││
+││4    ▼││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 9, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 9, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (2, sBar1.Position);
+			Assert.Equal (2, tv1.TopRow);
+			Assert.True (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (0, tv1.LeftColumn);
+			Assert.Equal (1, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (1, sBar2.Position);
+			Assert.Equal (1, tv2.TopRow);
+			Assert.False (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (0, tv2.LeftColumn);
+			Assert.Equal (0, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││3    ▲││
+││4    ░││
+││5    ┬││
+││6    │││
+││7    │││
+││8    │││
+││9    │││
+││10   ┴││
+││12345▼││
+││◄├┤░► ││
+│└──────┘│
+│┌──────┐│
+││2    ▲││
+││3    ┬││
+││4    ┴││
+││5    ▼││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 8, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 8, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (3, sBar1.Position);
+			Assert.Equal (3, tv1.TopRow);
+			Assert.True (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (0, tv1.LeftColumn);
+			Assert.Equal (1, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (2, sBar2.Position);
+			Assert.Equal (2, tv2.TopRow);
+			Assert.False (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (0, tv2.LeftColumn);
+			Assert.Equal (0, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││4    ▲││
+││5    ░││
+││6    ┬││
+││7    │││
+││8    │││
+││9    │││
+││10   │││
+││12345┴││
+││     ▼││
+││◄├┤░► ││
+│└──────┘│
+│┌──────┐│
+││3    ▲││
+││4    ┬││
+││5    ┴││
+││6    ▼││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (3, sBar1.Position);
+			Assert.Equal (3, tv1.TopRow);
+			Assert.True (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (1, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (1, tv1.LeftColumn);
+			Assert.Equal (1, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (3, sBar2.Position);
+			Assert.Equal (3, tv2.TopRow);
+			Assert.False (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (0, tv2.LeftColumn);
+			Assert.Equal (0, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││     ▲││
+││     ░││
+││     ┬││
+││     │││
+││     │││
+││     │││
+││0    │││
+││23456┴││
+││     ▼││
+││◄├─┤► ││
+│└──────┘│
+│┌──────┐│
+││4    ▲││
+││5    ┬││
+││6    ┴││
+││7    ▼││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (3, sBar1.Position);
+			Assert.Equal (3, tv1.TopRow);
+			Assert.True (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (2, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (2, tv1.LeftColumn);
+			Assert.Equal (1, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (4, sBar2.Position);
+			Assert.Equal (4, tv2.TopRow);
+			Assert.False (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (0, tv2.LeftColumn);
+			Assert.Equal (0, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││     ▲││
+││     ░││
+││     ┬││
+││     │││
+││     │││
+││     │││
+││     │││
+││34567┴││
+││     ▼││
+││◄├─┤► ││
+│└──────┘│
+│┌──────┐│
+││5    ▲││
+││6    ┬││
+││7    ┴││
+││8    ▼││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (3, sBar1.Position);
+			Assert.Equal (3, tv1.TopRow);
+			Assert.True (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (3, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (3, tv1.LeftColumn);
+			Assert.Equal (1, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (5, sBar2.Position);
+			Assert.Equal (5, tv2.TopRow);
+			Assert.False (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (0, tv2.LeftColumn);
+			Assert.Equal (0, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││     ▲││
+││     ░││
+││     ┬││
+││     │││
+││     │││
+││     │││
+││     │││
+││45678┴││
+││     ▼││
+││◄├─┤► ││
+│└──────┘│
+│┌──────┐│
+││6    ▲││
+││7    ┬││
+││8    ┴││
+││9    ▼││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (3, sBar1.Position);
+			Assert.Equal (3, tv1.TopRow);
+			Assert.True (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (4, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (4, tv1.LeftColumn);
+			Assert.Equal (1, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (6, sBar2.Position);
+			Assert.Equal (6, tv2.TopRow);
+			Assert.False (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (0, tv2.LeftColumn);
+			Assert.Equal (0, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││     ▲││
+││     ░││
+││     ┬││
+││     │││
+││     │││
+││     │││
+││     │││
+││56789┴││
+││     ▼││
+││◄░├┤► ││
+│└──────┘│
+│┌──────┐│
+││7    ▲││
+││8    ┬││
+││9    ┴││
+││10   ▼││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 3, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (3, sBar1.Position);
+			Assert.Equal (3, tv1.TopRow);
+			Assert.True (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (5, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (5, tv1.LeftColumn);
+			Assert.Equal (1, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (8, sBar2.Position);
+			Assert.Equal (8, tv2.TopRow);
+			Assert.True (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (0, tv2.LeftColumn);
+			Assert.Equal (1, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││     ▲││
+││     ░││
+││     ┬││
+││     │││
+││     │││
+││     │││
+││     │││
+││67890┴││
+││     ▼││
+││◄░├┤► ││
+│└──────┘│
+│┌──────┐│
+││9    ▲││
+││10   ◊││
+││12345▼││
+││◄├┤░► ││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 0, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 2, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.MouseEvent (new MouseEvent { X = 0, Y = 2, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (2, sBar1.Position);
+			Assert.Equal (2, tv1.TopRow);
+			Assert.True (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (5, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (5, tv1.LeftColumn);
+			Assert.Equal (1, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (9, sBar2.Position);
+			Assert.Equal (9, tv2.TopRow);
+			Assert.True (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (0, tv2.LeftColumn);
+			Assert.Equal (1, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││     ▲││
+││     ░││
+││     ┬││
+││     │││
+││     │││
+││     │││
+││     │││
+││     ┴││
+││67890▼││
+││◄░├┤► ││
+│└──────┘│
+│┌──────┐│
+││10   ▲││
+││12345◊││
+││     ▼││
+││◄├┤░► ││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 0, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (1, sBar1.Position);
+			Assert.Equal (1, tv1.TopRow);
+			Assert.True (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (5, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (5, tv1.LeftColumn);
+			Assert.Equal (1, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (9, sBar2.Position);
+			Assert.Equal (9, tv2.TopRow);
+			Assert.True (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (1, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (1, tv2.LeftColumn);
+			Assert.Equal (1, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││     ▲││
+││     ┬││
+││     │││
+││     │││
+││     │││
+││     │││
+││     ┴││
+││     ░││
+││     ▼││
+││◄░├┤► ││
+│└──────┘│
+│┌──────┐│
+││0    ▲││
+││23456◊││
+││     ▼││
+││◄├─┤► ││
+│└──────┘│
+└────────┘", output);
+
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar1 }));
+			Assert.True (sBar1.MouseEvent (new MouseEvent { X = 0, Y = 0, Flags = MouseFlags.Button1Released, View = sBar1 }));
+			Assert.True (sBar2.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Pressed, View = sBar2 }));
+			Assert.True (sBar2.OtherScrollBarView.MouseEvent (new MouseEvent { X = 4, Y = 0, Flags = MouseFlags.Button1Released, View = sBar2 }));
+			win.Redraw (win.Bounds);
+			Application.MainLoop.MainIteration ();
+			win.Redraw (win.Bounds);
+
+			// sBar1
+			Assert.True (sBar1.Visible);
+			Assert.Equal (0, sBar1.Position);
+			Assert.Equal (0, tv1.TopRow);
+			Assert.False (sBar1.OtherScrollBarView.Visible);
+			Assert.Equal (0, sBar1.OtherScrollBarView.Position);
+			Assert.Equal (0, tv1.LeftColumn);
+			Assert.Equal (0, tv1.BottomOffset);
+			Assert.Equal (1, tv1.RightOffset);
+			Assert.Equal (new Point (0, 0), tv1.CursorPosition);
+
+			// sBar2
+			Assert.True (sBar2.Visible);
+			Assert.Equal (9, sBar2.Position);
+			Assert.Equal (9, tv2.TopRow);
+			Assert.True (sBar2.OtherScrollBarView.Visible);
+			Assert.Equal (2, sBar2.OtherScrollBarView.Position);
+			Assert.Equal (2, tv2.LeftColumn);
+			Assert.Equal (1, tv2.BottomOffset);
+			Assert.Equal (1, tv2.RightOffset);
+			Assert.Equal (new Point (0, 0), tv2.CursorPosition);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+┌────────┐
+│┌──────┐│
+││1    ▲││
+││2    ┬││
+││3    │││
+││4    │││
+││5    │││
+││6    │││
+││7    │││
+││8    ┴││
+││9    ░││
+││10   ▼││
+│└──────┘│
+│┌──────┐│
+││     ▲││
+││34567◊││
+││     ▼││
+││◄├─┤► ││
+│└──────┘│
+└────────┘", output);
+		}
 	}
 	}
 }
 }

+ 40 - 1
UnitTests/Views/StatusBarTests.cs

@@ -18,12 +18,13 @@ namespace Terminal.Gui.ViewTests {
 			Assert.Equal (Key.CtrlMask | Key.Q, si.Shortcut);
 			Assert.Equal (Key.CtrlMask | Key.Q, si.Shortcut);
 			Assert.Equal ("~^Q~ Quit", si.Title);
 			Assert.Equal ("~^Q~ Quit", si.Title);
 			Assert.Null (si.Action);
 			Assert.Null (si.Action);
+			Assert.True (si.IsEnabled ());
 			si = new StatusItem (Key.CtrlMask | Key.Q, "~^Q~ Quit", () => { });
 			si = new StatusItem (Key.CtrlMask | Key.Q, "~^Q~ Quit", () => { });
 			Assert.NotNull (si.Action);
 			Assert.NotNull (si.Action);
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void StatusBar_Contructor_Default ()
+		public void StatusBar_Constructor_Default ()
 		{
 		{
 			var sb = new StatusBar ();
 			var sb = new StatusBar ();
 
 
@@ -155,5 +156,43 @@ CTRL-O Open {Application.Driver.VLine} CTRL-Q Quit
 			Assert.Equal ("~^A~ Save As", sb.Items [1].Title);
 			Assert.Equal ("~^A~ Save As", sb.Items [1].Title);
 			Assert.Equal ("~^Q~ Quit", 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.MainIteration ();
+			Assert.NotNull (win);
+			Assert.False (CanExecuteNew ());
+			Assert.True (CanExecuteClose ());
+		}
 	}
 	}
 }
 }

+ 32 - 2
UnitTests/Views/TextViewTests.cs

@@ -6634,11 +6634,11 @@ This is the second line.
 			Kill_Delete_WordBackward ();
 			Kill_Delete_WordBackward ();
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 
 
-			expectedEventCount += 1;
+			expectedEventCount += 2;
 			Kill_To_End_Delete_Forwards_And_Copy_To_The_Clipboard ();
 			Kill_To_End_Delete_Forwards_And_Copy_To_The_Clipboard ();
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 
 
-			expectedEventCount += 1;
+			expectedEventCount += 2;
 			Kill_To_Start_Delete_Backwards_And_Copy_To_The_Clipboard ();
 			Kill_To_Start_Delete_Backwards_And_Copy_To_The_Clipboard ();
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 		}
 		}
@@ -6827,5 +6827,35 @@ This is the second line.
 			Assert.Null (exception);
 			Assert.Null (exception);
 			Assert.Equal (textToReplace, tv.Text);
 			Assert.Equal (textToReplace, tv.Text);
 		}
 		}
+
+		[Fact]
+		[TextViewTestsAutoInitShutdown]
+		public void Paste_Always_Render_Screen ()
+		{
+			var win = new Window ();
+			win.Border.BorderStyle = BorderStyle.None;
+			win.Border.DrawMarginFrame = false;
+			win.Add (_textView);
+			Application.Top.Add (win);
+			Application.Begin (Application.Top);
+
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+TAB to jump between text field", output);
+
+			Assert.True (_textView.ProcessKey (new KeyEvent (Key.End | Key.ShiftMask, new KeyModifiers () { Shift = true }))); // Select line
+			Assert.Equal ("TAB to jump between text fields.", _textView.SelectedText);
+			Assert.True (_textView.ProcessKey (new KeyEvent (Key.C | Key.CtrlMask, new KeyModifiers ()))); // Copy
+			Assert.Equal ("TAB to jump between text fields.", Clipboard.Contents);
+			Assert.True (_textView.ProcessKey (new KeyEvent (Key.End, new KeyModifiers ()))); // Go to end of line
+			Assert.True (_textView.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ()))); // New line
+			Assert.Equal (new Point (0, 1), _textView.CursorPosition);
+			Assert.Equal ("", _textView.SelectedText);
+			Assert.True (_textView.ProcessKey (new KeyEvent (Key.Y | Key.CtrlMask, new KeyModifiers ()))); // Paste
+			Assert.Equal ($"TAB to jump between text fields.{Environment.NewLine}TAB to jump between text fields.", _textView.Text);
+			win.Redraw (win.Bounds);
+			TestHelpers.AssertDriverContentsWithFrameAre (@"
+ to jump between text fields.
+ to jump between text fields.", output);
+		}
 	}
 	}
 }
 }

+ 43 - 0
UnitTests/Views/ViewTests.cs

@@ -1915,11 +1915,25 @@ Y
 			Assert.True (view1.CanFocus);
 			Assert.True (view1.CanFocus);
 			Assert.True (view1.HasFocus);
 			Assert.True (view1.HasFocus);
 			Assert.True (view2.CanFocus);
 			Assert.True (view2.CanFocus);
+			Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
+			Assert.True (Application.Top.ProcessKey (new KeyEvent (Key.Tab, new KeyModifiers ())));
+			Assert.True (view1.CanFocus);
+			Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
+			Assert.True (view2.CanFocus);
 			Assert.True (view2.HasFocus);
 			Assert.True (view2.HasFocus);
 
 
+			Assert.True (Application.Top.ProcessKey (new KeyEvent (Key.Tab, new KeyModifiers ())));
+			Assert.True (view1.CanFocus);
+			Assert.True (view1.HasFocus);
+			Assert.True (view2.CanFocus);
+			Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
 			view1.CanFocus = false;
 			view1.CanFocus = false;
 			Assert.False (view1.CanFocus);
 			Assert.False (view1.CanFocus);
 			Assert.False (view1.HasFocus);
 			Assert.False (view1.HasFocus);
+			Assert.True (view2.CanFocus);
+			Assert.True (view2.HasFocus);
 			Assert.Equal (win2, Application.Current.Focused);
 			Assert.Equal (win2, Application.Current.Focused);
 			Assert.Equal (view2, Application.Current.MostFocused);
 			Assert.Equal (view2, Application.Current.MostFocused);
 		}
 		}
@@ -1941,11 +1955,26 @@ Y
 			Assert.True (view1.CanFocus);
 			Assert.True (view1.CanFocus);
 			Assert.True (view1.HasFocus);
 			Assert.True (view1.HasFocus);
 			Assert.True (view2.CanFocus);
 			Assert.True (view2.CanFocus);
+			Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
+			Assert.True (Application.Top.ProcessKey (new KeyEvent (Key.Tab | Key.CtrlMask, new KeyModifiers ())));
+			Assert.True (Application.Top.ProcessKey (new KeyEvent (Key.Tab | Key.CtrlMask, new KeyModifiers ())));
+			Assert.True (view1.CanFocus);
+			Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
+			Assert.True (view2.CanFocus);
 			Assert.True (view2.HasFocus);
 			Assert.True (view2.HasFocus);
 
 
+			Assert.True (Application.Top.ProcessKey (new KeyEvent (Key.Tab | Key.CtrlMask, new KeyModifiers ())));
+			Assert.True (view1.CanFocus);
+			Assert.True (view1.HasFocus);
+			Assert.True (view2.CanFocus);
+			Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
 			view1.CanFocus = false;
 			view1.CanFocus = false;
 			Assert.False (view1.CanFocus);
 			Assert.False (view1.CanFocus);
 			Assert.False (view1.HasFocus);
 			Assert.False (view1.HasFocus);
+			Assert.True (view2.CanFocus);
+			Assert.False (view2.HasFocus);
 			Assert.Equal (win1, Application.Current.Focused);
 			Assert.Equal (win1, Application.Current.Focused);
 			Assert.Equal (view12, Application.Current.MostFocused);
 			Assert.Equal (view12, Application.Current.MostFocused);
 		}
 		}
@@ -1966,13 +1995,27 @@ Y
 			Assert.True (view1.CanFocus);
 			Assert.True (view1.CanFocus);
 			Assert.True (view1.HasFocus);
 			Assert.True (view1.HasFocus);
 			Assert.True (view2.CanFocus);
 			Assert.True (view2.CanFocus);
+			Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
+			Assert.True (Application.Top.ProcessKey (new KeyEvent (Key.Tab | Key.CtrlMask, new KeyModifiers ())));
+			Assert.True (view1.CanFocus);
+			Assert.False (view1.HasFocus); // Only one of the most focused toplevels view can have focus
+			Assert.True (view2.CanFocus);
 			Assert.True (view2.HasFocus);
 			Assert.True (view2.HasFocus);
 
 
+			Assert.True (Application.Top.ProcessKey (new KeyEvent (Key.Tab | Key.CtrlMask, new KeyModifiers ())));
+			Assert.True (view1.CanFocus);
+			Assert.True (view1.HasFocus);
+			Assert.True (view2.CanFocus);
+			Assert.False (view2.HasFocus); // Only one of the most focused toplevels view can have focus
+
 			win1.CanFocus = false;
 			win1.CanFocus = false;
 			Assert.False (view1.CanFocus);
 			Assert.False (view1.CanFocus);
 			Assert.False (view1.HasFocus);
 			Assert.False (view1.HasFocus);
 			Assert.False (win1.CanFocus);
 			Assert.False (win1.CanFocus);
 			Assert.False (win1.HasFocus);
 			Assert.False (win1.HasFocus);
+			Assert.True (view2.CanFocus);
+			Assert.True (view2.HasFocus);
 			Assert.Equal (win2, Application.Current.Focused);
 			Assert.Equal (win2, Application.Current.Focused);
 			Assert.Equal (view2, Application.Current.MostFocused);
 			Assert.Equal (view2, Application.Current.MostFocused);
 		}
 		}

+ 2 - 1
UnitTests/xunit.runner.json

@@ -1,5 +1,6 @@
 {
 {
   "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
   "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
   "parallelizeTestCollections": false,
   "parallelizeTestCollections": false,
-  "parallelizeAssembly": false
+  "parallelizeAssembly": false,
+  "stopOnFail": true
 }
 }

+ 2 - 2
global.json

@@ -1,6 +1,6 @@
 {
 {
   "sdk":{
   "sdk":{
-    "version":"7.0.100",
-    "rollForward":"latestMajor"
+    "version":"7.0.200",
+    "rollForward":"latestMinor"
   }
   }
 }
 }

+ 12 - 0
nuget.config

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <config>
+    <add key="defaultPushSource" value="https://api.nuget.org/v3/index.json" />
+  </config>
+  <packageSources>
+
+    <!--To inherit the global NuGet package sources remove the <clear/> line below -->
+    <clear />
+    <add key="nuget" value="https://api.nuget.org/v3/index.json" />
+  </packageSources>
+</configuration>