浏览代码

Merge branch 'v2_develop' into copilot/enable-menubar-replacement

Tig 2 周之前
父节点
当前提交
649186cfdd
共有 100 个文件被更改,包括 1722 次插入1660 次删除
  1. 79 0
      .github/workflows/README.md
  2. 74 28
      .github/workflows/unit-tests.yml
  3. 1 0
      .gitignore
  4. 21 153
      CONTRIBUTING.md
  5. 0 2
      Examples/CommunityToolkitExample/LoginView.cs
  6. 4 4
      Examples/CommunityToolkitExample/LoginViewModel.cs
  7. 0 1
      Examples/CommunityToolkitExample/Message.cs
  8. 7 8
      Examples/CommunityToolkitExample/Program.cs
  9. 25 21
      Examples/CommunityToolkitExample/README.md
  10. 27 36
      Examples/Example/Example.cs
  11. 1 4
      Examples/Example/README.md
  12. 11 45
      Examples/FluentExample/Program.cs
  13. 2 2
      Examples/NativeAot/Program.cs
  14. 7 8
      Examples/ReactiveExample/Program.cs
  15. 8 4
      Examples/ReactiveExample/README.md
  16. 28 21
      Examples/ReactiveExample/TerminalScheduler.cs
  17. 1 2
      Examples/ReactiveExample/ViewExtensions.cs
  18. 31 28
      Examples/RunnableWrapperExample/Program.cs
  19. 15 15
      Examples/SelfContained/Program.cs
  20. 26 0
      Examples/SelfContained/README.md
  21. 1 1
      Examples/UICatalog/README.md
  22. 2 2
      Examples/UICatalog/Resources/config.json
  23. 5 5
      Examples/UICatalog/Scenario.cs
  24. 8 8
      Examples/UICatalog/Scenarios/Adornments.cs
  25. 7 0
      Examples/UICatalog/Scenarios/AllViewsTester.cs
  26. 1 1
      Examples/UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs
  27. 4 4
      Examples/UICatalog/Scenarios/Arrangement.cs
  28. 15 15
      Examples/UICatalog/Scenarios/Bars.cs
  29. 5 5
      Examples/UICatalog/Scenarios/Buttons.cs
  30. 3 2
      Examples/UICatalog/Scenarios/ChineseUI.cs
  31. 1 1
      Examples/UICatalog/Scenarios/Clipping.cs
  32. 2 2
      Examples/UICatalog/Scenarios/CombiningMarks.cs
  33. 1 1
      Examples/UICatalog/Scenarios/ComboBoxIteration.cs
  34. 1 1
      Examples/UICatalog/Scenarios/ComputedLayout.cs
  35. 5 5
      Examples/UICatalog/Scenarios/ConfigurationEditor.cs
  36. 11 7
      Examples/UICatalog/Scenarios/ContextMenus.cs
  37. 17 17
      Examples/UICatalog/Scenarios/CsvEditor.cs
  38. 8 2
      Examples/UICatalog/Scenarios/Dialogs.cs
  39. 6 6
      Examples/UICatalog/Scenarios/DynamicStatusBar.cs
  40. 19 11
      Examples/UICatalog/Scenarios/Editor.cs
  41. 1 1
      Examples/UICatalog/Scenarios/EditorsAndHelpers/ArrangementEditor.cs
  42. 1 1
      Examples/UICatalog/Scenarios/EditorsAndHelpers/DimEditor.cs
  43. 1 1
      Examples/UICatalog/Scenarios/EditorsAndHelpers/PosEditor.cs
  44. 6 6
      Examples/UICatalog/Scenarios/FileDialogExamples.cs
  45. 1 1
      Examples/UICatalog/Scenarios/Generic.cs
  46. 4 4
      Examples/UICatalog/Scenarios/HexEditor.cs
  47. 3 3
      Examples/UICatalog/Scenarios/Images.cs
  48. 1 1
      Examples/UICatalog/Scenarios/InteractiveTree.cs
  49. 4 4
      Examples/UICatalog/Scenarios/KeyBindings.cs
  50. 4 4
      Examples/UICatalog/Scenarios/Keys.cs
  51. 1 1
      Examples/UICatalog/Scenarios/LineCanvasExperiment.cs
  52. 1 1
      Examples/UICatalog/Scenarios/ListColumns.cs
  53. 1 1
      Examples/UICatalog/Scenarios/ListViewWithSelection.cs
  54. 2 2
      Examples/UICatalog/Scenarios/ListsAndCombos.cs
  55. 1 1
      Examples/UICatalog/Scenarios/Localization.cs
  56. 7 7
      Examples/UICatalog/Scenarios/Mazing.cs
  57. 2 2
      Examples/UICatalog/Scenarios/Menus.cs
  58. 9 9
      Examples/UICatalog/Scenarios/MessageBoxes.cs
  59. 2 2
      Examples/UICatalog/Scenarios/Mouse.cs
  60. 1 1
      Examples/UICatalog/Scenarios/MultiColouredTable.cs
  61. 4 4
      Examples/UICatalog/Scenarios/Navigation.cs
  62. 14 11
      Examples/UICatalog/Scenarios/Notepad.cs
  63. 1 1
      Examples/UICatalog/Scenarios/PosAlignDemo.cs
  64. 14 10
      Examples/UICatalog/Scenarios/ProgressBarStyles.cs
  65. 4 4
      Examples/UICatalog/Scenarios/RunTExample.cs
  66. 3 3
      Examples/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs
  67. 15 15
      Examples/UICatalog/Scenarios/Scrolling.cs
  68. 31 31
      Examples/UICatalog/Scenarios/Shortcuts.cs
  69. 8 9
      Examples/UICatalog/Scenarios/SingleBackgroundWorker.cs
  70. 1 1
      Examples/UICatalog/Scenarios/Sliders.cs
  71. 17 17
      Examples/UICatalog/Scenarios/SpinnerStyles.cs
  72. 1 1
      Examples/UICatalog/Scenarios/SyntaxHighlighting.cs
  73. 8 8
      Examples/UICatalog/Scenarios/TableEditor.cs
  74. 3 6
      Examples/UICatalog/Scenarios/TextEffectsScenario.cs
  75. 1 1
      Examples/UICatalog/Scenarios/TextFormatterDemo.cs
  76. 1 1
      Examples/UICatalog/Scenarios/TextStyles.cs
  77. 1 1
      Examples/UICatalog/Scenarios/Themes.cs
  78. 4 4
      Examples/UICatalog/Scenarios/Threading.cs
  79. 2 2
      Examples/UICatalog/Scenarios/Transparent.cs
  80. 18 15
      Examples/UICatalog/Scenarios/TreeUseCases.cs
  81. 3 3
      Examples/UICatalog/Scenarios/ViewportSettings.cs
  82. 3 3
      Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs
  83. 11 8
      Examples/UICatalog/Scenarios/WizardAsView.cs
  84. 271 268
      Examples/UICatalog/Scenarios/Wizards.cs
  85. 13 25
      Examples/UICatalog/UICatalog.cs
  86. 28 19
      Examples/UICatalog/UICatalogRunnable.cs
  87. 15 0
      Terminal.Gui/App/Application.Clipboard.cs
  88. 0 18
      Terminal.Gui/App/Application.Current.cs
  89. 21 15
      Terminal.Gui/App/Application.Driver.cs
  90. 20 6
      Terminal.Gui/App/Application.Lifecycle.cs
  91. 12 2
      Terminal.Gui/App/Application.Mouse.cs
  92. 49 9
      Terminal.Gui/App/Application.Navigation.cs
  93. 36 22
      Terminal.Gui/App/Application.Run.cs
  94. 0 8
      Terminal.Gui/App/Application.Screen.cs
  95. 16 0
      Terminal.Gui/App/Application.TopRunnable.cs
  96. 182 80
      Terminal.Gui/App/ApplicationImpl.Lifecycle.cs
  97. 171 432
      Terminal.Gui/App/ApplicationImpl.Run.cs
  98. 11 11
      Terminal.Gui/App/ApplicationImpl.Screen.cs
  99. 150 55
      Terminal.Gui/App/ApplicationImpl.cs
  100. 16 0
      Terminal.Gui/App/ApplicationModelUsage.cs

+ 79 - 0
.github/workflows/README.md

@@ -0,0 +1,79 @@
+## CI/CD Workflows
+
+The repository uses multiple GitHub Actions workflows. What runs and when:
+
+### 1) Build Solution (`.github/workflows/build.yml`)
+
+- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`); supports `workflow_call`
+- **Runner/timeout**: `ubuntu-latest`, 10 minutes
+- **Steps**:
+- Checkout and setup .NET 8.x GA
+- `dotnet restore`
+- Build Debug: `dotnet build --configuration Debug --no-restore -property:NoWarn=0618%3B0612`
+- Build Release (library): `dotnet build Terminal.Gui/Terminal.Gui.csproj --configuration Release --no-incremental --force -property:NoWarn=0618%3B0612`
+- Pack Release: `dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages -property:NoWarn=0618%3B0612`
+- Restore NativeAot/SelfContained examples, then restore solution again
+- Build Release for `Examples/NativeAot` and `Examples/SelfContained`
+- Build Release solution
+- Upload artifacts named `build-artifacts`, retention 1 day
+
+### 2) Build & Run Unit Tests (`.github/workflows/unit-tests.yml`)
+
+- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
+- **Matrix**: Ubuntu/Windows/macOS
+- **Timeout**: 15 minutes per job
+- **Process**:
+1. Calls build workflow to build solution once
+2. Downloads build artifacts
+3. Runs `dotnet restore` (required for `--no-build` to work)
+4. **Performance optimizations**:
+   - Disables Windows Defender on Windows runners (significant speedup)
+   - Collects code coverage **only on Linux** (ubuntu-latest) for performance
+   - Windows and macOS skip coverage collection to reduce test time
+   - Increased blame-hang-timeout to 120s for Windows/macOS (60s for Linux)
+5. Runs two test jobs:
+   - **Non-parallel UnitTests**: `Tests/UnitTests` with blame/diag flags; `xunit.stopOnFail=false`
+   - **Parallel UnitTestsParallelizable**: `Tests/UnitTestsParallelizable` with blame/diag flags; `xunit.stopOnFail=false`
+6. Uploads test logs and diagnostic data from all runners
+7. **Uploads code coverage to Codecov only from Linux runner**
+
+**Test results**: All tests output to unified `TestResults/` directory at repository root
+
+### 3) Build & Run Integration Tests (`.github/workflows/integration-tests.yml`)
+
+- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
+- **Matrix**: Ubuntu/Windows/macOS
+- **Timeout**: 15 minutes
+- **Process**:
+1. Calls build workflow
+2. Downloads build artifacts
+3. Runs `dotnet restore`
+4. **Performance optimizations** (same as unit tests):
+   - Disables Windows Defender on Windows runners
+   - Collects code coverage **only on Linux**
+   - Increased blame-hang-timeout to 120s for Windows/macOS
+5. Runs IntegrationTests with blame/diag flags; `xunit.stopOnFail=true`
+6. Uploads logs per-OS
+7. **Uploads coverage to Codecov only from Linux runner**
+
+### 4) Publish to NuGet (`.github/workflows/publish.yml`)
+
+- **Triggers**: push to `v2_release`, `v2_develop`, and tags `v*`(ignores `**.md`)
+- Uses GitVersion to compute SemVer, builds Release, packs with symbols, and pushes to NuGet.org using `NUGET_API_KEY`
+
+### 5) Build and publish API docs (`.github/workflows/api-docs.yml`)
+
+- **Triggers**: push to `v1_release` and `v2_develop`
+- Builds DocFX site on Windows and deploys to GitHub Pages when `ref_name` is `v2_release` or `v2_develop`
+
+
+### Replicating CI Locally
+
+```bash
+# Full CI sequence:
+dotnet restore
+dotnet build --configuration Debug --no-restore
+dotnet test Tests/UnitTests --no-build --verbosity normal
+dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
+dotnet build --configuration Release --no-restore
+```

+ 74 - 28
.github/workflows/unit-tests.yml

@@ -120,7 +120,7 @@ jobs:
       matrix:
         os: [ ubuntu-latest, windows-latest, macos-latest ]
 
-    timeout-minutes: 15
+    timeout-minutes: 60
     steps:
 
     - name: Checkout code
@@ -154,35 +154,81 @@ jobs:
       shell: bash
       run: echo "VSTEST_DUMP_PATH=logs/UnitTestsParallelizable/${{ runner.os }}/" >> $GITHUB_ENV
 
-    - name: Run UnitTestsParallelizable
+    - name: Run UnitTestsParallelizable (10 iterations with varying parallelization)
       shell: bash
       run: |
-        if [ "${{ runner.os }}" == "Linux" ]; then
-          # Run with coverage on Linux only
-          dotnet test Tests/UnitTestsParallelizable \
-            --no-build \
-            --verbosity normal \
-            --collect:"XPlat Code Coverage" \
-            --settings Tests/UnitTests/runsettings.coverage.xml \
-            --diag:logs/UnitTestsParallelizable/${{ runner.os }}/logs.txt \
-            --blame \
-            --blame-crash \
-            --blame-hang \
-            --blame-hang-timeout 60s \
-            --blame-crash-collect-always
-        else
-          # Run without coverage on Windows/macOS for speed
-          dotnet test Tests/UnitTestsParallelizable \
-            --no-build \
-            --verbosity normal \
-            --settings Tests/UnitTestsParallelizable/runsettings.xml \
-            --diag:logs/UnitTestsParallelizable/${{ runner.os }}/logs.txt \
-            --blame \
-            --blame-crash \
-            --blame-hang \
-            --blame-hang-timeout 60s \
-            --blame-crash-collect-always
-        fi
+        # Run tests 3 times with different parallelization settings to expose concurrency issues
+        for RUN in {1..3}; do
+          echo "============================================"
+          echo "Starting test run $RUN of 3"
+          echo "============================================"
+          
+          # Use a combination of run number and timestamp to create different execution patterns
+          SEED=$((1000 + $RUN + $(date +%s) % 1000))
+          echo "Using randomization seed: $SEED"
+          
+          # Vary the xUnit parallelization based on run number to expose race conditions
+          # Runs 1-3: Default parallelization (2x CPU cores)
+          # Runs 4-6: Max parallelization (unlimited)
+          # Runs 7-9: Single threaded (1)
+          # Run 10: Random (1-4 threads)
+          if [ $RUN -le 3 ]; then
+            XUNIT_MAX_PARALLEL_THREADS="2x"
+            echo "Run $RUN: Using default parallelization (2x)"
+          elif [ $RUN -le 6 ]; then
+            XUNIT_MAX_PARALLEL_THREADS="unlimited"
+            echo "Run $RUN: Using maximum parallelization (unlimited)"
+          elif [ $RUN -le 9 ]; then
+            XUNIT_MAX_PARALLEL_THREADS="1"
+            echo "Run $RUN: Using single-threaded execution"
+          else
+            # Random parallelization based on seed
+            PROC_COUNT=$(( ($SEED % 4) + 1 ))
+            XUNIT_MAX_PARALLEL_THREADS="$PROC_COUNT"
+            echo "Run $RUN: Using random parallelization with $PROC_COUNT threads"
+          fi
+          
+          # Run tests with or without coverage based on OS and run number
+          if [ "${{ runner.os }}" == "Linux" ] && [ $RUN -eq 1 ]; then
+            echo "Run $RUN: Running with coverage collection"
+            dotnet test Tests/UnitTestsParallelizable \
+              --no-build \
+              --verbosity normal \
+              --collect:"XPlat Code Coverage" \
+              --settings Tests/UnitTests/runsettings.coverage.xml \
+              --diag:logs/UnitTestsParallelizable/${{ runner.os }}/run${RUN}-logs.txt \
+              --blame \
+              --blame-crash \
+              --blame-hang \
+              --blame-hang-timeout 60s \
+              --blame-crash-collect-always \
+              -- xUnit.MaxParallelThreads=${XUNIT_MAX_PARALLEL_THREADS}
+          else
+            dotnet test Tests/UnitTestsParallelizable \
+              --no-build \
+              --verbosity normal \
+              --settings Tests/UnitTestsParallelizable/runsettings.xml \
+              --diag:logs/UnitTestsParallelizable/${{ runner.os }}/run${RUN}-logs.txt \
+              --blame \
+              --blame-crash \
+              --blame-hang \
+              --blame-hang-timeout 60s \
+              --blame-crash-collect-always \
+              -- xUnit.MaxParallelThreads=${XUNIT_MAX_PARALLEL_THREADS}
+          fi
+          
+          if [ $? -ne 0 ]; then
+            echo "ERROR: Test run $RUN failed!"
+            exit 1
+          fi
+          
+          echo "Test run $RUN completed successfully"
+          echo ""
+        done
+        
+        echo "============================================"
+        echo "All 10 test runs completed successfully!"
+        echo "============================================"
 
     - name: Upload UnitTestsParallelizable Logs
       if: always()

+ 1 - 0
.gitignore

@@ -73,3 +73,4 @@ log.*
 !/Tests/coverage/.gitkeep   # keep folder in repo
 /Tests/report/
 *.cobertura.xml
+/docfx/docs/migratingfromv1.md

+ 21 - 153
CONTRIBUTING.md

@@ -7,19 +7,16 @@ Welcome! This guide provides everything you need to know to contribute effective
 ## Table of Contents
 
 - [Project Overview](#project-overview)
-- [Building and Testing](#building-and-testing)
+- [Key Architecture Concepts](#key-architecture-concepts)
 - [Coding Conventions](#coding-conventions)
+- [Building and Testing](#building-and-testing)
 - [Testing Requirements](#testing-requirements)
 - [API Documentation Requirements](#api-documentation-requirements)
 - [Pull Request Guidelines](#pull-request-guidelines)
 - [CI/CD Workflows](#cicd-workflows)
 - [Repository Structure](#repository-structure)
 - [Branching Model](#branching-model)
-- [Key Architecture Concepts](#key-architecture-concepts)
 - [What NOT to Do](#what-not-to-do)
-- [Additional Resources](#additional-resources)
-
----
 
 ## Project Overview
 
@@ -32,8 +29,18 @@ Welcome! This guide provides everything you need to know to contribute effective
 - **Version**: v2 (Alpha), v1 (maintenance mode)
 - **Branching**: GitFlow model (v2_develop is default/active development)
 
----
+## Key Architecture Concepts
+
+**⚠️ CRITICAL - AI Agents MUST understand these concepts before starting work.**
 
+- **Application Lifecycle** - How `Application.Init`, `Application.Run`, and `Application.Shutdown` work - [Application Deep Dive](./docfx/docs/application.md)
+- **Cancellable Workflow Patern** - [CWP Deep Dive](./docfx/docs/cancellable-work-pattern.md)
+- **View Hierarchy** - Understanding `View`, `Runnable`, `Window`, and view containment - [View Deep Dive](./docfx/docs/View.md)
+- **Layout System** - Pos, Dim, and automatic layout -  [Layout System](./docfx/docs/layout.md)
+- **Event System** - How keyboard, mouse, and application events flow - [Events Deep Dive](./docfx/docs/events.md)
+- **Driver Architecture** - How console drivers abstract platform differences - [Drivers](./docfx/docs/drivers.md)
+- **Drawing Model** - How rendering works with Attributes, Colors, and Glyphs  - [Drawing Deep Dive](./docfx/docs/drivers.md)
+ 
 ## Building and Testing
 
 ### Required Tools
@@ -89,28 +96,18 @@ Welcome! This guide provides everything you need to know to contribute effective
 
 ### Common Build Issues
 
-#### Issue: Build Warnings
-- **Expected**: None warnings (~100 currently).
-- **Action**: Don't add new warnings; fix warnings in code you modify
-
 #### Issue: NativeAot/SelfContained Build
+
 - **Solution**: Restore these projects explicitly:
   ```bash
   dotnet restore ./Examples/NativeAot/NativeAot.csproj -f
   dotnet restore ./Examples/SelfContained/SelfContained.csproj -f
   ```
 
-### Running Examples
-
-**UICatalog** (comprehensive demo app):
-```bash
-dotnet run --project Examples/UICatalog/UICatalog.csproj
-```
-
----
-
 ## Coding Conventions
 
+**⚠️ CRITICAL - These rules MUST be followed in ALL new or modified code**
+
 ### Code Style Tenets
 
 1. **Six-Year-Old Reading Level** - Readability over terseness
@@ -161,8 +158,6 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
 
 **⚠️ CRITICAL - These conventions apply to ALL code - production code, test code, examples, and samples.**
 
----
-
 ## Testing Requirements
 
 ### Code Coverage
@@ -178,19 +173,17 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
 
 ### Test Patterns
 
-- **Parallelizable tests preferred** - Add new tests to `UnitTestsParallelizable` when possible
-- **Avoid static dependencies** - Don't use `Application.Init`, `ConfigurationManager` in tests
-- **Don't use `[AutoInitShutdown]`** - Legacy pattern, being phased out
 - **Make tests granular** - Each test should cover smallest area possible
 - Follow existing test patterns in respective test projects
+- **Avoid adding new tests to the `UnitTests` Project** - Make them parallelizable and add them to `UnitTests.Parallelizable`
+- **Avoid static dependencies** - DO NOT use the legacy/static `Application` API or `ConfigurationManager` in tests unless the tests explicitly test related functionality.
+- **Don't use `[AutoInitShutdown]` or `[SetupFakeApplication]`** - Legacy pattern, being phased out
 
 ### Test Configuration
 
 - `xunit.runner.json` - xUnit configuration
 - `coverlet.runsettings` - Coverage settings (OpenCover format)
 
----
-
 ## API Documentation Requirements
 
 **All public APIs MUST have XML documentation:**
@@ -202,16 +195,15 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
 - Complex topics → `docfx/docs/*.md` files
 - Proper English and grammar - Clear, concise, complete. Use imperative mood.
 
----
-
 ## Pull Request Guidelines
 
 ### PR Requirements
 
+- **ALWAYS** include instructions for pulling down locally at end of Description
+
 - **Title**: "Fixes #issue. Terse description". If multiple issues, list all, separated by commas (e.g. "Fixes #123, #456. Terse description")
 - **Description**: 
   - Include "- Fixes #issue" for each issue near the top
-  - **ALWAYS** include instructions for pulling down locally at end of Description
   - Suggest user setup a remote named `copilot` pointing to your fork
   - Example:
     ```markdown
@@ -220,99 +212,14 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
     git fetch copilot <branch-name>
     git checkout copilot/<branch-name>
     ```
-- **Coding Style**: Follow all coding conventions in this document for new and modified code
 - **Tests**: Add tests for new functionality (see [Testing Requirements](#testing-requirements))
 - **Coverage**: Maintain or increase code coverage
 - **Scenarios**: Update UICatalog scenarios when adding features
 - **Warnings**: **CRITICAL - PRs must not introduce any new warnings**
   - Any file modified in a PR that currently generates warnings **MUST** be fixed to remove those warnings
   - Exception: Warnings caused by `[Obsolete]` attributes can remain
-  - Expected baseline: ~326 warnings (mostly nullable reference warnings, unused variables, xUnit suggestions)
   - Action: Before submitting a PR, verify your changes don't add new warnings and fix any warnings in files you modify
 
----
-
-## CI/CD Workflows
-
-The repository uses multiple GitHub Actions workflows. What runs and when:
-
-### 1) Build Solution (`.github/workflows/build.yml`)
-
-- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`); supports `workflow_call`
-- **Runner/timeout**: `ubuntu-latest`, 10 minutes
-- **Steps**:
-- Checkout and setup .NET 8.x GA
-- `dotnet restore`
-- Build Debug: `dotnet build --configuration Debug --no-restore -property:NoWarn=0618%3B0612`
-- Build Release (library): `dotnet build Terminal.Gui/Terminal.Gui.csproj --configuration Release --no-incremental --force -property:NoWarn=0618%3B0612`
-- Pack Release: `dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages -property:NoWarn=0618%3B0612`
-- Restore NativeAot/SelfContained examples, then restore solution again
-- Build Release for `Examples/NativeAot` and `Examples/SelfContained`
-- Build Release solution
-- Upload artifacts named `build-artifacts`, retention 1 day
-
-### 2) Build & Run Unit Tests (`.github/workflows/unit-tests.yml`)
-
-- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
-- **Matrix**: Ubuntu/Windows/macOS
-- **Timeout**: 15 minutes per job
-- **Process**:
-1. Calls build workflow to build solution once
-2. Downloads build artifacts
-3. Runs `dotnet restore` (required for `--no-build` to work)
-4. **Performance optimizations**:
-   - Disables Windows Defender on Windows runners (significant speedup)
-   - Collects code coverage **only on Linux** (ubuntu-latest) for performance
-   - Windows and macOS skip coverage collection to reduce test time
-   - Increased blame-hang-timeout to 120s for Windows/macOS (60s for Linux)
-5. Runs two test jobs:
-   - **Non-parallel UnitTests**: `Tests/UnitTests` with blame/diag flags; `xunit.stopOnFail=false`
-   - **Parallel UnitTestsParallelizable**: `Tests/UnitTestsParallelizable` with blame/diag flags; `xunit.stopOnFail=false`
-6. Uploads test logs and diagnostic data from all runners
-7. **Uploads code coverage to Codecov only from Linux runner**
-
-**Test results**: All tests output to unified `TestResults/` directory at repository root
-
-### 3) Build & Run Integration Tests (`.github/workflows/integration-tests.yml`)
-
-- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
-- **Matrix**: Ubuntu/Windows/macOS
-- **Timeout**: 15 minutes
-- **Process**:
-1. Calls build workflow
-2. Downloads build artifacts
-3. Runs `dotnet restore`
-4. **Performance optimizations** (same as unit tests):
-   - Disables Windows Defender on Windows runners
-   - Collects code coverage **only on Linux**
-   - Increased blame-hang-timeout to 120s for Windows/macOS
-5. Runs IntegrationTests with blame/diag flags; `xunit.stopOnFail=true`
-6. Uploads logs per-OS
-7. **Uploads coverage to Codecov only from Linux runner**
-
-### 4) Publish to NuGet (`.github/workflows/publish.yml`)
-
-- **Triggers**: push to `v2_release`, `v2_develop`, and tags `v*`(ignores `**.md`)
-- Uses GitVersion to compute SemVer, builds Release, packs with symbols, and pushes to NuGet.org using `NUGET_API_KEY`
-
-### 5) Build and publish API docs (`.github/workflows/api-docs.yml`)
-
-- **Triggers**: push to `v1_release` and `v2_develop`
-- Builds DocFX site on Windows and deploys to GitHub Pages when `ref_name` is `v2_release` or `v2_develop`
-
-
-### Replicating CI Locally
-
-```bash
-# Full CI sequence:
-dotnet restore
-dotnet build --configuration Debug --no-restore
-dotnet test Tests/UnitTests --no-build --verbosity normal
-dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
-dotnet build --configuration Release --no-restore
-```
-
----
 
 ## Repository Structure
 
@@ -364,7 +271,6 @@ dotnet build --configuration Release --no-restore
 
 **`/.github/workflows/`** - CI/CD pipelines (see [CI/CD Workflows](#cicd-workflows))
 
----
 
 ## Branching Model
 
@@ -374,31 +280,6 @@ dotnet build --configuration Release --no-restore
 - `v2_release` - Stable releases, matches NuGet
 - `v1_develop`, `v1_release` - Legacy v1 (maintenance only)
 
----
-
-## Key Architecture Concepts
-
-**⚠️ CRITICAL - Contributors should understand these concepts before starting work.**
-
-See `/docfx/docs/` for deep dives on:
-
-- **Application Lifecycle** - How `Application.Init`, `Application.Run`, and `Application.Shutdown` work
-- **View Hierarchy** - Understanding `View`, `Toplevel`, `Window`, and view containment
-- **Layout System** - Pos, Dim, and automatic layout
-- **Event System** - How keyboard, mouse, and application events flow
-- **Driver Architecture** - How console drivers abstract platform differences
-- **Drawing Model** - How rendering works with Attributes, Colors, and Glyphs
-
-Key documentation:
-- [View Documentation](https://gui-cs.github.io/Terminal.Gui/docs/View.html)
-- [Events Deep Dive](https://gui-cs.github.io/Terminal.Gui/docs/events.html)
-- [Layout System](https://gui-cs.github.io/Terminal.Gui/docs/layout.html)
-- [Keyboard Handling](https://gui-cs.github.io/Terminal.Gui/docs/keyboard.html)
-- [Mouse Support](https://gui-cs.github.io/Terminal.Gui/docs/mouse.html)
-- [Drivers](https://gui-cs.github.io/Terminal.Gui/docs/drivers.html)
-
----
-
 ## What NOT to Do
 
 - ❌ Don't add new linters/formatters (use existing)
@@ -412,17 +293,4 @@ Key documentation:
 - ❌ **Don't use redundant type names with `new`** (**ALWAYS PREFER** target-typed `new ()`)
 - ❌ **Don't introduce new warnings** (fix warnings in files you modify; exception: `[Obsolete]` warnings)
 
----
-
-## Additional Resources
-
-- **Full Documentation**: https://gui-cs.github.io/Terminal.Gui
-- **API Reference**: https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.App.html
-- **Deep Dives**: `/docfx/docs/` directory
-- **Getting Started**: https://gui-cs.github.io/Terminal.Gui/docs/getting-started.html
-- **Migrating from v1 to v2**: https://gui-cs.github.io/Terminal.Gui/docs/migratingfromv1.html
-- **Showcase**: https://gui-cs.github.io/Terminal.Gui/docs/showcase.html
-
----
-
 **Thank you for contributing to Terminal.Gui!** 🎉

+ 0 - 2
Examples/CommunityToolkitExample/LoginView.cs

@@ -64,8 +64,6 @@ internal partial class LoginView : IRecipient<Message<LoginActions>>
                 }
         }
         SetText ();
-        // BUGBUG: This should not be needed:
-        Application.LayoutAndDraw ();
     }
 
     private void SetText ()

+ 4 - 4
Examples/CommunityToolkitExample/LoginViewModel.cs

@@ -12,7 +12,7 @@ internal partial class LoginViewModel : ObservableObject
     private const string INVALID_LOGIN_MESSAGE = "Please enter a valid user name and password.";
     private const string LOGGING_IN_PROGRESS_MESSAGE = "Logging in...";
     private const string VALID_LOGIN_MESSAGE = "The input is valid!";
-    
+
     [ObservableProperty]
     private bool _canLogin;
 
@@ -28,7 +28,7 @@ internal partial class LoginViewModel : ObservableObject
 
     [ObservableProperty]
     private string _usernameLengthMessage;
-    
+
     [ObservableProperty]
     private Scheme? _validationScheme;
 
@@ -105,7 +105,7 @@ internal partial class LoginViewModel : ObservableObject
     {
         switch (loginAction)
         {
-             case LoginActions.Clear:
+            case LoginActions.Clear:
                 LoginProgressMessage = message;
                 ValidationMessage = INVALID_LOGIN_MESSAGE;
                 ValidationScheme = SchemeManager.GetScheme ("Error");
@@ -115,7 +115,7 @@ internal partial class LoginViewModel : ObservableObject
                 break;
             case LoginActions.Validation:
                 ValidationMessage = CanLogin ? VALID_LOGIN_MESSAGE : INVALID_LOGIN_MESSAGE;
-                ValidationScheme = CanLogin ? SchemeManager.GetScheme ("Base") : SchemeManager.GetScheme("Error");
+                ValidationScheme = CanLogin ? SchemeManager.GetScheme ("Base") : SchemeManager.GetScheme ("Error");
                 break;
         }
         WeakReferenceMessenger.Default.Send (new Message<LoginActions> { Value = loginAction });

+ 0 - 1
Examples/CommunityToolkitExample/Message.cs

@@ -1,5 +1,4 @@
 namespace CommunityToolkitExample;
-
 internal class Message<T>
 {
     public T? Value { get; set; }

+ 7 - 8
Examples/CommunityToolkitExample/Program.cs

@@ -1,8 +1,6 @@
 using Microsoft.Extensions.DependencyInjection;
-using Terminal.Gui.Configuration;
 using Terminal.Gui.App;
-using Terminal.Gui.ViewBase;
-
+using Terminal.Gui.Configuration;
 
 namespace CommunityToolkitExample;
 
@@ -14,10 +12,10 @@ public static class Program
     {
         ConfigurationManager.Enable (ConfigLocations.All);
         Services = ConfigureServices ();
-        Application.Init ();
-        Application.Run (Services.GetRequiredService<LoginView> ());
-        Application.TopRunnable?.Dispose ();
-        Application.Shutdown ();
+        using IApplication app = Application.Create ();
+        app.Init ();
+        using var loginView = Services.GetRequiredService<LoginView> ();
+        app.Run (loginView);
     }
 
     private static IServiceProvider ConfigureServices ()
@@ -25,6 +23,7 @@ public static class Program
         var services = new ServiceCollection ();
         services.AddTransient<LoginView> ();
         services.AddTransient<LoginViewModel> ();
+
         return services.BuildServiceProvider ();
     }
-}
+}

+ 25 - 21
Examples/CommunityToolkitExample/README.md

@@ -6,9 +6,10 @@ Right away we use IoC to load our views and view models.
 
 ``` csharp
 // As a public property for access further in the application if needed. 
-public static IServiceProvider Services { get; private set; }
+public static IServiceProvider? Services { get; private set; }
 ...
 // In Main
+ConfigurationManager.Enable (ConfigLocations.All);
 Services = ConfigureServices ();
 ...
 private static IServiceProvider ConfigureServices ()
@@ -20,16 +21,19 @@ private static IServiceProvider ConfigureServices ()
 }
 ```
 
-Now, we start the app and get our main view.
+Now, we start the app using the modern Terminal.Gui model and get our main view.
 
 ``` csharp
-Application.Run (Services.GetRequiredService<LoginView> ());
+using IApplication app = Application.Create ();
+app.Init ();
+using var loginView = Services.GetRequiredService<LoginView> ();
+app.Run (loginView);
 ```
 
 Our view implements `IRecipient<T>` to demonstrate the use of the `WeakReferenceMessenger`. The binding of the view events is then created.
 
 ``` csharp
-internal partial class LoginView : IRecipient<Message<LoginAction>>
+internal partial class LoginView : IRecipient<Message<LoginActions>>
 {
     public LoginView (LoginViewModel viewModel)
     {
@@ -41,15 +45,16 @@ internal partial class LoginView : IRecipient<Message<LoginAction>>
         passwordInput.TextChanged += (_, _) =>
                                      {
                                          ViewModel.Password = passwordInput.Text;
-                                         SetText ();
                                      };
-        loginButton.Accept += (_, _) =>
+        loginButton.Accepting += (_, e) =>
                               {
                                   if (!ViewModel.CanLogin) { return; }
                                   ViewModel.LoginCommand.Execute (null);
+                                  // When Accepting is handled, set e.Handled to true to prevent further processing.
+                                  e.Handled = true;
                               };
         ...
-        // Let the view model know the view is intialized.
+        // Let the view model know the view is initialized.
         Initialized += (_, _) => { ViewModel.Initialized (); };
     }
     ...
@@ -101,54 +106,53 @@ The use of `WeakReferenceMessenger` provides one method of signaling the view fr
 ...
 private async Task Login ()
 {
-    SendMessage (LoginAction.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE);
+    SendMessage (LoginActions.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE);
     await Task.Delay (TimeSpan.FromSeconds (1));
     Clear ();
 }
 
-private void SendMessage (LoginAction loginAction, string message = "")
+private void SendMessage (LoginActions loginAction, string message = "")
 {
     switch (loginAction)
     {
-        case LoginAction.LoginProgress:
+        case LoginActions.LoginProgress:
             LoginProgressMessage = message;
             break;
-        case LoginAction.Validation:
+        case LoginActions.Validation:
             ValidationMessage = CanLogin ? VALID_LOGIN_MESSAGE : INVALID_LOGIN_MESSAGE;
-            ValidationScheme = CanLogin ? Colors.Schemes ["Base"] : Colors.Schemes ["Error"];
+            ValidationScheme = CanLogin ? SchemeManager.GetScheme ("Base") : SchemeManager.GetScheme ("Error");
             break;
     }
-    WeakReferenceMessenger.Default.Send (new Message<LoginAction> { Value = loginAction });
+    WeakReferenceMessenger.Default.Send (new Message<LoginActions> { Value = loginAction });
 }
 
 private void ValidateLogin ()
 {
     CanLogin = !string.IsNullOrEmpty (Username) && !string.IsNullOrEmpty (Password);
-    SendMessage (LoginAction.Validation);
+    SendMessage (LoginActions.Validation);
 }
 ...
 ```
 
-And the view's `Receive` function which provides an `Application.Refresh()` call to update the UI immediately.
+The view's `Receive` function updates the UI based on messages from the view model. In the modern Terminal.Gui model, UI updates are automatically refreshed, so no manual `Application.Refresh()` call is needed.
 
 ``` csharp
-public void Receive (Message<LoginAction> message)
+public void Receive (Message<LoginActions> message)
 {
     switch (message.Value)
     {
-        case LoginAction.LoginProgress:
+        case LoginActions.LoginProgress:
             {
                 loginProgressLabel.Text = ViewModel.LoginProgressMessage;
                 break;
             }
-        case LoginAction.Validation:
+        case LoginActions.Validation:
             {
                 validationLabel.Text = ViewModel.ValidationMessage;
-                validationLabel.Scheme = ViewModel.ValidationScheme;
+                validationLabel.SetScheme (ViewModel.ValidationScheme);
                 break;
             }
     }
-    SetText();
-    Application.Refresh ();
+    SetText ();
 }
 ```

+ 27 - 36
Examples/Example/Example.cs

@@ -3,30 +3,28 @@
 // This is a simple example application.  For the full range of functionality
 // see the UICatalog project
 
-using Terminal.Gui.Configuration;
 using Terminal.Gui.App;
-using Terminal.Gui.Drawing;
+using Terminal.Gui.Configuration;
 using Terminal.Gui.ViewBase;
 using Terminal.Gui.Views;
-using Attribute = Terminal.Gui.Drawing.Attribute;
 
 // Override the default configuration for the application to use the Light theme
-//ConfigurationManager.RuntimeConfig = """{ "Theme": "Light" }""";
-ConfigurationManager.Enable(ConfigLocations.All);
-
+ConfigurationManager.RuntimeConfig = """{ "Theme": "Light" }""";
+ConfigurationManager.Enable (ConfigLocations.All);
 
+IApplication app = Application.Create ();
 
-Application.Run<ExampleWindow> ().Dispose ();
+app.Run<ExampleWindow> ();
 
-// Before the application exits, reset Terminal.Gui for clean shutdown
-Application.Shutdown ();
+// Dispose the app to clean up and enable Console.WriteLine below
+app.Dispose ();
 
 // To see this output on the screen it must be done after shutdown,
 // which restores the previous screen.
 Console.WriteLine ($@"Username: {ExampleWindow.UserName}");
 
 // Defines a top-level window with border and title
-public class ExampleWindow : Window
+public sealed class ExampleWindow : Window
 {
     public static string UserName { get; set; }
 
@@ -74,39 +72,32 @@ public class ExampleWindow : Window
 
         // When login button is clicked display a message popup
         btnLogin.Accepting += (s, e) =>
-                           {
-                               if (userNameText.Text == "admin" && passwordText.Text == "password")
-                               {
-                                   MessageBox.Query ("Logging In", "Login Successful", "Ok");
-                                   UserName = userNameText.Text;
-                                   Application.RequestStop ();
-                               }
-                               else
-                               {
-                                   MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
-                               }
-                               // When Accepting is handled, set e.Handled to true to prevent further processing.
-                               e.Handled = true;
-                           };
+                              {
+                                  if (userNameText.Text == "admin" && passwordText.Text == "password")
+                                  {
+                                      MessageBox.Query (App, "Logging In", "Login Successful", "Ok");
+                                      UserName = userNameText.Text;
+                                      Application.RequestStop ();
+                                  }
+                                  else
+                                  {
+                                      MessageBox.ErrorQuery (App, "Logging In", "Incorrect username or password", "Ok");
+                                  }
+
+                                  // When Accepting is handled, set e.Handled to true to prevent further processing.
+                                  e.Handled = true;
+                              };
 
         // Add the views to the Window
         Add (usernameLabel, userNameText, passwordLabel, passwordText, btnLogin);
 
-        ListView lv = new ListView ()
+        var lv = new ListView
         {
-            Y = Pos.AnchorEnd(),
-            Height= Dim.Auto(),
-            Width = Dim.Auto()
+            Y = Pos.AnchorEnd (),
+            Height = Dim.Auto (),
+            Width = Dim.Auto ()
         };
         lv.SetSource (["One", "Two", "Three", "Four"]);
         Add (lv);
     }
-
-    public override void EndInit ()
-    {
-        base.EndInit ();
-        // Set the theme to "Anders" if it exists, otherwise use "Default"
-        ThemeManager.Theme = ThemeManager.GetThemeNames ().FirstOrDefault (x => x == "Anders") ?? "Default";
-    }
 }
- 

+ 1 - 4
Examples/Example/README.md

@@ -1,11 +1,8 @@
 # Terminal.Gui C# Example
 
-This example shows how to use the Terminal.Gui library to create a simple GUI application in C#.
+This example shows how to use the Terminal.Gui library to create a simple TUI application in C#.
 
 This is the same code found in the Terminal.Gui README.md file.
 
 To explore the full range of functionality in Terminal.Gui, see the [UICatalog](../UICatalog) project
 
-See [README.md](https://github.com/gui-cs/Terminal.Gui) for a list of all Terminal.Gui samples.
-
-Note, the old `demo.cs` example has been deleted because it was not a very good example. It can still be found in the [git history](https://github.com/gui-cs/Terminal.Gui/tree/v1.8.2).

+ 11 - 45
Examples/FluentExample/Program.cs

@@ -5,63 +5,31 @@ using Terminal.Gui.Drawing;
 using Terminal.Gui.ViewBase;
 using Terminal.Gui.Views;
 
-#if POST_4148
-// Run the application with fluent API - automatically creates, runs, and disposes the runnable
-
-// Display the result
-if (Application.Create ()
-               .Init ()
-               .Run<ColorPickerView> ()
-               .Shutdown () is Color { } result)
-{
-    Console.WriteLine (@$"Selected Color: {(Color?)result}");
-}
-else
-{
-    Console.WriteLine (@"No color selected");
-}
-#else
-
-// Run using traditional approach
-IApplication app = Application.Create ();
-app.Init ();
-var colorPicker = new ColorPickerView ();
-app.Run (colorPicker);
+IApplication? app = Application.Create ()
+                               .Init ()
+                               .Run<ColorPickerView> ();
 
-Color? resultColor = colorPicker.Result;
+// Run the application with fluent API - automatically creates, runs, and disposes the runnable
+Color? result = app.GetResult () as Color?;
 
-colorPicker.Dispose ();
-app.Shutdown ();
+// Shut down the app with Dispose before we can use Console.WriteLine
+app.Dispose ();
 
-if (resultColor is { } result)
+if (result is { })
 {
-    Console.WriteLine (@$"Selected Color: {(Color?)result}");
+    Console.WriteLine (@$"Selected Color: {result}");
 }
 else
 {
     Console.WriteLine (@"No color selected");
 }
 
-#endif
-
-#if POST_4148
 /// <summary>
 ///     A runnable view that allows the user to select a color.
-///     Demonstrates IRunnable<TResult> pattern with automatic disposal.
+///     Demonstrates the Runnable with type pattern with automatic disposal.
 /// </summary>
 public class ColorPickerView : Runnable<Color?>
 {
-
-#else
-/// <summary>
-///     A runnable view that allows the user to select a color.
-///     Uses the traditional approach without automatic disposal/Fluent API.
-/// </summary>
-public class ColorPickerView : Toplevel
-{
-    public Color? Result { get; set; }
-
-#endif
     public ColorPickerView ()
     {
         Title = "Select a Color (Esc to quit)";
@@ -126,7 +94,6 @@ public class ColorPickerView : Toplevel
         Add (instructions, colorPicker, okButton, cancelButton);
     }
 
-#if POST_4148
     protected override bool OnIsRunningChanging (bool oldIsRunning, bool newIsRunning)
     {
         // Alternative place to extract result before stopping
@@ -134,10 +101,9 @@ public class ColorPickerView : Toplevel
         if (!newIsRunning && Result is null)
         {
             // User pressed Esc - could extract current selection here
-            // Result = _colorPicker.SelectedColor;
+            //Result = SelectedColor;
         }
 
         return base.OnIsRunningChanging (oldIsRunning, newIsRunning);
     }
-#endif
 }

+ 2 - 2
Examples/NativeAot/Program.cs

@@ -101,13 +101,13 @@ public class ExampleWindow : Window
         {
             if (userNameText.Text == "admin" && passwordText.Text == "password")
             {
-                MessageBox.Query ("Logging In", "Login Successful", "Ok");
+                MessageBox.Query (App, "Logging In", "Login Successful", "Ok");
                 UserName = userNameText.Text;
                 Application.RequestStop ();
             }
             else
             {
-                MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
+                MessageBox.ErrorQuery (App, "Logging In", "Incorrect username or password", "Ok");
             }
             // Anytime Accepting is handled, make sure to set e.Handled to true.
             e.Handled = true;

+ 7 - 8
Examples/ReactiveExample/Program.cs

@@ -1,9 +1,7 @@
 using System.Reactive.Concurrency;
 using ReactiveUI;
-using ReactiveUI.SourceGenerators;
-using Terminal.Gui.Configuration;
 using Terminal.Gui.App;
-using Terminal.Gui.ViewBase;
+using Terminal.Gui.Configuration;
 
 namespace ReactiveExample;
 
@@ -12,11 +10,12 @@ public static class Program
     private static void Main (string [] args)
     {
         ConfigurationManager.Enable (ConfigLocations.All);
-        Application.Init ();
-        RxApp.MainThreadScheduler = TerminalScheduler.Default;
+        using IApplication app = Application.Create ();
+        app.Init ();
+        RxApp.MainThreadScheduler = new TerminalScheduler (app);
         RxApp.TaskpoolScheduler = TaskPoolScheduler.Default;
-        Application.Run (new LoginView (new LoginViewModel ()));
-        Application.TopRunnable.Dispose ();
-        Application.Shutdown ();
+        var loginView = new LoginView (new ());
+        app.Run (loginView);
+        loginView.Dispose ();
     }
 }

+ 8 - 4
Examples/ReactiveExample/README.md

@@ -7,10 +7,14 @@ This is a sample app that shows how to use `System.Reactive` and `ReactiveUI` wi
 In order to use reactive extensions scheduling, copy-paste the `TerminalScheduler.cs` file into your project, and add the following lines to the composition root of your `Terminal.Gui` application:
 
 ```cs
-Application.Init ();
-RxApp.MainThreadScheduler = TerminalScheduler.Default;
+ConfigurationManager.Enable (ConfigLocations.All);
+using IApplication app = Application.Create ();
+app.Init ();
+RxApp.MainThreadScheduler = new TerminalScheduler (app);
 RxApp.TaskpoolScheduler = TaskPoolScheduler.Default;
-Application.Run (new RootView (new RootViewModel ()));
+var loginView = new LoginView (new ());
+app.Run (loginView);
+loginView.Dispose ();
 ```
 
 From now on, you can use `.ObserveOn(RxApp.MainThreadScheduler)` to return to the main loop from a background thread. This is useful when you have a `IObservable<TValue>` updated from a background thread, and you wish to update the UI with `TValue`s received from that observable.
@@ -43,6 +47,6 @@ If you combine `OneWay` and `OneWayToSource` data bindings, you get `TwoWay` dat
 // 'clearButton' is 'Button'
 clearButton
 	.Events ()
-	.Clicked
+	.Accepting
 	.InvokeCommand (ViewModel, x => x.Clear);
 ```

+ 28 - 21
Examples/ReactiveExample/TerminalScheduler.cs

@@ -1,4 +1,4 @@
-using System;
+#nullable enable
 using System.Reactive.Concurrency;
 using System.Reactive.Disposables;
 using Terminal.Gui.App;
@@ -7,8 +7,9 @@ namespace ReactiveExample;
 
 public class TerminalScheduler : LocalScheduler
 {
-    public static readonly TerminalScheduler Default = new ();
-    private TerminalScheduler () { }
+    public TerminalScheduler (IApplication? application) { _application = application; }
+
+    private readonly IApplication? _application = null;
 
     public override IDisposable Schedule<TState> (
         TState state,
@@ -21,15 +22,15 @@ public class TerminalScheduler : LocalScheduler
             var composite = new CompositeDisposable (2);
             var cancellation = new CancellationDisposable ();
 
-            Application.Invoke (
-                                (_) =>
-                                {
-                                    if (!cancellation.Token.IsCancellationRequested)
-                                    {
-                                        composite.Add (action (this, state));
-                                    }
-                                }
-                               );
+            _application?.Invoke (
+                                 (_) =>
+                                 {
+                                     if (!cancellation.Token.IsCancellationRequested)
+                                     {
+                                         composite.Add (action (this, state));
+                                     }
+                                 }
+                                );
             composite.Add (cancellation);
 
             return composite;
@@ -39,16 +40,22 @@ public class TerminalScheduler : LocalScheduler
         {
             var composite = new CompositeDisposable (2);
 
-            object timeout = Application.AddTimeout (
-                                                     dueTime,
-                                                     () =>
-                                                     {
-                                                         composite.Add (action (this, state));
+            object? timeout = _application?.AddTimeout (
+                                                      dueTime,
+                                                      () =>
+                                                      {
+                                                          composite.Add (action (this, state));
 
-                                                         return false;
-                                                     }
-                                                    );
-            composite.Add (Disposable.Create (() => Application.RemoveTimeout (timeout)));
+                                                          return false;
+                                                      }
+                                                     );
+            composite.Add (Disposable.Create (() =>
+                                              {
+                                                  if (timeout is { })
+                                                  {
+                                                      _application?.RemoveTimeout (timeout);
+                                                  }
+                                              }));
 
             return composite;
         }

+ 1 - 2
Examples/ReactiveExample/ViewExtensions.cs

@@ -1,5 +1,4 @@
-using System;
-using Terminal.Gui.ViewBase;
+using Terminal.Gui.ViewBase;
 using Terminal.Gui.Views;
 
 namespace ReactiveExample;

+ 31 - 28
Examples/RunnableWrapperExample/Program.cs

@@ -13,41 +13,42 @@ var textField = new TextField { Width = 40, Text = "Default text" };
 textField.Title = "Enter your name";
 textField.BorderStyle = LineStyle.Single;
 
-var textRunnable = textField.AsRunnable (tf => tf.Text);
+RunnableWrapper<TextField, string> textRunnable = textField.AsRunnable (tf => tf.Text);
 app.Run (textRunnable);
 
 if (textRunnable.Result is { } name)
 {
-    MessageBox.Query ("Result", $"You entered: {name}", "OK");
+    MessageBox.Query (app, "Result", $"You entered: {name}", "OK");
 }
 else
 {
-    MessageBox.Query ("Result", "Canceled", "OK");
+    MessageBox.Query (app, "Result", "Canceled", "OK");
 }
+
 textRunnable.Dispose ();
 
 // Example 2: Use IApplication.RunView() for one-liner
-var selectedColor = app.RunView (
-    new ColorPicker
-    {
-        Title = "Pick a Color",
-        BorderStyle = LineStyle.Single
-    },
-    cp => cp.SelectedColor);
+Color selectedColor = app.RunView (
+                                   new ColorPicker
+                                   {
+                                       Title = "Pick a Color",
+                                       BorderStyle = LineStyle.Single
+                                   },
+                                   cp => cp.SelectedColor);
 
-MessageBox.Query ("Result", $"Selected color: {selectedColor}", "OK");
+MessageBox.Query (app, "Result", $"Selected color: {selectedColor}", "OK");
 
 // Example 3: FlagSelector with typed enum result
-var flagSelector = new FlagSelector<SelectorStyles>
+FlagSelector<SelectorStyles> flagSelector = new()
 {
     Title = "Choose Styles",
     BorderStyle = LineStyle.Single
 };
 
-var flagsRunnable = flagSelector.AsRunnable (fs => fs.Value);
+RunnableWrapper<FlagSelector<SelectorStyles>, SelectorStyles?> flagsRunnable = flagSelector.AsRunnable (fs => fs.Value);
 app.Run (flagsRunnable);
 
-MessageBox.Query ("Result", $"Selected styles: {flagsRunnable.Result}", "OK");
+MessageBox.Query (app, "Result", $"Selected styles: {flagsRunnable.Result}", "OK");
 flagsRunnable.Dispose ();
 
 // Example 4: Any View without result extraction
@@ -58,29 +59,31 @@ var label = new Label
     Y = Pos.Center ()
 };
 
-var labelRunnable = label.AsRunnable ();
+RunnableWrapper<Label, object> labelRunnable = label.AsRunnable ();
 app.Run (labelRunnable);
 
 // Can still access the wrapped view
-MessageBox.Query ("Result", $"Label text was: {labelRunnable.WrappedView.Text}", "OK");
+MessageBox.Query (app, "Result", $"Label text was: {labelRunnable.WrappedView.Text}", "OK");
 labelRunnable.Dispose ();
 
 // Example 5: Complex custom View made runnable
-var formView = CreateCustomForm ();
-var formRunnable = formView.AsRunnable (ExtractFormData);
+View formView = CreateCustomForm ();
+RunnableWrapper<View, FormData> formRunnable = formView.AsRunnable (ExtractFormData);
 
 app.Run (formRunnable);
 
 if (formRunnable.Result is { } formData)
 {
     MessageBox.Query (
-        "Form Results",
-        $"Name: {formData.Name}\nAge: {formData.Age}\nAgreed: {formData.Agreed}",
-        "OK");
+                      app,
+                      "Form Results",
+                      $"Name: {formData.Name}\nAge: {formData.Age}\nAgreed: {formData.Agreed}",
+                      "OK");
 }
+
 formRunnable.Dispose ();
 
-app.Shutdown ();
+app.Dispose ();
 
 // Helper method to create a custom form
 View CreateCustomForm ()
@@ -126,10 +129,10 @@ View CreateCustomForm ()
     };
 
     okButton.Accepting += (s, e) =>
-    {
-        form.App?.RequestStop ();
-        e.Handled = true;
-    };
+                          {
+                              form.App?.RequestStop ();
+                              e.Handled = true;
+                          };
 
     form.Add (new Label { Text = "Name:", X = 2, Y = 1 });
     form.Add (nameField);
@@ -148,7 +151,7 @@ FormData ExtractFormData (View form)
     var ageField = form.SubViews.FirstOrDefault (v => v.Id == "ageField") as TextField;
     var agreeCheckbox = form.SubViews.FirstOrDefault (v => v.Id == "agreeCheckbox") as CheckBox;
 
-    return new FormData
+    return new()
     {
         Name = nameField?.Text ?? string.Empty,
         Age = int.TryParse (ageField?.Text, out int age) ? age : 0,
@@ -157,7 +160,7 @@ FormData ExtractFormData (View form)
 }
 
 // Result type for custom form
-record FormData
+internal record FormData
 {
     public string Name { get; init; } = string.Empty;
     public int Age { get; init; }

+ 15 - 15
Examples/SelfContained/Program.cs

@@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using Terminal.Gui.Configuration;
 using Terminal.Gui.App;
+using Terminal.Gui.Drawing;
 using Terminal.Gui.ViewBase;
 using Terminal.Gui.Views;
 
@@ -16,7 +17,9 @@ public static class Program
     private static void Main (string [] args)
     {
         ConfigurationManager.Enable (ConfigLocations.All);
-        Application.Init ();
+
+        IApplication app = Application.Create ();
+        app.Init ();
 
         #region The code in this region is not intended for use in a self-contained single-file. It's just here to make sure there is no functionality break with localization in Terminal.Gui using single-file
 
@@ -33,28 +36,25 @@ public static class Program
 
         #endregion
 
-        ExampleWindow app = new ();
-        Application.Run (app);
+        using ExampleWindow exampleWindow = new ();
+        string? userName = app.Run (exampleWindow) as string;
 
-        // Dispose the app object before shutdown
-        app.Dispose ();
 
-        // Before the application exits, reset Terminal.Gui for clean shutdown
-        Application.Shutdown ();
+        // Shutdown the application in order to free resources and clean up the terminal
+        app.Dispose ();
 
         // To see this output on the screen it must be done after shutdown,
         // which restores the previous screen.
-        Console.WriteLine ($@"Username: {ExampleWindow.UserName}");
+        Console.WriteLine ($@"Username: {userName}");
     }
 }
 
 // Defines a top-level window with border and title
-public class ExampleWindow : Window
+public class ExampleWindow : Runnable<string>
 {
-    public static string? UserName;
-
     public ExampleWindow ()
     {
+        BorderStyle = LineStyle.Single;
         Title = $"Example App ({Application.QuitKey} to quit)";
 
         // Create input components and labels
@@ -100,13 +100,13 @@ public class ExampleWindow : Window
                            {
                                if (userNameText.Text == "admin" && passwordText.Text == "password")
                                {
-                                   MessageBox.Query ("Logging In", "Login Successful", "Ok");
-                                   UserName = userNameText.Text;
-                                   Application.RequestStop ();
+                                   MessageBox.Query (App, "Logging In", "Login Successful", "Ok");
+                                   Result = userNameText.Text;
+                                   App?.RequestStop ();
                                }
                                else
                                {
-                                   MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
+                                   MessageBox.ErrorQuery (App, "Logging In", "Incorrect username or password", "Ok");
                                }
                                // When Accepting is handled, set e.Handled to true to prevent further processing.
                                e.Handled = true;

+ 26 - 0
Examples/SelfContained/README.md

@@ -2,6 +2,32 @@
 
 This project aims to test the `Terminal.Gui` library to create a simple `self-contained` `single-file` GUI application in C#, ensuring that all its features are available.
 
+## Modern Terminal.Gui API
+
+This example uses the modern Terminal.Gui application model:
+
+```csharp
+ConfigurationManager.Enable (ConfigLocations.All);
+
+IApplication app = Application.Create ();
+app.Init ();
+
+using ExampleWindow exampleWindow = new ();
+string? userName = app.Run (exampleWindow) as string;
+
+app.Dispose ();
+
+Console.WriteLine ($@"Username: {userName}");
+```
+
+Key aspects of the modern model:
+- Use `Application.Create()` to create an `IApplication` instance
+- Call `app.Init()` to initialize the application
+- Use `app.Run(view)` to run views with proper resource management
+- Call `app.Dispose()` to clean up resources and restore the terminal
+- Event handling uses `Accepting` event instead of legacy `Accept` event
+- Set `e.Handled = true` in event handlers to prevent further processing
+
 With `Debug` the `.csproj` is used and with `Release` the latest `nuget package` is used, either in `Solution Configurations` or in `Profile Publish`.
 
 To publish the self-contained single file in `Debug` or `Release` mode, it is not necessary to select it in the `Solution Configurations`, just choose the `Debug` or `Release` configuration in the `Publish Profile`.

+ 1 - 1
Examples/UICatalog/README.md

@@ -80,7 +80,7 @@ The default `Window` shows the Scenario name and supports exiting the Scenario t
 
 ![screenshot](generic_screenshot.png)
 
-To build a more advanced scenario, where control of the `Toplevel` and `Window` is needed (e.g. for scenarios using `MenuBar` or `StatusBar`), simply use `Application.Top` per normal Terminal.Gui programming, as seen in the `Notepad` scenario.
+To build a more advanced scenario, where control of the `Runnable` and `Window` is needed (e.g. for scenarios using `MenuBar` or `StatusBar`), simply use `Application.Top` per normal Terminal.Gui programming, as seen in the `Notepad` scenario.
 
 For complete control, the `Init` and `Run` overrides can be implemented. The `base.Init` creates `Win`. The `base.Run` simply calls `Application.Run(Application.Top)`.
 

+ 2 - 2
Examples/UICatalog/Resources/config.json

@@ -11,7 +11,7 @@
       "Hot Dog Stand": {
         "Schemes": [
           {
-            "Toplevel": {
+            "Runnable": {
               "Normal": {
                 "Foreground": "Black",
                 "Background": "#FFFF00"
@@ -177,7 +177,7 @@
             }
           },
           {
-            "TopLevel": {
+            "Runnable": {
               "Normal": {
                 "Foreground": "DarkGray",
                 "Background": "White"

+ 5 - 5
Examples/UICatalog/Scenario.cs

@@ -67,7 +67,7 @@ namespace UICatalog;
 ///         };
 /// 
 ///         var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
-///         button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed the button!", "Ok");
+///         button.Accept += (s, e) => MessageBox.ErrorQuery (App, "Error", "You pressed the button!", "Ok");
 ///         appWindow.Add (button);
 /// 
 ///         // Run - Start the application.
@@ -210,20 +210,20 @@ public class Scenario : IDisposable
         void OnClearedContents (object? sender, EventArgs args) => BenchmarkResults.ClearedContentCount++;
     }
 
-    private void OnApplicationOnIteration (object? s, IterationEventArgs a)
+    private void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
     {
         BenchmarkResults.IterationCount++;
         if (BenchmarkResults.IterationCount > BENCHMARK_MAX_NATURAL_ITERATIONS + (_demoKeys!.Count * BENCHMARK_KEY_PACING))
         {
-            Application.RequestStop ();
+            a.Value?.RequestStop ();
         }
     }
 
-    // BUGBUG: This is incompatible with modals. This should be using the new equivalent of Toplevel.Ready 
+    // BUGBUG: This is incompatible with modals. This should be using the new equivalent of Runnable.Ready 
     // BUGBUG: which will be IsRunningChanged with newIsRunning == true
     private void OnApplicationSessionBegun (object? sender, SessionTokenEventArgs e)
     {
-        SubscribeAllSubViews (Application.TopRunnable!);
+        SubscribeAllSubViews (Application.TopRunnableView!);
 
         _demoKeys = GetDemoKeyStrokes ();
 

+ 8 - 8
Examples/UICatalog/Scenarios/Adornments.cs

@@ -11,7 +11,7 @@ public class Adornments : Scenario
     {
         Application.Init ();
 
-        Window app = new ()
+        Window appWindow = new ()
         {
             Title = GetQuitKeyAndName (),
             BorderStyle = LineStyle.None
@@ -28,7 +28,7 @@ public class Adornments : Scenario
 
         editor.Border!.Thickness = new (1, 2, 1, 1);
 
-        app.Add (editor);
+        appWindow.Add (editor);
 
         var window = new Window
         {
@@ -38,7 +38,7 @@ public class Adornments : Scenario
             Width = Dim.Fill (Dim.Func (_ => editor.Frame.Width)),
             Height = Dim.Fill ()
         };
-        app.Add (window);
+        appWindow.Add (window);
 
         var tf1 = new TextField { Width = 10, Text = "TextField" };
         var color = new ColorPicker16 { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd () };
@@ -60,7 +60,7 @@ public class Adornments : Scenario
         var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
 
         button.Accepting += (s, e) =>
-                             MessageBox.Query (20, 7, "Hi", $"Am I a {window.GetType ().Name}?", "Yes", "No");
+                             MessageBox.Query (appWindow.App, 20, 7, "Hi", $"Am I a {window.GetType ().Name}?", "Yes", "No");
 
         var label = new TextView
         {
@@ -121,7 +121,7 @@ public class Adornments : Scenario
                                       Text = "text (Y = 1)",
                                       CanFocus = true
                                   };
-                                  textFieldInPadding.Accepting += (s, e) => MessageBox.Query (20, 7, "TextField", textFieldInPadding.Text, "Ok");
+                                  textFieldInPadding.Accepting += (s, e) => MessageBox.Query (appWindow.App, 20, 7, "TextField", textFieldInPadding.Text, "Ok");
                                   window.Padding.Add (textFieldInPadding);
 
                                   var btnButtonInPadding = new Button
@@ -132,7 +132,7 @@ public class Adornments : Scenario
                                       CanFocus = true,
                                       HighlightStates = MouseState.None,
                                   };
-                                  btnButtonInPadding.Accepting += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok");
+                                  btnButtonInPadding.Accepting += (s, e) => MessageBox.Query (appWindow.App, 20, 7, "Hi", "Button in Padding Pressed!", "Ok");
                                   btnButtonInPadding.BorderStyle = LineStyle.Dashed;
                                   btnButtonInPadding.Border!.Thickness = new (1, 1, 1, 1);
                                   window.Padding.Add (btnButtonInPadding);
@@ -155,8 +155,8 @@ public class Adornments : Scenario
         editor.AutoSelectSuperView = window;
         editor.AutoSelectAdornments = true;
 
-        Application.Run (app);
-        app.Dispose ();
+        Application.Run (appWindow);
+        appWindow.Dispose ();
 
         Application.Shutdown ();
     }

+ 7 - 0
Examples/UICatalog/Scenarios/AllViewsTester.cs

@@ -220,6 +220,13 @@ public class AllViewsTester : Scenario
     {
         Debug.Assert (_curView is null);
 
+        // Skip RunnableWrapper types as they have generic constraints that cannot be satisfied
+        if (type.IsGenericType && type.GetGenericTypeDefinition().Name.StartsWith("RunnableWrapper"))
+        {
+            Logging.Warning ($"Cannot create an instance of {type.Name} because it is a RunnableWrapper with unsatisfiable generic constraints.");
+            return;
+        }
+
         // If we are to create a generic Type
         if (type.IsGenericType)
         {

+ 1 - 1
Examples/UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs

@@ -78,7 +78,7 @@ public class AnimationScenario : Scenario
         if (!f.Exists)
         {
             Debug.WriteLine ($"Could not find {f.FullName}");
-            MessageBox.ErrorQuery ("Could not find gif", $"Could not find\n{f.FullName}", "Ok");
+            MessageBox.ErrorQuery (_imageView?.App, "Could not find gif", $"Could not find\n{f.FullName}", "Ok");
 
             return;
         }

+ 4 - 4
Examples/UICatalog/Scenarios/Arrangement.cs

@@ -183,9 +183,9 @@ public class Arrangement : Scenario
 
         datePicker.SetScheme (new Scheme (
                                           new Attribute (
-                                                         SchemeManager.GetScheme (Schemes.Toplevel).Normal.Foreground.GetBrighterColor (),
-                                                         SchemeManager.GetScheme (Schemes.Toplevel).Normal.Background.GetBrighterColor (),
-                                                         SchemeManager.GetScheme (Schemes.Toplevel).Normal.Style)));
+                                                         SchemeManager.GetScheme (Schemes.Runnable).Normal.Foreground.GetBrighterColor (),
+                                                         SchemeManager.GetScheme (Schemes.Runnable).Normal.Background.GetBrighterColor (),
+                                                         SchemeManager.GetScheme (Schemes.Runnable).Normal.Style)));
 
         TransparentView transparentView = new ()
         {
@@ -237,7 +237,7 @@ public class Arrangement : Scenario
             Width = Dim.Auto (minimumContentDim: 15),
             Height = Dim.Auto (minimumContentDim: 3),
             Title = $"Overlapped{id} _{GetNextHotKey ()}",
-            SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Toplevel),
+            SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Runnable),
             Id = $"Overlapped{id}",
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,

+ 15 - 15
Examples/UICatalog/Scenarios/Bars.cs

@@ -14,9 +14,9 @@ public class Bars : Scenario
     public override void Main ()
     {
         Application.Init ();
-        Toplevel app = new ();
+        Runnable app = new ();
 
-        app.Loaded += App_Loaded;
+        app.IsModalChanged += App_Loaded;
 
         Application.Run (app);
         app.Dispose ();
@@ -28,7 +28,7 @@ public class Bars : Scenario
     // QuitKey and it only sticks if changed after init
     private void App_Loaded (object sender, EventArgs e)
     {
-        Application.TopRunnable!.Title = GetQuitKeyAndName ();
+        Application.TopRunnableView!.Title = GetQuitKeyAndName ();
 
         ObservableCollection<string> eventSource = new ();
         ListView eventLog = new ListView ()
@@ -37,11 +37,11 @@ public class Bars : Scenario
             X = Pos.AnchorEnd (),
             Width = Dim.Auto (),
             Height = Dim.Fill (), // Make room for some wide things
-            SchemeName = "Toplevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (eventSource)
         };
         eventLog.Border!.Thickness = new (0, 1, 0, 0);
-        Application.TopRunnable.Add (eventLog);
+        Application.TopRunnableView.Add (eventLog);
 
         FrameView menuBarLikeExamples = new ()
         {
@@ -51,7 +51,7 @@ public class Bars : Scenario
             Width = Dim.Fill () - Dim.Width (eventLog),
             Height = Dim.Percent(33),
         };
-        Application.TopRunnable.Add (menuBarLikeExamples);
+        Application.TopRunnableView.Add (menuBarLikeExamples);
 
         Label label = new Label ()
         {
@@ -98,7 +98,7 @@ public class Bars : Scenario
             Width = Dim.Fill () - Dim.Width (eventLog),
             Height = Dim.Percent (33),
         };
-        Application.TopRunnable.Add (menuLikeExamples);
+        Application.TopRunnableView.Add (menuLikeExamples);
 
         label = new Label ()
         {
@@ -212,7 +212,7 @@ public class Bars : Scenario
             Width = Dim.Width (menuLikeExamples),
             Height = Dim.Percent (33),
         };
-        Application.TopRunnable.Add (statusBarLikeExamples);
+        Application.TopRunnableView.Add (statusBarLikeExamples);
 
         label = new Label ()
         {
@@ -249,7 +249,7 @@ public class Bars : Scenario
         ConfigStatusBar (bar);
         statusBarLikeExamples.Add (bar);
 
-        foreach (FrameView frameView in Application.TopRunnable.SubViews.Where (f => f is FrameView)!)
+        foreach (FrameView frameView in Application.TopRunnableView.SubViews.Where (f => f is FrameView)!)
         {
             foreach (Bar barView in frameView.SubViews.Where (b => b is Bar)!)
             {
@@ -309,7 +309,7 @@ public class Bars : Scenario
     //                                                  new TimeSpan (0),
     //                                                  () =>
     //                                                  {
-    //                                                      MessageBox.Query ("File", "New");
+    //                                                      MessageBox.Query (App, "File", "New");
 
     //                                                      return false;
     //                                                  });
@@ -331,7 +331,7 @@ public class Bars : Scenario
     //                                               new TimeSpan (0),
     //                                               () =>
     //                                               {
-    //                                                   MessageBox.Query ("File", "Open");
+    //                                                   MessageBox.Query (App, "File", "Open");
 
     //                                                   return false;
     //                                               });
@@ -353,7 +353,7 @@ public class Bars : Scenario
     //                                               new TimeSpan (0),
     //                                               () =>
     //                                               {
-    //                                                   MessageBox.Query ("File", "Save");
+    //                                                   MessageBox.Query (App, "File", "Save");
 
     //                                                   return false;
     //                                               });
@@ -375,7 +375,7 @@ public class Bars : Scenario
     //                                                 new TimeSpan (0),
     //                                                 () =>
     //                                                 {
-    //                                                     MessageBox.Query ("File", "Save As");
+    //                                                     MessageBox.Query (App, "File", "Save As");
 
     //                                                     return false;
     //                                                 });
@@ -383,7 +383,7 @@ public class Bars : Scenario
 
     //    contextMenu.Add (newMenu, open, save, saveAs);
 
-    //    contextMenu.KeyBindings.Add (Key.Esc, Command.QuitToplevel);
+    //    contextMenu.KeyBindings.Add (Key.Esc, Command.Quit);
 
     //    contextMenu.Initialized += Menu_Initialized;
 
@@ -555,7 +555,7 @@ public class Bars : Scenario
 
         return;
 
-        void Button_Clicked (object sender, EventArgs e) { MessageBox.Query ("Hi", $"You clicked {sender}"); }
+        void Button_Clicked (object sender, EventArgs e) { MessageBox.Query ((sender as View)?.App, "Hi", $"You clicked {sender}"); }
 
     }
 

+ 5 - 5
Examples/UICatalog/Scenarios/Buttons.cs

@@ -59,7 +59,7 @@ public class Buttons : Scenario
 
                                     if (e.Handled)
                                     {
-                                        MessageBox.ErrorQuery ("Error", "This button is no longer the Quit button; the Swap Default button is.", "_Ok");
+                                        MessageBox.ErrorQuery ((s as View)?.App, "Error", "This button is no longer the Quit button; the Swap Default button is.", "_Ok");
                                     }
                                 };
         main.Add (swapButton);
@@ -69,7 +69,7 @@ public class Buttons : Scenario
             button.Accepting += (s, e) =>
                              {
                                  string btnText = button.Text;
-                                 MessageBox.Query ("Message", $"Did you click {txt}?", "Yes", "No");
+                                 MessageBox.Query ((s as View)?.App, "Message", $"Did you click {txt}?", "Yes", "No");
                                  e.Handled = true;
                              };
         }
@@ -112,7 +112,7 @@ public class Buttons : Scenario
                  );
         button.Accepting += (s, e) =>
                          {
-                             MessageBox.Query ("Message", "Question?", "Yes", "No");
+                             MessageBox.Query ((s as View)?.App, "Message", "Question?", "Yes", "No");
                              e.Handled = true;
                          };
 
@@ -294,7 +294,7 @@ public class Buttons : Scenario
             X = 2,
             Y = Pos.Bottom (osAlignment) + 1,
             Width = Dim.Width (computedFrame) - 2,
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Text = mhkb
         };
         moveHotKeyBtn.Accepting += (s, e) =>
@@ -311,7 +311,7 @@ public class Buttons : Scenario
             X = Pos.Left (absoluteFrame) + 1,
             Y = Pos.Bottom (osAlignment) + 1,
             Width = Dim.Width (absoluteFrame) - 2,
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Text = muhkb
         };
         moveUnicodeHotKeyBtn.Accepting += (s, e) =>

+ 3 - 2
Examples/UICatalog/Scenarios/ChineseUI.cs

@@ -32,8 +32,9 @@ public class ChineseUI : Scenario
 
         btn.Accepting += (s, e) =>
                       {
-                          int result = MessageBox.Query (
-                                                         "Confirm",
+                          int? result = MessageBox.Query (
+                                                          (s as View)?.App,
+                                                          "Confirm",
                                                          "Are you sure you want to quit ui?",
                                                          0,
                                                          "Yes",

+ 1 - 1
Examples/UICatalog/Scenarios/Clipping.cs

@@ -118,7 +118,7 @@ public class Clipping : Scenario
             Height = Dim.Auto (minimumContentDim: 4),
             Width = Dim.Auto (minimumContentDim: 14),
             Title = $"Overlapped{id} _{GetNextHotKey ()}",
-            SchemeName = SchemeManager.SchemesToSchemeName(Schemes.Toplevel),
+            SchemeName = SchemeManager.SchemesToSchemeName(Schemes.Runnable),
             Id = $"Overlapped{id}",
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,

+ 2 - 2
Examples/UICatalog/Scenarios/CombiningMarks.cs

@@ -8,12 +8,12 @@ public class CombiningMarks : Scenario
     public override void Main ()
     {
         Application.Init ();
-        var top = new Toplevel ();
+        var top = new Runnable ();
 
         top.DrawComplete += (s, e) =>
         {
             // Forces reset _lineColsOffset because we're dealing with direct draw
-            Application.TopRunnable!.SetNeedsDraw ();
+            Application.TopRunnableView!.SetNeedsDraw ();
 
             var i = -1;
             top.Move (0, ++i);

+ 1 - 1
Examples/UICatalog/Scenarios/ComboBoxIteration.cs

@@ -25,7 +25,7 @@ public class ComboBoxIteration : Scenario
 
         var lbComboBox = new Label
         {
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             X = Pos.Right (lbListView) + 1,
             Width = Dim.Percent (40)
         };

+ 1 - 1
Examples/UICatalog/Scenarios/ComputedLayout.cs

@@ -280,7 +280,7 @@ public class ComputedLayout : Scenario
             Y = Pos.Percent (50),
             Width = Dim.Percent (80),
             Height = Dim.Percent (10),
-            SchemeName = "TopLevel"
+            SchemeName = "Runnable"
         };
 
         textView.Text =

+ 5 - 5
Examples/UICatalog/Scenarios/ConfigurationEditor.cs

@@ -60,7 +60,7 @@ public class ConfigurationEditor : Scenario
 
         win.Add (_tabView, statusBar);
 
-        win.Loaded += (s, a) =>
+        win.IsModalChanged += (s, a) =>
                       {
                           Open ();
                       };
@@ -75,7 +75,7 @@ public class ConfigurationEditor : Scenario
 
         void ConfigurationManagerOnApplied (object? sender, ConfigurationManagerEventArgs e)
         {
-            Application.TopRunnable?.SetNeedsDraw ();
+            Application.TopRunnableView?.SetNeedsDraw ();
         }
     }
     public void Save ()
@@ -153,9 +153,9 @@ public class ConfigurationEditor : Scenario
                 continue;
             }
 
-            int result = MessageBox.Query (
+            int? result = MessageBox.Query (editor?.App,
                                            "Save Changes",
-                                           $"Save changes to {editor.FileInfo!.Name}",
+                                           $"Save changes to {editor?.FileInfo!.Name}",
                                            "_Yes",
                                            "_No",
                                            "_Cancel"
@@ -164,7 +164,7 @@ public class ConfigurationEditor : Scenario
             switch (result)
             {
                 case 0:
-                    editor.Save ();
+                    editor?.Save ();
 
                     break;
 

+ 11 - 7
Examples/UICatalog/Scenarios/ContextMenus.cs

@@ -26,7 +26,7 @@ public class ContextMenus : Scenario
         {
             Title = GetQuitKeyAndName (),
             Arrangement = ViewArrangement.Fixed,
-            SchemeName = "Toplevel"
+            SchemeName = "Runnable"
         };
 
         _appWindow.Initialized += AppWindowOnInitialized;
@@ -49,7 +49,7 @@ public class ContextMenus : Scenario
             var text = "Context Menu";
             var width = 20;
 
-            CreateWinContextMenu ();
+            CreateWinContextMenu (ApplicationImpl.Instance);
 
             var label = new Label
             {
@@ -84,7 +84,11 @@ public class ContextMenus : Scenario
             _appWindow.MouseClick += OnAppWindowOnMouseClick;
 
             CultureInfo originalCulture = Thread.CurrentThread.CurrentUICulture;
-            _appWindow.Closed += (s, e) => { Thread.CurrentThread.CurrentUICulture = originalCulture; };
+            _appWindow.IsRunningChanged += (s, e) => {
+                                               if (!e.Value)
+                                               {
+                                                   Thread.CurrentThread.CurrentUICulture = originalCulture;
+                                               } };
         }
 
         void OnAppWindowOnMouseClick (object? s, MouseEventArgs e)
@@ -108,7 +112,7 @@ public class ContextMenus : Scenario
         }
     }
 
-    private void CreateWinContextMenu ()
+    private void CreateWinContextMenu (IApplication? app)
     {
         _winContextMenu = new (
                                [
@@ -122,7 +126,7 @@ public class ContextMenus : Scenario
                                    {
                                        Title = "_Configuration...",
                                        HelpText = "Show configuration",
-                                       Action = () => MessageBox.Query (
+                                       Action = () => MessageBox.Query (app,
                                                                         50,
                                                                         10,
                                                                         "Configuration",
@@ -140,7 +144,7 @@ public class ContextMenus : Scenario
                                                               Title = "_Setup...",
                                                               HelpText = "Perform setup",
                                                               Action = () => MessageBox
-                                                                           .Query (
+                                                                           .Query (app,
                                                                                    50,
                                                                                    10,
                                                                                    "Setup",
@@ -154,7 +158,7 @@ public class ContextMenus : Scenario
                                                               Title = "_Maintenance...",
                                                               HelpText = "Maintenance mode",
                                                               Action = () => MessageBox
-                                                                           .Query (
+                                                                           .Query (app,
                                                                                    50,
                                                                                    10,
                                                                                    "Maintenance",

+ 17 - 17
Examples/UICatalog/Scenarios/CsvEditor.cs

@@ -215,7 +215,7 @@ public class CsvEditor : Scenario
                                       _tableView.Table.Columns
                                      );
 
-            int result = MessageBox.Query (
+            int? result = MessageBox.Query (ApplicationImpl.Instance,
                                            "Column Type",
                                            "Pick a data type for the column",
                                            "Date",
@@ -225,7 +225,7 @@ public class CsvEditor : Scenario
                                            "Cancel"
                                           );
 
-            if (result <= -1 || result >= 4)
+            if (result is null || result >= 4)
             {
                 return;
             }
@@ -308,7 +308,7 @@ public class CsvEditor : Scenario
 
         if (_tableView.SelectedColumn == -1)
         {
-            MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
 
             return;
         }
@@ -320,7 +320,7 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Could not remove column", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Could not remove column", ex.Message, "Ok");
         }
     }
 
@@ -342,7 +342,7 @@ public class CsvEditor : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (60, 20, "Failed to set text", ex.Message, "Ok");
+                MessageBox.ErrorQuery (ApplicationImpl.Instance, 60, 20, "Failed to set text", ex.Message, "Ok");
             }
 
             _tableView.Update ();
@@ -388,7 +388,7 @@ public class CsvEditor : Scenario
 
         if (_tableView.SelectedColumn == -1)
         {
-            MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
 
             return;
         }
@@ -413,7 +413,7 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Error moving column", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error moving column", ex.Message, "Ok");
         }
     }
 
@@ -426,7 +426,7 @@ public class CsvEditor : Scenario
 
         if (_tableView.SelectedRow == -1)
         {
-            MessageBox.ErrorQuery ("No Rows", "No row selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Rows", "No row selected", "Ok");
 
             return;
         }
@@ -446,7 +446,7 @@ public class CsvEditor : Scenario
                     return;
                 }
 
-                object?[] arrayItems = currentRow.ItemArray;
+                object? [] arrayItems = currentRow.ItemArray;
                 _currentTable.Rows.Remove (currentRow);
 
                 // Removing and Inserting the same DataRow seems to result in it loosing its values so we have to create a new instance
@@ -462,7 +462,7 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Error moving column", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error moving column", ex.Message, "Ok");
         }
     }
 
@@ -470,7 +470,7 @@ public class CsvEditor : Scenario
     {
         if (_tableView?.Table is null)
         {
-            MessageBox.ErrorQuery ("No Table Loaded", "No table has currently be opened", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Table Loaded", "No table has currently be opened", "Ok");
 
             return true;
         }
@@ -575,14 +575,14 @@ public class CsvEditor : Scenario
                 _selectedCellTextField.SuperView.Enabled = true;
             }
 
-            if (Application.TopRunnable is { })
+            if (Application.TopRunnableView is { })
             {
-                Application.TopRunnable.Title = $"{GetName ()} - {Path.GetFileName (_currentFile)}";
+                Application.TopRunnableView.Title = $"{GetName ()} - {Path.GetFileName (_currentFile)}";
             }
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery (
+            MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                    "Open Failed",
                                    $"Error on line {lineNumber}{Environment.NewLine}{ex.Message}",
                                    "Ok"
@@ -612,7 +612,7 @@ public class CsvEditor : Scenario
     {
         if (_tableView?.Table is null || string.IsNullOrWhiteSpace (_currentFile) || _currentTable is null)
         {
-            MessageBox.ErrorQuery ("No file loaded", "No file is currently loaded", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No file loaded", "No file is currently loaded", "Ok");
 
             return;
         }
@@ -674,7 +674,7 @@ public class CsvEditor : Scenario
 
         if (col.DataType == typeof (string))
         {
-            MessageBox.ErrorQuery (
+            MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                    "Cannot Format Column",
                                    "String columns cannot be Formatted, try adding a new column to the table with a date/numerical Type",
                                    "Ok"
@@ -711,7 +711,7 @@ public class CsvEditor : Scenario
 
         if (_tableView.SelectedColumn == -1)
         {
-            MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
 
             return;
         }

+ 8 - 2
Examples/UICatalog/Scenarios/Dialogs.cs

@@ -266,7 +266,7 @@ public class Dialogs : Scenario
             {
                 Title = titleEdit.Text,
                 Text = "Dialog Text",
-                ButtonAlignment = (Alignment)Enum.Parse (typeof (Alignment), alignmentGroup.Labels! [(int)alignmentGroup.Value!.Value] [1..]),
+                ButtonAlignment = (Alignment)Enum.Parse (typeof (Alignment), alignmentGroup.Labels! [(int)alignmentGroup.Value!.Value] [0..]),
 
                 Buttons = buttons.ToArray ()
             };
@@ -340,7 +340,13 @@ public class Dialogs : Scenario
                               };
             dialog.Add (addChar);
 
-            dialog.Closed += (s, e) => { buttonPressedLabel.Text = $"{clicked}"; };
+            dialog.IsRunningChanged += (s, e) =>
+                                       {
+                                           if (!e.Value)
+                                           {
+                                               buttonPressedLabel.Text = $"{clicked}";
+                                           }
+                                       };
         }
         catch (FormatException)
         {

+ 6 - 6
Examples/UICatalog/Scenarios/DynamicStatusBar.cs

@@ -15,7 +15,7 @@ public class DynamicStatusBar : Scenario
     public override void Main ()
     {
         Application.Init ();
-        Application.Run<DynamicStatusBarSample> ().Dispose ();
+        Application.Run<DynamicStatusBarSample> ();
         Application.Shutdown ();
     }
 
@@ -79,7 +79,7 @@ public class DynamicStatusBar : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery ("Binding Error", $"Binding failed: {ex}.", "Ok");
+                MessageBox.ErrorQuery (ApplicationImpl.Instance, "Binding Error", $"Binding failed: {ex}.", "Ok");
             }
         }
     }
@@ -140,7 +140,7 @@ public class DynamicStatusBar : Scenario
         public TextView TextAction { get; }
         public TextField TextShortcut { get; }
         public TextField TextTitle { get; }
-        public Action CreateAction (DynamicStatusItem item) { return () => MessageBox.ErrorQuery (item.Title, item.Action, "Ok"); }
+        public Action CreateAction (DynamicStatusItem item) { return () => MessageBox.ErrorQuery (ApplicationImpl.Instance, item.Title, item.Action, "Ok"); }
 
         public void EditStatusItem (Shortcut statusItem)
         {
@@ -184,7 +184,7 @@ public class DynamicStatusBar : Scenario
                               {
                                   if (string.IsNullOrEmpty (TextTitle.Text))
                                   {
-                                      MessageBox.ErrorQuery ("Invalid title", "Must enter a valid title!.", "Ok");
+                                      MessageBox.ErrorQuery (App, "Invalid title", "Must enter a valid title!.", "Ok");
                                   }
                                   else
                                   {
@@ -200,7 +200,7 @@ public class DynamicStatusBar : Scenario
                                       TextTitle.Text = string.Empty;
                                       Application.RequestStop ();
                                   };
-            var dialog = new Dialog { Title = "Enter the menu details.", Buttons = [btnOk, btnCancel], Height = Dim.Auto (DimAutoStyle.Content, 17, Application.Screen.Height) };
+            var dialog = new Dialog { Title = "Enter the menu details.", Buttons = [btnOk, btnCancel], Height = Dim.Auto (DimAutoStyle.Content, 17, App?.Screen.Height) };
 
             Width = Dim.Fill ();
             Height = Dim.Fill () - 2;
@@ -382,7 +382,7 @@ public class DynamicStatusBar : Scenario
                               {
                                   if (string.IsNullOrEmpty (frmStatusBarDetails.TextTitle.Text) && _currentEditStatusItem != null)
                                   {
-                                      MessageBox.ErrorQuery ("Invalid title", "Must enter a valid title!.", "Ok");
+                                      MessageBox.ErrorQuery (App, "Invalid title", "Must enter a valid title!.", "Ok");
                                   }
                                   else if (_currentEditStatusItem != null)
                                   {

+ 19 - 11
Examples/UICatalog/Scenarios/Editor.cs

@@ -156,7 +156,7 @@ public class Editor : Scenario
                                        new (Key.F2, "Open", Open),
                                        new (Key.F3, "Save", () => Save ()),
                                        new (Key.F4, "Save As", () => SaveAs ()),
-                                       new (Key.Empty, $"OS Clipboard IsSupported : {Clipboard.IsSupported}", null),
+                                       new (Key.Empty, $"OS Clipboard IsSupported : {Application.Clipboard!.IsSupported}", null),
                                        siCursorPosition
                                    ]
                                   )
@@ -170,7 +170,14 @@ public class Editor : Scenario
 
         _appWindow.Add (statusBar);
 
-        _appWindow.Closed += (s, e) => Thread.CurrentThread.CurrentUICulture = new ("en-US");
+        _appWindow.IsRunningChanged += (s, e) =>
+                                       {
+                                           if (!e.Value)
+                                           {
+                                               // BUGBUG: This should restore the original culture info
+                                               Thread.CurrentThread.CurrentUICulture = new ("en-US");
+                                           }
+                                       };
 
         CreateFindReplace ();
 
@@ -193,7 +200,8 @@ public class Editor : Scenario
 
         Debug.Assert (_textView.IsDirty);
 
-        int r = MessageBox.ErrorQuery (
+        int? r = MessageBox.ErrorQuery (
+                                       ApplicationImpl.Instance,
                                        "Save File",
                                        $"Do you want save changes in {_appWindow.Title}?",
                                        "Yes",
@@ -228,7 +236,7 @@ public class Editor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Error", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.Message, "Ok");
         }
     }
 
@@ -307,11 +315,11 @@ public class Editor : Scenario
 
         if (!found)
         {
-            MessageBox.Query ("Find", $"The following specified text was not found: '{_textToFind}'", "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, "Find", $"The following specified text was not found: '{_textToFind}'", "Ok");
         }
         else if (gaveFullTurn)
         {
-            MessageBox.Query (
+            MessageBox.Query (ApplicationImpl.Instance,
                               "Find",
                               $"No more occurrences were found for the following specified text: '{_textToFind}'",
                               "Ok"
@@ -887,7 +895,7 @@ public class Editor : Scenario
 
         if (_textView.ReplaceAllText (_textToFind, _matchCase, _matchWholeWord, _textToReplace))
         {
-            MessageBox.Query (
+            MessageBox.Query (ApplicationImpl.Instance,
                               "Replace All",
                               $"All occurrences were replaced for the following specified text: '{_textToReplace}'",
                               "Ok"
@@ -895,7 +903,7 @@ public class Editor : Scenario
         }
         else
         {
-            MessageBox.Query (
+            MessageBox.Query (ApplicationImpl.Instance,
                               "Replace All",
                               $"None of the following specified text was found: '{_textToFind}'",
                               "Ok"
@@ -1147,7 +1155,7 @@ public class Editor : Scenario
         {
             if (File.Exists (path))
             {
-                if (MessageBox.Query (
+                if (MessageBox.Query (ApplicationImpl.Instance,
                                       "Save File",
                                       "File already exists. Overwrite any way?",
                                       "No",
@@ -1186,11 +1194,11 @@ public class Editor : Scenario
             _originalText = Encoding.Unicode.GetBytes (_textView.Text);
             _saved = true;
             _textView.ClearHistoryChanges ();
-            MessageBox.Query ("Save File", "File was successfully saved.", "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, "Save File", "File was successfully saved.", "Ok");
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Error", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.Message, "Ok");
 
             return false;
         }

+ 1 - 1
Examples/UICatalog/Scenarios/EditorsAndHelpers/ArrangementEditor.cs

@@ -45,7 +45,7 @@ public sealed class ArrangementEditor : EditorBase
             if (ViewToEdit.Arrangement.HasFlag (ViewArrangement.Overlapped))
             {
                 ViewToEdit.ShadowStyle = ShadowStyle.Transparent;
-                ViewToEdit.SchemeName = "Toplevel";
+                ViewToEdit.SchemeName = "Runnable";
             }
             else
             {

+ 1 - 1
Examples/UICatalog/Scenarios/EditorsAndHelpers/DimEditor.cs

@@ -157,7 +157,7 @@ public class DimEditor : EditorBase
         }
         catch (Exception e)
         {
-            MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
+            MessageBox.ErrorQuery (App, "Exception", e.Message, "Ok");
         }
     }
 }

+ 1 - 1
Examples/UICatalog/Scenarios/EditorsAndHelpers/PosEditor.cs

@@ -160,7 +160,7 @@ public class PosEditor : EditorBase
         }
         catch (Exception e)
         {
-            MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
+            MessageBox.ErrorQuery (App, "Exception", e.Message, "Ok");
         }
     }
 }

+ 6 - 6
Examples/UICatalog/Scenarios/FileDialogExamples.cs

@@ -133,7 +133,7 @@ public class FileDialogExamples : Scenario
                              }
                              catch (Exception ex)
                              {
-                                 MessageBox.ErrorQuery ("Error", ex.ToString (), "_Ok");
+                                 MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.ToString (), "_Ok");
                              }
                              finally
                              {
@@ -153,7 +153,7 @@ public class FileDialogExamples : Scenario
         {
             if (File.Exists (e.Dialog.Path))
             {
-                int result = MessageBox.Query ("Overwrite?", "File already exists", "_Yes", "_No");
+                int? result = MessageBox.Query (ApplicationImpl.Instance, "Overwrite?", "File already exists", "_Yes", "_No");
                 e.Cancel = result == 1;
             }
         }
@@ -243,12 +243,12 @@ public class FileDialogExamples : Scenario
             IReadOnlyList<string> multiSelected = fd.MultiSelected;
             string path = fd.Path;
 
-            // This needs to be disposed before opening other toplevel
+            // This needs to be disposed before opening other runnable
             fd.Dispose ();
 
             if (canceled)
             {
-                MessageBox.Query (
+                MessageBox.Query (ApplicationImpl.Instance,
                                   "Canceled",
                                   "You canceled navigation and did not pick anything",
                                   "Ok"
@@ -256,7 +256,7 @@ public class FileDialogExamples : Scenario
             }
             else if (_cbAllowMultipleSelection.CheckedState == CheckState.Checked)
             {
-                MessageBox.Query (
+                MessageBox.Query (ApplicationImpl.Instance,
                                   "Chosen!",
                                   "You chose:" + Environment.NewLine + string.Join (Environment.NewLine, multiSelected.Select (m => m)),
                                   "Ok"
@@ -264,7 +264,7 @@ public class FileDialogExamples : Scenario
             }
             else
             {
-                MessageBox.Query (
+                MessageBox.Query (ApplicationImpl.Instance,
                                   "Chosen!",
                                   "You chose:" + Environment.NewLine + path,
                                   "Ok"

+ 1 - 1
Examples/UICatalog/Scenarios/Generic.cs

@@ -29,7 +29,7 @@ public sealed class Generic : Scenario
                             {
                                 // When Accepting is handled, set e.Handled to true to prevent further processing.
                                 e.Handled = true;
-                                MessageBox.ErrorQuery ("Error", "You pressed the button!", "_Ok");
+                                MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", "You pressed the button!", "_Ok");
                             };
 
         appWindow.Add (button);

+ 4 - 4
Examples/UICatalog/Scenarios/HexEditor.cs

@@ -181,7 +181,7 @@ public class HexEditor : Scenario
         }
     }
 
-    private void Copy () { MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok"); }
+    private void Copy () { MessageBox.ErrorQuery (ApplicationImpl.Instance, "Not Implemented", "Functionality not yet implemented.", "Ok"); }
 
     private void CreateDemoFile (string fileName)
     {
@@ -208,7 +208,7 @@ public class HexEditor : Scenario
         ms.Close ();
     }
 
-    private void Cut () { MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok"); }
+    private void Cut () { MessageBox.ErrorQuery (ApplicationImpl.Instance, "Not Implemented", "Functionality not yet implemented.", "Ok"); }
 
     private Stream LoadFile ()
     {
@@ -216,7 +216,7 @@ public class HexEditor : Scenario
 
         if (!_saved && _hexView!.Edits.Count > 0 && _hexView.Source is {})
         {
-            if (MessageBox.ErrorQuery (
+            if (MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                        "Save",
                                        "The changes were not saved. Want to open without saving?",
                                        "_Yes",
@@ -267,7 +267,7 @@ public class HexEditor : Scenario
         d.Dispose ();
     }
 
-    private void Paste () { MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "_Ok"); }
+    private void Paste () { MessageBox.ErrorQuery (ApplicationImpl.Instance, "Not Implemented", "Functionality not yet implemented.", "_Ok"); }
     private void Quit () { Application.RequestStop (); }
 
     private void Save ()

+ 3 - 3
Examples/UICatalog/Scenarios/Images.cs

@@ -183,7 +183,7 @@ public class Images : Scenario
 
         if (!_sixelSupportResult.SupportsTransparency)
         {
-            if (MessageBox.Query (
+            if (MessageBox.Query (ApplicationImpl.Instance,
                                   "Transparency Not Supported",
                                   "It looks like your terminal does not support transparent sixel backgrounds. Do you want to try anyway?",
                                   "Yes",
@@ -288,7 +288,7 @@ public class Images : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Could not open file", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Could not open file", ex.Message, "Ok");
 
             return;
         }
@@ -492,7 +492,7 @@ public class Images : Scenario
     {
         if (_imageView.FullResImage == null)
         {
-            MessageBox.Query ("No Image Loaded", "You must first open an image.  Use the 'Open Image' button above.", "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, "No Image Loaded", "You must first open an image.  Use the 'Open Image' button above.", "Ok");
 
             return;
         }

+ 1 - 1
Examples/UICatalog/Scenarios/InteractiveTree.cs

@@ -173,7 +173,7 @@ public class InteractiveTree : Scenario
 
                 if (parent is null)
                 {
-                    MessageBox.ErrorQuery (
+                    MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                            "Could not delete",
                                            $"Parent of '{toDelete}' was unexpectedly null",
                                            "Ok"

+ 4 - 4
Examples/UICatalog/Scenarios/KeyBindings.cs

@@ -164,17 +164,17 @@ public class KeyBindingsDemo : View
 
         AddCommand (Command.Save, ctx =>
                                  {
-                                     MessageBox.Query ($"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
+                                     MessageBox.Query (ApplicationImpl.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
                                      return true;
                                  });
         AddCommand (Command.New, ctx =>
                                 {
-                                    MessageBox.Query ($"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
+                                    MessageBox.Query (ApplicationImpl.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
                                     return true;
                                 });
         AddCommand (Command.HotKey, ctx =>
         {
-            MessageBox.Query ($"{ctx.Command}", $"Ctx: {ctx}\nCommand: {ctx.Command}", buttons: "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, $"{ctx.Command}", $"Ctx: {ctx}\nCommand: {ctx.Command}", buttons: "Ok");
             SetFocus ();
             return true;
         });
@@ -189,7 +189,7 @@ public class KeyBindingsDemo : View
                                              {
                                                  return false;
                                              }
-                                             MessageBox.Query ($"{keyCommandContext.Binding}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
+                                             MessageBox.Query (ApplicationImpl.Instance, $"{keyCommandContext.Binding}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
                                              Application.RequestStop ();
                                              return true;
                                          });

+ 4 - 4
Examples/UICatalog/Scenarios/Keys.cs

@@ -86,7 +86,7 @@ public class Keys : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (keyList)
         };
-        appKeyListView.SchemeName = "TopLevel";
+        appKeyListView.SchemeName = "Runnable";
         win.Add (appKeyListView);
 
         // View key events...
@@ -114,7 +114,7 @@ public class Keys : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (keyDownList)
         };
-        appKeyListView.SchemeName = "TopLevel";
+        appKeyListView.SchemeName = "Runnable";
         win.Add (onKeyDownListView);
 
         // KeyDownNotHandled
@@ -134,7 +134,7 @@ public class Keys : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (keyDownNotHandledList)
         };
-        appKeyListView.SchemeName = "TopLevel";
+        appKeyListView.SchemeName = "Runnable";
         win.Add (onKeyDownNotHandledListView);
 
 
@@ -155,7 +155,7 @@ public class Keys : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (swallowedList)
         };
-        appKeyListView.SchemeName = "TopLevel";
+        appKeyListView.SchemeName = "Runnable";
         win.Add (onSwallowedListView);
 
         Application.Driver!.InputProcessor.AnsiSequenceSwallowed += (s, e) => { swallowedList.Add (e.Replace ("\x1b", "Esc")); };

+ 1 - 1
Examples/UICatalog/Scenarios/LineCanvasExperiment.cs

@@ -101,7 +101,7 @@ public class LineCanvasExperiment : Scenario
         //    Width = view4.Width,
         //    Height = 5,
 
-        //    //Scheme = Colors.Schemes ["TopLevel"],
+        //    //Scheme = Colors.Schemes ["Runnable"],
         //    SuperViewRendersLineCanvas = true,
         //    BorderStyle = LineStyle.Double
         //};

+ 1 - 1
Examples/UICatalog/Scenarios/ListColumns.cs

@@ -336,7 +336,7 @@ public class ListColumns : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (60, 20, "Failed to set", ex.Message, "Ok");
+                MessageBox.ErrorQuery (ApplicationImpl.Instance, 60, 20, "Failed to set", ex.Message, "Ok");
             }
         }
     }

+ 1 - 1
Examples/UICatalog/Scenarios/ListViewWithSelection.cs

@@ -98,7 +98,7 @@ public class ListViewWithSelection : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (_eventList)
         };
-        _eventListView.SchemeName = "TopLevel";
+        _eventListView.SchemeName = "Runnable";
         _appWindow.Add (_eventListView);
 
         _listView.SelectedItemChanged += (s, a) => LogEvent (s as View, a, "SelectedItemChanged");

+ 2 - 2
Examples/UICatalog/Scenarios/ListsAndCombos.cs

@@ -35,7 +35,7 @@ public class ListsAndCombos : Scenario
         // ListView
         var lbListView = new Label
         {
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             X = 0,
 
             Width = Dim.Percent (40),
@@ -91,7 +91,7 @@ public class ListsAndCombos : Scenario
         // ComboBox
         var lbComboBox = new Label
         {
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             X = Pos.Right (lbListView) + 1,
 
             Width = Dim.Percent (40),

+ 1 - 1
Examples/UICatalog/Scenarios/Localization.cs

@@ -181,7 +181,7 @@ public class Localization : Scenario
         wizardButton.Accepting += (sender, e) => ShowWizard ();
         win.Add (wizardButton);
 
-        win.Unloaded += (sender, e) => Quit ();
+        win.IsRunningChanged += (sender, e) => Quit ();
 
         win.Add (menu);
 

+ 7 - 7
Examples/UICatalog/Scenarios/Mazing.cs

@@ -9,7 +9,7 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Games")]
 public class Mazing : Scenario
 {
-    private Toplevel? _top;
+    private Window? _top;
     private MazeGenerator? _m;
 
     private List<Point>? _potions;
@@ -33,17 +33,17 @@ public class Mazing : Scenario
         _top.KeyBindings.Add (Key.CursorDown, Command.Down);
 
         // Changing the key-bindings of a View is not allowed, however,
-        // by default, Toplevel doesn't bind any of our movement keys, so
+        // by default, Runnable doesn't bind any of our movement keys, so
         // we can take advantage of the CommandNotBound event to handle them
         // 
-        // An alternative implementation would be to create a TopLevel subclass that
+        // An alternative implementation would be to create a Runnable subclass that
         // calls AddCommand/KeyBindings.Add in the constructor. See the Snake game scenario
         // for an example.
         _top.CommandNotBound += TopCommandNotBound;
 
         _top.DrawingContent += (s, _) =>
                                {
-                                   if (s is not Toplevel top)
+                                   if (s is not Runnable top)
                                    {
                                        return;
                                    }
@@ -171,7 +171,7 @@ public class Mazing : Scenario
                 if (_m.PlayerHp <= 0)
                 {
                     _message = "You died!";
-                    Application.TopRunnable!.SetNeedsDraw (); // trigger redraw
+                    Application.TopRunnableView!.SetNeedsDraw (); // trigger redraw
                     _dead = true;
 
                     return; // Stop further action if dead
@@ -190,7 +190,7 @@ public class Mazing : Scenario
                 _message = string.Empty;
             }
 
-            Application.TopRunnable!.SetNeedsDraw (); // trigger redraw
+            Application.TopRunnableView!.SetNeedsDraw (); // trigger redraw
         }
 
         // Optional win condition:
@@ -200,7 +200,7 @@ public class Mazing : Scenario
             _m = new (); // Generate a new maze
             _m.PlayerHp = hp;
             GenerateNpcs ();
-            Application.TopRunnable!.SetNeedsDraw (); // trigger redraw
+            Application.TopRunnableView!.SetNeedsDraw (); // trigger redraw
         }
     }
 }

+ 2 - 2
Examples/UICatalog/Scenarios/Menus.cs

@@ -21,7 +21,7 @@ public class Menus : Scenario
         Logging.Logger = CreateLogger ();
 
         Application.Init ();
-        Toplevel app = new ();
+        Runnable app = new ();
         app.Title = GetQuitKeyAndName ();
 
         ObservableCollection<string> eventSource = new ();
@@ -32,7 +32,7 @@ public class Menus : Scenario
             X = Pos.AnchorEnd (),
             Width = Dim.Auto (),
             Height = Dim.Fill (), // Make room for some wide things
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (eventSource)
         };
         eventLog.Border!.Thickness = new (0, 1, 0, 0);

+ 9 - 9
Examples/UICatalog/Scenarios/MessageBoxes.cs

@@ -251,7 +251,7 @@ public class MessageBoxes : Scenario
                                                {
                                                    buttonPressedLabel.Text =
                                                        $"{MessageBox.Query (
-                                                                             width,
+                                                                            ApplicationImpl.Instance, width,
                                                                              height,
                                                                              titleEdit.Text,
                                                                              messageEdit.Text,
@@ -263,14 +263,14 @@ public class MessageBoxes : Scenario
                                                else
                                                {
                                                    buttonPressedLabel.Text =
-                                                       $"{MessageBox.ErrorQuery (
-                                                                                  width,
-                                                                                  height,
-                                                                                  titleEdit.Text,
-                                                                                  messageEdit.Text,
-                                                                                  defaultButton,
-                                                                                  ckbWrapMessage.CheckedState == CheckState.Checked,
-                                                                                  btns.ToArray ()
+                                                       $"{MessageBox.ErrorQuery (ApplicationImpl.Instance,
+                                                                                 width,
+                                                                                 height,
+                                                                                 titleEdit.Text,
+                                                                                 messageEdit.Text,
+                                                                                 defaultButton,
+                                                                                 ckbWrapMessage.CheckedState == CheckState.Checked,
+                                                                                 btns.ToArray ()
                                                                                  )}";
                                                }
                                            }

+ 2 - 2
Examples/UICatalog/Scenarios/Mouse.cs

@@ -247,7 +247,7 @@ public class Mouse : Scenario
             Y = Pos.Bottom (label),
             Width = 50,
             Height = Dim.Fill (),
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (appLogList)
         };
         win.Add (label, appLog);
@@ -278,7 +278,7 @@ public class Mouse : Scenario
             Y = Pos.Bottom (label),
             Width = Dim.Percent (50),
             Height = Dim.Fill (),
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (winLogList)
         };
         win.Add (label, winLog);

+ 1 - 1
Examples/UICatalog/Scenarios/MultiColouredTable.cs

@@ -99,7 +99,7 @@ public class MultiColouredTable : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (60, 20, "Failed to set text", ex.Message, "Ok");
+                MessageBox.ErrorQuery (ApplicationImpl.Instance, 60, 20, "Failed to set text", ex.Message, "Ok");
             }
 
             _tableView.Update ();

+ 4 - 4
Examples/UICatalog/Scenarios/Navigation.cs

@@ -59,7 +59,7 @@ public class Navigation : Scenario
             Y = 0,
             Title = $"TopButton _{GetNextHotKey ()}"
         };
-        button.Accepting += (sender, args) => MessageBox.Query ("hi", button.Title, "_Ok");
+        button.Accepting += (sender, args) => MessageBox.Query (ApplicationImpl.Instance, "hi", button.Title, "_Ok");
 
         testFrame.Add (button);
 
@@ -180,7 +180,7 @@ public class Navigation : Scenario
             X = 1,
             Y = 7,
             Id = "datePicker",
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,
             CanFocus = true, // Can't drag without this? BUGBUG
@@ -210,7 +210,7 @@ public class Navigation : Scenario
 
         return;
 
-        void OnApplicationIteration (object sender, IterationEventArgs args)
+        void OnApplicationIteration (object sender, EventArgs<IApplication> args)
         {
             if (progressBar.Fraction == 1.0)
             {
@@ -237,7 +237,7 @@ public class Navigation : Scenario
             Height = Dim.Auto (),
             Width = Dim.Auto (),
             Title = $"Overlapped{id} _{GetNextHotKey ()}",
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Id = $"Overlapped{id}",
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,

+ 14 - 11
Examples/UICatalog/Scenarios/Notepad.cs

@@ -71,7 +71,7 @@ public class Notepad : Scenario
                                        new MenuItem
                                        {
                                            Title = "_About",
-                                           Action = () => MessageBox.Query ("Notepad", "About Notepad...", "Ok")
+                                           Action = () => MessageBox.Query (ApplicationImpl.Instance,  "Notepad", "About Notepad...", "Ok")
                                        }
                                    ]
                                   )
@@ -110,10 +110,13 @@ public class Notepad : Scenario
         _tabView.SelectedTabChanged += TabView_SelectedTabChanged;
         _tabView.HasFocusChanging += (s, e) => _focusedTabView = _tabView;
 
-        top.Ready += (s, e) =>
+        top.IsModalChanged += (s, e) =>
                      {
-                         New ();
-                         LenShortcut.Title = $"Len:{_focusedTabView?.Text?.Length ?? 0}";
+                         if (e.Value)
+                         {
+                             New ();
+                             LenShortcut.Title = $"Len:{_focusedTabView?.Text?.Length ?? 0}";
+                         }
                      };
 
         Application.Run (top);
@@ -193,15 +196,15 @@ public class Notepad : Scenario
 
         if (tab.UnsavedChanges)
         {
-            int result = MessageBox.Query (
-                                           "Save Changes",
-                                           $"Save changes to {tab.Text.TrimEnd ('*')}",
-                                           "Yes",
-                                           "No",
-                                           "Cancel"
+            int? result = MessageBox.Query (ApplicationImpl.Instance,
+                                            "Save Changes",
+                                            $"Save changes to {tab.Text.TrimEnd ('*')}",
+                                            "Yes",
+                                            "No",
+                                            "Cancel"
                                           );
 
-            if (result == -1 || result == 2)
+            if (result is null || result == 2)
             {
                 // user cancelled
                 return;

+ 1 - 1
Examples/UICatalog/Scenarios/PosAlignDemo.cs

@@ -20,7 +20,7 @@ public sealed class PosAlignDemo : Scenario
             Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()} - {GetDescription ()}"
         };
 
-        SetupControls (appWindow, Dimension.Width, Schemes.Toplevel);
+        SetupControls (appWindow, Dimension.Width, Schemes.Runnable);
 
         SetupControls (appWindow, Dimension.Height, Schemes.Error);
 

+ 14 - 10
Examples/UICatalog/Scenarios/ProgressBarStyles.cs

@@ -27,7 +27,7 @@ public class ProgressBarStyles : Scenario
     {
         Application.Init ();
 
-        Window app = new ()
+        Window win = new ()
         {
             Title = GetQuitKeyAndName (), BorderStyle = LineStyle.Single,
         };
@@ -38,7 +38,7 @@ public class ProgressBarStyles : Scenario
             ShowViewIdentifier = true
 
         };
-        app.Add (editor);
+        win.Add (editor);
 
         View container = new ()
         {
@@ -47,7 +47,7 @@ public class ProgressBarStyles : Scenario
             Width = Dim.Fill (),
             Height = Dim.Fill (),
         };
-        app.Add (container);
+        win.Add (container);
 
         const float fractionStep = 0.01F;
 
@@ -278,8 +278,8 @@ public class ProgressBarStyles : Scenario
 
 
 
-        app.Initialized += App_Initialized;
-        app.Unloaded += App_Unloaded;
+        win.Initialized += Win_Initialized;
+        win.IsRunningChanged += Win_IsRunningChanged;
 
         _pulseTimer = new Timer (
                                  _ =>
@@ -292,14 +292,18 @@ public class ProgressBarStyles : Scenario
                                  0,
                                  300
                                 );
-        Application.Run (app);
-        app.Dispose ();
+        Application.Run (win);
+        win.Dispose ();
         Application.Shutdown ();
 
         return;
 
-        void App_Unloaded (object sender, EventArgs args)
+        void Win_IsRunningChanged (object sender, EventArgs<bool> args)
         {
+            if (args.Value)
+            {
+                return;
+            }
             if (_fractionTimer != null)
             {
                 _fractionTimer.Dispose ();
@@ -312,11 +316,11 @@ public class ProgressBarStyles : Scenario
                 _pulseTimer = null;
             }
 
-            app.Unloaded -= App_Unloaded;
+            win.IsRunningChanged -= Win_IsRunningChanged;
         }
     }
 
-    private void App_Initialized (object sender, EventArgs e)
+    private void Win_Initialized (object sender, EventArgs e)
     {
         _pbList.SelectedItem = 0;
     }

+ 4 - 4
Examples/UICatalog/Scenarios/RunTExample.cs

@@ -8,7 +8,7 @@ public class RunTExample : Scenario
     public override void Main ()
     {
         // No need to call Init if Application.Run<T> is used
-        Application.Run<ExampleWindow> ().Dispose ();
+        Application.Run<ExampleWindow> ();
         Application.Shutdown ();
     }
 
@@ -63,12 +63,12 @@ public class RunTExample : Scenario
                                {
                                    if (_usernameText.Text == "admin" && passwordText.Text == "password")
                                    {
-                                       MessageBox.Query ("Login Successful", $"Username: {_usernameText.Text}", "Ok");
-                                       Application.RequestStop ();
+                                       MessageBox.Query (App, "Login Successful", $"Username: {_usernameText.Text}", "Ok");
+                                       App?.RequestStop ();
                                    }
                                    else
                                    {
-                                       MessageBox.ErrorQuery (
+                                       MessageBox.ErrorQuery (App,
                                                               "Error Logging In",
                                                               "Incorrect username or password (hint: admin/password)",
                                                               "Ok"

+ 3 - 3
Examples/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs

@@ -166,7 +166,7 @@ public class RuneWidthGreaterThanOne : Scenario
     {
         if (_text is { })
         {
-            MessageBox.Query ("Say Hello 你", $"Hello {_text.Text}", "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, "Say Hello 你", $"Hello {_text.Text}", "Ok");
         }
     }
 
@@ -197,7 +197,7 @@ public class RuneWidthGreaterThanOne : Scenario
     {
         if (_text is { })
         {
-            MessageBox.Query ("Say Hello", $"Hello {_text.Text}", "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, "Say Hello", $"Hello {_text.Text}", "Ok");
         }
     }
 
@@ -252,7 +252,7 @@ public class RuneWidthGreaterThanOne : Scenario
     {
         if (_text is { })
         {
-            MessageBox.Query ("こんにちはと言う", $"こんにちは {_text.Text}", "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, "こんにちはと言う", $"こんにちは {_text.Text}", "Ok");
         }
     }
 

+ 15 - 15
Examples/UICatalog/Scenarios/Scrolling.cs

@@ -16,13 +16,13 @@ public class Scrolling : Scenario
     {
         Application.Init ();
 
-        var app = new Window
+        var win = new Window
         {
             Title = GetQuitKeyAndName ()
         };
 
         var label = new Label { X = 0, Y = 0 };
-        app.Add (label);
+        win.Add (label);
 
         var demoView = new AllViewsView
         {
@@ -42,7 +42,7 @@ public class Scrolling : Scenario
                                             $"{demoView}\nContentSize: {demoView.GetContentSize ()}\nViewport.Location: {demoView.Viewport.Location}";
                                     };
 
-        app.Add (demoView);
+        win.Add (demoView);
 
         var hCheckBox = new CheckBox
         {
@@ -51,7 +51,7 @@ public class Scrolling : Scenario
             Text = "_HorizontalScrollBar.Visible",
             CheckedState = demoView.HorizontalScrollBar.Visible ? CheckState.Checked : CheckState.UnChecked
         };
-        app.Add (hCheckBox);
+        win.Add (hCheckBox);
         hCheckBox.CheckedStateChanged += (sender, args) => { demoView.HorizontalScrollBar.Visible = args.Value == CheckState.Checked; };
 
         var vCheckBox = new CheckBox
@@ -61,7 +61,7 @@ public class Scrolling : Scenario
             Text = "_VerticalScrollBar.Visible",
             CheckedState = demoView.VerticalScrollBar.Visible ? CheckState.Checked : CheckState.UnChecked
         };
-        app.Add (vCheckBox);
+        win.Add (vCheckBox);
         vCheckBox.CheckedStateChanged += (sender, args) => { demoView.VerticalScrollBar.Visible = args.Value == CheckState.Checked; };
 
         var ahCheckBox = new CheckBox
@@ -77,7 +77,7 @@ public class Scrolling : Scenario
                                                demoView.HorizontalScrollBar.AutoShow = e.Result == CheckState.Checked;
                                                demoView.VerticalScrollBar.AutoShow = e.Result == CheckState.Checked;
                                            };
-        app.Add (ahCheckBox);
+        win.Add (ahCheckBox);
 
         demoView.VerticalScrollBar.VisibleChanging += (sender, args) => { vCheckBox.CheckedState = args.NewValue ? CheckState.Checked : CheckState.UnChecked; };
 
@@ -92,19 +92,19 @@ public class Scrolling : Scenario
             X = Pos.Center (), Y = Pos.AnchorEnd (), Width = Dim.Fill ()
         };
 
-        app.Add (progress);
+        win.Add (progress);
 
-        app.Initialized += AppOnInitialized;
-        app.Unloaded += AppUnloaded;
+        win.Initialized += WinOnInitialized;
+        win.IsRunningChanged += WinIsRunningChanged;
 
-        Application.Run (app);
-        app.Unloaded -= AppUnloaded;
-        app.Dispose ();
+        Application.Run (win);
+        win.IsRunningChanged -= WinIsRunningChanged;
+        win.Dispose ();
         Application.Shutdown ();
 
         return;
 
-        void AppOnInitialized (object? sender, EventArgs e)
+        void WinOnInitialized (object? sender, EventArgs e)
         {
             bool TimerFn ()
             {
@@ -116,9 +116,9 @@ public class Scrolling : Scenario
             _progressTimer = Application.AddTimeout (TimeSpan.FromMilliseconds (200), TimerFn);
         }
 
-        void AppUnloaded (object? sender, EventArgs args)
+        void WinIsRunningChanged (object? sender, EventArgs<bool> args)
         {
-            if (_progressTimer is { })
+            if (!args.Value && _progressTimer is { })
             {
                 Application.RemoveTimeout (_progressTimer);
                 _progressTimer = null;

+ 31 - 31
Examples/UICatalog/Scenarios/Shortcuts.cs

@@ -15,7 +15,7 @@ public class Shortcuts : Scenario
         var quitKey = Application.QuitKey;
         Window app = new ();
 
-        app.Loaded += App_Loaded;
+        app.IsModalChanged += App_Loaded;
 
         Application.Run (app);
         app.Dispose ();
@@ -28,7 +28,7 @@ public class Shortcuts : Scenario
     private void App_Loaded (object? sender, EventArgs e)
     {
         Application.QuitKey = Key.F4.WithCtrl;
-        Application.TopRunnable!.Title = GetQuitKeyAndName ();
+        Application.TopRunnableView!.Title = GetQuitKeyAndName ();
 
         ObservableCollection<string> eventSource = new ();
 
@@ -38,7 +38,7 @@ public class Shortcuts : Scenario
             X = Pos.AnchorEnd (),
             Y = 0,
             Height = Dim.Fill (4),
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (eventSource),
             BorderStyle = LineStyle.Double,
             Title = "E_vents"
@@ -46,14 +46,14 @@ public class Shortcuts : Scenario
 
         eventLog.Width = Dim.Func (
                                    _ => Math.Min (
-                                                  Application.TopRunnable.Viewport.Width / 2,
+                                                  Application.TopRunnableView.Viewport.Width / 2,
                                                   eventLog?.MaxLength + eventLog!.GetAdornmentsThickness ().Horizontal ?? 0));
 
         eventLog.Width = Dim.Func (
                                    _ => Math.Min (
                                                   eventLog.SuperView!.Viewport.Width / 2,
                                                   eventLog?.MaxLength + eventLog!.GetAdornmentsThickness ().Horizontal ?? 0));
-        Application.TopRunnable.Add (eventLog);
+        Application.TopRunnableView.Add (eventLog);
 
         var alignKeysShortcut = new Shortcut
         {
@@ -86,7 +86,7 @@ public class Shortcuts : Scenario
                                                                           };
 
 
-        Application.TopRunnable.Add (alignKeysShortcut);
+        Application.TopRunnableView.Add (alignKeysShortcut);
 
         var commandFirstShortcut = new Shortcut
         {
@@ -115,7 +115,7 @@ public class Shortcuts : Scenario
                                                                                                       $"{commandFirstShortcut.Id}.CommandView.CheckedStateChanging: {cb.Text}");
                                                                                      eventLog.MoveDown ();
 
-                                                                                     IEnumerable<View> toAlign = Application.TopRunnable.SubViews.OfType<Shortcut> ();
+                                                                                     IEnumerable<View> toAlign = Application.TopRunnableView.SubViews.OfType<Shortcut> ();
                                                                                      IEnumerable<View> enumerable = toAlign as View [] ?? toAlign.ToArray ();
 
                                                                                      foreach (View view in enumerable)
@@ -134,7 +134,7 @@ public class Shortcuts : Scenario
                                                                                  }
                                                                              };
 
-        Application.TopRunnable.Add (commandFirstShortcut);
+        Application.TopRunnableView.Add (commandFirstShortcut);
 
         var canFocusShortcut = new Shortcut
         {
@@ -159,7 +159,7 @@ public class Shortcuts : Scenario
                                                                                  SetCanFocus (e.Result == CheckState.Checked);
                                                                              }
                                                                          };
-        Application.TopRunnable.Add (canFocusShortcut);
+        Application.TopRunnableView.Add (canFocusShortcut);
 
         var appShortcut = new Shortcut
         {
@@ -173,7 +173,7 @@ public class Shortcuts : Scenario
             BindKeyToApplication = true
         };
 
-        Application.TopRunnable.Add (appShortcut);
+        Application.TopRunnableView.Add (appShortcut);
 
         var buttonShortcut = new Shortcut
         {
@@ -193,7 +193,7 @@ public class Shortcuts : Scenario
         var button = (Button)buttonShortcut.CommandView;
         buttonShortcut.Accepting += Button_Clicked;
 
-        Application.TopRunnable.Add (buttonShortcut);
+        Application.TopRunnableView.Add (buttonShortcut);
 
         var optionSelectorShortcut = new Shortcut
         {
@@ -221,7 +221,7 @@ public class Shortcuts : Scenario
                                                                                     }
                                                                                 };
 
-        Application.TopRunnable.Add (optionSelectorShortcut);
+        Application.TopRunnableView.Add (optionSelectorShortcut);
 
         var sliderShortcut = new Shortcut
         {
@@ -248,7 +248,7 @@ public class Shortcuts : Scenario
                                                                            eventLog.MoveDown ();
                                                                        };
 
-        Application.TopRunnable.Add (sliderShortcut);
+        Application.TopRunnableView.Add (sliderShortcut);
 
         ListView listView = new ListView ()
         {
@@ -270,7 +270,7 @@ public class Shortcuts : Scenario
             Key = Key.F5.WithCtrl,
         };
 
-        Application.TopRunnable.Add (listViewShortcut);
+        Application.TopRunnableView.Add (listViewShortcut);
 
         var noCommandShortcut = new Shortcut
         {
@@ -282,7 +282,7 @@ public class Shortcuts : Scenario
             Key = Key.D0
         };
 
-        Application.TopRunnable.Add (noCommandShortcut);
+        Application.TopRunnableView.Add (noCommandShortcut);
 
         var noKeyShortcut = new Shortcut
         {
@@ -295,7 +295,7 @@ public class Shortcuts : Scenario
             HelpText = "Keyless"
         };
 
-        Application.TopRunnable.Add (noKeyShortcut);
+        Application.TopRunnableView.Add (noKeyShortcut);
 
         var noHelpShortcut = new Shortcut
         {
@@ -308,7 +308,7 @@ public class Shortcuts : Scenario
             HelpText = ""
         };
 
-        Application.TopRunnable.Add (noHelpShortcut);
+        Application.TopRunnableView.Add (noHelpShortcut);
         noHelpShortcut.SetFocus ();
 
         var framedShortcut = new Shortcut
@@ -339,8 +339,8 @@ public class Shortcuts : Scenario
             framedShortcut.KeyView.SchemeName = framedShortcut.KeyView.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Base);
         }
 
-        framedShortcut.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Toplevel);
-        Application.TopRunnable.Add (framedShortcut);
+        framedShortcut.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Runnable);
+        Application.TopRunnableView.Add (framedShortcut);
 
         // Horizontal
         var progressShortcut = new Shortcut
@@ -387,7 +387,7 @@ public class Shortcuts : Scenario
                          };
         timer.Start ();
 
-        Application.TopRunnable.Add (progressShortcut);
+        Application.TopRunnableView.Add (progressShortcut);
 
         var textField = new TextField
         {
@@ -408,7 +408,7 @@ public class Shortcuts : Scenario
         };
         textField.CanFocus = true;
 
-        Application.TopRunnable.Add (textFieldShortcut);
+        Application.TopRunnableView.Add (textFieldShortcut);
 
         var bgColorShortcut = new Shortcut
         {
@@ -450,19 +450,19 @@ public class Shortcuts : Scenario
                                         eventSource.Add ($"ColorChanged: {o.GetType ().Name} - {args.Result}");
                                         eventLog.MoveDown ();
 
-                                        Application.TopRunnable.SetScheme (
-                                                                   new (Application.TopRunnable.GetScheme ())
+                                        Application.TopRunnableView.SetScheme (
+                                                                   new (Application.TopRunnableView.GetScheme ())
                                                                    {
                                                                        Normal = new (
-                                                                                     Application.TopRunnable!.GetAttributeForRole (VisualRole.Normal).Foreground,
+                                                                                     Application.TopRunnableView!.GetAttributeForRole (VisualRole.Normal).Foreground,
                                                                                      args.Result,
-                                                                                     Application.TopRunnable!.GetAttributeForRole (VisualRole.Normal).Style)
+                                                                                     Application.TopRunnableView!.GetAttributeForRole (VisualRole.Normal).Style)
                                                                    });
                                     }
                                 };
         bgColorShortcut.CommandView = bgColor;
 
-        Application.TopRunnable.Add (bgColorShortcut);
+        Application.TopRunnableView.Add (bgColorShortcut);
 
         var appQuitShortcut = new Shortcut
         {
@@ -476,9 +476,9 @@ public class Shortcuts : Scenario
         };
         appQuitShortcut.Accepting += (o, args) => { Application.RequestStop (); };
 
-        Application.TopRunnable.Add (appQuitShortcut);
+        Application.TopRunnableView.Add (appQuitShortcut);
 
-        foreach (Shortcut shortcut in Application.TopRunnable.SubViews.OfType<Shortcut> ())
+        foreach (Shortcut shortcut in Application.TopRunnableView.SubViews.OfType<Shortcut> ())
         {
             shortcut.Selecting += (o, args) =>
                                   {
@@ -529,7 +529,7 @@ public class Shortcuts : Scenario
 
         void SetCanFocus (bool canFocus)
         {
-            foreach (Shortcut peer in Application.TopRunnable!.SubViews.OfType<Shortcut> ())
+            foreach (Shortcut peer in Application.TopRunnableView!.SubViews.OfType<Shortcut> ())
             {
                 if (peer.CanFocus)
                 {
@@ -542,7 +542,7 @@ public class Shortcuts : Scenario
         {
             var max = 0;
 
-            IEnumerable<Shortcut> toAlign = Application.TopRunnable!.SubViews.OfType<Shortcut> ().Where(s => !s.Y.Has<PosAnchorEnd>(out _)).Cast<Shortcut>();
+            IEnumerable<Shortcut> toAlign = Application.TopRunnableView!.SubViews.OfType<Shortcut> ().Where(s => !s.Y.Has<PosAnchorEnd>(out _)).Cast<Shortcut>();
             IEnumerable<Shortcut> enumerable = toAlign as Shortcut [] ?? toAlign.ToArray ();
 
             if (align)
@@ -566,6 +566,6 @@ public class Shortcuts : Scenario
     {
         e.Handled = true;
         var view = sender as View;
-        MessageBox.Query ("Hi", $"You clicked {view?.Text}", "_Ok");
+        MessageBox.Query ((sender as View)?.App, "Hi", $"You clicked {view?.Text}", "_Ok");
     }
 }

+ 8 - 9
Examples/UICatalog/Scenarios/SingleBackgroundWorker.cs

@@ -5,7 +5,7 @@ using System.ComponentModel;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Single BackgroundWorker", "A single BackgroundWorker threading opening another Toplevel")]
+[ScenarioMetadata ("Single BackgroundWorker", "A single BackgroundWorker threading opening another Runnable")]
 [ScenarioCategory ("Threading")]
 [ScenarioCategory ("Arrangement")]
 [ScenarioCategory ("Runnable")]
@@ -13,7 +13,7 @@ public class SingleBackgroundWorker : Scenario
 {
     public override void Main ()
     {
-        Application.Run<MainApp> ().Dispose ();
+        Application.Run<MainApp> ();
         Application.Shutdown ();
     }
 
@@ -174,7 +174,7 @@ public class SingleBackgroundWorker : Scenario
 
                                                   StagingUIController builderUI =
                                                       new (_startStaging, e.Result as ObservableCollection<string>);
-                                                  Toplevel? top = Application.TopRunnable;
+                                                  View? top = Application.TopRunnableView;
 
                                                   if (top is { })
                                                   {
@@ -200,7 +200,7 @@ public class SingleBackgroundWorker : Scenario
 
     public class StagingUIController : Window
     {
-        private Toplevel? _top;
+        private Runnable? _top;
 
         public StagingUIController (DateTime? start, ObservableCollection<string>? list)
         {
@@ -209,7 +209,6 @@ public class SingleBackgroundWorker : Scenario
                 Title = "_top",
                 Width = Dim.Fill (),
                 Height = Dim.Fill (),
-                Modal = true
             };
 
             _top.KeyDown += (s, e) =>
@@ -224,7 +223,7 @@ public class SingleBackgroundWorker : Scenario
 
             bool Close ()
             {
-                int n = MessageBox.Query (
+                int? n = MessageBox.Query (App,
                                           50,
                                           7,
                                           "Close Window.",
@@ -251,7 +250,7 @@ public class SingleBackgroundWorker : Scenario
                                                         {
                                                             if (Close ())
                                                             {
-                                                                Application.RequestStop ();
+                                                                App?.RequestStop ();
                                                             }
                                                         }
                                            }
@@ -270,7 +269,7 @@ public class SingleBackgroundWorker : Scenario
                                                 {
                                                     if (Close ())
                                                     {
-                                                        Application.RequestStop ();
+                                                        App?.RequestStop ();
                                                     }
                                                 }
                                                )
@@ -304,7 +303,7 @@ public class SingleBackgroundWorker : Scenario
         {
             if (_top is { })
             {
-                Application.Run (_top);
+                App?.Run (_top);
                 _top.Dispose ();
                 _top = null;
             }

+ 1 - 1
Examples/UICatalog/Scenarios/Sliders.cs

@@ -590,7 +590,7 @@ public class Sliders : Scenario
             Y = Pos.Bottom (spacingOptions),
             Width = Dim.Fill (),
             Height = Dim.Fill (),
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (eventSource)
         };
         configView.Add (eventLog);

+ 17 - 17
Examples/UICatalog/Scenarios/SpinnerStyles.cs

@@ -14,7 +14,7 @@ public class SpinnerViewStyles : Scenario
     {
         Application.Init ();
 
-        Window app = new ()
+        Window win = new ()
         {
             Title = GetQuitKeyAndName ()
         };
@@ -40,7 +40,7 @@ public class SpinnerViewStyles : Scenario
             //Title = "Preview",
             BorderStyle = LineStyle.Single
         };
-        app.Add (preview);
+        win.Add (preview);
 
         var spinner = new SpinnerView { X = Pos.Center (), Y = 0 };
         preview.Add (spinner);
@@ -54,7 +54,7 @@ public class SpinnerViewStyles : Scenario
             CheckedState = CheckState.Checked,
             Text = "Ascii Only"
         };
-        app.Add (ckbAscii);
+        win.Add (ckbAscii);
 
         var ckbNoSpecial = new CheckBox
         {
@@ -64,28 +64,28 @@ public class SpinnerViewStyles : Scenario
             CheckedState = CheckState.Checked,
             Text = "No Special"
         };
-        app.Add (ckbNoSpecial);
+        win.Add (ckbNoSpecial);
 
         var ckbReverse = new CheckBox
         {
             X = Pos.Center () - 22, Y = Pos.Bottom (preview) + 1, CheckedState = CheckState.UnChecked, Text = "Reverse"
         };
-        app.Add (ckbReverse);
+        win.Add (ckbReverse);
 
         var ckbBounce = new CheckBox
         {
             X = Pos.Right (ckbReverse) + 2, Y = Pos.Bottom (preview) + 1, CheckedState = CheckState.UnChecked, Text = "Bounce"
         };
-        app.Add (ckbBounce);
+        win.Add (ckbBounce);
 
         var delayLabel = new Label { X = Pos.Right (ckbBounce) + 2, Y = Pos.Bottom (preview) + 1, Text = "Delay:" };
-        app.Add (delayLabel);
+        win.Add (delayLabel);
 
         var delayField = new TextField
         {
             X = Pos.Right (delayLabel), Y = Pos.Bottom (preview) + 1, Width = 5, Text = DEFAULT_DELAY.ToString ()
         };
-        app.Add (delayField);
+        win.Add (delayField);
 
         delayField.TextChanged += (s, e) =>
                                   {
@@ -96,13 +96,13 @@ public class SpinnerViewStyles : Scenario
                                   };
 
         var customLabel = new Label { X = Pos.Right (delayField) + 2, Y = Pos.Bottom (preview) + 1, Text = "Custom:" };
-        app.Add (customLabel);
+        win.Add (customLabel);
 
         var customField = new TextField
         {
             X = Pos.Right (customLabel), Y = Pos.Bottom (preview) + 1, Width = 12, Text = DEFAULT_CUSTOM
         };
-        app.Add (customField);
+        win.Add (customField);
 
         string [] styleArray = styleDict.Select (e => e.Value.Key).ToArray ();
 
@@ -117,7 +117,7 @@ public class SpinnerViewStyles : Scenario
         };
         styles.SetSource (new ObservableCollection<string> (styleArray));
         styles.SelectedItem = 0; // SpinnerStyle.Custom;
-        app.Add (styles);
+        win.Add (styles);
         SetCustom ();
 
         customField.TextChanged += (s, e) =>
@@ -166,7 +166,7 @@ public class SpinnerViewStyles : Scenario
 
         ckbBounce.CheckedStateChanging += (s, e) => { spinner.SpinBounce = e.Result == CheckState.Checked; };
 
-        app.Unloaded += App_Unloaded;
+        win.IsRunningChanged += WinIsRunningChanged;
 
         void SetCustom ()
         {
@@ -199,23 +199,23 @@ public class SpinnerViewStyles : Scenario
             }
         }
 
-        void App_Unloaded (object sender, EventArgs args)
+        void WinIsRunningChanged (object sender, EventArgs<bool> args)
         {
-            if (spinner is {})
+            if (!args.Value && spinner is {})
             {
                 spinner.Dispose ();
                 spinner = null;
             }
         }
 
-        Application.Run (app);
-        app.Unloaded -= App_Unloaded;
+        Application.Run (win);
+        win.IsRunningChanged -= WinIsRunningChanged;
         if (spinner is { })
         {
             spinner.Dispose ();
             spinner = null;
         }
-        app.Dispose ();
+        win.Dispose ();
 
         Application.Shutdown ();
     }

+ 1 - 1
Examples/UICatalog/Scenarios/SyntaxHighlighting.cs

@@ -120,7 +120,7 @@ public class SyntaxHighlighting : Scenario
         Application.Init ();
 
         // Setup - Create a top-level application window and configure it.
-        Toplevel appWindow = new ();
+        Runnable appWindow = new ();
 
         var menu = new MenuBar ();
 

+ 8 - 8
Examples/UICatalog/Scenarios/TableEditor.cs

@@ -499,7 +499,7 @@ public class TableEditor : Scenario
         Application.Init ();
 
         // Setup - Create a top-level application window and configure it.
-        Toplevel appWindow = new ();
+        Runnable appWindow = new ();
 
         _tableView = new () { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill (1) };
 
@@ -1026,7 +1026,7 @@ public class TableEditor : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (60, 20, "Failed to set text", ex.Message, "Ok");
+                MessageBox.ErrorQuery ((sender as View)?.App, 60, 20, "Failed to set text", ex.Message, "Ok");
             }
 
             _tableView!.Update ();
@@ -1165,7 +1165,7 @@ public class TableEditor : Scenario
         }
         catch (Exception e)
         {
-            MessageBox.ErrorQuery ("Could not find local drives", e.Message, "Ok");
+            MessageBox.ErrorQuery (_tableView?.App, "Could not find local drives", e.Message, "Ok");
         }
 
         _tableView!.Table = source;
@@ -1199,10 +1199,10 @@ public class TableEditor : Scenario
         ok.Accepting += (s, e) =>
                         {
                             accepted = true;
-                            Application.RequestStop ();
+                            (s as View)?.App?.RequestStop ();
                         };
         var cancel = new Button { Text = "Cancel" };
-        cancel.Accepting += (s, e) => { Application.RequestStop (); };
+        cancel.Accepting += (s, e) => { (s as View)?.App?.RequestStop (); };
 
         var d = new Dialog
         {
@@ -1218,7 +1218,7 @@ public class TableEditor : Scenario
         d.Add (lbl, tf);
         tf.SetFocus ();
 
-        Application.Run (d);
+        _tableView.App?.Run (d);
         d.Dispose ();
 
         if (accepted)
@@ -1229,7 +1229,7 @@ public class TableEditor : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (60, 20, "Failed to set", ex.Message, "Ok");
+                MessageBox.ErrorQuery (_tableView.App, 60, 20, "Failed to set", ex.Message, "Ok");
             }
 
             _tableView!.Update ();
@@ -1512,7 +1512,7 @@ public class TableEditor : Scenario
                                                                              _checkedFileSystemInfos!.Contains,
                                                                              CheckOrUncheckFile
                                                                             )
-                { UseRadioButtons = radio };
+            { UseRadioButtons = radio };
         }
         else
         {

+ 3 - 6
Examples/UICatalog/Scenarios/TextEffectsScenario.cs

@@ -23,14 +23,11 @@ public class TextEffectsScenario : Scenario
             Title = "Text Effects Scenario"
         };
 
-        w.Loaded += (s, e) => { SetupGradientLineCanvas (w, w.Frame.Size); };
+        w.IsModalChanged += (s, e) => { SetupGradientLineCanvas (w, w.Frame.Size); };
 
-        w.SizeChanging += (s, e) =>
+        w.ViewportChanged += (s, e) =>
                           {
-                              if (e.Size.HasValue)
-                              {
-                                  SetupGradientLineCanvas (w, e.Size.Value);
-                              }
+                              SetupGradientLineCanvas (w, e.NewViewport.Size);
                           };
 
         w.SetScheme (new ()

+ 1 - 1
Examples/UICatalog/Scenarios/TextFormatterDemo.cs

@@ -30,7 +30,7 @@ public class TextFormatterDemo : Scenario
 
         var blockText = new Label
         {
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             X = 0,
             Y = 0,
 

+ 1 - 1
Examples/UICatalog/Scenarios/TextStyles.cs

@@ -5,7 +5,7 @@ namespace UICatalog.Scenarios;
 [ScenarioMetadata ("Text Styles", "Shows Attribute.TextStyles including bold, italic, etc...")]
 [ScenarioCategory ("Text and Formatting")]
 [ScenarioCategory ("Colors")]
-public sealed class TestStyles : Scenario
+public sealed class TextStyles : Scenario
 {
     private CheckBox? _drawDirectly;
 

+ 1 - 1
Examples/UICatalog/Scenarios/Themes.cs

@@ -129,7 +129,7 @@ public sealed class Themes : Scenario
                                           {
                                               if (_view is { })
                                               {
-                                                  Application.TopRunnable!.SchemeName = args.NewValue;
+                                                  Application.TopRunnableView!.SchemeName = args.NewValue;
 
                                                   if (_view.HasScheme)
                                                   {

+ 4 - 4
Examples/UICatalog/Scenarios/Threading.cs

@@ -75,7 +75,7 @@ public class Threading : Scenario
             Y = Pos.Y (_btnActionCancel) + 6,
             Width = 10,
             Height = 10,
-            SchemeName = "TopLevel"
+            SchemeName = "Runnable"
         };
 
         win.Add (new Label { X = Pos.Right (_itemsList) + 10, Y = Pos.Y (_btnActionCancel) + 4, Text = "Task Logs:" });
@@ -86,7 +86,7 @@ public class Threading : Scenario
             Y = Pos.Y (_itemsList),
             Width = 50,
             Height = Dim.Fill (),
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (_log)
         };
 
@@ -162,10 +162,10 @@ public class Threading : Scenario
         void Win_Loaded (object sender, EventArgs args)
         {
             _btnActionCancel.SetFocus ();
-            win.Loaded -= Win_Loaded;
+            win.IsModalChanged -= Win_Loaded;
         }
 
-        win.Loaded += Win_Loaded;
+        win.IsModalChanged += Win_Loaded;
 
         Application.Run (win);
         win.Dispose ();

+ 2 - 2
Examples/UICatalog/Scenarios/Transparent.cs

@@ -46,7 +46,7 @@ public sealed class Transparent : Scenario
         };
         appButton.Accepting += (sender, args) =>
                                {
-                                   MessageBox.Query ("AppButton", "Transparency is cool!", "_Ok");
+                                   MessageBox.Query ((sender as View)?.App, "AppButton", "Transparency is cool!", "_Ok");
                                    args.Handled = true;
                                };
         appWindow.Add (appButton);
@@ -106,7 +106,7 @@ public sealed class Transparent : Scenario
             };
             button.Accepting += (sender, args) =>
                                 {
-                                    MessageBox.Query ("Clicked!", "Button in Transparent View", "_Ok");
+                                    MessageBox.Query (App, "Clicked!", "Button in Transparent View", "_Ok");
                                     args.Handled = true;
                                 };
             //button.Visible = false;

+ 18 - 15
Examples/UICatalog/Scenarios/TreeUseCases.cs

@@ -71,10 +71,13 @@ public class TreeUseCases : Scenario
 
         appWindow.Add (menu, statusBar);
 
-        appWindow.Ready += (sender, args) =>
+        appWindow.IsModalChanged += (sender, args) =>
         {
-            // Start with the most basic use case
-            LoadSimpleNodes ();
+            if (args.Value)
+            {
+                // Start with the most basic use case
+                LoadSimpleNodes ();
+            }
         };
 
         Application.Run (appWindow);
@@ -92,9 +95,9 @@ public class TreeUseCases : Scenario
 
         if (_currentTree is { })
         {
-            if (Application.TopRunnable is { })
+            if (Application.TopRunnableView is { })
             {
-                Application.TopRunnable.Remove (_currentTree);
+                Application.TopRunnableView.Remove (_currentTree);
             }
 
             _currentTree.Dispose ();
@@ -116,9 +119,9 @@ public class TreeUseCases : Scenario
             tree.TreeBuilder = new GameObjectTreeBuilder ();
         }
 
-        if (Application.TopRunnable is { })
+        if (Application.TopRunnableView is { })
         {
-            Application.TopRunnable.Add (tree);
+            Application.TopRunnableView.Add (tree);
         }
 
         tree.AddObject (army1);
@@ -141,9 +144,9 @@ public class TreeUseCases : Scenario
 
         if (_currentTree is { })
         {
-            if (Application.TopRunnable is { })
+            if (Application.TopRunnableView is { })
             {
-                Application.TopRunnable.Remove (_currentTree);
+                Application.TopRunnableView.Remove (_currentTree);
             }
 
             _currentTree.Dispose ();
@@ -151,9 +154,9 @@ public class TreeUseCases : Scenario
 
         TreeView tree = new () { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill (1) };
 
-        if (Application.TopRunnable is { })
+        if (Application.TopRunnableView is { })
         {
-            Application.TopRunnable.Add (tree);
+            Application.TopRunnableView.Add (tree);
         }
 
         tree.AddObject (myHouse);
@@ -165,9 +168,9 @@ public class TreeUseCases : Scenario
     {
         if (_currentTree is { })
         {
-            if (Application.TopRunnable is { })
+            if (Application.TopRunnableView is { })
             {
-                Application.TopRunnable.Remove (_currentTree);
+                Application.TopRunnableView.Remove (_currentTree);
             }
 
             _currentTree.Dispose ();
@@ -175,9 +178,9 @@ public class TreeUseCases : Scenario
 
         TreeView tree = new () { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill (1) };
 
-        if (Application.TopRunnable is { })
+        if (Application.TopRunnableView is { })
         {
-            Application.TopRunnable.Add (tree);
+            Application.TopRunnableView.Add (tree);
         }
 
         TreeNode root1 = new ("Root1");

+ 3 - 3
Examples/UICatalog/Scenarios/ViewportSettings.cs

@@ -102,7 +102,7 @@ public class ViewportSettings : Scenario
             Title = GetQuitKeyAndName (),
 
             // Use a different colorscheme so ViewSettings.ClearContentOnly is obvious
-            SchemeName = "Toplevel",
+            SchemeName = "Runnable",
             BorderStyle = LineStyle.None
         };
 
@@ -169,13 +169,13 @@ public class ViewportSettings : Scenario
         };
 
         charMap.Accepting += (s, e) =>
-                              MessageBox.Query (20, 7, "Hi", $"Am I a {view.GetType ().Name}?", "Yes", "No");
+                              MessageBox.Query ((s as View)?.App, 20, 7, "Hi", $"Am I a {view.GetType ().Name}?", "Yes", "No");
 
         var buttonAnchored = new Button
         {
             X = Pos.AnchorEnd () - 10, Y = Pos.AnchorEnd () - 4, Text = "Bottom Rig_ht"
         };
-        buttonAnchored.Accepting += (sender, args) => MessageBox.Query ("Hi", $"You pressed {((Button)sender)?.Text}", "_Ok");
+        buttonAnchored.Accepting += (sender, args) => MessageBox.Query ((sender as View)?.App, "Hi", $"You pressed {((Button)sender)?.Text}", "_Ok");
 
         view.Margin!.Data = "Margin";
         view.Margin!.Thickness = new (0);

+ 3 - 3
Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs

@@ -16,9 +16,9 @@ public class WindowsAndFrameViews : Scenario
             Title = GetQuitKeyAndName ()
         };
 
-        static int About ()
+        static int? About ()
         {
-            return MessageBox.Query (
+            return MessageBox.Query (ApplicationImpl.Instance,
                                      "About UI Catalog",
                                      "UI Catalog is a comprehensive sample library for Terminal.Gui",
                                      "Ok"
@@ -99,7 +99,7 @@ public class WindowsAndFrameViews : Scenario
             };
 
             pressMeButton.Accepting += (s, e) =>
-                                        MessageBox.ErrorQuery (loopWin.Title, "Neat?", "Yes", "No");
+                                        MessageBox.ErrorQuery ((s as View)?.App, loopWin.Title, "Neat?", "Yes", "No");
             loopWin.Add (pressMeButton);
 
             var subWin = new Window

+ 11 - 8
Examples/UICatalog/Scenarios/WizardAsView.cs

@@ -21,6 +21,7 @@ public class WizardAsView : Scenario
                                        {
                                            Title = "_Restart Configuration...",
                                            Action = () => MessageBox.Query (
+                                                                            ApplicationImpl.Instance,
                                                                             "Wizard",
                                                                             "Are you sure you want to reset the Wizard and start over?",
                                                                             "Ok",
@@ -31,6 +32,7 @@ public class WizardAsView : Scenario
                                        {
                                            Title = "Re_boot Server...",
                                            Action = () => MessageBox.Query (
+                                                                            ApplicationImpl.Instance,
                                                                             "Wizard",
                                                                             "Are you sure you want to reboot the server start over?",
                                                                             "Ok",
@@ -41,6 +43,7 @@ public class WizardAsView : Scenario
                                        {
                                            Title = "_Shutdown Server...",
                                            Action = () => MessageBox.Query (
+                                                                            ApplicationImpl.Instance,
                                                                             "Wizard",
                                                                             "Are you sure you want to cancel setup and shutdown?",
                                                                             "Ok",
@@ -63,7 +66,7 @@ public class WizardAsView : Scenario
 
         // Set Modal to false to cause the Wizard class to render without a frame and
         // behave like an non-modal View (vs. a modal/pop-up Window).
-        wizard.Modal = false;
+       // wizard.Modal = false;
 
         wizard.MovingBack += (s, args) =>
                              {
@@ -80,13 +83,13 @@ public class WizardAsView : Scenario
         wizard.Finished += (s, args) =>
                            {
                                //args.Cancel = true;
-                               MessageBox.Query ("Setup Wizard", "Finished", "Ok");
+                               MessageBox.Query ((s as View)?.App, "Setup Wizard", "Finished", "Ok");
                                Application.RequestStop ();
                            };
 
         wizard.Cancelled += (s, args) =>
                             {
-                                int btn = MessageBox.Query ("Setup Wizard", "Are you sure you want to cancel?", "Yes", "No");
+                                int? btn = MessageBox.Query ((s as View)?.App, "Setup Wizard", "Are you sure you want to cancel?", "Yes", "No");
                                 args.Cancel = btn == 1;
 
                                 if (btn == 0)
@@ -123,7 +126,7 @@ public class WizardAsView : Scenario
                             {
                                 secondStep.Title = "2nd Step";
 
-                                MessageBox.Query (
+                                MessageBox.Query ((s as View)?.App,
                                                   "Wizard Scenario",
                                                   "This Wizard Step's title was changed to '2nd Step'",
                                                   "Ok"
@@ -145,11 +148,11 @@ public class WizardAsView : Scenario
         lastStep.HelpText =
             "The wizard is complete!\n\nPress the Finish button to continue.\n\nPressing Esc will cancel.";
 
-        Window topLevel = new ();
-        topLevel.Add (menu, wizard);
+        Window window = new ();
+        window.Add (menu, wizard);
 
-        Application.Run (topLevel);
-        topLevel.Dispose ();
+        Application.Run (window);
+        window.Dispose ();
         Application.Shutdown ();
     }
 }

+ 271 - 268
Examples/UICatalog/Scenarios/Wizards.cs

@@ -1,13 +1,9 @@
-using System;
-using System.Linq;
-
-namespace UICatalog.Scenarios;
+namespace UICatalog.Scenarios;
 
 [ScenarioMetadata ("Wizards", "Demonstrates the Wizard class")]
 [ScenarioCategory ("Dialogs")]
 [ScenarioCategory ("Wizards")]
 [ScenarioCategory ("Runnable")]
-
 public class Wizards : Scenario
 {
     public override void Main ()
@@ -85,10 +81,10 @@ public class Wizards : Scenario
         void Win_Loaded (object sender, EventArgs args)
         {
             frame.Height = widthEdit.Frame.Height + heightEdit.Frame.Height + titleEdit.Frame.Height + 2;
-            win.Loaded -= Win_Loaded;
+            win.IsModalChanged -= Win_Loaded;
         }
 
-        win.Loaded += Win_Loaded;
+        win.IsModalChanged += Win_Loaded;
 
         label = new ()
         {
@@ -108,267 +104,277 @@ public class Wizards : Scenario
         };
 
         showWizardButton.Accepting += (s, e) =>
-                                   {
-                                       try
-                                       {
-                                           var width = 0;
-                                           int.TryParse (widthEdit.Text, out width);
-                                           var height = 0;
-                                           int.TryParse (heightEdit.Text, out height);
-
-                                           if (width < 1 || height < 1)
-                                           {
-                                               MessageBox.ErrorQuery (
-                                                                      "Nope",
-                                                                      "Height and width must be greater than 0 (much bigger)",
-                                                                      "Ok"
-                                                                     );
-
-                                               return;
-                                           }
-
-                                           actionLabel.Text = string.Empty;
-
-                                           var wizard = new Wizard { Title = titleEdit.Text, Width = width, Height = height };
-
-                                           wizard.MovingBack += (s, args) =>
-                                                                {
-                                                                    //args.Cancel = true;
-                                                                    actionLabel.Text = "Moving Back";
-                                                                };
-
-                                           wizard.MovingNext += (s, args) =>
-                                                                {
-                                                                    //args.Cancel = true;
-                                                                    actionLabel.Text = "Moving Next";
-                                                                };
-
-                                           wizard.Finished += (s, args) =>
-                                                              {
-                                                                  //args.Cancel = true;
-                                                                  actionLabel.Text = "Finished";
-                                                              };
-
-                                           wizard.Cancelled += (s, args) =>
-                                                               {
-                                                                   //args.Cancel = true;
-                                                                   actionLabel.Text = "Cancelled";
-                                                               };
-
-                                           // Add 1st step
-                                           var firstStep = new WizardStep { Title = "End User License Agreement" };
-                                           firstStep.NextButtonText = "Accept!";
-
-                                           firstStep.HelpText =
-                                               "This is the End User License Agreement.\n\n\n\n\n\nThis is a test of the emergency broadcast system. This is a test of the emergency broadcast system.\nThis is a test of the emergency broadcast system.\n\n\nThis is a test of the emergency broadcast system.\n\nThis is a test of the emergency broadcast system.\n\n\n\nThe end of the EULA.";
-
-                                           OptionSelector optionSelector = new ()
-                                           {
-                                               Labels = ["_One", "_Two", "_3"]
-                                           };
-                                           firstStep.Add (optionSelector);
-
-                                           wizard.AddStep (firstStep);
-
-                                           // Add 2nd step
-                                           var secondStep = new WizardStep { Title = "Second Step" };
-                                           wizard.AddStep (secondStep);
-
-                                           secondStep.HelpText =
-                                               "This is the help text for the Second Step.\n\nPress the button to change the Title.\n\nIf First Name is empty the step will prevent moving to the next step.";
-
-                                           var buttonLbl = new Label { Text = "Second Step Button: ", X = 1, Y = 1 };
-
-                                           var button = new Button
-                                           {
-                                               Text = "Press Me to Rename Step", X = Pos.Right (buttonLbl), Y = Pos.Top (buttonLbl)
-                                           };
-
-                                           OptionSelector optionSelecor2 = new ()
-                                           {
-                                               Labels = ["_A", "_B", "_C"],
-                                               Orientation = Orientation.Horizontal
-                                           };
-                                           secondStep.Add (optionSelecor2);
-
-                                           button.Accepting += (s, e) =>
-                                                            {
-                                                                secondStep.Title = "2nd Step";
-
-                                                                MessageBox.Query (
-                                                                                  "Wizard Scenario",
-                                                                                  "This Wizard Step's title was changed to '2nd Step'"
-                                                                                 );
-                                                            };
-                                           secondStep.Add (buttonLbl, button);
-                                           var lbl = new Label { Text = "First Name: ", X = 1, Y = Pos.Bottom (buttonLbl) };
-
-                                           var firstNameField =
-                                               new TextField { Text = "Number", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
-                                           secondStep.Add (lbl, firstNameField);
-                                           lbl = new () { Text = "Last Name:  ", X = 1, Y = Pos.Bottom (lbl) };
-                                           var lastNameField = new TextField { Text = "Six", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
-                                           secondStep.Add (lbl, lastNameField);
-
-                                           var thirdStepEnabledCeckBox = new CheckBox
-                                           {
-                                               Text = "Enable Step _3",
-                                               CheckedState = CheckState.UnChecked,
-                                               X = Pos.Left (lastNameField),
-                                               Y = Pos.Bottom (lastNameField)
-                                           };
-                                           secondStep.Add (thirdStepEnabledCeckBox);
-
-                                           // Add a frame 
-                                           var frame = new FrameView
-                                           {
-                                               X = 0,
-                                               Y = Pos.Bottom (thirdStepEnabledCeckBox) + 2,
-                                               Width = Dim.Fill (),
-                                               Height = 4,
-                                               Title = "A Broken Frame (by Depeche Mode)",
-                                               TabStop = TabBehavior.NoStop
-                                           };
-                                           frame.Add (new TextField { Text = "This is a TextField inside of the frame." });
-                                           secondStep.Add (frame);
-
-                                           wizard.StepChanging += (s, args) =>
+                                      {
+                                          try
+                                          {
+                                              var width = 0;
+                                              int.TryParse (widthEdit.Text, out width);
+                                              var height = 0;
+                                              int.TryParse (heightEdit.Text, out height);
+
+                                              if (width < 1 || height < 1)
+                                              {
+                                                  MessageBox.ErrorQuery (
+                                                                         (s as View)?.App,
+                                                                         "Nope",
+                                                                         "Height and width must be greater than 0 (much bigger)",
+                                                                         "Ok"
+                                                                        );
+
+                                                  return;
+                                              }
+
+                                              actionLabel.Text = string.Empty;
+
+                                              var wizard = new Wizard { Title = titleEdit.Text, Width = width, Height = height };
+
+                                              wizard.MovingBack += (s, args) =>
+                                                                   {
+                                                                       //args.Cancel = true;
+                                                                       actionLabel.Text = "Moving Back";
+                                                                   };
+
+                                              wizard.MovingNext += (s, args) =>
+                                                                   {
+                                                                       //args.Cancel = true;
+                                                                       actionLabel.Text = "Moving Next";
+                                                                   };
+
+                                              wizard.Finished += (s, args) =>
+                                                                 {
+                                                                     //args.Cancel = true;
+                                                                     actionLabel.Text = "Finished";
+                                                                 };
+
+                                              wizard.Cancelled += (s, args) =>
                                                                   {
-                                                                      if (args.OldStep == secondStep && string.IsNullOrEmpty (firstNameField.Text))
-                                                                      {
-                                                                          args.Cancel = true;
-
-                                                                          int btn = MessageBox.ErrorQuery (
-                                                                               "Second Step",
-                                                                               "You must enter a First Name to continue",
-                                                                               "Ok"
-                                                                              );
-                                                                      }
+                                                                      //args.Cancel = true;
+                                                                      actionLabel.Text = "Cancelled";
                                                                   };
 
-                                           // Add 3rd (optional) step
-                                           var thirdStep = new WizardStep { Title = "Third Step (Optional)" };
-                                           wizard.AddStep (thirdStep);
-
-                                           thirdStep.HelpText =
-                                               "This is step is optional (WizardStep.Enabled = false). Enable it with the checkbox in Step 2.";
-                                           var step3Label = new Label { Text = "This step is optional.", X = 0, Y = 0 };
-                                           thirdStep.Add (step3Label);
-                                           var progLbl = new Label { Text = "Third Step ProgressBar: ", X = 1, Y = 10 };
-
-                                           var progressBar = new ProgressBar
-                                           {
-                                               X = Pos.Right (progLbl), Y = Pos.Top (progLbl), Width = 40, Fraction = 0.42F
-                                           };
-                                           thirdStep.Add (progLbl, progressBar);
-                                           thirdStep.Enabled = thirdStepEnabledCeckBox.CheckedState == CheckState.Checked;
-                                           thirdStepEnabledCeckBox.CheckedStateChanged += (s, e) => { thirdStep.Enabled = thirdStepEnabledCeckBox.CheckedState == CheckState.Checked; };
-
-                                           // Add 4th step
-                                           var fourthStep = new WizardStep { Title = "Step Four" };
-                                           wizard.AddStep (fourthStep);
-
-                                           var someText = new TextView
-                                           {
-                                               Text =
-                                                   "This step (Step Four) shows how to show/hide the Help pane. The step contains this TextView (but it's hard to tell it's a TextView because of Issue #1800).",
-                                               X = 0,
-                                               Y = 0,
-                                               Width = Dim.Fill (),
-                                               WordWrap = true,
-                                               AllowsTab = false,
-                                               SchemeName = "Base"
-                                           };
-
-                                           someText.Height = Dim.Fill (
-                                                                       Dim.Func (
-                                                                                 v => someText.SuperView is { IsInitialized: true }
-                                                                                          ? someText.SuperView.SubViews
-                                                                                                    .First (view => view.Y.Has<PosAnchorEnd> (out _))
-                                                                                                    .Frame.Height
-                                                                                          : 1));
-                                           var help = "This is helpful.";
-                                           fourthStep.Add (someText);
-
-                                           var hideHelpBtn = new Button
-                                           {
-                                               Text = "Press me to show/hide help",
-                                               X = Pos.Center (),
-                                               Y = Pos.AnchorEnd ()
-                                           };
-
-                                           hideHelpBtn.Accepting += (s, e) =>
-                                                                 {
-                                                                     if (fourthStep.HelpText.Length > 0)
-                                                                     {
-                                                                         fourthStep.HelpText = string.Empty;
-                                                                     }
-                                                                     else
+                                              // Add 1st step
+                                              var firstStep = new WizardStep { Title = "End User License Agreement" };
+                                              firstStep.NextButtonText = "Accept!";
+
+                                              firstStep.HelpText =
+                                                  "This is the End User License Agreement.\n\n\n\n\n\nThis is a test of the emergency broadcast system. This is a test of the emergency broadcast system.\nThis is a test of the emergency broadcast system.\n\n\nThis is a test of the emergency broadcast system.\n\nThis is a test of the emergency broadcast system.\n\n\n\nThe end of the EULA.";
+
+                                              OptionSelector optionSelector = new ()
+                                              {
+                                                  Labels = ["_One", "_Two", "_3"]
+                                              };
+                                              firstStep.Add (optionSelector);
+
+                                              wizard.AddStep (firstStep);
+
+                                              // Add 2nd step
+                                              var secondStep = new WizardStep { Title = "Second Step" };
+                                              wizard.AddStep (secondStep);
+
+                                              secondStep.HelpText =
+                                                  "This is the help text for the Second Step.\n\nPress the button to change the Title.\n\nIf First Name is empty the step will prevent moving to the next step.";
+
+                                              var buttonLbl = new Label { Text = "Second Step Button: ", X = 1, Y = 1 };
+
+                                              var button = new Button
+                                              {
+                                                  Text = "Press Me to Rename Step", X = Pos.Right (buttonLbl), Y = Pos.Top (buttonLbl)
+                                              };
+
+                                              OptionSelector optionSelecor2 = new ()
+                                              {
+                                                  Labels = ["_A", "_B", "_C"],
+                                                  Orientation = Orientation.Horizontal
+                                              };
+                                              secondStep.Add (optionSelecor2);
+
+                                              button.Accepting += (s, e) =>
+                                                                  {
+                                                                      secondStep.Title = "2nd Step";
+
+                                                                      MessageBox.Query (
+                                                                                        (s as View)?.App,
+                                                                                        "Wizard Scenario",
+                                                                                        "This Wizard Step's title was changed to '2nd Step'"
+                                                                                       );
+                                                                  };
+                                              secondStep.Add (buttonLbl, button);
+                                              var lbl = new Label { Text = "First Name: ", X = 1, Y = Pos.Bottom (buttonLbl) };
+
+                                              var firstNameField =
+                                                  new TextField { Text = "Number", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
+                                              secondStep.Add (lbl, firstNameField);
+                                              lbl = new () { Text = "Last Name:  ", X = 1, Y = Pos.Bottom (lbl) };
+                                              var lastNameField = new TextField { Text = "Six", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
+                                              secondStep.Add (lbl, lastNameField);
+
+                                              var thirdStepEnabledCeckBox = new CheckBox
+                                              {
+                                                  Text = "Enable Step _3",
+                                                  CheckedState = CheckState.UnChecked,
+                                                  X = Pos.Left (lastNameField),
+                                                  Y = Pos.Bottom (lastNameField)
+                                              };
+                                              secondStep.Add (thirdStepEnabledCeckBox);
+
+                                              // Add a frame 
+                                              var frame = new FrameView
+                                              {
+                                                  X = 0,
+                                                  Y = Pos.Bottom (thirdStepEnabledCeckBox) + 2,
+                                                  Width = Dim.Fill (),
+                                                  Height = 4,
+                                                  Title = "A Broken Frame (by Depeche Mode)",
+                                                  TabStop = TabBehavior.NoStop
+                                              };
+                                              frame.Add (new TextField { Text = "This is a TextField inside of the frame." });
+                                              secondStep.Add (frame);
+
+                                              wizard.StepChanging += (s, args) =>
                                                                      {
-                                                                         fourthStep.HelpText = help;
-                                                                     }
-                                                                 };
-                                           fourthStep.Add (hideHelpBtn);
-                                           fourthStep.NextButtonText = "_Go To Last Step";
-                                           //var scrollBar = new ScrollBarView (someText, true);
-
-                                           //scrollBar.ChangedPosition += (s, e) =>
-                                           //                             {
-                                           //                                 someText.TopRow = scrollBar.Position;
-
-                                           //                                 if (someText.TopRow != scrollBar.Position)
-                                           //                                 {
-                                           //                                     scrollBar.Position = someText.TopRow;
-                                           //                                 }
-
-                                           //                                 someText.SetNeedsDraw ();
-                                           //                             };
-
-                                           //someText.DrawingContent += (s, e) =>
-                                           //                        {
-                                           //                            scrollBar.Size = someText.Lines;
-                                           //                            scrollBar.Position = someText.TopRow;
-
-                                           //                            if (scrollBar.OtherScrollBarView != null)
-                                           //                            {
-                                           //                                scrollBar.OtherScrollBarView.Size = someText.Maxlength;
-                                           //                                scrollBar.OtherScrollBarView.Position = someText.LeftColumn;
-                                           //                            }
-                                           //                        };
-                                           //fourthStep.Add (scrollBar);
-
-                                           // Add last step
-                                           var lastStep = new WizardStep { Title = "The last step" };
-                                           wizard.AddStep (lastStep);
-
-                                           lastStep.HelpText =
-                                               "The wizard is complete!\n\nPress the Finish button to continue.\n\nPressing ESC will cancel the wizard.";
-
-                                           var finalFinalStepEnabledCeckBox =
-                                               new CheckBox { Text = "Enable _Final Final Step", CheckedState = CheckState.UnChecked, X = 0, Y = 1 };
-                                           lastStep.Add (finalFinalStepEnabledCeckBox);
-
-                                           // Add an optional FINAL last step
-                                           var finalFinalStep = new WizardStep { Title = "The VERY last step" };
-                                           wizard.AddStep (finalFinalStep);
-
-                                           finalFinalStep.HelpText =
-                                               "This step only shows if it was enabled on the other last step.";
-                                           finalFinalStep.Enabled = thirdStepEnabledCeckBox.CheckedState == CheckState.Checked;
-
-                                           finalFinalStepEnabledCeckBox.CheckedStateChanged += (s, e) =>
-                                                                                   {
-                                                                                       finalFinalStep.Enabled = finalFinalStepEnabledCeckBox.CheckedState == CheckState.Checked;
-                                                                                   };
-
-                                           Application.Run (wizard);
-                                           wizard.Dispose ();
-                                       }
-                                       catch (FormatException)
-                                       {
-                                           actionLabel.Text = "Invalid Options";
-                                       }
-                                   };
+                                                                         if (args.OldStep == secondStep && string.IsNullOrEmpty (firstNameField.Text))
+                                                                         {
+                                                                             args.Cancel = true;
+
+                                                                             int? btn = MessageBox.ErrorQuery (
+                                                                                  (s as View)?.App,
+                                                                                  "Second Step",
+                                                                                  "You must enter a First Name to continue",
+                                                                                  "Ok"
+                                                                                 );
+                                                                         }
+                                                                     };
+
+                                              // Add 3rd (optional) step
+                                              var thirdStep = new WizardStep { Title = "Third Step (Optional)" };
+                                              wizard.AddStep (thirdStep);
+
+                                              thirdStep.HelpText =
+                                                  "This is step is optional (WizardStep.Enabled = false). Enable it with the checkbox in Step 2.";
+                                              var step3Label = new Label { Text = "This step is optional.", X = 0, Y = 0 };
+                                              thirdStep.Add (step3Label);
+                                              var progLbl = new Label { Text = "Third Step ProgressBar: ", X = 1, Y = 10 };
+
+                                              var progressBar = new ProgressBar
+                                              {
+                                                  X = Pos.Right (progLbl), Y = Pos.Top (progLbl), Width = 40, Fraction = 0.42F
+                                              };
+                                              thirdStep.Add (progLbl, progressBar);
+                                              thirdStep.Enabled = thirdStepEnabledCeckBox.CheckedState == CheckState.Checked;
+
+                                              thirdStepEnabledCeckBox.CheckedStateChanged += (s, e) =>
+                                                                                             {
+                                                                                                 thirdStep.Enabled =
+                                                                                                     thirdStepEnabledCeckBox.CheckedState == CheckState.Checked;
+                                                                                             };
+
+                                              // Add 4th step
+                                              var fourthStep = new WizardStep { Title = "Step Four" };
+                                              wizard.AddStep (fourthStep);
+
+                                              var someText = new TextView
+                                              {
+                                                  Text =
+                                                      "This step (Step Four) shows how to show/hide the Help pane. The step contains this TextView (but it's hard to tell it's a TextView because of Issue #1800).",
+                                                  X = 0,
+                                                  Y = 0,
+                                                  Width = Dim.Fill (),
+                                                  WordWrap = true,
+                                                  AllowsTab = false,
+                                                  SchemeName = "Base"
+                                              };
+
+                                              someText.Height = Dim.Fill (
+                                                                          Dim.Func (v => someText.SuperView is { IsInitialized: true }
+                                                                                             ? someText.SuperView.SubViews
+                                                                                                       .First (view => view.Y.Has<PosAnchorEnd> (out _))
+                                                                                                       .Frame.Height
+                                                                                             : 1));
+                                              var help = "This is helpful.";
+                                              fourthStep.Add (someText);
+
+                                              var hideHelpBtn = new Button
+                                              {
+                                                  Text = "Press me to show/hide help",
+                                                  X = Pos.Center (),
+                                                  Y = Pos.AnchorEnd ()
+                                              };
+
+                                              hideHelpBtn.Accepting += (s, e) =>
+                                                                       {
+                                                                           if (fourthStep.HelpText.Length > 0)
+                                                                           {
+                                                                               fourthStep.HelpText = string.Empty;
+                                                                           }
+                                                                           else
+                                                                           {
+                                                                               fourthStep.HelpText = help;
+                                                                           }
+                                                                       };
+                                              fourthStep.Add (hideHelpBtn);
+                                              fourthStep.NextButtonText = "_Go To Last Step";
+
+                                              //var scrollBar = new ScrollBarView (someText, true);
+
+                                              //scrollBar.ChangedPosition += (s, e) =>
+                                              //                             {
+                                              //                                 someText.TopRow = scrollBar.Position;
+
+                                              //                                 if (someText.TopRow != scrollBar.Position)
+                                              //                                 {
+                                              //                                     scrollBar.Position = someText.TopRow;
+                                              //                                 }
+
+                                              //                                 someText.SetNeedsDraw ();
+                                              //                             };
+
+                                              //someText.DrawingContent += (s, e) =>
+                                              //                        {
+                                              //                            scrollBar.Size = someText.Lines;
+                                              //                            scrollBar.Position = someText.TopRow;
+
+                                              //                            if (scrollBar.OtherScrollBarView != null)
+                                              //                            {
+                                              //                                scrollBar.OtherScrollBarView.Size = someText.Maxlength;
+                                              //                                scrollBar.OtherScrollBarView.Position = someText.LeftColumn;
+                                              //                            }
+                                              //                        };
+                                              //fourthStep.Add (scrollBar);
+
+                                              // Add last step
+                                              var lastStep = new WizardStep { Title = "The last step" };
+                                              wizard.AddStep (lastStep);
+
+                                              lastStep.HelpText =
+                                                  "The wizard is complete!\n\nPress the Finish button to continue.\n\nPressing ESC will cancel the wizard.";
+
+                                              var finalFinalStepEnabledCeckBox =
+                                                  new CheckBox { Text = "Enable _Final Final Step", CheckedState = CheckState.UnChecked, X = 0, Y = 1 };
+                                              lastStep.Add (finalFinalStepEnabledCeckBox);
+
+                                              // Add an optional FINAL last step
+                                              var finalFinalStep = new WizardStep { Title = "The VERY last step" };
+                                              wizard.AddStep (finalFinalStep);
+
+                                              finalFinalStep.HelpText =
+                                                  "This step only shows if it was enabled on the other last step.";
+                                              finalFinalStep.Enabled = thirdStepEnabledCeckBox.CheckedState == CheckState.Checked;
+
+                                              finalFinalStepEnabledCeckBox.CheckedStateChanged += (s, e) =>
+                                                                                                  {
+                                                                                                      finalFinalStep.Enabled =
+                                                                                                          finalFinalStepEnabledCeckBox.CheckedState
+                                                                                                          == CheckState.Checked;
+                                                                                                  };
+
+                                              Application.Run (wizard);
+                                              wizard.Dispose ();
+                                          }
+                                          catch (FormatException)
+                                          {
+                                              actionLabel.Text = "Invalid Options";
+                                          }
+                                      };
         win.Add (showWizardButton);
 
         Application.Run (win);
@@ -376,8 +382,5 @@ public class Wizards : Scenario
         Application.Shutdown ();
     }
 
-    private void Wizard_StepChanged (object sender, StepChangeEventArgs e)
-    {
-        throw new NotImplementedException ();
-    }
+    private void Wizard_StepChanged (object sender, StepChangeEventArgs e) { throw new NotImplementedException (); }
 }

+ 13 - 25
Examples/UICatalog/UICatalog.cs

@@ -73,8 +73,8 @@ public class UICatalog
             CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
         }
 
-        UICatalogTop.CachedScenarios = Scenario.GetScenarios ();
-        UICatalogTop.CachedCategories = Scenario.GetAllCategories ();
+        UICatalogRunnable.CachedScenarios = Scenario.GetScenarios ();
+        UICatalogRunnable.CachedCategories = Scenario.GetAllCategories ();
 
         // Process command line args
 
@@ -136,7 +136,7 @@ public class UICatalog
                                                                   "The name of the Scenario to run. If not provided, the UI Catalog UI will be shown.",
                                                                   getDefaultValue: () => "none"
                                                                  ).FromAmong (
-                                                                              UICatalogTop.CachedScenarios.Select (s => s.GetName ())
+                                                                              UICatalogRunnable.CachedScenarios.Select (s => s.GetName ())
                                                                                           .Append ("none")
                                                                                           .ToArray ()
                                                                              );
@@ -249,7 +249,7 @@ public class UICatalog
     ///     killed and the Scenario is run as though it were Application.TopRunnable. When the Scenario exits, this function exits.
     /// </summary>
     /// <returns></returns>
-    private static Scenario RunUICatalogTopLevel ()
+    private static Scenario RunUICatalogRunnable ()
     {
         // Run UI Catalog UI. When it exits, if _selectedScenario is != null then
         // a Scenario was selected. Otherwise, the user wants to quit UI Catalog.
@@ -261,12 +261,11 @@ public class UICatalog
 
         _uiCatalogDriver = Application.Driver!.GetName ();
 
-        Toplevel top = Application.Run<UICatalogTop> ();
-        top.Dispose ();
+        Application.Run<UICatalogRunnable> ();
         Application.Shutdown ();
         VerifyObjectsWereDisposed ();
 
-        return UICatalogTop.CachedSelectedScenario!;
+        return UICatalogRunnable.CachedSelectedScenario!;
     }
 
     [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
@@ -347,7 +346,7 @@ public class UICatalog
 
     private static void ConfigFileChanged (object sender, FileSystemEventArgs e)
     {
-        if (Application.TopRunnable == null)
+        if (Application.TopRunnableView == null)
         {
             return;
         }
@@ -372,15 +371,15 @@ public class UICatalog
                 ConfigurationManager.Enable (ConfigLocations.All);
             }
 
-            int item = UICatalogTop.CachedScenarios!.IndexOf (
-                                                              UICatalogTop.CachedScenarios!.FirstOrDefault (
+            int item = UICatalogRunnable.CachedScenarios!.IndexOf (
+                                                              UICatalogRunnable.CachedScenarios!.FirstOrDefault (
                                                                    s =>
                                                                        s.GetName ()
                                                                         .Equals (options.Scenario, StringComparison.OrdinalIgnoreCase)
                                                                   )!);
-            UICatalogTop.CachedSelectedScenario = (Scenario)Activator.CreateInstance (UICatalogTop.CachedScenarios [item].GetType ())!;
+            UICatalogRunnable.CachedSelectedScenario = (Scenario)Activator.CreateInstance (UICatalogRunnable.CachedScenarios [item].GetType ())!;
 
-            BenchmarkResults? results = RunScenario (UICatalogTop.CachedSelectedScenario, options.Benchmark);
+            BenchmarkResults? results = RunScenario (UICatalogRunnable.CachedSelectedScenario, options.Benchmark);
 
             if (results is { })
             {
@@ -416,7 +415,7 @@ public class UICatalog
             StartConfigWatcher ();
         }
 
-        while (RunUICatalogTopLevel () is { } scenario)
+        while (RunUICatalogRunnable () is { } scenario)
         {
 #if DEBUG_IDISPOSABLE
             VerifyObjectsWereDisposed ();
@@ -495,7 +494,7 @@ public class UICatalog
 
         var maxScenarios = 5;
 
-        foreach (Scenario s in UICatalogTop.CachedScenarios!)
+        foreach (Scenario s in UICatalogRunnable.CachedScenarios!)
         {
             resultsList.Add (RunScenario (s, true)!);
             maxScenarios--;
@@ -654,7 +653,6 @@ public class UICatalog
         if (!View.EnableDebugIDisposableAsserts)
         {
             View.Instances.Clear ();
-            SessionToken.Instances.Clear ();
 
             return;
         }
@@ -668,16 +666,6 @@ public class UICatalog
         }
 
         View.Instances.Clear ();
-
-        // Validate there are no outstanding Application sessions
-        // after a scenario was selected to run. This proves the main UI Catalog
-        // 'app' closed cleanly.
-        foreach (SessionToken? inst in SessionToken.Instances)
-        {
-            Debug.Assert (inst.WasDisposed);
-        }
-
-        SessionToken.Instances.Clear ();
 #endif
     }
 }

+ 28 - 19
Examples/UICatalog/UICatalogTop.cs → Examples/UICatalog/UICatalogRunnable.cs

@@ -14,7 +14,7 @@ namespace UICatalog;
 ///     This is the main UI Catalog app view. It is run fresh when the app loads (if a Scenario has not been passed on
 ///     the command line) and each time a Scenario ends.
 /// </summary>
-public class UICatalogTop : Toplevel
+public class UICatalogRunnable : Runnable
 {
     // When a scenario is run, the main app is killed. The static
     // members are cached so that when the scenario exits the
@@ -23,12 +23,12 @@ public class UICatalogTop : Toplevel
     // Note, we used to pass this to scenarios that run, but it just added complexity
     // So that was removed. But we still have this here to demonstrate how changing
     // the scheme works.
-    public static string? CachedTopLevelScheme { get; set; }
+    public static string? CachedRunnableScheme { get; set; }
 
     // Diagnostics
     private static ViewDiagnosticFlags _diagnosticFlags;
 
-    public UICatalogTop ()
+    public UICatalogRunnable ()
     {
         _diagnosticFlags = Diagnostics;
 
@@ -39,8 +39,8 @@ public class UICatalogTop : Toplevel
 
         Add (_menuBar, _categoryList, _scenarioList, _statusBar);
 
-        Loaded += LoadedHandler;
-        Unloaded += UnloadedHandler;
+        IsModalChanged += IsModalChangedHandler;
+        IsRunningChanged += IsRunningChangedHandler;
 
         // Restore previous selections
         if (_categoryList.Source?.Count > 0) {
@@ -50,15 +50,20 @@ public class UICatalogTop : Toplevel
         }
         _scenarioList.SelectedRow = _cachedScenarioIndex;
 
-        SchemeName = CachedTopLevelScheme = SchemeManager.SchemesToSchemeName (Schemes.Base);
+        SchemeName = CachedRunnableScheme = SchemeManager.SchemesToSchemeName (Schemes.Base);
         ConfigurationManager.Applied += ConfigAppliedHandler;
     }
 
 
     private static bool _isFirstRunning = true;
 
-    private void LoadedHandler (object? sender, EventArgs? args)
+    private void IsModalChangedHandler (object? sender, EventArgs<bool> args)
     {
+        if (!args.Value)
+        {
+            return;
+        }
+
         if (_disableMouseCb is { })
         {
             _disableMouseCb.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked;
@@ -85,15 +90,18 @@ public class UICatalogTop : Toplevel
             _statusBar.VisibleChanged += (s, e) => { ShowStatusBar = _statusBar.Visible; };
         }
 
-        Loaded -= LoadedHandler;
+        IsModalChanged -= IsModalChangedHandler;
         _categoryList!.EnsureSelectedItemVisible ();
         _scenarioList.EnsureSelectedCellIsVisible ();
     }
 
-    private void UnloadedHandler (object? sender, EventArgs? args)
+    private void IsRunningChangedHandler (object? sender, EventArgs<bool> args)
     {
-        ConfigurationManager.Applied -= ConfigAppliedHandler;
-        Unloaded -= UnloadedHandler;
+        if (!args.Value)
+        {
+            ConfigurationManager.Applied -= ConfigAppliedHandler;
+            IsRunningChanged -= IsRunningChangedHandler;
+        }
     }
 
     #region MenuBar
@@ -144,6 +152,7 @@ public class UICatalogTop : Toplevel
                                                               "_About...",
                                                               "About UI Catalog",
                                                               () => MessageBox.Query (
+                                                                                      App,
                                                                                       "",
                                                                                       GetAboutBoxMessage (),
                                                                                       wrapMessage: false,
@@ -239,14 +248,14 @@ public class UICatalogTop : Toplevel
                                                         {
                                                             return;
                                                         }
-                                                        CachedTopLevelScheme = SchemeManager.GetSchemesForCurrentTheme ()!.Keys.ToArray () [(int)args.Value];
-                                                        SchemeName = CachedTopLevelScheme;
+                                                        CachedRunnableScheme = SchemeManager.GetSchemesForCurrentTheme ()!.Keys.ToArray () [(int)args.Value];
+                                                        SchemeName = CachedRunnableScheme;
                                                         SetNeedsDraw ();
                                                     };
 
                 menuItem = new ()
                 {
-                    Title = "Scheme for Toplevel",
+                    Title = "Scheme for Runnable",
                     SubMenu = new (
                                    [
                                        new ()
@@ -391,12 +400,12 @@ public class UICatalogTop : Toplevel
         _topSchemesSelector.Labels = SchemeManager.GetSchemeNames ().ToArray ();
         _topSchemesSelector.Value = selectedScheme;
 
-        if (CachedTopLevelScheme is null || !SchemeManager.GetSchemeNames ().Contains (CachedTopLevelScheme))
+        if (CachedRunnableScheme is null || !SchemeManager.GetSchemeNames ().Contains (CachedRunnableScheme))
         {
-            CachedTopLevelScheme = SchemeManager.SchemesToSchemeName (Schemes.Base);
+            CachedRunnableScheme = SchemeManager.SchemesToSchemeName (Schemes.Base);
         }
 
-        int newSelectedItem = SchemeManager.GetSchemeNames ().IndexOf (CachedTopLevelScheme!);
+        int newSelectedItem = SchemeManager.GetSchemeNames ().IndexOf (CachedRunnableScheme!);
         // if the item is in bounds then select it
         if (newSelectedItem >= 0 && newSelectedItem < SchemeManager.GetSchemeNames ().Count)
         {
@@ -685,7 +694,7 @@ public class UICatalogTop : Toplevel
     {
         UpdateThemesMenu ();
 
-        SchemeName = CachedTopLevelScheme;
+        SchemeName = CachedRunnableScheme;
 
         if (_shQuit is { })
         {
@@ -700,7 +709,7 @@ public class UICatalogTop : Toplevel
         _disableMouseCb!.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked;
         _force16ColorsShortcutCb!.CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
 
-        Application.TopRunnable?.SetNeedsDraw ();
+        Application.TopRunnableView?.SetNeedsDraw ();
     }
 
     private void ConfigAppliedHandler (object? sender, ConfigurationManagerEventArgs? a) { ConfigApplied (); }

+ 15 - 0
Terminal.Gui/App/Application.Clipboard.cs

@@ -0,0 +1,15 @@
+namespace Terminal.Gui.App;
+
+public static partial class Application // Clipboard handling
+{
+    /// <summary>
+    ///     Gets the clipboard for the application.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Provides access to the OS clipboard through the driver.
+    ///     </para>
+    /// </remarks>
+    [Obsolete ("The legacy static Application object is going away. Use IApplication.Clipboard instead.")]
+    public static IClipboard? Clipboard => ApplicationImpl.Instance.Clipboard;
+}

+ 0 - 18
Terminal.Gui/App/Application.Current.cs

@@ -1,18 +0,0 @@
-using System.Collections.Concurrent;
-
-namespace Terminal.Gui.App;
-
-public static partial class Application // Current handling
-{
-    /// <inheritdoc cref="IApplication.SessionStack"/>
-    [Obsolete ("The legacy static Application object is going away.")] public static ConcurrentStack<Toplevel> SessionStack => ApplicationImpl.Instance.SessionStack;
-
-    /// <summary>The <see cref="Toplevel"/> that is on the top of the <see cref="SessionStack"/>.</summary>
-    /// <value>The top runnable.</value>
-    [Obsolete ("The legacy static Application object is going away.")]
-    public static Toplevel? TopRunnable
-    {
-        get => ApplicationImpl.Instance.TopRunnable;
-        internal set => ApplicationImpl.Instance.TopRunnable = value;
-    }
-}

+ 21 - 15
Terminal.Gui/App/Application.Driver.cs

@@ -13,38 +13,44 @@ public static partial class Application // Driver abstractions
         internal set => ApplicationImpl.Instance.Driver = value;
     }
 
+    private static bool _force16Colors = false; // Resources/config.json overrides
+
     /// <inheritdoc cref="IApplication.Force16Colors"/>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [Obsolete ("The legacy static Application object is going away.")]
     public static bool Force16Colors
     {
-        get => ApplicationImpl.Instance.Force16Colors;
-        set => ApplicationImpl.Instance.Force16Colors = value;
+        get => _force16Colors;
+        set
+        {
+            bool oldValue = _force16Colors;
+            _force16Colors = value;
+            Force16ColorsChanged?.Invoke (null, new ValueChangedEventArgs<bool> (oldValue, _force16Colors));
+        }
     }
 
+    /// <summary>Raised when <see cref="Force16Colors"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<bool>>? Force16ColorsChanged;
+
+    private static string _forceDriver = string.Empty; // Resources/config.json overrides
+
     /// <inheritdoc cref="IApplication.ForceDriver"/>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [Obsolete ("The legacy static Application object is going away.")]
     public static string ForceDriver
     {
-        get => ApplicationImpl.Instance.ForceDriver;
+        get => _forceDriver;
         set
         {
-            if (!string.IsNullOrEmpty (ApplicationImpl.Instance.ForceDriver) && value != Driver?.GetName ())
-            {
-                // ForceDriver cannot be changed if it has a valid value
-                return;
-            }
-
-            if (ApplicationImpl.Instance.Initialized && value != Driver?.GetName ())
-            {
-                throw new InvalidOperationException ($"The {nameof (ForceDriver)} can only be set before initialized.");
-            }
-
-            ApplicationImpl.Instance.ForceDriver = value;
+            string oldValue = _forceDriver;
+            _forceDriver = value;
+            ForceDriverChanged?.Invoke (null, new ValueChangedEventArgs<string> (oldValue, _forceDriver));
         }
     }
 
+    /// <summary>Raised when <see cref="ForceDriver"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<string>>? ForceDriverChanged;
+
     /// <inheritdoc cref="IApplication.Sixel"/>
     [Obsolete ("The legacy static Application object is going away.")] 
     public static List<SixelToRender> Sixel => ApplicationImpl.Instance.Sixel;

+ 20 - 6
Terminal.Gui/App/Application.Lifecycle.cs

@@ -18,7 +18,16 @@ public static partial class Application // Lifecycle (Init/Shutdown)
     ///     <see cref="IApplication"/> instance for all subsequent application operations.
     /// </remarks>
     /// <returns>A new <see cref="IApplication"/> instance.</returns>
-    public static IApplication Create () { return new ApplicationImpl (); }
+    /// <exception cref="InvalidOperationException">
+    ///     Thrown if the legacy static Application model has already been used in this process.
+    /// </exception>
+    public static IApplication Create ()
+    {
+        //Debug.Fail ("Application.Create() called");
+        ApplicationImpl.MarkInstanceBasedModelUsed ();
+
+        return new ApplicationImpl ();
+    }
 
     /// <inheritdoc cref="IApplication.Init"/>
     [RequiresUnreferencedCode ("AOT")]
@@ -26,6 +35,7 @@ public static partial class Application // Lifecycle (Init/Shutdown)
     [Obsolete ("The legacy static Application object is going away.")]
     public static void Init (string? driverName = null)
     {
+        //Debug.Fail ("Application.Init() called - parallelizable tests should not use legacy static Application model");
         ApplicationImpl.Instance.Init (driverName ?? ForceDriver);
     }
 
@@ -35,13 +45,13 @@ public static partial class Application // Lifecycle (Init/Shutdown)
     [Obsolete ("The legacy static Application object is going away.")]
     public static int? MainThreadId
     {
-        get => ((ApplicationImpl)ApplicationImpl.Instance).MainThreadId;
-        set => ((ApplicationImpl)ApplicationImpl.Instance).MainThreadId = value;
+        get => ApplicationImpl.Instance.MainThreadId;
+        internal set => ApplicationImpl.Instance.MainThreadId = value;
     }
 
-    /// <inheritdoc cref="IApplication.Shutdown"/>
+    /// <inheritdoc cref="IApplication.Dispose"/>
     [Obsolete ("The legacy static Application object is going away.")]
-    public static void Shutdown () => ApplicationImpl.Instance.Shutdown ();
+    public static void Shutdown () => ApplicationImpl.Instance.Dispose ();
 
     /// <inheritdoc cref="IApplication.Initialized"/>
     [Obsolete ("The legacy static Application object is going away.")]
@@ -65,5 +75,9 @@ public static partial class Application // Lifecycle (Init/Shutdown)
     // guaranteeing that the state of this singleton is deterministic when Init
     // starts running and after Shutdown returns.
     [Obsolete ("The legacy static Application object is going away.")]
-    internal static void ResetState (bool ignoreDisposed = false) => ApplicationImpl.Instance?.ResetState (ignoreDisposed);
+    internal static void ResetState (bool ignoreDisposed = false)
+    {
+        // Use the static reset method to bypass the fence check
+        ApplicationImpl.ResetStateStatic (ignoreDisposed);
+    }
 }

+ 12 - 2
Terminal.Gui/App/Application.Mouse.cs

@@ -4,15 +4,25 @@ namespace Terminal.Gui.App;
 
 public static partial class Application // Mouse handling
 {
+    private static bool _isMouseDisabled = false; // Resources/config.json overrides
+
     /// <summary>Disable or enable the mouse. The mouse is enabled by default.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [Obsolete ("The legacy static Application object is going away.")]
     public static bool IsMouseDisabled
     {
-        get => Mouse.IsMouseDisabled;
-        set => Mouse.IsMouseDisabled = value;
+        get => _isMouseDisabled;
+        set
+        {
+            bool oldValue = _isMouseDisabled;
+            _isMouseDisabled = value;
+            IsMouseDisabledChanged?.Invoke (null, new ValueChangedEventArgs<bool> (oldValue, _isMouseDisabled));
+        }
     }
 
+    /// <summary>Raised when <see cref="IsMouseDisabled"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<bool>>? IsMouseDisabledChanged;
+
     /// <summary>
     ///     Gets the <see cref="IMouse"/> instance that manages mouse event handling and state.
     /// </summary>

+ 49 - 9
Terminal.Gui/App/Application.Navigation.cs

@@ -13,22 +13,42 @@ public static partial class Application // Navigation stuff
         internal set => ApplicationImpl.Instance.Navigation = value;
     }
 
+    private static Key _nextTabGroupKey = Key.F6; // Resources/config.json overrides
+
     /// <summary>Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
-      [Obsolete ("The legacy static Application object is going away.")]public static Key NextTabGroupKey
+    public static Key NextTabGroupKey
     {
-        get => ApplicationImpl.Instance.Keyboard.NextTabGroupKey;
-        set => ApplicationImpl.Instance.Keyboard.NextTabGroupKey = value;
+        get => _nextTabGroupKey;
+        set
+        {
+            Key oldValue = _nextTabGroupKey;
+            _nextTabGroupKey = value;
+            NextTabGroupKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _nextTabGroupKey));
+        }
     }
 
+    /// <summary>Raised when <see cref="NextTabGroupKey"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<Key>>? NextTabGroupKeyChanged;
+
+    private static Key _nextTabKey = Key.Tab; // Resources/config.json overrides
+
     /// <summary>Alternative key to navigate forwards through views. Tab is the primary key.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key NextTabKey
     {
-        get => ApplicationImpl.Instance.Keyboard.NextTabKey;
-        set => ApplicationImpl.Instance.Keyboard.NextTabKey = value;
+        get => _nextTabKey;
+        set
+        {
+            Key oldValue = _nextTabKey;
+            _nextTabKey = value;
+            NextTabKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _nextTabKey));
+        }
     }
 
+    /// <summary>Raised when <see cref="NextTabKey"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<Key>>? NextTabKeyChanged;
+
     /// <summary>
     ///     Raised when the user releases a key.
     ///     <para>
@@ -48,19 +68,39 @@ public static partial class Application // Navigation stuff
         remove => ApplicationImpl.Instance.Keyboard.KeyUp -= value;
     }
 
+    private static Key _prevTabGroupKey = Key.F6.WithShift; // Resources/config.json overrides
+
     /// <summary>Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key PrevTabGroupKey
     {
-        get => ApplicationImpl.Instance.Keyboard.PrevTabGroupKey;
-        set => ApplicationImpl.Instance.Keyboard.PrevTabGroupKey = value;
+        get => _prevTabGroupKey;
+        set
+        {
+            Key oldValue = _prevTabGroupKey;
+            _prevTabGroupKey = value;
+            PrevTabGroupKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _prevTabGroupKey));
+        }
     }
 
+    /// <summary>Raised when <see cref="PrevTabGroupKey"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<Key>>? PrevTabGroupKeyChanged;
+
+    private static Key _prevTabKey = Key.Tab.WithShift; // Resources/config.json overrides
+
     /// <summary>Alternative key to navigate backwards through views. Shift+Tab is the primary key.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key PrevTabKey
     {
-        get => ApplicationImpl.Instance.Keyboard.PrevTabKey;
-        set => ApplicationImpl.Instance.Keyboard.PrevTabKey = value;
+        get => _prevTabKey;
+        set
+        {
+            Key oldValue = _prevTabKey;
+            _prevTabKey = value;
+            PrevTabKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _prevTabKey));
+        }
     }
+
+    /// <summary>Raised when <see cref="PrevTabKey"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<Key>>? PrevTabKeyChanged;
 }

+ 36 - 22
Terminal.Gui/App/Application.Run.cs

@@ -4,46 +4,60 @@ namespace Terminal.Gui.App;
 
 public static partial class Application // Run (Begin -> Run -> Layout/Draw -> End -> Stop)
 {
+    private static Key _quitKey = Key.Esc; // Resources/config.json overrides
+
     /// <summary>Gets or sets the key to quit the application.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key QuitKey
     {
-        get => ApplicationImpl.Instance.Keyboard.QuitKey;
-        set => ApplicationImpl.Instance.Keyboard.QuitKey = value;
+        get => _quitKey;
+        set
+        {
+            Key oldValue = _quitKey;
+            _quitKey = value;
+            QuitKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _quitKey));
+        }
     }
 
+    /// <summary>Raised when <see cref="QuitKey"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<Key>>? QuitKeyChanged;
+
+    private static Key _arrangeKey = Key.F5.WithCtrl; // Resources/config.json overrides
+
     /// <summary>Gets or sets the key to activate arranging views using the keyboard.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key ArrangeKey
     {
-        get => ApplicationImpl.Instance.Keyboard.ArrangeKey;
-        set => ApplicationImpl.Instance.Keyboard.ArrangeKey = value;
+        get => _arrangeKey;
+        set
+        {
+            Key oldValue = _arrangeKey;
+            _arrangeKey = value;
+            ArrangeKeyChanged?.Invoke (null, new ValueChangedEventArgs<Key> (oldValue, _arrangeKey));
+        }
     }
 
+    /// <summary>Raised when <see cref="ArrangeKey"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<Key>>? ArrangeKeyChanged;
+
     /// <inheritdoc cref="IApplication.Begin(IRunnable)"/>
     [Obsolete ("The legacy static Application object is going away.")]
-    public static SessionToken Begin (Toplevel toplevel) => ApplicationImpl.Instance.Begin (toplevel);
+    public static SessionToken Begin (IRunnable runnable) => ApplicationImpl.Instance.Begin (runnable)!;
 
     /// <inheritdoc cref="IApplication.PositionCursor"/>
     [Obsolete ("The legacy static Application object is going away.")]
     public static bool PositionCursor () => ApplicationImpl.Instance.PositionCursor ();
 
-    /// <inheritdoc cref="IApplication.Run(Func{Exception, bool}, string)"/>
-    [RequiresUnreferencedCode ("AOT")]
-    [RequiresDynamicCode ("AOT")]
-    [Obsolete ("The legacy static Application object is going away.")]
-    public static Toplevel Run (Func<Exception, bool>? errorHandler = null, string? driverName = null) => ApplicationImpl.Instance.Run (errorHandler, driverName);
-
-    /// <inheritdoc cref="IApplication.Run{TView}(Func{Exception, bool}, string)"/>
+    /// <inheritdoc cref="IApplication.Run{TRunnable}(Func{Exception, bool}, string)"/>
     [RequiresUnreferencedCode ("AOT")]
     [RequiresDynamicCode ("AOT")]
     [Obsolete ("The legacy static Application object is going away.")]
-    public static TView Run<TView> (Func<Exception, bool>? errorHandler = null, string? driverName = null)
-        where TView : Toplevel, new() => ApplicationImpl.Instance.Run<TView> (errorHandler, driverName);
+    public static IApplication Run<TRunnable> (Func<Exception, bool>? errorHandler = null, string? driverName = null)
+        where TRunnable : IRunnable, new() => ApplicationImpl.Instance.Run<TRunnable> (errorHandler, driverName);
 
-    /// <inheritdoc cref="IApplication.Run(Toplevel, Func{Exception, bool})"/>
+    /// <inheritdoc cref="IApplication.Run(IRunnable, Func{Exception, bool})"/>
     [Obsolete ("The legacy static Application object is going away.")]
-    public static void Run (Toplevel view, Func<Exception, bool>? errorHandler = null) => ApplicationImpl.Instance.Run (view, errorHandler);
+    public static void Run (IRunnable runnable, Func<Exception, bool>? errorHandler = null) => ApplicationImpl.Instance.Run (runnable, errorHandler);
 
     /// <inheritdoc cref="IApplication.AddTimeout"/>
     [Obsolete ("The legacy static Application object is going away.")]
@@ -56,7 +70,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
     /// <inheritdoc cref="IApplication.TimedEvents"/>
     /// 
     [Obsolete ("The legacy static Application object is going away.")]
-    public static ITimedEvents? TimedEvents => ApplicationImpl.Instance?.TimedEvents;
+    public static ITimedEvents? TimedEvents => ApplicationImpl.Instance.TimedEvents;
 
     /// <inheritdoc cref="IApplication.Invoke(Action{IApplication})"/>
     [Obsolete ("The legacy static Application object is going away.")]
@@ -78,17 +92,17 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
         set => ApplicationImpl.Instance.StopAfterFirstIteration = value;
     }
 
-    /// <inheritdoc cref="IApplication.RequestStop(Toplevel)"/>
+    /// <inheritdoc cref="IApplication.RequestStop(IRunnable)"/>
     [Obsolete ("The legacy static Application object is going away.")]
-    public static void RequestStop (Toplevel? top = null) => ApplicationImpl.Instance.RequestStop (top);
+    public static void RequestStop (IRunnable? runnable = null) => ApplicationImpl.Instance.RequestStop (runnable);
 
-    /// <inheritdoc cref="IApplication.End(RunnableSessionToken)"/>
+    /// <inheritdoc cref="IApplication.End(SessionToken)"/>
     [Obsolete ("The legacy static Application object is going away.")]
     public static void End (SessionToken sessionToken) => ApplicationImpl.Instance.End (sessionToken);
 
     /// <inheritdoc cref="IApplication.Iteration"/>
     [Obsolete ("The legacy static Application object is going away.")]
-    public static event EventHandler<IterationEventArgs>? Iteration
+    public static event EventHandler<EventArgs<IApplication?>>? Iteration
     {
         add => ApplicationImpl.Instance.Iteration += value;
         remove => ApplicationImpl.Instance.Iteration -= value;
@@ -104,7 +118,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
 
     /// <inheritdoc cref="IApplication.SessionEnded"/>
     [Obsolete ("The legacy static Application object is going away.")]
-    public static event EventHandler<ToplevelEventArgs>? SessionEnded
+    public static event EventHandler<SessionTokenEventArgs>? SessionEnded
     {
         add => ApplicationImpl.Instance.SessionEnded += value;
         remove => ApplicationImpl.Instance.SessionEnded -= value;

+ 0 - 8
Terminal.Gui/App/Application.Screen.cs

@@ -12,14 +12,6 @@ public static partial class Application // Screen related stuff; intended to hid
         set => ApplicationImpl.Instance.Screen = value;
     }
 
-    /// <inheritdoc cref="IApplication.ScreenChanged"/>
-    [Obsolete ("The legacy static Application object is going away.")]
-    public static event EventHandler<EventArgs<Rectangle>>? ScreenChanged
-    {
-        add => ApplicationImpl.Instance.ScreenChanged += value;
-        remove => ApplicationImpl.Instance.ScreenChanged -= value;
-    }
-
     /// <inheritdoc cref="IApplication.ClearScreenNextIteration"/>
 
     [Obsolete ("The legacy static Application object is going away.")]

+ 16 - 0
Terminal.Gui/App/Application.TopRunnable.cs

@@ -0,0 +1,16 @@
+using System.Collections.Concurrent;
+
+namespace Terminal.Gui.App;
+
+public static partial class Application // TopRunnable handling
+{
+    /// <summary>The <see cref="View"/> that is on the top of the <see cref="IApplication.SessionStack"/>.</summary>
+    /// <value>The top runnable.</value>
+    [Obsolete ("The legacy static Application object is going away.")]
+    public static View? TopRunnableView => ApplicationImpl.Instance.TopRunnableView;
+
+    /// <summary>The <see cref="View"/> that is on the top of the <see cref="IApplication.SessionStack"/>.</summary>
+    /// <value>The top runnable.</value>
+    [Obsolete ("The legacy static Application object is going away.")]
+    public static IRunnable? TopRunnable => ApplicationImpl.Instance.TopRunnable;
+}

+ 182 - 80
Terminal.Gui/App/ApplicationImpl.Lifecycle.cs

@@ -5,6 +5,9 @@ namespace Terminal.Gui.App;
 
 public partial class ApplicationImpl
 {
+    /// <inheritdoc/>
+    public int? MainThreadId { get; set; }
+
     /// <inheritdoc/>
     public bool Initialized { get; set; }
 
@@ -23,6 +26,29 @@ public partial class ApplicationImpl
             throw new InvalidOperationException ("Init called multiple times without Shutdown");
         }
 
+        // Thread-safe fence check: Ensure we're not mixing application models
+        // Use lock to make check-and-set atomic
+        lock (_modelUsageLock)
+        {
+            // If this is a legacy static instance and instance-based model was used, throw
+            if (this == _instance && ModelUsage == ApplicationModelUsage.InstanceBased)
+            {
+                throw new InvalidOperationException (ERROR_LEGACY_AFTER_MODERN);
+            }
+
+            // If this is an instance-based instance and legacy static model was used, throw
+            if (this != _instance && ModelUsage == ApplicationModelUsage.LegacyStatic)
+            {
+                throw new InvalidOperationException (ERROR_MODERN_AFTER_LEGACY);
+            }
+
+            // If no model has been set yet, set it now based on which instance this is
+            if (ModelUsage == ApplicationModelUsage.None)
+            {
+                ModelUsage = this == _instance ? ApplicationModelUsage.LegacyStatic : ApplicationModelUsage.InstanceBased;
+            }
+        }
+
         if (!string.IsNullOrWhiteSpace (driverName))
         {
             _driverName = driverName;
@@ -41,26 +67,24 @@ public partial class ApplicationImpl
 
         // Preserve existing keyboard settings if they exist
         bool hasExistingKeyboard = _keyboard is { };
-        Key existingQuitKey = _keyboard?.QuitKey ?? Key.Esc;
-        Key existingArrangeKey = _keyboard?.ArrangeKey ?? Key.F5.WithCtrl;
-        Key existingNextTabKey = _keyboard?.NextTabKey ?? Key.Tab;
-        Key existingPrevTabKey = _keyboard?.PrevTabKey ?? Key.Tab.WithShift;
-        Key existingNextTabGroupKey = _keyboard?.NextTabGroupKey ?? Key.F6;
-        Key existingPrevTabGroupKey = _keyboard?.PrevTabGroupKey ?? Key.F6.WithShift;
+        Key existingQuitKey = _keyboard?.QuitKey ?? Application.QuitKey;
+        Key existingArrangeKey = _keyboard?.ArrangeKey ?? Application.ArrangeKey;
+        Key existingNextTabKey = _keyboard?.NextTabKey ?? Application.NextTabKey;
+        Key existingPrevTabKey = _keyboard?.PrevTabKey ?? Application.PrevTabKey;
+        Key existingNextTabGroupKey = _keyboard?.NextTabGroupKey ?? Application.NextTabGroupKey;
+        Key existingPrevTabGroupKey = _keyboard?.PrevTabGroupKey ?? Application.PrevTabGroupKey;
 
         // Reset keyboard to ensure fresh state with default bindings
         _keyboard = new KeyboardImpl { App = this };
 
-        // Restore previously set keys if they existed and were different from defaults
-        if (hasExistingKeyboard)
-        {
-            _keyboard.QuitKey = existingQuitKey;
-            _keyboard.ArrangeKey = existingArrangeKey;
-            _keyboard.NextTabKey = existingNextTabKey;
-            _keyboard.PrevTabKey = existingPrevTabKey;
-            _keyboard.NextTabGroupKey = existingNextTabGroupKey;
-            _keyboard.PrevTabGroupKey = existingPrevTabGroupKey;
-        }
+        // Sync keys from Application static properties (or existing keyboard if it had custom values)
+        // This ensures we respect any Application.QuitKey etc changes made before Init()
+        _keyboard.QuitKey = existingQuitKey;
+        _keyboard.ArrangeKey = existingArrangeKey;
+        _keyboard.NextTabKey = existingNextTabKey;
+        _keyboard.PrevTabKey = existingPrevTabKey;
+        _keyboard.NextTabGroupKey = existingNextTabGroupKey;
+        _keyboard.PrevTabGroupKey = existingPrevTabGroupKey;
 
         CreateDriver (_driverName);
         Screen = Driver!.Screen;
@@ -72,23 +96,75 @@ public partial class ApplicationImpl
         SynchronizationContext.SetSynchronizationContext (new ());
         MainThreadId = Thread.CurrentThread.ManagedThreadId;
 
+        _result = null;
+
         return this;
     }
 
-    /// <summary>Shutdown an application initialized with <see cref="Init"/>.</summary>
-    public object? Shutdown ()
+    #region IDisposable Implementation
+
+    private bool _disposed;
+
+    /// <summary>
+    ///     Disposes the application instance and releases all resources.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         This method implements the <see cref="IDisposable"/> pattern and performs the same cleanup
+    ///         as <see cref="IDisposable.Dispose"/>, but without returning a result.
+    ///     </para>
+    ///     <para>
+    ///         After calling <see cref="Dispose()"/>, use <see cref="GetResult"/> or <see cref="IApplication.GetResult{T}"/>
+    ///         to retrieve the result from the last run session.
+    ///     </para>
+    /// </remarks>
+    public void Dispose ()
+    {
+        Dispose (true);
+        GC.SuppressFinalize (this);
+    }
+
+    /// <summary>
+    ///     Disposes the application instance and releases all resources.
+    /// </summary>
+    /// <param name="disposing">
+    ///     <see langword="true"/> if called from <see cref="Dispose()"/>;
+    ///     <see langword="false"/> if called from finalizer.
+    /// </param>
+    protected virtual void Dispose (bool disposing)
     {
-        // Extract result from framework-owned runnable before disposal
-        object? result = null;
-        IRunnable? runnableToDispose = FrameworkOwnedRunnable;
+        if (_disposed)
+        {
+            return;
+        }
+
+        if (disposing)
+        {
+            // Dispose managed resources
+            DisposeCore ();
+        }
 
-        if (runnableToDispose is { })
+        // For the singleton instance (legacy Application.Init/Shutdown pattern),
+        // we need to allow re-initialization after disposal. This enables:
+        // Application.Init() -> Application.Shutdown() -> Application.Init()
+        // For modern instance-based usage, this doesn't matter as new instances are created.
+        if (this == _instance)
+        {
+            // Reset disposed flag to allow re-initialization
+            _disposed = false;
+        }
+        else
         {
-            // Extract the result using reflection to get the Result property value
-            var resultProperty = runnableToDispose.GetType().GetProperty("Result");
-            result = resultProperty?.GetValue(runnableToDispose);
+            // For instance-based usage, mark as disposed
+            _disposed = true;
         }
+    }
 
+    /// <summary>
+    ///     Core disposal logic - same as Shutdown() but without returning result.
+    /// </summary>
+    private void DisposeCore ()
+    {
         // Stop the coordinator if running
         Coordinator?.Stop ();
 
@@ -110,16 +186,6 @@ public partial class ApplicationImpl
         }
 #endif
 
-        // Dispose the framework-owned runnable if it exists
-        if (runnableToDispose is { })
-        {
-            if (runnableToDispose is IDisposable disposable)
-            {
-                disposable.Dispose();
-            }
-            FrameworkOwnedRunnable = null;
-        }
-
         // Clean up all application state (including sync context)
         // ResetState handles the case where Initialized is false
         ResetState ();
@@ -136,39 +202,25 @@ public partial class ApplicationImpl
 
         // Clear the event to prevent memory leaks
         InitializedChanged = null;
-
-        return result;
     }
 
-#if DEBUG
-    /// <summary>
-    ///     DEBUG ONLY: Asserts that an event has no remaining subscribers.
-    /// </summary>
-    /// <param name="eventName">The name of the event for diagnostic purposes.</param>
-    /// <param name="eventDelegate">The event delegate to check.</param>
-    private static void AssertNoEventSubscribers (string eventName, Delegate? eventDelegate)
+    #endregion IDisposable Implementation
+
+    /// <summary>Shutdown an application initialized with <see cref="Init"/>.</summary>
+    [Obsolete ("Use Dispose() or a using statement instead. This method will be removed in a future version.")]
+    public object? Shutdown ()
     {
-        if (eventDelegate is null)
-        {
-            return;
-        }
+        // Shutdown is now just a wrapper around Dispose that returns the result
+        object? result = GetResult ();
+        Dispose ();
 
-        Delegate [] subscribers = eventDelegate.GetInvocationList ();
+        return result;
+    }
 
-        if (subscribers.Length > 0)
-        {
-            string subscriberInfo = string.Join (
-                                                 ", ",
-                                                 subscribers.Select (d => $"{d.Method.DeclaringType?.Name}.{d.Method.Name}"
-                                                                    )
-                                                );
+    private object? _result;
 
-            Debug.Fail (
-                        $"Application.{eventName} has {subscribers.Length} remaining subscriber(s) after Shutdown: {subscriberInfo}"
-                       );
-        }
-    }
-#endif
+    /// <inheritdoc/>
+    public object? GetResult () => _result;
 
     /// <inheritdoc/>
     public void ResetState (bool ignoreDisposed = false)
@@ -180,10 +232,13 @@ public partial class ApplicationImpl
         // === 0. Stop all timers ===
         TimedEvents?.StopAll ();
 
-        // === 1. Stop all running toplevels ===
-        foreach (Toplevel t in SessionStack)
+        // === 1. Stop all running runnables ===
+        foreach (SessionToken token in SessionStack!.Reverse ())
         {
-            t.Running = false;
+            if (token.Runnable is { })
+            {
+                End (token);
+            }
         }
 
         // === 2. Close and dispose popover ===
@@ -198,29 +253,18 @@ public partial class ApplicationImpl
         Popover?.Dispose ();
         Popover = null;
 
-        // === 3. Clean up toplevels ===
-        SessionStack.Clear ();
-        RunnableSessionStack?.Clear ();
+        // === 3. Clean up runnables ===
+        SessionStack?.Clear ();
 
 #if DEBUG_IDISPOSABLE
 
         // Don't dispose the TopRunnable. It's up to caller dispose it
-        if (View.EnableDebugIDisposableAsserts && !ignoreDisposed && TopRunnable is { })
+        if (View.EnableDebugIDisposableAsserts && !ignoreDisposed && TopRunnableView is { })
         {
-            Debug.Assert (TopRunnable.WasDisposed, $"Title = {TopRunnable.Title}, Id = {TopRunnable.Id}");
-
-            // If End wasn't called _CachedSessionTokenToplevel may be null
-            if (CachedSessionTokenToplevel is { })
-            {
-                Debug.Assert (CachedSessionTokenToplevel.WasDisposed);
-                Debug.Assert (CachedSessionTokenToplevel == TopRunnable);
-            }
+            Debug.Assert (TopRunnableView.WasDisposed, $"Title = {TopRunnableView.Title}, Id = {TopRunnableView.Id}");
         }
 #endif
 
-        TopRunnable = null;
-        CachedSessionTokenToplevel = null;
-
         // === 4. Clean up driver ===
         if (Driver is { })
         {
@@ -241,6 +285,17 @@ public partial class ApplicationImpl
         ClearScreenNextIteration = false;
 
         // === 6. Reset input systems ===
+        // Dispose keyboard and mouse to unsubscribe from events
+        if (_keyboard is IDisposable keyboardDisposable)
+        {
+            keyboardDisposable.Dispose ();
+        }
+
+        if (_mouse is IDisposable mouseDisposable)
+        {
+            mouseDisposable.Dispose ();
+        }
+
         // Mouse and Keyboard will be lazy-initialized on next access
         _mouse = null;
         _keyboard = null;
@@ -273,10 +328,57 @@ public partial class ApplicationImpl
         // gui.cs does no longer process any callbacks. See #1084 for more details:
         // (https://github.com/gui-cs/Terminal.Gui/issues/1084).
         SynchronizationContext.SetSynchronizationContext (null);
+
+        // === 12. Unsubscribe from Application static property change events ===
+        UnsubscribeApplicationEvents ();
     }
 
     /// <summary>
     ///     Raises the <see cref="InitializedChanged"/> event.
     /// </summary>
     internal void RaiseInitializedChanged (object sender, EventArgs<bool> e) { InitializedChanged?.Invoke (sender, e); }
+
+#if DEBUG
+    /// <summary>
+    ///     DEBUG ONLY: Asserts that an event has no remaining subscribers.
+    /// </summary>
+    /// <param name="eventName">The name of the event for diagnostic purposes.</param>
+    /// <param name="eventDelegate">The event delegate to check.</param>
+    private static void AssertNoEventSubscribers (string eventName, Delegate? eventDelegate)
+    {
+        if (eventDelegate is null)
+        {
+            return;
+        }
+
+        Delegate [] subscribers = eventDelegate.GetInvocationList ();
+
+        if (subscribers.Length > 0)
+        {
+            string subscriberInfo = string.Join (
+                                                 ", ",
+                                                 subscribers.Select (d => $"{d.Method.DeclaringType?.Name}.{d.Method.Name}"
+                                                                    )
+                                                );
+
+            Debug.Fail (
+                        $"Application.{eventName} has {subscribers.Length} remaining subscriber(s) after Shutdown: {subscriberInfo}"
+                       );
+        }
+    }
+#endif
+
+    // Event handlers for Application static property changes
+    private void OnForce16ColorsChanged (object? sender, ValueChangedEventArgs<bool> e) { Force16Colors = e.NewValue; }
+
+    private void OnForceDriverChanged (object? sender, ValueChangedEventArgs<string> e) { ForceDriver = e.NewValue; }
+
+    /// <summary>
+    ///     Unsubscribes from Application static property change events.
+    /// </summary>
+    private void UnsubscribeApplicationEvents ()
+    {
+        Application.Force16ColorsChanged -= OnForce16ColorsChanged;
+        Application.ForceDriverChanged -= OnForceDriverChanged;
+    }
 }

+ 171 - 432
Terminal.Gui/App/ApplicationImpl.Run.cs

@@ -1,321 +1,44 @@
-using System.Diagnostics;
+using System.Collections.Concurrent;
 using System.Diagnostics.CodeAnalysis;
 
 namespace Terminal.Gui.App;
 
 public partial class ApplicationImpl
 {
-    /// <summary>
-    ///     INTERNAL: Gets or sets the managed thread ID of the application's main UI thread, which is set during
-    ///     <see cref="Init"/> and used to determine if code is executing on the main thread.
-    /// </summary>
-    /// <value>
-    ///     The managed thread ID of the main UI thread, or <see langword="null"/> if the application is not initialized.
-    /// </value>
-    internal int? MainThreadId { get; set; }
-
-    #region Begin->Run->Stop->End
-
-    // TODO: This API is not used anywhere; it can be deleted
-    /// <inheritdoc/>
-    public event EventHandler<SessionTokenEventArgs>? SessionBegun;
-
-    // TODO: This API is not used anywhere; it can be deleted
-    /// <inheritdoc/>
-    public event EventHandler<ToplevelEventArgs>? SessionEnded;
-
-    /// <inheritdoc/>
-    public SessionToken Begin (Toplevel toplevel)
-    {
-        ArgumentNullException.ThrowIfNull (toplevel);
-
-        // Ensure the mouse is ungrabbed.
-        if (Mouse.MouseGrabView is { })
-        {
-            Mouse.UngrabMouse ();
-        }
-
-        var rs = new SessionToken (toplevel);
-
-#if DEBUG_IDISPOSABLE
-        if (View.EnableDebugIDisposableAsserts && TopRunnable is { } && toplevel != TopRunnable && !SessionStack.Contains (TopRunnable))
-        {
-            // This assertion confirm if the TopRunnable was already disposed
-            Debug.Assert (TopRunnable.WasDisposed);
-            Debug.Assert (TopRunnable == CachedSessionTokenToplevel);
-        }
-#endif
-
-        lock (SessionStack)
-        {
-            if (TopRunnable is { } && toplevel != TopRunnable && !SessionStack.Contains (TopRunnable))
-            {
-                // If TopRunnable was already disposed and isn't on the Toplevels Stack,
-                // clean it up here if is the same as _CachedSessionTokenToplevel
-                if (TopRunnable == CachedSessionTokenToplevel)
-                {
-                    TopRunnable = null;
-                }
-                else
-                {
-                    // Probably this will never hit
-                    throw new ObjectDisposedException (TopRunnable.GetType ().FullName);
-                }
-            }
-
-            // BUGBUG: We should not depend on `Id` internally.
-            // BUGBUG: It is super unclear what this code does anyway.
-            if (string.IsNullOrEmpty (toplevel.Id))
-            {
-                var count = 1;
-                var id = (SessionStack.Count + count).ToString ();
-
-                while (SessionStack.Count > 0 && SessionStack.FirstOrDefault (x => x.Id == id) is { })
-                {
-                    count++;
-                    id = (SessionStack.Count + count).ToString ();
-                }
-
-                toplevel.Id = (SessionStack.Count + count).ToString ();
-
-                SessionStack.Push (toplevel);
-            }
-            else
-            {
-                Toplevel? dup = SessionStack.FirstOrDefault (x => x.Id == toplevel.Id);
-
-                if (dup is null)
-                {
-                    SessionStack.Push (toplevel);
-                }
-            }
-        }
-
-        if (TopRunnable is null)
-        {
-            toplevel.App = this;
-            TopRunnable = toplevel;
-        }
-
-        if ((TopRunnable?.Modal == false && toplevel.Modal)
-            || (TopRunnable?.Modal == false && !toplevel.Modal)
-            || (TopRunnable?.Modal == true && toplevel.Modal))
-        {
-            if (toplevel.Visible)
-            {
-                if (TopRunnable is { HasFocus: true })
-                {
-                    TopRunnable.HasFocus = false;
-                }
-
-                // Force leave events for any entered views in the old TopRunnable
-                if (Mouse.LastMousePosition is { })
-                {
-                    Mouse.RaiseMouseEnterLeaveEvents (Mouse.LastMousePosition!.Value, new ());
-                }
-
-                TopRunnable?.OnDeactivate (toplevel);
-                Toplevel previousTop = TopRunnable!;
-
-                TopRunnable = toplevel;
-                TopRunnable.App = this;
-                TopRunnable.OnActivate (previousTop);
-            }
-        }
-
-        // View implements ISupportInitializeNotification which is derived from ISupportInitialize
-        if (!toplevel.IsInitialized)
-        {
-            toplevel.BeginInit ();
-            toplevel.EndInit (); // Calls Layout
-        }
-
-        // Try to set initial focus to any TabStop
-        if (!toplevel.HasFocus)
-        {
-            toplevel.SetFocus ();
-        }
-
-        toplevel.OnLoaded ();
-
-        LayoutAndDraw (true);
-
-        if (PositionCursor ())
-        {
-            Driver?.UpdateCursor ();
-        }
-
-        SessionBegun?.Invoke (this, new (rs));
-
-        return rs;
-    }
+    // Lock object to protect session stack operations and cached state updates
+    private readonly object _sessionStackLock = new ();
 
-    /// <inheritdoc/>
-    public bool StopAfterFirstIteration { get; set; }
+    #region Session State - Stack and TopRunnable
 
     /// <inheritdoc/>
-    public void RaiseIteration ()
-    {
-        Iteration?.Invoke (null, new ());
-    }
+    public ConcurrentStack<SessionToken>? SessionStack { get; } = new ();
 
     /// <inheritdoc/>
-    public event EventHandler<IterationEventArgs>? Iteration;
+    public IRunnable? TopRunnable { get; private set; }
 
     /// <inheritdoc/>
-    [RequiresUnreferencedCode ("AOT")]
-    [RequiresDynamicCode ("AOT")]
-    public Toplevel Run (Func<Exception, bool>? errorHandler = null, string? driverName = null) => Run<Toplevel> (errorHandler, driverName);
+    public View? TopRunnableView => TopRunnable as View;
 
     /// <inheritdoc/>
-    [RequiresUnreferencedCode ("AOT")]
-    [RequiresDynamicCode ("AOT")]
-    public TView Run<TView> (Func<Exception, bool>? errorHandler = null, string? driverName = null)
-        where TView : Toplevel, new ()
-    {
-        if (!Initialized)
-        {
-            // Init() has NOT been called. Auto-initialize as per interface contract.
-            Init (driverName);
-        }
-
-        TView top = new ();
-        Run (top, errorHandler);
-
-        return top;
-    }
+    public event EventHandler<SessionTokenEventArgs>? SessionBegun;
 
     /// <inheritdoc/>
-    public void Run (Toplevel view, Func<Exception, bool>? errorHandler = null)
-    {
-        Logging.Information ($"Run '{view}'");
-        ArgumentNullException.ThrowIfNull (view);
-
-        if (!Initialized)
-        {
-            throw new NotInitializedException (nameof (Run));
-        }
-
-        if (Driver == null)
-        {
-            throw new InvalidOperationException ("Driver was inexplicably null when trying to Run view");
-        }
-
-        TopRunnable = view;
+    public event EventHandler<SessionTokenEventArgs>? SessionEnded;
 
-        SessionToken rs = Begin (view);
+    #endregion Session State - Stack and TopRunnable
 
-        TopRunnable.Running = true;
-
-        var firstIteration = true;
-
-        while (SessionStack.TryPeek (out Toplevel? found) && found == view && view.Running)
-        {
-            if (Coordinator is null)
-            {
-                throw new ($"{nameof (IMainLoopCoordinator)} inexplicably became null during Run");
-            }
-
-            Coordinator.RunIteration ();
-
-            if (StopAfterFirstIteration && firstIteration)
-            {
-                Logging.Information ("Run - Stopping after first iteration as requested");
-                RequestStop ((Toplevel?)view);
-            }
-
-            firstIteration = false;
-        }
-
-        Logging.Information ("Run - Calling End");
-        End (rs);
-    }
+    #region Main Loop Iteration
 
     /// <inheritdoc/>
-    public void End (SessionToken sessionToken)
-    {
-        ArgumentNullException.ThrowIfNull (sessionToken);
-
-        if (Popover?.GetActivePopover () as View is { Visible: true } visiblePopover)
-        {
-            ApplicationPopover.HideWithQuitCommand (visiblePopover);
-        }
-
-        sessionToken.Toplevel?.OnUnloaded ();
-
-        // End the Session
-        // First, take it off the Toplevel Stack
-        if (SessionStack.TryPop (out Toplevel? topOfStack))
-        {
-            if (topOfStack != sessionToken.Toplevel)
-            {
-                // If the top of the stack is not the SessionToken.Toplevel then
-                // this call to End is not balanced with the call to Begin that started the Session
-                throw new ArgumentException ("End must be balanced with calls to Begin");
-            }
-        }
-
-        // Notify that it is closing
-        sessionToken.Toplevel?.OnClosed (sessionToken.Toplevel);
-
-        if (SessionStack.TryPeek (out Toplevel? newTop))
-        {
-            newTop.App = this;
-            TopRunnable = newTop;
-            TopRunnable?.SetNeedsDraw ();
-        }
-
-        if (sessionToken.Toplevel is { HasFocus: true })
-        {
-            sessionToken.Toplevel.HasFocus = false;
-        }
-
-        if (TopRunnable is { HasFocus: false })
-        {
-            TopRunnable.SetFocus ();
-        }
-
-        CachedSessionTokenToplevel = sessionToken.Toplevel;
-
-        sessionToken.Toplevel = null;
-        sessionToken.Dispose ();
-
-        // BUGBUG: Why layout and draw here? This causes the screen to be cleared!
-        //LayoutAndDraw (true);
-
-        // TODO: This API is not used (correctly) anywhere; it can be deleted
-        // TODO: Instead, callers should use the new equivalent of Toplevel.Ready 
-        // TODO: which will be IsRunningChanged with newIsRunning == true
-        SessionEnded?.Invoke (this, new (CachedSessionTokenToplevel));
-    }
+    public bool StopAfterFirstIteration { get; set; }
 
     /// <inheritdoc/>
-    public void RequestStop () { RequestStop ((Toplevel?)null); }
+    public event EventHandler<EventArgs<IApplication?>>? Iteration;
 
     /// <inheritdoc/>
-    public void RequestStop (Toplevel? top)
-    {
-        Logging.Trace ($"TopRunnable: '{(top is { } ? top : "null")}'");
-
-        top ??= TopRunnable;
-
-        if (top == null)
-        {
-            return;
-        }
+    public void RaiseIteration () { Iteration?.Invoke (null, new (this)); }
 
-        ToplevelClosingEventArgs ev = new (top);
-        top.OnClosing (ev);
-
-        if (ev.Cancel)
-        {
-            return;
-        }
-
-        top.Running = false;
-    }
-
-    #endregion Begin->Run->Stop->End
+    #endregion Main Loop Iteration
 
     #region Timeouts and Invoke
 
@@ -334,7 +57,7 @@ public partial class ApplicationImpl
     public void Invoke (Action<IApplication>? action)
     {
         // If we are already on the main UI thread
-        if (TopRunnable is { Running: true } && MainThreadId == Thread.CurrentThread.ManagedThreadId)
+        if (TopRunnableView is IRunnable { IsRunning: true } && MainThreadId == Thread.CurrentThread.ManagedThreadId)
         {
             action?.Invoke (this);
 
@@ -356,7 +79,7 @@ public partial class ApplicationImpl
     public void Invoke (Action action)
     {
         // If we are already on the main UI thread
-        if (TopRunnable is { Running: true } && MainThreadId == Thread.CurrentThread.ManagedThreadId)
+        if (TopRunnableView is IRunnable { IsRunning: true } && MainThreadId == Thread.CurrentThread.ManagedThreadId)
         {
             action?.Invoke ();
 
@@ -376,126 +99,148 @@ public partial class ApplicationImpl
 
     #endregion Timeouts and Invoke
 
-    #region IRunnable Support
+    #region Session Lifecycle - Begin
 
     /// <inheritdoc/>
-    public RunnableSessionToken Begin (IRunnable runnable)
+    public SessionToken? Begin (IRunnable runnable)
     {
         ArgumentNullException.ThrowIfNull (runnable);
 
-        // Ensure the mouse is ungrabbed
-        if (Mouse.MouseGrabView is { })
+        if (runnable.IsRunning)
         {
-            Mouse.UngrabMouse ();
+            throw new ArgumentException (@"The runnable is already running.", nameof (runnable));
         }
 
         // Create session token
-        RunnableSessionToken token = new (runnable);
-
-        // Set the App property if the runnable is a View (needed for IsRunning/IsModal checks)
-        if (runnable is View runnableView)
-        {
-            runnableView.App = this;
-        }
+        SessionToken token = new (runnable);
 
-        // Get old IsRunning and IsModal values BEFORE any stack changes
+        // Get old IsRunning value BEFORE any stack changes (safe - cached value)
         bool oldIsRunning = runnable.IsRunning;
-        bool oldIsModalValue = runnable.IsModal;
 
-        // Raise IsRunningChanging (false -> true) - can be canceled
+        // Raise IsRunningChanging OUTSIDE lock (false -> true) - can be canceled
         if (runnable.RaiseIsRunningChanging (oldIsRunning, true))
         {
             // Starting was canceled
-            return token;
+            return null;
         }
 
-        // Push token onto RunnableSessionStack (IsRunning becomes true)
-        RunnableSessionStack?.Push (token);
+        // Set the application reference in the runnable
+        runnable.SetApp (this);
+
+        // Ensure the mouse is ungrabbed
+        Mouse.UngrabMouse ();
 
-        // Update TopRunnable to the new top of stack
         IRunnable? previousTop = null;
 
-        // In Phase 1, Toplevel doesn't implement IRunnable yet
-        // In Phase 2, it will, and this will work properly
-        if (TopRunnable is IRunnable r)
+        // CRITICAL SECTION - Atomic stack + cached state update
+        lock (_sessionStackLock)
         {
-            previousTop = r;
-        }
+            // Get the previous top BEFORE pushing new token
+            if (SessionStack?.TryPeek (out SessionToken? previousToken) == true && previousToken?.Runnable is { })
+            {
+                previousTop = previousToken.Runnable;
+            }
 
-        // Set TopRunnable (handles both Toplevel and IRunnable)
-        if (runnable is Toplevel tl)
-        {
-            TopRunnable = tl;
-        }
-        else if (runnable is View v)
-        {
-            // For now, we can't set a non-Toplevel View as TopRunnable
-            // This is a limitation of the current architecture
-            // In Phase 2, we'll make TopRunnable an IRunnable property
-            Logging.Warning ($"WIP on Issue #4148 - Runnable '{runnable}' is a View but not a Toplevel; cannot set as TopRunnable");
+            if (previousTop == runnable)
+            {
+                throw new ArgumentOutOfRangeException (nameof (runnable), runnable, @"Attempt to Run the runnable that's already the top runnable.");
+            }
+
+            // Push token onto SessionStack
+            SessionStack?.Push (token);
+
+            TopRunnable = runnable;
+
+            // Update cached state atomically - IsRunning and IsModal are now consistent
+            SessionBegun?.Invoke (this, new (token));
+            runnable.SetIsRunning (true);
+            runnable.SetIsModal (true);
+
+            // Previous top is no longer modal
+            if (previousTop != null)
+            {
+                previousTop.SetIsModal (false);
+            }
         }
 
-        // Raise IsRunningChanged (now true)
-        runnable.RaiseIsRunningChangedEvent (true);
+        // END CRITICAL SECTION - IsRunning/IsModal now thread-safe
 
-        // If there was a previous top, it's no longer modal
+        // Fire events AFTER lock released (avoid deadlocks in event handlers)
         if (previousTop != null)
         {
-            // Get old IsModal value (should be true before becoming non-modal)
-            bool oldIsModal = previousTop.IsModal;
-
-            // Raise IsModalChanging (true -> false)
-            previousTop.RaiseIsModalChanging (oldIsModal, false);
-
-            // IsModal is now false (derived property)
             previousTop.RaiseIsModalChangedEvent (false);
         }
 
-        // New runnable becomes modal
-        // Raise IsModalChanging (false -> true) using the old value we captured earlier
-        runnable.RaiseIsModalChanging (oldIsModalValue, true);
-
-        // IsModal is now true (derived property)
+        runnable.RaiseIsRunningChangedEvent (true);
         runnable.RaiseIsModalChangedEvent (true);
 
-        // Initialize if needed
-        if (runnable is View view && !view.IsInitialized)
-        {
-            view.BeginInit ();
-            view.EndInit ();
+        LayoutAndDraw ();
 
-            // Initialized event is raised by View.EndInit()
-        }
+        return token;
+    }
+
+    #endregion Session Lifecycle - Begin
 
-        // Initial Layout and draw
-        LayoutAndDraw (true);
+    #region Session Lifecycle - Run
+
+    /// <inheritdoc/>
+    [RequiresUnreferencedCode ("AOT")]
+    [RequiresDynamicCode ("AOT")]
+    public IApplication Run<TRunnable> (Func<Exception, bool>? errorHandler = null, string? driverName = null)
+        where TRunnable : IRunnable, new()
+    {
+        if (!Initialized)
+        {
+            // Init() has NOT been called. Auto-initialize as per interface contract.
+            Init (driverName);
+        }
 
-        // Set focus
-        if (runnable is View viewToFocus && !viewToFocus.HasFocus)
+        if (Driver is null)
         {
-            viewToFocus.SetFocus ();
+            throw new InvalidOperationException (@"Driver is null after Init.");
         }
 
-        if (PositionCursor ())
+        TRunnable runnable = new ();
+        object? result = Run (runnable, errorHandler);
+
+        // We created the runnable, so dispose it if it's disposable
+        if (runnable is IDisposable disposable)
         {
-            Driver?.UpdateCursor ();
+            disposable.Dispose ();
         }
 
-        return token;
+        return this;
     }
 
     /// <inheritdoc/>
-    public void Run (IRunnable runnable, Func<Exception, bool>? errorHandler = null)
+    public object? Run (IRunnable runnable, Func<Exception, bool>? errorHandler = null)
     {
         ArgumentNullException.ThrowIfNull (runnable);
 
         if (!Initialized)
         {
-            throw new NotInitializedException (nameof (Run));
+            throw new NotInitializedException (@"Init must be called before Run.");
         }
 
         // Begin the session (adds to stack, raises IsRunningChanging/IsRunningChanged)
-        RunnableSessionToken token = Begin (runnable);
+        SessionToken? token;
+
+        if (runnable.IsRunning)
+        {
+            // Find it on the stack
+            token = SessionStack?.FirstOrDefault (st => st.Runnable == runnable);
+        }
+        else
+        {
+            token = Begin (runnable);
+        }
+
+        if (token is null)
+        {
+            Logging.Trace (@"Run - Begin session failed or was cancelled.");
+
+            return null;
+        }
 
         try
         {
@@ -507,33 +252,19 @@ public partial class ApplicationImpl
             // End the session (raises IsRunningChanging/IsRunningChanged, pops from stack)
             End (token);
         }
-    }
 
-    /// <inheritdoc/>
-    public IApplication Run<TRunnable> (Func<Exception, bool>? errorHandler = null) where TRunnable : IRunnable, new ()
-    {
-        if (!Initialized)
-        {
-            throw new NotInitializedException (nameof (Run));
-        }
-
-        TRunnable runnable = new ();
-        
-        // Store the runnable for automatic disposal by Shutdown
-        FrameworkOwnedRunnable = runnable;
-        
-        Run (runnable, errorHandler);
-
-        return this;
+        return token.Result;
     }
 
     private void RunLoop (IRunnable runnable, Func<Exception, bool>? errorHandler)
     {
+        runnable.StopRequested = false;
+
         // Main loop - blocks until RequestStop() is called
-        // Note: IsRunning is a derived property (stack.Contains), so we check it each iteration
+        // Note: IsRunning is now a cached property, safe to check each iteration
         var firstIteration = true;
 
-        while (runnable.IsRunning)
+        while (runnable is { StopRequested: false, IsRunning: true })
         {
             if (Coordinator is null)
             {
@@ -563,8 +294,12 @@ public partial class ApplicationImpl
         }
     }
 
+    #endregion Session Lifecycle - Run
+
+    #region Session Lifecycle - End
+
     /// <inheritdoc/>
-    public void End (RunnableSessionToken token)
+    public void End (SessionToken token)
     {
         ArgumentNullException.ThrowIfNull (token);
 
@@ -573,76 +308,84 @@ public partial class ApplicationImpl
             return; // Already ended
         }
 
+        // TODO: Move Poppover to utilize IRunnable arch; Get all refs to anyting
+        // TODO: View-related out of ApplicationImpl.
+        if (Popover?.GetActivePopover () as View is { Visible: true } visiblePopover)
+        {
+            ApplicationPopover.HideWithQuitCommand (visiblePopover);
+        }
+
         IRunnable runnable = token.Runnable;
 
-        // Get old IsRunning value (should be true before stopping)
+        // Get old IsRunning value (safe - cached value)
         bool oldIsRunning = runnable.IsRunning;
 
-        // Raise IsRunningChanging (true -> false) - can be canceled
+        // Raise IsRunningChanging OUTSIDE lock (true -> false) - can be canceled
         // This is where Result should be extracted!
         if (runnable.RaiseIsRunningChanging (oldIsRunning, false))
         {
-            // Stopping was canceled
+            // Stopping was canceled - do not proceed with End
             return;
         }
 
-        // Current runnable is no longer modal
-        // Get old IsModal value (should be true before becoming non-modal)
-        bool oldIsModal = runnable.IsModal;
-
-        // Raise IsModalChanging (true -> false)
-        runnable.RaiseIsModalChanging (oldIsModal, false);
+        bool wasModal = runnable.IsModal;
+        IRunnable? previousRunnable = null;
 
-        // IsModal is now false (will be false after pop)
-        runnable.RaiseIsModalChangedEvent (false);
-
-        // Pop token from RunnableSessionStack (IsRunning becomes false)
-        if (RunnableSessionStack?.TryPop (out RunnableSessionToken? popped) == true && popped == token)
+        // CRITICAL SECTION - Atomic stack + cached state update
+        lock (_sessionStackLock)
         {
-            // Restore previous top runnable
-            if (RunnableSessionStack?.TryPeek (out RunnableSessionToken? previousToken) == true && previousToken?.Runnable is { })
+            // Pop token from SessionStack
+            if (wasModal && SessionStack?.TryPop (out SessionToken? popped) == true && popped == token)
             {
-                IRunnable? previousRunnable = previousToken.Runnable;
-
-                // Update TopRunnable if it's a Toplevel
-                if (previousRunnable is Toplevel tl)
+                // Restore previous top runnable
+                if (SessionStack?.TryPeek (out SessionToken? previousToken) == true && previousToken?.Runnable is { })
                 {
-                    TopRunnable = tl;
+                    previousRunnable = previousToken.Runnable;
+
+                    // Previous runnable becomes modal again
+                    previousRunnable.SetIsModal (true);
                 }
+            }
 
-                // Previous runnable becomes modal again
-                // Get old IsModal value (should be false before becoming modal again)
-                bool oldIsModalValue = previousRunnable.IsModal;
+            // Update cached state atomically - IsRunning and IsModal are now consistent
+            runnable.SetIsRunning (false);
+            runnable.SetIsModal (false);
+        }
 
-                // Raise IsModalChanging (false -> true)
-                previousRunnable.RaiseIsModalChanging (oldIsModalValue, true);
+        // END CRITICAL SECTION - IsRunning/IsModal now thread-safe
 
-                // IsModal is now true (derived property)
-                previousRunnable.RaiseIsModalChangedEvent (true);
-            }
-            else
-            {
-                // No more runnables, clear TopRunnable
-                if (TopRunnable is IRunnable)
-                {
-                    TopRunnable = null;
-                }
-            }
+        // Fire events AFTER lock released
+        if (wasModal)
+        {
+            runnable.RaiseIsModalChangedEvent (false);
         }
 
-        // Raise IsRunningChanged (now false)
-        runnable.RaiseIsRunningChangedEvent (false);
+        TopRunnable = null;
 
-        // Set focus to new TopRunnable if exists
-        if (TopRunnable is View viewToFocus && !viewToFocus.HasFocus)
+        if (previousRunnable != null)
         {
-            viewToFocus.SetFocus ();
+            TopRunnable = previousRunnable;
+            previousRunnable.RaiseIsModalChangedEvent (true);
         }
 
-        // Clear the token
+        runnable.RaiseIsRunningChangedEvent (false);
+
+        token.Result = runnable.Result;
+
+        _result = token.Result;
+
+        // Clear the Runnable from the token
         token.Runnable = null;
+        SessionEnded?.Invoke (this, new (token));
     }
 
+    #endregion Session Lifecycle - End
+
+    #region Session Lifecycle - RequestStop
+
+    /// <inheritdoc/>
+    public void RequestStop () { RequestStop (null); }
+
     /// <inheritdoc/>
     public void RequestStop (IRunnable? runnable)
     {
@@ -650,7 +393,7 @@ public partial class ApplicationImpl
         if (runnable is null)
         {
             // Try to get from TopRunnable
-            if (TopRunnable is IRunnable r)
+            if (TopRunnableView is IRunnable r)
             {
                 runnable = r;
             }
@@ -660,15 +403,11 @@ public partial class ApplicationImpl
             }
         }
 
-        // For Toplevel, use the existing mechanism
-        if (runnable is Toplevel toplevel)
-        {
-            RequestStop (toplevel);
-        }
+        runnable.StopRequested = true;
 
         // Note: The End() method will be called from the finally block in Run()
         // and that's where IsRunningChanging/IsRunningChanged will be raised
     }
 
-    #endregion IRunnable Support
+    #endregion Session Lifecycle - RequestStop
 }

+ 11 - 11
Terminal.Gui/App/ApplicationImpl.Screen.cs

@@ -126,9 +126,8 @@ public partial class ApplicationImpl
     }
 
     /// <summary>
-    ///     INTERNAL: Called when the application's size has changed. Sets the size of all <see cref="Toplevel"/>s and fires
-    ///     the
-    ///     <see cref="ScreenChanged"/> event.
+    ///     INTERNAL: Called when the application's screen has changed.
+    ///     Raises the <see cref="ScreenChanged"/> event.
     /// </summary>
     /// <param name="screen">The new screen size and position.</param>
     private void RaiseScreenChangedEvent (Rectangle screen)
@@ -137,13 +136,13 @@ public partial class ApplicationImpl
 
         ScreenChanged?.Invoke (this, new (screen));
 
-        foreach (Toplevel t in SessionStack)
+        foreach (SessionToken t in SessionStack!)
         {
-            t.OnSizeChanging (new (screen.Size));
-            t.SetNeedsLayout ();
+            if (t.Runnable is View runnableView)
+            {
+                runnableView.SetNeedsLayout ();
+            }
         }
-
-        LayoutAndDraw (true);
     }
 
     private void Driver_SizeChanged (object? sender, SizeChangedEventArgs e) { RaiseScreenChangedEvent (new (new (0, 0), e.Size!.Value)); }
@@ -151,7 +150,7 @@ public partial class ApplicationImpl
     /// <inheritdoc/>
     public void LayoutAndDraw (bool forceRedraw = false)
     {
-        List<View> tops = [.. SessionStack];
+        List<View?> tops = [.. SessionStack!.Select(r => r.Runnable! as View)!];
 
         if (Popover?.GetActivePopover () as View is { Visible: true } visiblePopover)
         {
@@ -160,7 +159,7 @@ public partial class ApplicationImpl
             tops.Insert (0, visiblePopover);
         }
 
-        bool neededLayout = View.Layout (tops.ToArray ().Reverse (), Screen.Size);
+        bool neededLayout = View.Layout (tops.ToArray ().Reverse ()!, Screen.Size);
 
         if (ClearScreenNextIteration)
         {
@@ -176,7 +175,8 @@ public partial class ApplicationImpl
         if (Driver is { })
         {
             Driver.Clip = new (Screen);
-            View.Draw (tops, neededLayout || forceRedraw);
+
+            View.Draw (views: tops!, neededLayout || forceRedraw);
             Driver.Clip = new (Screen);
             Driver?.Refresh ();
         }

+ 150 - 55
Terminal.Gui/App/ApplicationImpl.cs

@@ -9,23 +9,65 @@ namespace Terminal.Gui.App;
 public partial class ApplicationImpl : IApplication
 {
     /// <summary>
-    ///     INTERNAL: Creates a new instance of the Application backend.
+    ///     INTERNAL: Creates a new instance of the Application backend and subscribes to Application configuration property
+    ///     events.
     /// </summary>
-    internal ApplicationImpl () { }
+    internal ApplicationImpl ()
+    {
+        // Subscribe to Application static property change events
+        Application.Force16ColorsChanged += OnForce16ColorsChanged;
+        Application.ForceDriverChanged += OnForceDriverChanged;
+    }
 
     /// <summary>
     ///     INTERNAL: Creates a new instance of the Application backend.
     /// </summary>
     /// <param name="componentFactory"></param>
-    internal ApplicationImpl (IComponentFactory componentFactory) { _componentFactory = componentFactory; }
+    internal ApplicationImpl (IComponentFactory componentFactory) : this () { _componentFactory = componentFactory; }
+
+    private string? _driverName;
+
+    /// <inheritdoc/>
+    public new string ToString () => Driver?.ToString () ?? string.Empty;
+
+    #region Singleton - Legacy Static Support
+
+    /// <summary>
+    ///     Lock object for synchronizing access to ModelUsage and _instance.
+    /// </summary>
+    private static readonly object _modelUsageLock = new ();
 
-    #region Singleton
+    /// <summary>
+    ///     Tracks which application model has been used in this process.
+    /// </summary>
+    public static ApplicationModelUsage ModelUsage { get; private set; } = ApplicationModelUsage.None;
+
+    /// <summary>
+    ///     Error message for when trying to use modern model after legacy static model.
+    /// </summary>
+    internal const string ERROR_MODERN_AFTER_LEGACY =
+        "Cannot use modern instance-based model (Application.Create) after using legacy static Application model (Application.Init/ApplicationImpl.Instance). "
+        + "Use only one model per process.";
+
+    /// <summary>
+    ///     Error message for when trying to use legacy static model after modern model.
+    /// </summary>
+    internal const string ERROR_LEGACY_AFTER_MODERN =
+        "Cannot use legacy static Application model (Application.Init/ApplicationImpl.Instance) after using modern instance-based model (Application.Create). "
+        + "Use only one model per process.";
 
     /// <summary>
     ///     Configures the singleton instance of <see cref="Application"/> to use the specified backend implementation.
     /// </summary>
     /// <param name="app"></param>
-    public static void SetInstance (IApplication? app) { _instance = app; }
+    public static void SetInstance (IApplication? app)
+    {
+        lock (_modelUsageLock)
+        {
+            ModelUsage = ApplicationModelUsage.LegacyStatic;
+            _instance = app;
+        }
+    }
 
     // Private static readonly Lazy instance of Application
     private static IApplication? _instance;
@@ -33,35 +75,104 @@ public partial class ApplicationImpl : IApplication
     /// <summary>
     ///     Gets the currently configured backend implementation of <see cref="Application"/> gateway methods.
     /// </summary>
-    public static IApplication Instance => _instance ??= new ApplicationImpl ();
-
-    #endregion Singleton
-
-    private string? _driverName;
-
-    #region Input
+    public static IApplication Instance
+    {
+        get
+        {
+            //Debug.Fail ("ApplicationImpl.Instance accessed - parallelizable tests should not use legacy static Application model");
 
-    private IMouse? _mouse;
+            // Thread-safe: Use lock to make check-and-create atomic
+            lock (_modelUsageLock)
+            {
+                // If an instance already exists, return it without fence checking
+                // This allows for cleanup/reset operations
+                if (_instance is { })
+                {
+                    return _instance;
+                }
+
+                // Check if the instance-based model has already been used
+                if (ModelUsage == ApplicationModelUsage.InstanceBased)
+                {
+                    throw new InvalidOperationException (ERROR_LEGACY_AFTER_MODERN);
+                }
+
+                // Mark the usage and create the instance
+                ModelUsage = ApplicationModelUsage.LegacyStatic;
+
+                return _instance = new ApplicationImpl ();
+            }
+        }
+    }
 
     /// <summary>
-    ///     Handles mouse event state and processing.
+    ///     INTERNAL: Marks that the instance-based model has been used. Called by Application.Create().
     /// </summary>
-    public IMouse Mouse
+    internal static void MarkInstanceBasedModelUsed ()
     {
-        get
+        lock (_modelUsageLock)
         {
-            _mouse ??= new MouseImpl { App = this };
+            // Check if the legacy static model has already been initialized
+            if (ModelUsage == ApplicationModelUsage.LegacyStatic && _instance?.Initialized == true)
+            {
+                throw new InvalidOperationException (ERROR_MODERN_AFTER_LEGACY);
+            }
 
-            return _mouse;
+            ModelUsage = ApplicationModelUsage.InstanceBased;
         }
-        set => _mouse = value ?? throw new ArgumentNullException (nameof (value));
     }
 
-    private IKeyboard? _keyboard;
+    /// <summary>
+    ///     INTERNAL: Resets the model usage tracking. Only for testing purposes.
+    /// </summary>
+    internal static void ResetModelUsageTracking ()
+    {
+        lock (_modelUsageLock)
+        {
+            ModelUsage = ApplicationModelUsage.None;
+            _instance = null;
+        }
+    }
 
     /// <summary>
-    ///     Handles keyboard input and key bindings at the Application level
+    ///     INTERNAL: Resets state without going through the fence-checked Instance property.
+    ///     Used by Application.ResetState() to allow cleanup regardless of which model was used.
     /// </summary>
+    internal static void ResetStateStatic (bool ignoreDisposed = false)
+    {
+        // If an instance exists, reset it
+        _instance?.ResetState (ignoreDisposed);
+
+        // Reset Application static properties to their defaults
+        // This ensures tests start with clean state
+        Application.ForceDriver = string.Empty;
+        Application.Force16Colors = false;
+        Application.IsMouseDisabled = false;
+        Application.QuitKey = Key.Esc;
+        Application.ArrangeKey = Key.F5.WithCtrl;
+        Application.NextTabGroupKey = Key.F6;
+        Application.NextTabKey = Key.Tab;
+        Application.PrevTabGroupKey = Key.F6.WithShift;
+        Application.PrevTabKey = Key.Tab.WithShift;
+
+        // Always reset the model tracking to allow tests to use either model after reset
+        ResetModelUsageTracking ();
+    }
+
+    #endregion Singleton - Legacy Static Support
+
+    #region Screen and Driver
+
+    /// <inheritdoc/>
+    public IClipboard? Clipboard => Driver?.Clipboard;
+
+    #endregion Screen and Driver
+
+    #region Keyboard
+
+    private IKeyboard? _keyboard;
+
+    /// <inheritdoc/>
     public IKeyboard Keyboard
     {
         get
@@ -73,24 +184,28 @@ public partial class ApplicationImpl : IApplication
         set => _keyboard = value ?? throw new ArgumentNullException (nameof (value));
     }
 
-    #endregion Input
+    #endregion Keyboard
 
-    #region View Management
+    #region Mouse
 
-    private ApplicationPopover? _popover;
+    private IMouse? _mouse;
 
     /// <inheritdoc/>
-    public ApplicationPopover? Popover
+    public IMouse Mouse
     {
         get
         {
-            _popover ??= new () { App = this };
+            _mouse ??= new MouseImpl { App = this };
 
-            return _popover;
+            return _mouse;
         }
-        set => _popover = value;
+        set => _mouse = value ?? throw new ArgumentNullException (nameof (value));
     }
 
+    #endregion Mouse
+
+    #region Navigation and Popover
+
     private ApplicationNavigation? _navigation;
 
     /// <inheritdoc/>
@@ -105,39 +220,19 @@ public partial class ApplicationImpl : IApplication
         set => _navigation = value ?? throw new ArgumentNullException (nameof (value));
     }
 
-    private Toplevel? _topRunnable;
+    private ApplicationPopover? _popover;
 
     /// <inheritdoc/>
-    public Toplevel? TopRunnable
+    public ApplicationPopover? Popover
     {
-        get => _topRunnable;
-        set
+        get
         {
-            _topRunnable = value;
+            _popover ??= new () { App = this };
 
-            if (_topRunnable is { })
-            {
-                _topRunnable.App = this;
-            }
+            return _popover;
         }
+        set => _popover = value;
     }
 
-    // BUGBUG: Technically, this is not the full lst of sessions. There be dragons here, e.g. see how Toplevel.Id is used. What
-
-    /// <inheritdoc/>
-    public ConcurrentStack<Toplevel> SessionStack { get; } = new ();
-
-    /// <inheritdoc/>
-    public Toplevel? CachedSessionTokenToplevel { get; set; }
-
-    /// <inheritdoc/>
-    public ConcurrentStack<RunnableSessionToken>? RunnableSessionStack { get; } = new ();
-
-    /// <inheritdoc/>
-    public IRunnable? FrameworkOwnedRunnable { get; set; }
-
-    #endregion View Management
-
-    /// <inheritdoc/>
-    public new string ToString () => Driver?.ToString () ?? string.Empty;
+    #endregion Navigation and Popover
 }

+ 16 - 0
Terminal.Gui/App/ApplicationModelUsage.cs

@@ -0,0 +1,16 @@
+namespace Terminal.Gui.App;
+
+/// <summary>
+///     Defines the different application usage models.
+/// </summary>
+public enum ApplicationModelUsage
+{
+    /// <summary>No model has been used yet.</summary>
+    None,
+
+    /// <summary>Legacy static model (Application.Init/ApplicationImpl.Instance).</summary>
+    LegacyStatic,
+
+    /// <summary>Modern instance-based model (Application.Create).</summary>
+    InstanceBased
+}

部分文件因为文件数量过多而无法显示