Tig 2 viikkoa sitten
vanhempi
sitoutus
d9899dcf1e
100 muutettua tiedostoa jossa 1998 lisäystä ja 1062 poistoa
  1. 74 28
      .github/workflows/unit-tests.yml
  2. 1 0
      .gitignore
  3. 2 2
      Examples/Example/Example.cs
  4. 2 2
      Examples/NativeAot/Program.cs
  5. 30 27
      Examples/RunnableWrapperExample/Program.cs
  6. 2 2
      Examples/SelfContained/Program.cs
  7. 3 3
      Examples/UICatalog/Scenario.cs
  8. 8 8
      Examples/UICatalog/Scenarios/Adornments.cs
  9. 1 1
      Examples/UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs
  10. 5 5
      Examples/UICatalog/Scenarios/Bars.cs
  11. 3 3
      Examples/UICatalog/Scenarios/Buttons.cs
  12. 3 2
      Examples/UICatalog/Scenarios/ChineseUI.cs
  13. 3 3
      Examples/UICatalog/Scenarios/ConfigurationEditor.cs
  14. 5 5
      Examples/UICatalog/Scenarios/ContextMenus.cs
  15. 15 15
      Examples/UICatalog/Scenarios/CsvEditor.cs
  16. 1 1
      Examples/UICatalog/Scenarios/Dialogs.cs
  17. 5 5
      Examples/UICatalog/Scenarios/DynamicStatusBar.cs
  18. 11 10
      Examples/UICatalog/Scenarios/Editor.cs
  19. 1 1
      Examples/UICatalog/Scenarios/EditorsAndHelpers/DimEditor.cs
  20. 1 1
      Examples/UICatalog/Scenarios/EditorsAndHelpers/PosEditor.cs
  21. 5 5
      Examples/UICatalog/Scenarios/FileDialogExamples.cs
  22. 1 1
      Examples/UICatalog/Scenarios/Generic.cs
  23. 4 4
      Examples/UICatalog/Scenarios/HexEditor.cs
  24. 3 3
      Examples/UICatalog/Scenarios/Images.cs
  25. 1 1
      Examples/UICatalog/Scenarios/InteractiveTree.cs
  26. 4 4
      Examples/UICatalog/Scenarios/KeyBindings.cs
  27. 1 1
      Examples/UICatalog/Scenarios/ListColumns.cs
  28. 9 9
      Examples/UICatalog/Scenarios/MessageBoxes.cs
  29. 1 1
      Examples/UICatalog/Scenarios/MultiColouredTable.cs
  30. 2 2
      Examples/UICatalog/Scenarios/Navigation.cs
  31. 8 8
      Examples/UICatalog/Scenarios/Notepad.cs
  32. 3 3
      Examples/UICatalog/Scenarios/RunTExample.cs
  33. 3 3
      Examples/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs
  34. 1 1
      Examples/UICatalog/Scenarios/Shortcuts.cs
  35. 4 4
      Examples/UICatalog/Scenarios/SingleBackgroundWorker.cs
  36. 7 7
      Examples/UICatalog/Scenarios/TableEditor.cs
  37. 2 2
      Examples/UICatalog/Scenarios/Transparent.cs
  38. 2 2
      Examples/UICatalog/Scenarios/ViewportSettings.cs
  39. 3 3
      Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs
  40. 6 3
      Examples/UICatalog/Scenarios/WizardAsView.cs
  41. 269 266
      Examples/UICatalog/Scenarios/Wizards.cs
  42. 1 0
      Examples/UICatalog/UICatalogTop.cs
  43. 15 0
      Terminal.Gui/App/Application.Clipboard.cs
  44. 21 15
      Terminal.Gui/App/Application.Driver.cs
  45. 17 4
      Terminal.Gui/App/Application.Lifecycle.cs
  46. 12 2
      Terminal.Gui/App/Application.Mouse.cs
  47. 49 9
      Terminal.Gui/App/Application.Navigation.cs
  48. 25 5
      Terminal.Gui/App/Application.Run.cs
  49. 1 1
      Terminal.Gui/App/Application.TopRunnable.cs
  50. 103 49
      Terminal.Gui/App/ApplicationImpl.Lifecycle.cs
  51. 2 11
      Terminal.Gui/App/ApplicationImpl.Run.cs
  52. 136 12
      Terminal.Gui/App/ApplicationImpl.cs
  53. 16 0
      Terminal.Gui/App/ApplicationModelUsage.cs
  54. 1 1
      Terminal.Gui/App/ApplicationNavigation.cs
  55. 1 1
      Terminal.Gui/App/ApplicationRunnableExtensions.cs
  56. 32 0
      Terminal.Gui/App/Clipboard/Clipboard.cs
  57. 27 4
      Terminal.Gui/App/IApplication.cs
  58. 0 5
      Terminal.Gui/App/IterationEventArgs.cs
  59. 110 55
      Terminal.Gui/App/Keyboard/KeyboardImpl.cs
  60. 27 4
      Terminal.Gui/App/Mouse/MouseImpl.cs
  61. 2 2
      Terminal.Gui/App/Runnable/IRunnable.cs
  62. 80 4
      Terminal.Gui/Configuration/ConfigurationManager.cs
  63. 5 7
      Terminal.Gui/Configuration/SourcesManager.cs
  64. 4 4
      Terminal.Gui/Drivers/FakeDriver/FakeInputProcessor.cs
  65. 9 6
      Terminal.Gui/Drivers/IInputProcessor.cs
  66. 1 1
      Terminal.Gui/Drivers/InputProcessorImpl.cs
  67. 10 8
      Terminal.Gui/Drivers/OutputBase.cs
  68. 1 1
      Terminal.Gui/Drivers/WindowsDriver/WindowsInputProcessor.cs
  69. 3 2
      Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs
  70. 6 3
      Terminal.Gui/FileServices/IFileOperations.cs
  71. 95 83
      Terminal.Gui/Input/InputBindings.cs
  72. 1 1
      Terminal.Gui/ViewBase/Runnable.cs
  73. 2 1
      Terminal.Gui/ViewBase/RunnableWrapper.cs
  74. 1 0
      Terminal.Gui/ViewBase/View.Diagnostics.cs
  75. 2 2
      Terminal.Gui/ViewBase/View.Drawing.Attribute.cs
  76. 13 3
      Terminal.Gui/Views/Button.cs
  77. 7 7
      Terminal.Gui/Views/CharMap/CharMap.cs
  78. 7 3
      Terminal.Gui/Views/CheckBox.cs
  79. 35 4
      Terminal.Gui/Views/CollectionNavigation/CollectionNavigator.cs
  80. 38 10
      Terminal.Gui/Views/CollectionNavigation/CollectionNavigatorBase.cs
  81. 2 2
      Terminal.Gui/Views/Color/ColorPicker.Prompt.cs
  82. 37 7
      Terminal.Gui/Views/Dialog.cs
  83. 9 9
      Terminal.Gui/Views/FileDialogs/DefaultFileOperations.cs
  84. 10 10
      Terminal.Gui/Views/FileDialogs/FileDialog.cs
  85. 9 5
      Terminal.Gui/Views/FrameView.cs
  86. 0 1
      Terminal.Gui/Views/GraphView/GraphView.cs
  87. 4 4
      Terminal.Gui/Views/Menu/MenuBar.cs
  88. 412 178
      Terminal.Gui/Views/MessageBox.cs
  89. 1 1
      Terminal.Gui/Views/Selectors/SelectorBase.cs
  90. 8 2
      Terminal.Gui/Views/StatusBar.cs
  91. 2 2
      Terminal.Gui/Views/TableView/TableView.cs
  92. 5 5
      Terminal.Gui/Views/TextInput/TextField.cs
  93. 4 4
      Terminal.Gui/Views/TextInput/TextView.cs
  94. 13 4
      Terminal.Gui/Views/Window.cs
  95. 1 1
      Terminal.Gui/Views/Wizard/Wizard.cs
  96. 12 11
      Tests/IntegrationTests/FluentTests/FileDialogFluentTests.cs
  97. 1 1
      Tests/IntegrationTests/FluentTests/GuiTestContextTests.cs
  98. 1 1
      Tests/StressTests/ScenariosStressTests.cs
  99. 1 6
      Tests/TerminalGuiFluentTesting/GuiTestContext.Input.cs
  100. 33 21
      Tests/TerminalGuiFluentTesting/GuiTestContext.cs

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

@@ -120,7 +120,7 @@ jobs:
       matrix:
       matrix:
         os: [ ubuntu-latest, windows-latest, macos-latest ]
         os: [ ubuntu-latest, windows-latest, macos-latest ]
 
 
-    timeout-minutes: 15
+    timeout-minutes: 60
     steps:
     steps:
 
 
     - name: Checkout code
     - name: Checkout code
@@ -154,35 +154,81 @@ jobs:
       shell: bash
       shell: bash
       run: echo "VSTEST_DUMP_PATH=logs/UnitTestsParallelizable/${{ runner.os }}/" >> $GITHUB_ENV
       run: echo "VSTEST_DUMP_PATH=logs/UnitTestsParallelizable/${{ runner.os }}/" >> $GITHUB_ENV
 
 
-    - name: Run UnitTestsParallelizable
+    - name: Run UnitTestsParallelizable (10 iterations with varying parallelization)
       shell: bash
       shell: bash
       run: |
       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 10 times with different parallelization settings to expose concurrency issues
+        for RUN in {1..10}; do
+          echo "============================================"
+          echo "Starting test run $RUN of 10"
+          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
     - name: Upload UnitTestsParallelizable Logs
       if: always()
       if: always()

+ 1 - 0
.gitignore

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

+ 2 - 2
Examples/Example/Example.cs

@@ -77,13 +77,13 @@ public class ExampleWindow : Window
                            {
                            {
                                if (userNameText.Text == "admin" && passwordText.Text == "password")
                                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;
                                    UserName = userNameText.Text;
                                    Application.RequestStop ();
                                    Application.RequestStop ();
                                }
                                }
                                else
                                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.
                                // When Accepting is handled, set e.Handled to true to prevent further processing.
                                e.Handled = true;
                                e.Handled = true;

+ 2 - 2
Examples/NativeAot/Program.cs

@@ -101,13 +101,13 @@ public class ExampleWindow : Window
         {
         {
             if (userNameText.Text == "admin" && passwordText.Text == "password")
             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;
                 UserName = userNameText.Text;
                 Application.RequestStop ();
                 Application.RequestStop ();
             }
             }
             else
             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.
             // Anytime Accepting is handled, make sure to set e.Handled to true.
             e.Handled = true;
             e.Handled = true;

+ 30 - 27
Examples/RunnableWrapperExample/Program.cs

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

+ 2 - 2
Examples/SelfContained/Program.cs

@@ -100,13 +100,13 @@ public class ExampleWindow : Window
                            {
                            {
                                if (userNameText.Text == "admin" && passwordText.Text == "password")
                                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;
                                    UserName = userNameText.Text;
                                    Application.RequestStop ();
                                    Application.RequestStop ();
                                }
                                }
                                else
                                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.
                                // When Accepting is handled, set e.Handled to true to prevent further processing.
                                e.Handled = true;
                                e.Handled = true;

+ 3 - 3
Examples/UICatalog/Scenario.cs

@@ -67,7 +67,7 @@ namespace UICatalog;
 ///         };
 ///         };
 /// 
 /// 
 ///         var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
 ///         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);
 ///         appWindow.Add (button);
 /// 
 /// 
 ///         // Run - Start the application.
 ///         // Run - Start the application.
@@ -210,12 +210,12 @@ public class Scenario : IDisposable
         void OnClearedContents (object? sender, EventArgs args) => BenchmarkResults.ClearedContentCount++;
         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++;
         BenchmarkResults.IterationCount++;
         if (BenchmarkResults.IterationCount > BENCHMARK_MAX_NATURAL_ITERATIONS + (_demoKeys!.Count * BENCHMARK_KEY_PACING))
         if (BenchmarkResults.IterationCount > BENCHMARK_MAX_NATURAL_ITERATIONS + (_demoKeys!.Count * BENCHMARK_KEY_PACING))
         {
         {
-            Application.RequestStop ();
+            a.Value?.RequestStop ();
         }
         }
     }
     }
 
 

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

@@ -11,7 +11,7 @@ public class Adornments : Scenario
     {
     {
         Application.Init ();
         Application.Init ();
 
 
-        Window app = new ()
+        Window appWindow = new ()
         {
         {
             Title = GetQuitKeyAndName (),
             Title = GetQuitKeyAndName (),
             BorderStyle = LineStyle.None
             BorderStyle = LineStyle.None
@@ -28,7 +28,7 @@ public class Adornments : Scenario
 
 
         editor.Border!.Thickness = new (1, 2, 1, 1);
         editor.Border!.Thickness = new (1, 2, 1, 1);
 
 
-        app.Add (editor);
+        appWindow.Add (editor);
 
 
         var window = new Window
         var window = new Window
         {
         {
@@ -38,7 +38,7 @@ public class Adornments : Scenario
             Width = Dim.Fill (Dim.Func (_ => editor.Frame.Width)),
             Width = Dim.Fill (Dim.Func (_ => editor.Frame.Width)),
             Height = Dim.Fill ()
             Height = Dim.Fill ()
         };
         };
-        app.Add (window);
+        appWindow.Add (window);
 
 
         var tf1 = new TextField { Width = 10, Text = "TextField" };
         var tf1 = new TextField { Width = 10, Text = "TextField" };
         var color = new ColorPicker16 { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd () };
         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!" };
         var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
 
 
         button.Accepting += (s, e) =>
         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
         var label = new TextView
         {
         {
@@ -121,7 +121,7 @@ public class Adornments : Scenario
                                       Text = "text (Y = 1)",
                                       Text = "text (Y = 1)",
                                       CanFocus = true
                                       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);
                                   window.Padding.Add (textFieldInPadding);
 
 
                                   var btnButtonInPadding = new Button
                                   var btnButtonInPadding = new Button
@@ -132,7 +132,7 @@ public class Adornments : Scenario
                                       CanFocus = true,
                                       CanFocus = true,
                                       HighlightStates = MouseState.None,
                                       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.BorderStyle = LineStyle.Dashed;
                                   btnButtonInPadding.Border!.Thickness = new (1, 1, 1, 1);
                                   btnButtonInPadding.Border!.Thickness = new (1, 1, 1, 1);
                                   window.Padding.Add (btnButtonInPadding);
                                   window.Padding.Add (btnButtonInPadding);
@@ -155,8 +155,8 @@ public class Adornments : Scenario
         editor.AutoSelectSuperView = window;
         editor.AutoSelectSuperView = window;
         editor.AutoSelectAdornments = true;
         editor.AutoSelectAdornments = true;
 
 
-        Application.Run (app);
-        app.Dispose ();
+        Application.Run (appWindow);
+        appWindow.Dispose ();
 
 
         Application.Shutdown ();
         Application.Shutdown ();
     }
     }

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

@@ -78,7 +78,7 @@ public class AnimationScenario : Scenario
         if (!f.Exists)
         if (!f.Exists)
         {
         {
             Debug.WriteLine ($"Could not find {f.FullName}");
             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;
             return;
         }
         }

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

@@ -309,7 +309,7 @@ public class Bars : Scenario
     //                                                  new TimeSpan (0),
     //                                                  new TimeSpan (0),
     //                                                  () =>
     //                                                  () =>
     //                                                  {
     //                                                  {
-    //                                                      MessageBox.Query ("File", "New");
+    //                                                      MessageBox.Query (App, "File", "New");
 
 
     //                                                      return false;
     //                                                      return false;
     //                                                  });
     //                                                  });
@@ -331,7 +331,7 @@ public class Bars : Scenario
     //                                               new TimeSpan (0),
     //                                               new TimeSpan (0),
     //                                               () =>
     //                                               () =>
     //                                               {
     //                                               {
-    //                                                   MessageBox.Query ("File", "Open");
+    //                                                   MessageBox.Query (App, "File", "Open");
 
 
     //                                                   return false;
     //                                                   return false;
     //                                               });
     //                                               });
@@ -353,7 +353,7 @@ public class Bars : Scenario
     //                                               new TimeSpan (0),
     //                                               new TimeSpan (0),
     //                                               () =>
     //                                               () =>
     //                                               {
     //                                               {
-    //                                                   MessageBox.Query ("File", "Save");
+    //                                                   MessageBox.Query (App, "File", "Save");
 
 
     //                                                   return false;
     //                                                   return false;
     //                                               });
     //                                               });
@@ -375,7 +375,7 @@ public class Bars : Scenario
     //                                                 new TimeSpan (0),
     //                                                 new TimeSpan (0),
     //                                                 () =>
     //                                                 () =>
     //                                                 {
     //                                                 {
-    //                                                     MessageBox.Query ("File", "Save As");
+    //                                                     MessageBox.Query (App, "File", "Save As");
 
 
     //                                                     return false;
     //                                                     return false;
     //                                                 });
     //                                                 });
@@ -555,7 +555,7 @@ public class Bars : Scenario
 
 
         return;
         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}"); }
 
 
     }
     }
 
 

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

@@ -59,7 +59,7 @@ public class Buttons : Scenario
 
 
                                     if (e.Handled)
                                     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);
         main.Add (swapButton);
@@ -69,7 +69,7 @@ public class Buttons : Scenario
             button.Accepting += (s, e) =>
             button.Accepting += (s, e) =>
                              {
                              {
                                  string btnText = button.Text;
                                  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;
                                  e.Handled = true;
                              };
                              };
         }
         }
@@ -112,7 +112,7 @@ public class Buttons : Scenario
                  );
                  );
         button.Accepting += (s, e) =>
         button.Accepting += (s, e) =>
                          {
                          {
-                             MessageBox.Query ("Message", "Question?", "Yes", "No");
+                             MessageBox.Query ((s as View)?.App, "Message", "Question?", "Yes", "No");
                              e.Handled = true;
                              e.Handled = true;
                          };
                          };
 
 

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

@@ -32,8 +32,9 @@ public class ChineseUI : Scenario
 
 
         btn.Accepting += (s, e) =>
         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?",
                                                          "Are you sure you want to quit ui?",
                                                          0,
                                                          0,
                                                          "Yes",
                                                          "Yes",

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

@@ -153,9 +153,9 @@ public class ConfigurationEditor : Scenario
                 continue;
                 continue;
             }
             }
 
 
-            int result = MessageBox.Query (
+            int? result = MessageBox.Query (editor?.App,
                                            "Save Changes",
                                            "Save Changes",
-                                           $"Save changes to {editor.FileInfo!.Name}",
+                                           $"Save changes to {editor?.FileInfo!.Name}",
                                            "_Yes",
                                            "_Yes",
                                            "_No",
                                            "_No",
                                            "_Cancel"
                                            "_Cancel"
@@ -164,7 +164,7 @@ public class ConfigurationEditor : Scenario
             switch (result)
             switch (result)
             {
             {
                 case 0:
                 case 0:
-                    editor.Save ();
+                    editor?.Save ();
 
 
                     break;
                     break;
 
 

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

@@ -49,7 +49,7 @@ public class ContextMenus : Scenario
             var text = "Context Menu";
             var text = "Context Menu";
             var width = 20;
             var width = 20;
 
 
-            CreateWinContextMenu ();
+            CreateWinContextMenu (ApplicationImpl.Instance);
 
 
             var label = new Label
             var label = new Label
             {
             {
@@ -108,7 +108,7 @@ public class ContextMenus : Scenario
         }
         }
     }
     }
 
 
-    private void CreateWinContextMenu ()
+    private void CreateWinContextMenu (IApplication? app)
     {
     {
         _winContextMenu = new (
         _winContextMenu = new (
                                [
                                [
@@ -122,7 +122,7 @@ public class ContextMenus : Scenario
                                    {
                                    {
                                        Title = "_Configuration...",
                                        Title = "_Configuration...",
                                        HelpText = "Show configuration",
                                        HelpText = "Show configuration",
-                                       Action = () => MessageBox.Query (
+                                       Action = () => MessageBox.Query (app,
                                                                         50,
                                                                         50,
                                                                         10,
                                                                         10,
                                                                         "Configuration",
                                                                         "Configuration",
@@ -140,7 +140,7 @@ public class ContextMenus : Scenario
                                                               Title = "_Setup...",
                                                               Title = "_Setup...",
                                                               HelpText = "Perform setup",
                                                               HelpText = "Perform setup",
                                                               Action = () => MessageBox
                                                               Action = () => MessageBox
-                                                                           .Query (
+                                                                           .Query (app,
                                                                                    50,
                                                                                    50,
                                                                                    10,
                                                                                    10,
                                                                                    "Setup",
                                                                                    "Setup",
@@ -154,7 +154,7 @@ public class ContextMenus : Scenario
                                                               Title = "_Maintenance...",
                                                               Title = "_Maintenance...",
                                                               HelpText = "Maintenance mode",
                                                               HelpText = "Maintenance mode",
                                                               Action = () => MessageBox
                                                               Action = () => MessageBox
-                                                                           .Query (
+                                                                           .Query (app,
                                                                                    50,
                                                                                    50,
                                                                                    10,
                                                                                    10,
                                                                                    "Maintenance",
                                                                                    "Maintenance",

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

@@ -215,7 +215,7 @@ public class CsvEditor : Scenario
                                       _tableView.Table.Columns
                                       _tableView.Table.Columns
                                      );
                                      );
 
 
-            int result = MessageBox.Query (
+            int? result = MessageBox.Query (ApplicationImpl.Instance,
                                            "Column Type",
                                            "Column Type",
                                            "Pick a data type for the column",
                                            "Pick a data type for the column",
                                            "Date",
                                            "Date",
@@ -225,7 +225,7 @@ public class CsvEditor : Scenario
                                            "Cancel"
                                            "Cancel"
                                           );
                                           );
 
 
-            if (result <= -1 || result >= 4)
+            if (result is null || result >= 4)
             {
             {
                 return;
                 return;
             }
             }
@@ -308,7 +308,7 @@ public class CsvEditor : Scenario
 
 
         if (_tableView.SelectedColumn == -1)
         if (_tableView.SelectedColumn == -1)
         {
         {
-            MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
 
 
             return;
             return;
         }
         }
@@ -320,7 +320,7 @@ public class CsvEditor : Scenario
         }
         }
         catch (Exception ex)
         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)
             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 ();
             _tableView.Update ();
@@ -388,7 +388,7 @@ public class CsvEditor : Scenario
 
 
         if (_tableView.SelectedColumn == -1)
         if (_tableView.SelectedColumn == -1)
         {
         {
-            MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
 
 
             return;
             return;
         }
         }
@@ -413,7 +413,7 @@ public class CsvEditor : Scenario
         }
         }
         catch (Exception ex)
         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)
         if (_tableView.SelectedRow == -1)
         {
         {
-            MessageBox.ErrorQuery ("No Rows", "No row selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Rows", "No row selected", "Ok");
 
 
             return;
             return;
         }
         }
@@ -446,7 +446,7 @@ public class CsvEditor : Scenario
                     return;
                     return;
                 }
                 }
 
 
-                object?[] arrayItems = currentRow.ItemArray;
+                object? [] arrayItems = currentRow.ItemArray;
                 _currentTable.Rows.Remove (currentRow);
                 _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
                 // 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)
         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)
         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;
             return true;
         }
         }
@@ -582,7 +582,7 @@ public class CsvEditor : Scenario
         }
         }
         catch (Exception ex)
         catch (Exception ex)
         {
         {
-            MessageBox.ErrorQuery (
+            MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                    "Open Failed",
                                    "Open Failed",
                                    $"Error on line {lineNumber}{Environment.NewLine}{ex.Message}",
                                    $"Error on line {lineNumber}{Environment.NewLine}{ex.Message}",
                                    "Ok"
                                    "Ok"
@@ -612,7 +612,7 @@ public class CsvEditor : Scenario
     {
     {
         if (_tableView?.Table is null || string.IsNullOrWhiteSpace (_currentFile) || _currentTable is null)
         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;
             return;
         }
         }
@@ -674,7 +674,7 @@ public class CsvEditor : Scenario
 
 
         if (col.DataType == typeof (string))
         if (col.DataType == typeof (string))
         {
         {
-            MessageBox.ErrorQuery (
+            MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                    "Cannot Format Column",
                                    "Cannot Format Column",
                                    "String columns cannot be Formatted, try adding a new column to the table with a date/numerical Type",
                                    "String columns cannot be Formatted, try adding a new column to the table with a date/numerical Type",
                                    "Ok"
                                    "Ok"
@@ -711,7 +711,7 @@ public class CsvEditor : Scenario
 
 
         if (_tableView.SelectedColumn == -1)
         if (_tableView.SelectedColumn == -1)
         {
         {
-            MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
 
 
             return;
             return;
         }
         }

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

@@ -266,7 +266,7 @@ public class Dialogs : Scenario
             {
             {
                 Title = titleEdit.Text,
                 Title = titleEdit.Text,
                 Text = "Dialog 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 ()
                 Buttons = buttons.ToArray ()
             };
             };

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

@@ -79,7 +79,7 @@ public class DynamicStatusBar : Scenario
             }
             }
             catch (Exception ex)
             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 TextView TextAction { get; }
         public TextField TextShortcut { get; }
         public TextField TextShortcut { get; }
         public TextField TextTitle { 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)
         public void EditStatusItem (Shortcut statusItem)
         {
         {
@@ -184,7 +184,7 @@ public class DynamicStatusBar : Scenario
                               {
                               {
                                   if (string.IsNullOrEmpty (TextTitle.Text))
                                   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
                                   else
                                   {
                                   {
@@ -200,7 +200,7 @@ public class DynamicStatusBar : Scenario
                                       TextTitle.Text = string.Empty;
                                       TextTitle.Text = string.Empty;
                                       Application.RequestStop ();
                                       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 ();
             Width = Dim.Fill ();
             Height = Dim.Fill () - 2;
             Height = Dim.Fill () - 2;
@@ -382,7 +382,7 @@ public class DynamicStatusBar : Scenario
                               {
                               {
                                   if (string.IsNullOrEmpty (frmStatusBarDetails.TextTitle.Text) && _currentEditStatusItem != null)
                                   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)
                                   else if (_currentEditStatusItem != null)
                                   {
                                   {

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

@@ -156,7 +156,7 @@ public class Editor : Scenario
                                        new (Key.F2, "Open", Open),
                                        new (Key.F2, "Open", Open),
                                        new (Key.F3, "Save", () => Save ()),
                                        new (Key.F3, "Save", () => Save ()),
                                        new (Key.F4, "Save As", () => SaveAs ()),
                                        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
                                        siCursorPosition
                                    ]
                                    ]
                                   )
                                   )
@@ -193,7 +193,8 @@ public class Editor : Scenario
 
 
         Debug.Assert (_textView.IsDirty);
         Debug.Assert (_textView.IsDirty);
 
 
-        int r = MessageBox.ErrorQuery (
+        int? r = MessageBox.ErrorQuery (
+                                       ApplicationImpl.Instance,
                                        "Save File",
                                        "Save File",
                                        $"Do you want save changes in {_appWindow.Title}?",
                                        $"Do you want save changes in {_appWindow.Title}?",
                                        "Yes",
                                        "Yes",
@@ -228,7 +229,7 @@ public class Editor : Scenario
         }
         }
         catch (Exception ex)
         catch (Exception ex)
         {
         {
-            MessageBox.ErrorQuery ("Error", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.Message, "Ok");
         }
         }
     }
     }
 
 
@@ -307,11 +308,11 @@ public class Editor : Scenario
 
 
         if (!found)
         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)
         else if (gaveFullTurn)
         {
         {
-            MessageBox.Query (
+            MessageBox.Query (ApplicationImpl.Instance,
                               "Find",
                               "Find",
                               $"No more occurrences were found for the following specified text: '{_textToFind}'",
                               $"No more occurrences were found for the following specified text: '{_textToFind}'",
                               "Ok"
                               "Ok"
@@ -887,7 +888,7 @@ public class Editor : Scenario
 
 
         if (_textView.ReplaceAllText (_textToFind, _matchCase, _matchWholeWord, _textToReplace))
         if (_textView.ReplaceAllText (_textToFind, _matchCase, _matchWholeWord, _textToReplace))
         {
         {
-            MessageBox.Query (
+            MessageBox.Query (ApplicationImpl.Instance,
                               "Replace All",
                               "Replace All",
                               $"All occurrences were replaced for the following specified text: '{_textToReplace}'",
                               $"All occurrences were replaced for the following specified text: '{_textToReplace}'",
                               "Ok"
                               "Ok"
@@ -895,7 +896,7 @@ public class Editor : Scenario
         }
         }
         else
         else
         {
         {
-            MessageBox.Query (
+            MessageBox.Query (ApplicationImpl.Instance,
                               "Replace All",
                               "Replace All",
                               $"None of the following specified text was found: '{_textToFind}'",
                               $"None of the following specified text was found: '{_textToFind}'",
                               "Ok"
                               "Ok"
@@ -1147,7 +1148,7 @@ public class Editor : Scenario
         {
         {
             if (File.Exists (path))
             if (File.Exists (path))
             {
             {
-                if (MessageBox.Query (
+                if (MessageBox.Query (ApplicationImpl.Instance,
                                       "Save File",
                                       "Save File",
                                       "File already exists. Overwrite any way?",
                                       "File already exists. Overwrite any way?",
                                       "No",
                                       "No",
@@ -1186,11 +1187,11 @@ public class Editor : Scenario
             _originalText = Encoding.Unicode.GetBytes (_textView.Text);
             _originalText = Encoding.Unicode.GetBytes (_textView.Text);
             _saved = true;
             _saved = true;
             _textView.ClearHistoryChanges ();
             _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)
         catch (Exception ex)
         {
         {
-            MessageBox.ErrorQuery ("Error", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.Message, "Ok");
 
 
             return false;
             return false;
         }
         }

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

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

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

@@ -133,7 +133,7 @@ public class FileDialogExamples : Scenario
                              }
                              }
                              catch (Exception ex)
                              catch (Exception ex)
                              {
                              {
-                                 MessageBox.ErrorQuery ("Error", ex.ToString (), "_Ok");
+                                 MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.ToString (), "_Ok");
                              }
                              }
                              finally
                              finally
                              {
                              {
@@ -153,7 +153,7 @@ public class FileDialogExamples : Scenario
         {
         {
             if (File.Exists (e.Dialog.Path))
             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;
                 e.Cancel = result == 1;
             }
             }
         }
         }
@@ -248,7 +248,7 @@ public class FileDialogExamples : Scenario
 
 
             if (canceled)
             if (canceled)
             {
             {
-                MessageBox.Query (
+                MessageBox.Query (ApplicationImpl.Instance,
                                   "Canceled",
                                   "Canceled",
                                   "You canceled navigation and did not pick anything",
                                   "You canceled navigation and did not pick anything",
                                   "Ok"
                                   "Ok"
@@ -256,7 +256,7 @@ public class FileDialogExamples : Scenario
             }
             }
             else if (_cbAllowMultipleSelection.CheckedState == CheckState.Checked)
             else if (_cbAllowMultipleSelection.CheckedState == CheckState.Checked)
             {
             {
-                MessageBox.Query (
+                MessageBox.Query (ApplicationImpl.Instance,
                                   "Chosen!",
                                   "Chosen!",
                                   "You chose:" + Environment.NewLine + string.Join (Environment.NewLine, multiSelected.Select (m => m)),
                                   "You chose:" + Environment.NewLine + string.Join (Environment.NewLine, multiSelected.Select (m => m)),
                                   "Ok"
                                   "Ok"
@@ -264,7 +264,7 @@ public class FileDialogExamples : Scenario
             }
             }
             else
             else
             {
             {
-                MessageBox.Query (
+                MessageBox.Query (ApplicationImpl.Instance,
                                   "Chosen!",
                                   "Chosen!",
                                   "You chose:" + Environment.NewLine + path,
                                   "You chose:" + Environment.NewLine + path,
                                   "Ok"
                                   "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.
                                 // When Accepting is handled, set e.Handled to true to prevent further processing.
                                 e.Handled = true;
                                 e.Handled = true;
-                                MessageBox.ErrorQuery ("Error", "You pressed the button!", "_Ok");
+                                MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", "You pressed the button!", "_Ok");
                             };
                             };
 
 
         appWindow.Add (button);
         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)
     private void CreateDemoFile (string fileName)
     {
     {
@@ -208,7 +208,7 @@ public class HexEditor : Scenario
         ms.Close ();
         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 ()
     private Stream LoadFile ()
     {
     {
@@ -216,7 +216,7 @@ public class HexEditor : Scenario
 
 
         if (!_saved && _hexView!.Edits.Count > 0 && _hexView.Source is {})
         if (!_saved && _hexView!.Edits.Count > 0 && _hexView.Source is {})
         {
         {
-            if (MessageBox.ErrorQuery (
+            if (MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                        "Save",
                                        "Save",
                                        "The changes were not saved. Want to open without saving?",
                                        "The changes were not saved. Want to open without saving?",
                                        "_Yes",
                                        "_Yes",
@@ -267,7 +267,7 @@ public class HexEditor : Scenario
         d.Dispose ();
         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 Quit () { Application.RequestStop (); }
 
 
     private void Save ()
     private void Save ()

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

@@ -183,7 +183,7 @@ public class Images : Scenario
 
 
         if (!_sixelSupportResult.SupportsTransparency)
         if (!_sixelSupportResult.SupportsTransparency)
         {
         {
-            if (MessageBox.Query (
+            if (MessageBox.Query (ApplicationImpl.Instance,
                                   "Transparency Not Supported",
                                   "Transparency Not Supported",
                                   "It looks like your terminal does not support transparent sixel backgrounds. Do you want to try anyway?",
                                   "It looks like your terminal does not support transparent sixel backgrounds. Do you want to try anyway?",
                                   "Yes",
                                   "Yes",
@@ -288,7 +288,7 @@ public class Images : Scenario
         }
         }
         catch (Exception ex)
         catch (Exception ex)
         {
         {
-            MessageBox.ErrorQuery ("Could not open file", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Could not open file", ex.Message, "Ok");
 
 
             return;
             return;
         }
         }
@@ -492,7 +492,7 @@ public class Images : Scenario
     {
     {
         if (_imageView.FullResImage == null)
         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;
             return;
         }
         }

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

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

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

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

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

@@ -336,7 +336,7 @@ public class ListColumns : Scenario
             }
             }
             catch (Exception ex)
             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");
             }
             }
         }
         }
     }
     }

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

@@ -251,7 +251,7 @@ public class MessageBoxes : Scenario
                                                {
                                                {
                                                    buttonPressedLabel.Text =
                                                    buttonPressedLabel.Text =
                                                        $"{MessageBox.Query (
                                                        $"{MessageBox.Query (
-                                                                             width,
+                                                                            ApplicationImpl.Instance, width,
                                                                              height,
                                                                              height,
                                                                              titleEdit.Text,
                                                                              titleEdit.Text,
                                                                              messageEdit.Text,
                                                                              messageEdit.Text,
@@ -263,14 +263,14 @@ public class MessageBoxes : Scenario
                                                else
                                                else
                                                {
                                                {
                                                    buttonPressedLabel.Text =
                                                    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 ()
                                                                                  )}";
                                                                                  )}";
                                                }
                                                }
                                            }
                                            }

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

@@ -99,7 +99,7 @@ public class MultiColouredTable : Scenario
             }
             }
             catch (Exception ex)
             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 ();
             _tableView.Update ();

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

@@ -59,7 +59,7 @@ public class Navigation : Scenario
             Y = 0,
             Y = 0,
             Title = $"TopButton _{GetNextHotKey ()}"
             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);
         testFrame.Add (button);
 
 
@@ -210,7 +210,7 @@ public class Navigation : Scenario
 
 
         return;
         return;
 
 
-        void OnApplicationIteration (object sender, IterationEventArgs args)
+        void OnApplicationIteration (object sender, EventArgs<IApplication> args)
         {
         {
             if (progressBar.Fraction == 1.0)
             if (progressBar.Fraction == 1.0)
             {
             {

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

@@ -71,7 +71,7 @@ public class Notepad : Scenario
                                        new MenuItem
                                        new MenuItem
                                        {
                                        {
                                            Title = "_About",
                                            Title = "_About",
-                                           Action = () => MessageBox.Query ("Notepad", "About Notepad...", "Ok")
+                                           Action = () => MessageBox.Query (ApplicationImpl.Instance,  "Notepad", "About Notepad...", "Ok")
                                        }
                                        }
                                    ]
                                    ]
                                   )
                                   )
@@ -193,15 +193,15 @@ public class Notepad : Scenario
 
 
         if (tab.UnsavedChanges)
         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
                 // user cancelled
                 return;
                 return;

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

@@ -63,12 +63,12 @@ public class RunTExample : Scenario
                                {
                                {
                                    if (_usernameText.Text == "admin" && passwordText.Text == "password")
                                    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
                                    else
                                    {
                                    {
-                                       MessageBox.ErrorQuery (
+                                       MessageBox.ErrorQuery (App,
                                                               "Error Logging In",
                                                               "Error Logging In",
                                                               "Incorrect username or password (hint: admin/password)",
                                                               "Incorrect username or password (hint: admin/password)",
                                                               "Ok"
                                                               "Ok"

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

@@ -166,7 +166,7 @@ public class RuneWidthGreaterThanOne : Scenario
     {
     {
         if (_text is { })
         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 { })
         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 { })
         if (_text is { })
         {
         {
-            MessageBox.Query ("こんにちはと言う", $"こんにちは {_text.Text}", "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, "こんにちはと言う", $"こんにちは {_text.Text}", "Ok");
         }
         }
     }
     }
 
 

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

@@ -566,6 +566,6 @@ public class Shortcuts : Scenario
     {
     {
         e.Handled = true;
         e.Handled = true;
         var view = sender as View;
         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");
     }
     }
 }
 }

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

@@ -224,7 +224,7 @@ public class SingleBackgroundWorker : Scenario
 
 
             bool Close ()
             bool Close ()
             {
             {
-                int n = MessageBox.Query (
+                int? n = MessageBox.Query (App,
                                           50,
                                           50,
                                           7,
                                           7,
                                           "Close Window.",
                                           "Close Window.",
@@ -251,7 +251,7 @@ public class SingleBackgroundWorker : Scenario
                                                         {
                                                         {
                                                             if (Close ())
                                                             if (Close ())
                                                             {
                                                             {
-                                                                Application.RequestStop ();
+                                                                App?.RequestStop ();
                                                             }
                                                             }
                                                         }
                                                         }
                                            }
                                            }
@@ -270,7 +270,7 @@ public class SingleBackgroundWorker : Scenario
                                                 {
                                                 {
                                                     if (Close ())
                                                     if (Close ())
                                                     {
                                                     {
-                                                        Application.RequestStop ();
+                                                        App?.RequestStop ();
                                                     }
                                                     }
                                                 }
                                                 }
                                                )
                                                )
@@ -304,7 +304,7 @@ public class SingleBackgroundWorker : Scenario
         {
         {
             if (_top is { })
             if (_top is { })
             {
             {
-                Application.Run (_top);
+                App?.Run (_top);
                 _top.Dispose ();
                 _top.Dispose ();
                 _top = null;
                 _top = null;
             }
             }

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

@@ -1026,7 +1026,7 @@ public class TableEditor : Scenario
             }
             }
             catch (Exception ex)
             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 ();
             _tableView!.Update ();
@@ -1165,7 +1165,7 @@ public class TableEditor : Scenario
         }
         }
         catch (Exception e)
         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;
         _tableView!.Table = source;
@@ -1199,10 +1199,10 @@ public class TableEditor : Scenario
         ok.Accepting += (s, e) =>
         ok.Accepting += (s, e) =>
                         {
                         {
                             accepted = true;
                             accepted = true;
-                            Application.RequestStop ();
+                            (s as View)?.App?.RequestStop ();
                         };
                         };
         var cancel = new Button { Text = "Cancel" };
         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
         var d = new Dialog
         {
         {
@@ -1218,7 +1218,7 @@ public class TableEditor : Scenario
         d.Add (lbl, tf);
         d.Add (lbl, tf);
         tf.SetFocus ();
         tf.SetFocus ();
 
 
-        Application.Run (d);
+        _tableView.App?.Run (d);
         d.Dispose ();
         d.Dispose ();
 
 
         if (accepted)
         if (accepted)
@@ -1229,7 +1229,7 @@ public class TableEditor : Scenario
             }
             }
             catch (Exception ex)
             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 ();
             _tableView!.Update ();
@@ -1512,7 +1512,7 @@ public class TableEditor : Scenario
                                                                              _checkedFileSystemInfos!.Contains,
                                                                              _checkedFileSystemInfos!.Contains,
                                                                              CheckOrUncheckFile
                                                                              CheckOrUncheckFile
                                                                             )
                                                                             )
-                { UseRadioButtons = radio };
+            { UseRadioButtons = radio };
         }
         }
         else
         else
         {
         {

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

@@ -46,7 +46,7 @@ public sealed class Transparent : Scenario
         };
         };
         appButton.Accepting += (sender, args) =>
         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;
                                    args.Handled = true;
                                };
                                };
         appWindow.Add (appButton);
         appWindow.Add (appButton);
@@ -106,7 +106,7 @@ public sealed class Transparent : Scenario
             };
             };
             button.Accepting += (sender, args) =>
             button.Accepting += (sender, args) =>
                                 {
                                 {
-                                    MessageBox.Query ("Clicked!", "Button in Transparent View", "_Ok");
+                                    MessageBox.Query (App, "Clicked!", "Button in Transparent View", "_Ok");
                                     args.Handled = true;
                                     args.Handled = true;
                                 };
                                 };
             //button.Visible = false;
             //button.Visible = false;

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

@@ -169,13 +169,13 @@ public class ViewportSettings : Scenario
         };
         };
 
 
         charMap.Accepting += (s, e) =>
         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
         var buttonAnchored = new Button
         {
         {
             X = Pos.AnchorEnd () - 10, Y = Pos.AnchorEnd () - 4, Text = "Bottom Rig_ht"
             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!.Data = "Margin";
         view.Margin!.Thickness = new (0);
         view.Margin!.Thickness = new (0);

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

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

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

@@ -21,6 +21,7 @@ public class WizardAsView : Scenario
                                        {
                                        {
                                            Title = "_Restart Configuration...",
                                            Title = "_Restart Configuration...",
                                            Action = () => MessageBox.Query (
                                            Action = () => MessageBox.Query (
+                                                                            ApplicationImpl.Instance,
                                                                             "Wizard",
                                                                             "Wizard",
                                                                             "Are you sure you want to reset the Wizard and start over?",
                                                                             "Are you sure you want to reset the Wizard and start over?",
                                                                             "Ok",
                                                                             "Ok",
@@ -31,6 +32,7 @@ public class WizardAsView : Scenario
                                        {
                                        {
                                            Title = "Re_boot Server...",
                                            Title = "Re_boot Server...",
                                            Action = () => MessageBox.Query (
                                            Action = () => MessageBox.Query (
+                                                                            ApplicationImpl.Instance,
                                                                             "Wizard",
                                                                             "Wizard",
                                                                             "Are you sure you want to reboot the server start over?",
                                                                             "Are you sure you want to reboot the server start over?",
                                                                             "Ok",
                                                                             "Ok",
@@ -41,6 +43,7 @@ public class WizardAsView : Scenario
                                        {
                                        {
                                            Title = "_Shutdown Server...",
                                            Title = "_Shutdown Server...",
                                            Action = () => MessageBox.Query (
                                            Action = () => MessageBox.Query (
+                                                                            ApplicationImpl.Instance,
                                                                             "Wizard",
                                                                             "Wizard",
                                                                             "Are you sure you want to cancel setup and shutdown?",
                                                                             "Are you sure you want to cancel setup and shutdown?",
                                                                             "Ok",
                                                                             "Ok",
@@ -80,13 +83,13 @@ public class WizardAsView : Scenario
         wizard.Finished += (s, args) =>
         wizard.Finished += (s, args) =>
                            {
                            {
                                //args.Cancel = true;
                                //args.Cancel = true;
-                               MessageBox.Query ("Setup Wizard", "Finished", "Ok");
+                               MessageBox.Query ((s as View)?.App, "Setup Wizard", "Finished", "Ok");
                                Application.RequestStop ();
                                Application.RequestStop ();
                            };
                            };
 
 
         wizard.Cancelled += (s, args) =>
         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;
                                 args.Cancel = btn == 1;
 
 
                                 if (btn == 0)
                                 if (btn == 0)
@@ -123,7 +126,7 @@ public class WizardAsView : Scenario
                             {
                             {
                                 secondStep.Title = "2nd Step";
                                 secondStep.Title = "2nd Step";
 
 
-                                MessageBox.Query (
+                                MessageBox.Query ((s as View)?.App,
                                                   "Wizard Scenario",
                                                   "Wizard Scenario",
                                                   "This Wizard Step's title was changed to '2nd Step'",
                                                   "This Wizard Step's title was changed to '2nd Step'",
                                                   "Ok"
                                                   "Ok"

+ 269 - 266
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")]
 [ScenarioMetadata ("Wizards", "Demonstrates the Wizard class")]
 [ScenarioCategory ("Dialogs")]
 [ScenarioCategory ("Dialogs")]
 [ScenarioCategory ("Wizards")]
 [ScenarioCategory ("Wizards")]
 [ScenarioCategory ("Runnable")]
 [ScenarioCategory ("Runnable")]
-
 public class Wizards : Scenario
 public class Wizards : Scenario
 {
 {
     public override void Main ()
     public override void Main ()
@@ -108,267 +104,277 @@ public class Wizards : Scenario
         };
         };
 
 
         showWizardButton.Accepting += (s, e) =>
         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);
         win.Add (showWizardButton);
 
 
         Application.Run (win);
         Application.Run (win);
@@ -376,8 +382,5 @@ public class Wizards : Scenario
         Application.Shutdown ();
         Application.Shutdown ();
     }
     }
 
 
-    private void Wizard_StepChanged (object sender, StepChangeEventArgs e)
-    {
-        throw new NotImplementedException ();
-    }
+    private void Wizard_StepChanged (object sender, StepChangeEventArgs e) { throw new NotImplementedException (); }
 }
 }

+ 1 - 0
Examples/UICatalog/UICatalogTop.cs

@@ -144,6 +144,7 @@ public class UICatalogTop : Toplevel
                                                               "_About...",
                                                               "_About...",
                                                               "About UI Catalog",
                                                               "About UI Catalog",
                                                               () => MessageBox.Query (
                                                               () => MessageBox.Query (
+                                                                                      App,
                                                                                       "",
                                                                                       "",
                                                                                       GetAboutBoxMessage (),
                                                                                       GetAboutBoxMessage (),
                                                                                       wrapMessage: false,
                                                                                       wrapMessage: false,

+ 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;
+}

+ 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;
         internal set => ApplicationImpl.Instance.Driver = value;
     }
     }
 
 
+    private static bool _force16Colors = false; // Resources/config.json overrides
+
     /// <inheritdoc cref="IApplication.Force16Colors"/>
     /// <inheritdoc cref="IApplication.Force16Colors"/>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [Obsolete ("The legacy static Application object is going away.")]
     [Obsolete ("The legacy static Application object is going away.")]
     public static bool Force16Colors
     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"/>
     /// <inheritdoc cref="IApplication.ForceDriver"/>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [Obsolete ("The legacy static Application object is going away.")]
     [Obsolete ("The legacy static Application object is going away.")]
     public static string ForceDriver
     public static string ForceDriver
     {
     {
-        get => ApplicationImpl.Instance.ForceDriver;
+        get => _forceDriver;
         set
         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"/>
     /// <inheritdoc cref="IApplication.Sixel"/>
     [Obsolete ("The legacy static Application object is going away.")] 
     [Obsolete ("The legacy static Application object is going away.")] 
     public static List<SixelToRender> Sixel => ApplicationImpl.Instance.Sixel;
     public static List<SixelToRender> Sixel => ApplicationImpl.Instance.Sixel;

+ 17 - 4
Terminal.Gui/App/Application.Lifecycle.cs

@@ -18,7 +18,15 @@ public static partial class Application // Lifecycle (Init/Shutdown)
     ///     <see cref="IApplication"/> instance for all subsequent application operations.
     ///     <see cref="IApplication"/> instance for all subsequent application operations.
     /// </remarks>
     /// </remarks>
     /// <returns>A new <see cref="IApplication"/> instance.</returns>
     /// <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 ()
+    {
+        ApplicationImpl.MarkInstanceBasedModelUsed ();
+
+        return new ApplicationImpl ();
+    }
 
 
     /// <inheritdoc cref="IApplication.Init"/>
     /// <inheritdoc cref="IApplication.Init"/>
     [RequiresUnreferencedCode ("AOT")]
     [RequiresUnreferencedCode ("AOT")]
@@ -26,6 +34,7 @@ public static partial class Application // Lifecycle (Init/Shutdown)
     [Obsolete ("The legacy static Application object is going away.")]
     [Obsolete ("The legacy static Application object is going away.")]
     public static void Init (string? driverName = null)
     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);
         ApplicationImpl.Instance.Init (driverName ?? ForceDriver);
     }
     }
 
 
@@ -35,8 +44,8 @@ public static partial class Application // Lifecycle (Init/Shutdown)
     [Obsolete ("The legacy static Application object is going away.")]
     [Obsolete ("The legacy static Application object is going away.")]
     public static int? MainThreadId
     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.Shutdown"/>
@@ -65,5 +74,9 @@ public static partial class Application // Lifecycle (Init/Shutdown)
     // guaranteeing that the state of this singleton is deterministic when Init
     // guaranteeing that the state of this singleton is deterministic when Init
     // starts running and after Shutdown returns.
     // starts running and after Shutdown returns.
     [Obsolete ("The legacy static Application object is going away.")]
     [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
 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>
     /// <summary>Disable or enable the mouse. The mouse is enabled by default.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [Obsolete ("The legacy static Application object is going away.")]
     [Obsolete ("The legacy static Application object is going away.")]
     public static bool IsMouseDisabled
     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>
     /// <summary>
     ///     Gets the <see cref="IMouse"/> instance that manages mouse event handling and state.
     ///     Gets the <see cref="IMouse"/> instance that manages mouse event handling and state.
     /// </summary>
     /// </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;
         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>
     /// <summary>Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [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>
     /// <summary>Alternative key to navigate forwards through views. Tab is the primary key.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key NextTabKey
     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>
     /// <summary>
     ///     Raised when the user releases a key.
     ///     Raised when the user releases a key.
     ///     <para>
     ///     <para>
@@ -48,19 +68,39 @@ public static partial class Application // Navigation stuff
         remove => ApplicationImpl.Instance.Keyboard.KeyUp -= value;
         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>
     /// <summary>Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key PrevTabGroupKey
     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>
     /// <summary>Alternative key to navigate backwards through views. Shift+Tab is the primary key.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key PrevTabKey
     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;
 }
 }

+ 25 - 5
Terminal.Gui/App/Application.Run.cs

@@ -4,22 +4,42 @@ namespace Terminal.Gui.App;
 
 
 public static partial class Application // Run (Begin -> Run -> Layout/Draw -> End -> Stop)
 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>
     /// <summary>Gets or sets the key to quit the application.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key QuitKey
     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>
     /// <summary>Gets or sets the key to activate arranging views using the keyboard.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     public static Key ArrangeKey
     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)"/>
     /// <inheritdoc cref="IApplication.Begin(IRunnable)"/>
     [Obsolete ("The legacy static Application object is going away.")]
     [Obsolete ("The legacy static Application object is going away.")]
     public static SessionToken Begin (Toplevel toplevel) => ApplicationImpl.Instance.Begin (toplevel);
     public static SessionToken Begin (Toplevel toplevel) => ApplicationImpl.Instance.Begin (toplevel);
@@ -88,7 +108,7 @@ public static partial class Application // Run (Begin -> Run -> Layout/Draw -> E
 
 
     /// <inheritdoc cref="IApplication.Iteration"/>
     /// <inheritdoc cref="IApplication.Iteration"/>
     [Obsolete ("The legacy static Application object is going away.")]
     [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;
         add => ApplicationImpl.Instance.Iteration += value;
         remove => ApplicationImpl.Instance.Iteration -= value;
         remove => ApplicationImpl.Instance.Iteration -= value;

+ 1 - 1
Terminal.Gui/App/Application.Current.cs → Terminal.Gui/App/Application.TopRunnable.cs

@@ -2,7 +2,7 @@ using System.Collections.Concurrent;
 
 
 namespace Terminal.Gui.App;
 namespace Terminal.Gui.App;
 
 
-public static partial class Application // Current handling
+public static partial class Application // TopRunnable handling
 {
 {
     /// <inheritdoc cref="IApplication.SessionStack"/>
     /// <inheritdoc cref="IApplication.SessionStack"/>
     [Obsolete ("The legacy static Application object is going away.")] public static ConcurrentStack<Toplevel> SessionStack => ApplicationImpl.Instance.SessionStack;
     [Obsolete ("The legacy static Application object is going away.")] public static ConcurrentStack<Toplevel> SessionStack => ApplicationImpl.Instance.SessionStack;

+ 103 - 49
Terminal.Gui/App/ApplicationImpl.Lifecycle.cs

@@ -1,10 +1,14 @@
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
 
 
 namespace Terminal.Gui.App;
 namespace Terminal.Gui.App;
 
 
 public partial class ApplicationImpl
 public partial class ApplicationImpl
 {
 {
+    /// <inheritdoc />
+    public int? MainThreadId { get; set; }
+
     /// <inheritdoc/>
     /// <inheritdoc/>
     public bool Initialized { get; set; }
     public bool Initialized { get; set; }
 
 
@@ -23,6 +27,29 @@ public partial class ApplicationImpl
             throw new InvalidOperationException ("Init called multiple times without Shutdown");
             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))
         if (!string.IsNullOrWhiteSpace (driverName))
         {
         {
             _driverName = driverName;
             _driverName = driverName;
@@ -41,26 +68,24 @@ public partial class ApplicationImpl
 
 
         // Preserve existing keyboard settings if they exist
         // Preserve existing keyboard settings if they exist
         bool hasExistingKeyboard = _keyboard is { };
         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
         // Reset keyboard to ensure fresh state with default bindings
         _keyboard = new KeyboardImpl { App = this };
         _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);
         CreateDriver (_driverName);
         Screen = Driver!.Screen;
         Screen = Driver!.Screen;
@@ -85,8 +110,8 @@ public partial class ApplicationImpl
         if (runnableToDispose is { })
         if (runnableToDispose is { })
         {
         {
             // Extract the result using reflection to get the Result property value
             // Extract the result using reflection to get the Result property value
-            var resultProperty = runnableToDispose.GetType().GetProperty("Result");
-            result = resultProperty?.GetValue(runnableToDispose);
+            PropertyInfo? resultProperty = runnableToDispose.GetType ().GetProperty ("Result");
+            result = resultProperty?.GetValue (runnableToDispose);
         }
         }
 
 
         // Stop the coordinator if running
         // Stop the coordinator if running
@@ -115,8 +140,9 @@ public partial class ApplicationImpl
         {
         {
             if (runnableToDispose is IDisposable disposable)
             if (runnableToDispose is IDisposable disposable)
             {
             {
-                disposable.Dispose();
+                disposable.Dispose ();
             }
             }
+
             FrameworkOwnedRunnable = null;
             FrameworkOwnedRunnable = null;
         }
         }
 
 
@@ -140,36 +166,6 @@ public partial class ApplicationImpl
         return result;
         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)
-    {
-        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
-
     /// <inheritdoc/>
     /// <inheritdoc/>
     public void ResetState (bool ignoreDisposed = false)
     public void ResetState (bool ignoreDisposed = false)
     {
     {
@@ -241,6 +237,17 @@ public partial class ApplicationImpl
         ClearScreenNextIteration = false;
         ClearScreenNextIteration = false;
 
 
         // === 6. Reset input systems ===
         // === 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 and Keyboard will be lazy-initialized on next access
         _mouse = null;
         _mouse = null;
         _keyboard = null;
         _keyboard = null;
@@ -273,10 +280,57 @@ public partial class ApplicationImpl
         // gui.cs does no longer process any callbacks. See #1084 for more details:
         // gui.cs does no longer process any callbacks. See #1084 for more details:
         // (https://github.com/gui-cs/Terminal.Gui/issues/1084).
         // (https://github.com/gui-cs/Terminal.Gui/issues/1084).
         SynchronizationContext.SetSynchronizationContext (null);
         SynchronizationContext.SetSynchronizationContext (null);
+
+        // === 12. Unsubscribe from Application static property change events ===
+        UnsubscribeApplicationEvents ();
     }
     }
 
 
     /// <summary>
     /// <summary>
     ///     Raises the <see cref="InitializedChanged"/> event.
     ///     Raises the <see cref="InitializedChanged"/> event.
     /// </summary>
     /// </summary>
     internal void RaiseInitializedChanged (object sender, EventArgs<bool> e) { InitializedChanged?.Invoke (sender, e); }
     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;
+    }
 }
 }

+ 2 - 11
Terminal.Gui/App/ApplicationImpl.Run.cs

@@ -5,15 +5,6 @@ namespace Terminal.Gui.App;
 
 
 public partial class ApplicationImpl
 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
     #region Begin->Run->Stop->End
 
 
     // TODO: This API is not used anywhere; it can be deleted
     // TODO: This API is not used anywhere; it can be deleted
@@ -156,11 +147,11 @@ public partial class ApplicationImpl
     /// <inheritdoc/>
     /// <inheritdoc/>
     public void RaiseIteration ()
     public void RaiseIteration ()
     {
     {
-        Iteration?.Invoke (null, new ());
+        Iteration?.Invoke (null, new (this));
     }
     }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    public event EventHandler<IterationEventArgs>? Iteration;
+    public event EventHandler<EventArgs<IApplication?>>? Iteration;
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
     [RequiresUnreferencedCode ("AOT")]
     [RequiresUnreferencedCode ("AOT")]

+ 136 - 12
Terminal.Gui/App/ApplicationImpl.cs

@@ -9,23 +9,72 @@ namespace Terminal.Gui.App;
 public partial class ApplicationImpl : IApplication
 public partial class ApplicationImpl : IApplication
 {
 {
     /// <summary>
     /// <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>
     /// </summary>
-    internal ApplicationImpl () { }
+    internal ApplicationImpl ()
+    {
+        // Subscribe to Application static property change events
+        Application.Force16ColorsChanged += OnForce16ColorsChanged;
+        Application.ForceDriverChanged += OnForceDriverChanged;
+    }
 
 
     /// <summary>
     /// <summary>
     ///     INTERNAL: Creates a new instance of the Application backend.
     ///     INTERNAL: Creates a new instance of the Application backend.
     /// </summary>
     /// </summary>
     /// <param name="componentFactory"></param>
     /// <param name="componentFactory"></param>
-    internal ApplicationImpl (IComponentFactory componentFactory) { _componentFactory = componentFactory; }
+    internal ApplicationImpl (IComponentFactory componentFactory) : this () { _componentFactory = componentFactory; }
+
+    private string? _driverName;
+
+    #region Clipboard
+
+    /// <inheritdoc/>
+    public IClipboard? Clipboard => Driver?.Clipboard;
+
+    #endregion Clipboard
+
+    /// <inheritdoc/>
+    public new string ToString () => Driver?.ToString () ?? string.Empty;
 
 
     #region Singleton
     #region Singleton
 
 
+    /// <summary>
+    ///     Lock object for synchronizing access to ModelUsage and _instance.
+    /// </summary>
+    private static readonly object _modelUsageLock = new ();
+
+    /// <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>
     /// <summary>
     ///     Configures the singleton instance of <see cref="Application"/> to use the specified backend implementation.
     ///     Configures the singleton instance of <see cref="Application"/> to use the specified backend implementation.
     /// </summary>
     /// </summary>
     /// <param name="app"></param>
     /// <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 readonly Lazy instance of Application
     private static IApplication? _instance;
     private static IApplication? _instance;
@@ -33,11 +82,91 @@ public partial class ApplicationImpl : IApplication
     /// <summary>
     /// <summary>
     ///     Gets the currently configured backend implementation of <see cref="Application"/> gateway methods.
     ///     Gets the currently configured backend implementation of <see cref="Application"/> gateway methods.
     /// </summary>
     /// </summary>
-    public static IApplication Instance => _instance ??= new ApplicationImpl ();
+    public static IApplication Instance
+    {
+        get
+        {
+            //Debug.Fail ("ApplicationImpl.Instance accessed - parallelizable tests should not use legacy static Application model");
 
 
-    #endregion Singleton
+            // 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 ();
+            }
+        }
+    }
 
 
-    private string? _driverName;
+    /// <summary>
+    ///     INTERNAL: Marks that the instance-based model has been used. Called by Application.Create().
+    /// </summary>
+    internal static void MarkInstanceBasedModelUsed ()
+    {
+        lock (_modelUsageLock)
+        {
+            // Check if the legacy static model has already been initialized
+            if (ModelUsage == ApplicationModelUsage.LegacyStatic && _instance?.Initialized == true)
+            {
+                throw new InvalidOperationException (ERROR_MODERN_AFTER_LEGACY);
+            }
+
+            ModelUsage = ApplicationModelUsage.InstanceBased;
+        }
+    }
+
+    /// <summary>
+    ///     INTERNAL: Resets the model usage tracking. Only for testing purposes.
+    /// </summary>
+    internal static void ResetModelUsageTracking ()
+    {
+        lock (_modelUsageLock)
+        {
+            ModelUsage = ApplicationModelUsage.None;
+            _instance = null;
+        }
+    }
+
+    /// <summary>
+    ///     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
 
 
     #region Input
     #region Input
 
 
@@ -122,8 +251,6 @@ public partial class ApplicationImpl : IApplication
         }
         }
     }
     }
 
 
-    // BUGBUG: Technically, this is not the full lst of sessions. There be dragons here, e.g. see how Toplevel.Id is used. What
-
     /// <inheritdoc/>
     /// <inheritdoc/>
     public ConcurrentStack<Toplevel> SessionStack { get; } = new ();
     public ConcurrentStack<Toplevel> SessionStack { get; } = new ();
 
 
@@ -137,7 +264,4 @@ public partial class ApplicationImpl : IApplication
     public IRunnable? FrameworkOwnedRunnable { get; set; }
     public IRunnable? FrameworkOwnedRunnable { get; set; }
 
 
     #endregion View Management
     #endregion View Management
-
-    /// <inheritdoc/>
-    public new string ToString () => Driver?.ToString () ?? string.Empty;
 }
 }

+ 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
+}

+ 1 - 1
Terminal.Gui/App/ApplicationNavigation.cs

@@ -13,7 +13,7 @@ public class ApplicationNavigation
     /// </summary>
     /// </summary>
     public ApplicationNavigation ()
     public ApplicationNavigation ()
     {
     {
-        // TODO: Move navigation key bindings here from AddApplicationKeyBindings
+        // TODO: Move navigation key bindings here from KeyboardImpl
     }
     }
 
 
     /// <summary>
     /// <summary>

+ 1 - 1
Terminal.Gui/App/ApplicationRunnableExtensions.cs

@@ -5,7 +5,7 @@ namespace Terminal.Gui.App;
 /// </summary>
 /// </summary>
 /// <remarks>
 /// <remarks>
 ///     These extensions provide convenience methods for wrapping views in <see cref="RunnableWrapper{TView, TResult}"/>
 ///     These extensions provide convenience methods for wrapping views in <see cref="RunnableWrapper{TView, TResult}"/>
-///     and running them in a single call, similar to how <see cref="IApplication.Run{TRunnable}()"/> works.
+///     and running them in a single call, similar to how <see cref="IApplication.Run(Func{Exception, bool}, string)"/> works.
 /// </remarks>
 /// </remarks>
 public static class ApplicationRunnableExtensions
 public static class ApplicationRunnableExtensions
 {
 {

+ 32 - 0
Terminal.Gui/App/Clipboard/Clipboard.cs

@@ -2,6 +2,9 @@ namespace Terminal.Gui.App;
 
 
 /// <summary>Provides cut, copy, and paste support for the OS clipboard.</summary>
 /// <summary>Provides cut, copy, and paste support for the OS clipboard.</summary>
 /// <remarks>
 /// <remarks>
+///     <para>
+///         <b>DEPRECATED:</b> This static class is obsolete. Use <see cref="IApplication.Clipboard"/> instead.
+///     </para>
 ///     <para>On Windows, the <see cref="Clipboard"/> class uses the Windows Clipboard APIs via P/Invoke.</para>
 ///     <para>On Windows, the <see cref="Clipboard"/> class uses the Windows Clipboard APIs via P/Invoke.</para>
 ///     <para>
 ///     <para>
 ///         On Linux, when not running under Windows Subsystem for Linux (WSL), the <see cref="Clipboard"/> class uses
 ///         On Linux, when not running under Windows Subsystem for Linux (WSL), the <see cref="Clipboard"/> class uses
@@ -16,6 +19,7 @@ namespace Terminal.Gui.App;
 ///         the Mac clipboard APIs vai P/Invoke.
 ///         the Mac clipboard APIs vai P/Invoke.
 ///     </para>
 ///     </para>
 /// </remarks>
 /// </remarks>
+[Obsolete ("Use IApplication.Clipboard instead. The static Clipboard class will be removed in a future release.")]
 public static class Clipboard
 public static class Clipboard
 {
 {
     private static string? _contents = string.Empty;
     private static string? _contents = string.Empty;
@@ -65,4 +69,32 @@ public static class Clipboard
     /// <summary>Returns true if the environmental dependencies are in place to interact with the OS clipboard.</summary>
     /// <summary>Returns true if the environmental dependencies are in place to interact with the OS clipboard.</summary>
     /// <remarks></remarks>
     /// <remarks></remarks>
     public static bool IsSupported => Application.Driver?.Clipboard?.IsSupported ?? false;
     public static bool IsSupported => Application.Driver?.Clipboard?.IsSupported ?? false;
+
+    /// <summary>Gets the OS clipboard data if possible.</summary>
+    /// <param name="result">The clipboard data if successful.</param>
+    /// <returns><see langword="true"/> if the clipboard data was retrieved successfully; otherwise, <see langword="false"/>.</returns>
+    public static bool TryGetClipboardData (out string result)
+    {
+        result = string.Empty;
+
+        if (IsSupported && Application.Driver?.Clipboard is { })
+        {
+            return Application.Driver.Clipboard.TryGetClipboardData (out result);
+        }
+
+        return false;
+    }
+
+    /// <summary>Sets the OS clipboard data if possible.</summary>
+    /// <param name="text">The text to set.</param>
+    /// <returns><see langword="true"/> if the clipboard data was set successfully; otherwise, <see langword="false"/>.</returns>
+    public static bool TrySetClipboardData (string text)
+    {
+        if (IsSupported && Application.Driver?.Clipboard is { })
+        {
+            return Application.Driver.Clipboard.TrySetClipboardData (text);
+        }
+
+        return false;
+    }
 }
 }

+ 27 - 4
Terminal.Gui/App/IApplication.cs

@@ -39,6 +39,16 @@ public interface IApplication
 
 
     #region Initialization and Shutdown
     #region Initialization and Shutdown
 
 
+    /// <summary>
+    ///     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>
+    public int? MainThreadId { get; internal set; }
+
+
     /// <summary>Initializes a new instance of <see cref="Terminal.Gui"/> Application.</summary>
     /// <summary>Initializes a new instance of <see cref="Terminal.Gui"/> Application.</summary>
     /// <param name="driverName">
     /// <param name="driverName">
     ///     The short name (e.g. "dotnet", "windows", "unix", or "fake") of the
     ///     The short name (e.g. "dotnet", "windows", "unix", or "fake") of the
@@ -218,7 +228,7 @@ public interface IApplication
     [RequiresUnreferencedCode ("AOT")]
     [RequiresUnreferencedCode ("AOT")]
     [RequiresDynamicCode ("AOT")]
     [RequiresDynamicCode ("AOT")]
     public TView Run<TView> (Func<Exception, bool>? errorHandler = null, string? driverName = null)
     public TView Run<TView> (Func<Exception, bool>? errorHandler = null, string? driverName = null)
-        where TView : Toplevel, new ();
+        where TView : Toplevel, new();
 
 
     /// <summary>
     /// <summary>
     ///     Runs a new Session using the provided <see cref="Toplevel"/> view and calling
     ///     Runs a new Session using the provided <see cref="Toplevel"/> view and calling
@@ -273,9 +283,11 @@ public interface IApplication
     ///     <para>
     ///     <para>
     ///         This event is raised before input processing, timeout callbacks, and rendering occur each iteration.
     ///         This event is raised before input processing, timeout callbacks, and rendering occur each iteration.
     ///     </para>
     ///     </para>
-    ///     <para>See also <see cref="AddTimeout"/> and <see cref="TimedEvents"/>.</para>
+    ///     <para>The event args contain the current application instance.</para>
     /// </remarks>
     /// </remarks>
-    public event EventHandler<IterationEventArgs>? Iteration;
+    /// <seealso cref="AddTimeout"/>
+    /// <seealso cref="TimedEvents"/>.
+    public event EventHandler<EventArgs<IApplication?>>? Iteration;
 
 
     /// <summary>Runs <paramref name="action"/> on the main UI loop thread.</summary>
     /// <summary>Runs <paramref name="action"/> on the main UI loop thread.</summary>
     /// <param name="action">The action to be invoked on the main processing thread.</param>
     /// <param name="action">The action to be invoked on the main processing thread.</param>
@@ -523,7 +535,7 @@ public interface IApplication
     ///         Supports fluent API: <c>var result = Application.Create().Init().Run&lt;MyView&gt;().Shutdown() as MyResultType</c>
     ///         Supports fluent API: <c>var result = Application.Create().Init().Run&lt;MyView&gt;().Shutdown() as MyResultType</c>
     ///     </para>
     ///     </para>
     /// </remarks>
     /// </remarks>
-    IApplication Run<TRunnable> (Func<Exception, bool>? errorHandler = null) where TRunnable : IRunnable, new ();
+    IApplication Run<TRunnable> (Func<Exception, bool>? errorHandler = null) where TRunnable : IRunnable, new();
 
 
     /// <summary>
     /// <summary>
     ///     Requests that the specified runnable session stop.
     ///     Requests that the specified runnable session stop.
@@ -574,6 +586,17 @@ public interface IApplication
     /// </remarks>
     /// </remarks>
     IDriver? Driver { get; set; }
     IDriver? Driver { get; set; }
 
 
+    /// <summary>
+    ///     Gets the clipboard for this application instance.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Provides access to the OS clipboard through the driver. Returns <see langword="null"/> if
+    ///         <see cref="Driver"/> is not initialized.
+    ///     </para>
+    /// </remarks>
+    IClipboard? Clipboard { get; }
+
     /// <summary>
     /// <summary>
     ///     Gets or sets whether <see cref="Driver"/> will be forced to output only the 16 colors defined in
     ///     Gets or sets whether <see cref="Driver"/> will be forced to output only the 16 colors defined in
     ///     <see cref="ColorName16"/>. The default is <see langword="false"/>, meaning 24-bit (TrueColor) colors will be
     ///     <see cref="ColorName16"/>. The default is <see langword="false"/>, meaning 24-bit (TrueColor) colors will be

+ 0 - 5
Terminal.Gui/App/IterationEventArgs.cs

@@ -1,5 +0,0 @@
-namespace Terminal.Gui.App;
-
-/// <summary>Event arguments for the <see cref="IApplication.Iteration"/> event.</summary>
-public class IterationEventArgs : EventArgs
-{ }

+ 110 - 55
Terminal.Gui/App/Keyboard/KeyboardImpl.cs

@@ -1,7 +1,10 @@
+using System.Collections.Concurrent;
+
 namespace Terminal.Gui.App;
 namespace Terminal.Gui.App;
 
 
 /// <summary>
 /// <summary>
 ///     INTERNAL: Implements <see cref="IKeyboard"/> to manage keyboard input and key bindings at the Application level.
 ///     INTERNAL: Implements <see cref="IKeyboard"/> to manage keyboard input and key bindings at the Application level.
+///     This implementation is thread-safe for all public operations.
 ///     <para>
 ///     <para>
 ///         This implementation decouples keyboard handling state from the static <see cref="App"/> class,
 ///         This implementation decouples keyboard handling state from the static <see cref="App"/> class,
 ///         enabling parallelizable unit tests and better testability.
 ///         enabling parallelizable unit tests and better testability.
@@ -10,19 +13,61 @@ namespace Terminal.Gui.App;
 ///         See <see cref="IKeyboard"/> for usage details.
 ///         See <see cref="IKeyboard"/> for usage details.
 ///     </para>
 ///     </para>
 /// </summary>
 /// </summary>
-internal class KeyboardImpl : IKeyboard
+internal class KeyboardImpl : IKeyboard, IDisposable
 {
 {
-    private Key _quitKey = Key.Esc; // Resources/config.json overrides
-    private Key _arrangeKey = Key.F5.WithCtrl; // Resources/config.json overrides
-    private Key _nextTabGroupKey = Key.F6; // Resources/config.json overrides
-    private Key _nextTabKey = Key.Tab; // Resources/config.json overrides
-    private Key _prevTabGroupKey = Key.F6.WithShift; // Resources/config.json overrides
-    private Key _prevTabKey = Key.Tab.WithShift; // Resources/config.json overrides
+    /// <summary>
+    ///     Initializes keyboard bindings and subscribes to Application configuration property events.
+    /// </summary>
+    public KeyboardImpl ()
+    {
+        // DON'T access Application static properties here - they trigger ApplicationImpl.Instance
+        // which sets ModelUsage to LegacyStatic, breaking parallel tests.
+        // These will be initialized from Application static properties in Init() or when accessed.
+
+        // Initialize to reasonable defaults that match Application defaults
+        // These will be updated by property change events if Application properties change
+        _quitKey = Key.Esc;
+        _arrangeKey = Key.F5.WithCtrl;
+        _nextTabGroupKey = Key.F6;
+        _nextTabKey = Key.Tab;
+        _prevTabGroupKey = Key.F6.WithShift;
+        _prevTabKey = Key.Tab.WithShift;
+
+        // Subscribe to Application static property change events
+        // so we get updated if they change
+        Application.QuitKeyChanged += OnQuitKeyChanged;
+        Application.ArrangeKeyChanged += OnArrangeKeyChanged;
+        Application.NextTabGroupKeyChanged += OnNextTabGroupKeyChanged;
+        Application.NextTabKeyChanged += OnNextTabKeyChanged;
+        Application.PrevTabGroupKeyChanged += OnPrevTabGroupKeyChanged;
+        Application.PrevTabKeyChanged += OnPrevTabKeyChanged;
+
+        AddKeyBindings ();
+    }
 
 
     /// <summary>
     /// <summary>
-    ///     Commands for Application.
+    ///     Commands for Application. Thread-safe for concurrent access.
     /// </summary>
     /// </summary>
-    private readonly Dictionary<Command, View.CommandImplementation> _commandImplementations = new ();
+    private readonly ConcurrentDictionary<Command, View.CommandImplementation> _commandImplementations = new ();
+
+    private Key _quitKey;
+    private Key _arrangeKey;
+    private Key _nextTabGroupKey;
+    private Key _nextTabKey;
+    private Key _prevTabGroupKey;
+    private Key _prevTabKey;
+
+    /// <inheritdoc/>
+    public void Dispose ()
+    {
+        // Unsubscribe from Application static property change events
+        Application.QuitKeyChanged -= OnQuitKeyChanged;
+        Application.ArrangeKeyChanged -= OnArrangeKeyChanged;
+        Application.NextTabGroupKeyChanged -= OnNextTabGroupKeyChanged;
+        Application.NextTabKeyChanged -= OnNextTabKeyChanged;
+        Application.PrevTabGroupKeyChanged -= OnPrevTabGroupKeyChanged;
+        Application.PrevTabKeyChanged -= OnPrevTabKeyChanged;
+    }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
     public IApplication? App { get; set; }
     public IApplication? App { get; set; }
@@ -102,14 +147,6 @@ internal class KeyboardImpl : IKeyboard
     /// <inheritdoc/>
     /// <inheritdoc/>
     public event EventHandler<Key>? KeyUp;
     public event EventHandler<Key>? KeyUp;
 
 
-    /// <summary>
-    ///     Initializes keyboard bindings.
-    /// </summary>
-    public KeyboardImpl ()
-    {
-        AddKeyBindings ();
-    }
-
     /// <inheritdoc/>
     /// <inheritdoc/>
     public bool RaiseKeyDownEvent (Key key)
     public bool RaiseKeyDownEvent (Key key)
     {
     {
@@ -165,7 +202,8 @@ internal class KeyboardImpl : IKeyboard
         }
         }
 
 
         bool? commandHandled = InvokeCommandsBoundToKey (key);
         bool? commandHandled = InvokeCommandsBoundToKey (key);
-        if(commandHandled is true)
+
+        if (commandHandled is true)
         {
         {
             return true;
             return true;
         }
         }
@@ -188,7 +226,6 @@ internal class KeyboardImpl : IKeyboard
             return true;
             return true;
         }
         }
 
 
-
         // TODO: Add Popover support
         // TODO: Add Popover support
 
 
         if (App?.SessionStack is { })
         if (App?.SessionStack is { })
@@ -214,6 +251,7 @@ internal class KeyboardImpl : IKeyboard
     public bool? InvokeCommandsBoundToKey (Key key)
     public bool? InvokeCommandsBoundToKey (Key key)
     {
     {
         bool? handled = null;
         bool? handled = null;
+
         // Invoke any Application-scoped KeyBindings.
         // Invoke any Application-scoped KeyBindings.
         // The first view that handles the key will stop the loop.
         // The first view that handles the key will stop the loop.
         // foreach (KeyValuePair<Key, KeyBinding> binding in KeyBindings.GetBindings (key))
         // foreach (KeyValuePair<Key, KeyBinding> binding in KeyBindings.GetBindings (key))
@@ -264,24 +302,6 @@ internal class KeyboardImpl : IKeyboard
         return null;
         return null;
     }
     }
 
 
-    /// <summary>
-    ///     <para>
-    ///         Sets the function that will be invoked for a <see cref="Command"/>.
-    ///     </para>
-    ///     <para>
-    ///         If AddCommand has already been called for <paramref name="command"/> <paramref name="f"/> will
-    ///         replace the old one.
-    ///     </para>
-    /// </summary>
-    /// <remarks>
-    ///     <para>
-    ///         This version of AddCommand is for commands that do not require a <see cref="ICommandContext"/>.
-    ///     </para>
-    /// </remarks>
-    /// <param name="command">The command.</param>
-    /// <param name="f">The function.</param>
-    private void AddCommand (Command command, Func<bool?> f) { _commandImplementations [command] = ctx => f (); }
-
     internal void AddKeyBindings ()
     internal void AddKeyBindings ()
     {
     {
         _commandImplementations.Clear ();
         _commandImplementations.Clear ();
@@ -296,6 +316,7 @@ internal class KeyboardImpl : IKeyboard
                         return true;
                         return true;
                     }
                     }
                    );
                    );
+
         AddCommand (
         AddCommand (
                     Command.Suspend,
                     Command.Suspend,
                     () =>
                     () =>
@@ -305,6 +326,7 @@ internal class KeyboardImpl : IKeyboard
                         return true;
                         return true;
                     }
                     }
                    );
                    );
+
         AddCommand (
         AddCommand (
                     Command.NextTabStop,
                     Command.NextTabStop,
                     () => App?.Navigation?.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop));
                     () => App?.Navigation?.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop));
@@ -351,31 +373,64 @@ internal class KeyboardImpl : IKeyboard
                         return false;
                         return false;
                     });
                     });
 
 
-        //SetKeysToHardCodedDefaults ();
-
         // Need to clear after setting the above to ensure actually clear
         // Need to clear after setting the above to ensure actually clear
-        // because set_QuitKey etc.. may call Add
-        KeyBindings.Clear ();
-
-        KeyBindings.Add (QuitKey, Command.Quit);
-        KeyBindings.Add (NextTabKey, Command.NextTabStop);
-        KeyBindings.Add (PrevTabKey, Command.PreviousTabStop);
-        KeyBindings.Add (NextTabGroupKey, Command.NextTabGroup);
-        KeyBindings.Add (PrevTabGroupKey, Command.PreviousTabGroup);
-        KeyBindings.Add (ArrangeKey, Command.Arrange);
-
-        KeyBindings.Add (Key.CursorRight, Command.NextTabStop);
-        KeyBindings.Add (Key.CursorDown, Command.NextTabStop);
-        KeyBindings.Add (Key.CursorLeft, Command.PreviousTabStop);
-        KeyBindings.Add (Key.CursorUp, Command.PreviousTabStop);
+        // because set_QuitKey etc. may call Add
+        //KeyBindings.Clear ();
+
+        // Use ReplaceCommands instead of Add, because it's possible that
+        // during construction the Application static properties changed, and
+        // we added those keys already.
+        KeyBindings.ReplaceCommands (QuitKey, Command.Quit);
+        KeyBindings.ReplaceCommands (NextTabKey, Command.NextTabStop);
+        KeyBindings.ReplaceCommands (PrevTabKey, Command.PreviousTabStop);
+        KeyBindings.ReplaceCommands (NextTabGroupKey, Command.NextTabGroup);
+        KeyBindings.ReplaceCommands (PrevTabGroupKey, Command.PreviousTabGroup);
+        KeyBindings.ReplaceCommands (ArrangeKey, Command.Arrange);
+
+        // TODO: Should these be configurable?
+        KeyBindings.ReplaceCommands (Key.CursorRight, Command.NextTabStop);
+        KeyBindings.ReplaceCommands (Key.CursorDown, Command.NextTabStop);
+        KeyBindings.ReplaceCommands (Key.CursorLeft, Command.PreviousTabStop);
+        KeyBindings.ReplaceCommands (Key.CursorUp, Command.PreviousTabStop);
 
 
         // TODO: Refresh Key should be configurable
         // TODO: Refresh Key should be configurable
-        KeyBindings.Add (Key.F5, Command.Refresh);
+        KeyBindings.ReplaceCommands (Key.F5, Command.Refresh);
 
 
         // TODO: Suspend Key should be configurable
         // TODO: Suspend Key should be configurable
         if (Environment.OSVersion.Platform == PlatformID.Unix)
         if (Environment.OSVersion.Platform == PlatformID.Unix)
         {
         {
-            KeyBindings.Add (Key.Z.WithCtrl, Command.Suspend);
+            KeyBindings.ReplaceCommands (Key.Z.WithCtrl, Command.Suspend);
         }
         }
     }
     }
+
+    /// <summary>
+    ///     <para>
+    ///         Sets the function that will be invoked for a <see cref="Command"/>.
+    ///     </para>
+    ///     <para>
+    ///         If AddCommand has already been called for <paramref name="command"/> <paramref name="f"/> will
+    ///         replace the old one.
+    ///     </para>
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         This version of AddCommand is for commands that do not require a <see cref="ICommandContext"/>.
+    ///     </para>
+    /// </remarks>
+    /// <param name="command">The command.</param>
+    /// <param name="f">The function.</param>
+    private void AddCommand (Command command, Func<bool?> f) { _commandImplementations [command] = ctx => f (); }
+
+    private void OnArrangeKeyChanged (object? sender, ValueChangedEventArgs<Key> e) { ArrangeKey = e.NewValue; }
+
+    private void OnNextTabGroupKeyChanged (object? sender, ValueChangedEventArgs<Key> e) { NextTabGroupKey = e.NewValue; }
+
+    private void OnNextTabKeyChanged (object? sender, ValueChangedEventArgs<Key> e) { NextTabKey = e.NewValue; }
+
+    private void OnPrevTabGroupKeyChanged (object? sender, ValueChangedEventArgs<Key> e) { PrevTabGroupKey = e.NewValue; }
+
+    private void OnPrevTabKeyChanged (object? sender, ValueChangedEventArgs<Key> e) { PrevTabKey = e.NewValue; }
+
+    // Event handlers for Application static property changes
+    private void OnQuitKeyChanged (object? sender, ValueChangedEventArgs<Key> e) { QuitKey = e.NewValue; }
 }
 }

+ 27 - 4
Terminal.Gui/App/Mouse/MouseImpl.cs

@@ -9,15 +9,25 @@ namespace Terminal.Gui.App;
 ///         enabling better testability and parallel test execution.
 ///         enabling better testability and parallel test execution.
 ///     </para>
 ///     </para>
 /// </summary>
 /// </summary>
-internal class MouseImpl : IMouse
+internal class MouseImpl : IMouse, IDisposable
 {
 {
     /// <summary>
     /// <summary>
-    ///     Initializes a new instance of the <see cref="MouseImpl"/> class.
+    ///     Initializes a new instance of the <see cref="MouseImpl"/> class and subscribes to Application configuration property events.
     /// </summary>
     /// </summary>
-    public MouseImpl () { }
+    public MouseImpl ()
+    {
+        // Subscribe to Application static property change events
+        Application.IsMouseDisabledChanged += OnIsMouseDisabledChanged;
+    }
+
+    private IApplication? _app;
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    public IApplication? App { get; set; }
+    public IApplication? App
+    {
+        get => _app;
+        set => _app = value;
+    }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
     public Point? LastMousePosition { get; set; }
     public Point? LastMousePosition { get; set; }
@@ -391,4 +401,17 @@ internal class MouseImpl : IMouse
 
 
         return false;
         return false;
     }
     }
+
+    // Event handler for Application static property changes
+    private void OnIsMouseDisabledChanged (object? sender, ValueChangedEventArgs<bool> e)
+    {
+        IsMouseDisabled = e.NewValue;
+    }
+
+    /// <inheritdoc/>
+    public void Dispose ()
+    {
+        // Unsubscribe from Application static property change events
+        Application.IsMouseDisabledChanged -= OnIsMouseDisabledChanged;
+    }
 }
 }

+ 2 - 2
Terminal.Gui/App/Runnable/IRunnable.cs

@@ -66,7 +66,7 @@ public interface IRunnable
     /// <summary>
     /// <summary>
     ///     Raised when <see cref="IsRunning"/> is changing (e.g., when <see cref="IApplication.Begin(IRunnable)"/> or
     ///     Raised when <see cref="IsRunning"/> is changing (e.g., when <see cref="IApplication.Begin(IRunnable)"/> or
     ///     <see cref="IApplication.End(RunnableSessionToken)"/> is called).
     ///     <see cref="IApplication.End(RunnableSessionToken)"/> is called).
-    ///     Can be canceled by setting <see cref="CancelEventArgs{T}.Cancel"/> to <see langword="true"/>.
+    ///     Can be canceled by setting `args.Cancel` to <see langword="true"/>.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
@@ -140,7 +140,7 @@ public interface IRunnable
 
 
     /// <summary>
     /// <summary>
     ///     Raised when this runnable is about to become modal (top of stack) or cease being modal.
     ///     Raised when this runnable is about to become modal (top of stack) or cease being modal.
-    ///     Can be canceled by setting <see cref="CancelEventArgs{T}.Cancel"/> to <see langword="true"/>.
+    ///     Can be canceled by setting `args.Cancel` to <see langword="true"/>.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>

+ 80 - 4
Terminal.Gui/Configuration/ConfigurationManager.cs

@@ -595,15 +595,53 @@ public static class ConfigurationManager
                                                                                   TypeInfoResolver = SourceGenerationContext.Default
                                                                                   TypeInfoResolver = SourceGenerationContext.Default
                                                                               });
                                                                               });
 
 
+    private static SourcesManager? _sourcesManager = new ();
+    private static readonly object _sourcesManagerLock = new ();
+
     /// <summary>
     /// <summary>
     ///     Gets the Sources Manager - manages the loading of configuration sources from files and resources.
     ///     Gets the Sources Manager - manages the loading of configuration sources from files and resources.
     /// </summary>
     /// </summary>
-    public static SourcesManager? SourcesManager { get; internal set; } = new ();
+    public static SourcesManager? SourcesManager
+    {
+        get
+        {
+            lock (_sourcesManagerLock)
+            {
+                return _sourcesManager;
+            }
+        }
+        internal set
+        {
+            lock (_sourcesManagerLock)
+            {
+                _sourcesManager = value;
+            }
+        }
+    }
+
+    private static string? _runtimeConfig = """{  }""";
+    private static readonly object _runtimeConfigLock = new ();
 
 
     /// <summary>
     /// <summary>
     ///     Gets or sets the in-memory config.json. See <see cref="ConfigLocations.Runtime"/>.
     ///     Gets or sets the in-memory config.json. See <see cref="ConfigLocations.Runtime"/>.
     /// </summary>
     /// </summary>
-    public static string? RuntimeConfig { get; set; } = """{  }""";
+    public static string? RuntimeConfig
+    {
+        get
+        {
+            lock (_runtimeConfigLock)
+            {
+                return _runtimeConfig;
+            }
+        }
+        set
+        {
+            lock (_runtimeConfigLock)
+            {
+                _runtimeConfig = value;
+            }
+        }
+    }
 
 
     [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
     [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
     private static readonly string _configFilename = "config.json";
     private static readonly string _configFilename = "config.json";
@@ -678,13 +716,32 @@ public static class ConfigurationManager
     [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
     [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
     internal static StringBuilder _jsonErrors = new ();
     internal static StringBuilder _jsonErrors = new ();
 
 
+    private static bool? _throwOnJsonErrors = false;
+    private static readonly object _throwOnJsonErrorsLock = new ();
+
     /// <summary>
     /// <summary>
     ///     Gets or sets whether the <see cref="ConfigurationManager"/> should throw an exception if it encounters an
     ///     Gets or sets whether the <see cref="ConfigurationManager"/> should throw an exception if it encounters an
     ///     error on deserialization. If <see langword="false"/> (the default), the error is logged and printed to the console
     ///     error on deserialization. If <see langword="false"/> (the default), the error is logged and printed to the console
     ///     when <see cref="Application.Shutdown"/> is called.
     ///     when <see cref="Application.Shutdown"/> is called.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
-    public static bool? ThrowOnJsonErrors { get; set; } = false;
+    public static bool? ThrowOnJsonErrors
+    {
+        get
+        {
+            lock (_throwOnJsonErrorsLock)
+            {
+                return _throwOnJsonErrors;
+            }
+        }
+        set
+        {
+            lock (_throwOnJsonErrorsLock)
+            {
+                _throwOnJsonErrors = value;
+            }
+        }
+    }
 
 
 #pragma warning disable IDE1006 // Naming Styles
 #pragma warning disable IDE1006 // Naming Styles
     private static readonly object _jsonErrorsLock = new ();
     private static readonly object _jsonErrorsLock = new ();
@@ -758,8 +815,27 @@ public static class ConfigurationManager
         return JsonSerializer.Serialize (emptyScope, typeof (SettingsScope), SerializerContext!);
         return JsonSerializer.Serialize (emptyScope, typeof (SettingsScope), SerializerContext!);
     }
     }
 
 
+    private static string _appName = Assembly.GetEntryAssembly ()?.FullName?.Split (',') [0]?.Trim ()!;
+    private static readonly object _appNameLock = new ();
+
     /// <summary>Name of the running application. By default, this property is set to the application's assembly name.</summary>
     /// <summary>Name of the running application. By default, this property is set to the application's assembly name.</summary>
-    public static string AppName { get; set; } = Assembly.GetEntryAssembly ()?.FullName?.Split (',') [0]?.Trim ()!;
+    public static string AppName
+    {
+        get
+        {
+            lock (_appNameLock)
+            {
+                return _appName;
+            }
+        }
+        set
+        {
+            lock (_appNameLock)
+            {
+                _appName = value;
+            }
+        }
+    }
 
 
     /// <summary>
     /// <summary>
     ///     INTERNAL: Retrieves all uninitialized configuration properties that belong to a specific scope from the cache.
     ///     INTERNAL: Retrieves all uninitialized configuration properties that belong to a specific scope from the cache.

+ 5 - 7
Terminal.Gui/Configuration/SourcesManager.cs

@@ -1,4 +1,5 @@
-using System.Diagnostics;
+using System.Collections.Concurrent;
+using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Diagnostics.CodeAnalysis;
 using System.Reflection;
 using System.Reflection;
 using System.Text.Json;
 using System.Text.Json;
@@ -13,7 +14,7 @@ public class SourcesManager
     /// <summary>
     /// <summary>
     ///     Provides a map from each of the <see cref="ConfigLocations"/> to file system and resource paths that have been loaded by <see cref="ConfigurationManager"/>.
     ///     Provides a map from each of the <see cref="ConfigLocations"/> to file system and resource paths that have been loaded by <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
-    public Dictionary<ConfigLocations, string> Sources { get; } = new ();
+    public ConcurrentDictionary<ConfigLocations, string> Sources { get; } = new ();
 
 
     /// <summary>INTERNAL: Loads <paramref name="stream"/> into the specified <see cref="SettingsScope"/>.</summary>
     /// <summary>INTERNAL: Loads <paramref name="stream"/> into the specified <see cref="SettingsScope"/>.</summary>
     /// <param name="settingsScope">The Settings Scope object that <paramref name="stream"/> will be loaded into.</param>
     /// <param name="settingsScope">The Settings Scope object that <paramref name="stream"/> will be loaded into.</param>
@@ -62,11 +63,8 @@ public class SourcesManager
 
 
     internal void AddSource (ConfigLocations location, string source)
     internal void AddSource (ConfigLocations location, string source)
     {
     {
-        if (!Sources.TryAdd (location, source))
-        {
-            //Logging.Warning ($"{location} has already been added to Sources.");
-            Sources [location] = source;
-        }
+        // ConcurrentDictionary's AddOrUpdate is thread-safe
+        Sources.AddOrUpdate (location, source, (key, oldValue) => source);
     }
     }
 
 
 
 

+ 4 - 4
Terminal.Gui/Drivers/FakeDriver/FakeInputProcessor.cs

@@ -1,4 +1,3 @@
-#nullable disable
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 
 
 namespace Terminal.Gui.Drivers;
 namespace Terminal.Gui.Drivers;
@@ -27,17 +26,18 @@ public class FakeInputProcessor : InputProcessorImpl<ConsoleKeyInfo>
     }
     }
 
 
     /// <inheritdoc />
     /// <inheritdoc />
-    public override void EnqueueMouseEvent (MouseEventArgs mouseEvent)
+    public override void EnqueueMouseEvent (IApplication? app, MouseEventArgs mouseEvent)
     {
     {
         // FakeDriver uses ConsoleKeyInfo as its input record type, which cannot represent mouse events.
         // FakeDriver uses ConsoleKeyInfo as its input record type, which cannot represent mouse events.
 
 
+        // TODO: Verify this is correct. This didn't check the threadId before.
         // If Application.Invoke is available (running in Application context), defer to next iteration
         // If Application.Invoke is available (running in Application context), defer to next iteration
         // to ensure proper timing - the event is raised after views are laid out.
         // to ensure proper timing - the event is raised after views are laid out.
         // Otherwise (unit tests), raise immediately so tests can verify synchronously.
         // Otherwise (unit tests), raise immediately so tests can verify synchronously.
-        if (Application.MainThreadId is { })
+        if (app is {} && app.MainThreadId != Thread.CurrentThread.ManagedThreadId)
         {
         {
             // Application is running - use Invoke to defer to next iteration
             // Application is running - use Invoke to defer to next iteration
-            ApplicationImpl.Instance.Invoke ((_) => RaiseMouseEvent (mouseEvent));
+            app?.Invoke ((_) => RaiseMouseEvent (mouseEvent));
         }
         }
         else
         else
         {
         {

+ 9 - 6
Terminal.Gui/Drivers/IInputProcessor.cs

@@ -1,5 +1,4 @@
-
-namespace Terminal.Gui.Drivers;
+namespace Terminal.Gui.Drivers;
 
 
 /// <summary>
 /// <summary>
 ///     Interface for main loop class that will process the queued input.
 ///     Interface for main loop class that will process the queued input.
@@ -12,7 +11,7 @@ public interface IInputProcessor
     public event EventHandler<string>? AnsiSequenceSwallowed;
     public event EventHandler<string>? AnsiSequenceSwallowed;
 
 
     /// <summary>
     /// <summary>
-    /// Gets the name of the driver associated with this input processor.
+    ///     Gets the name of the driver associated with this input processor.
     /// </summary>
     /// </summary>
     string? DriverName { get; init; }
     string? DriverName { get; init; }
 
 
@@ -58,7 +57,8 @@ public interface IInputProcessor
     ///     Called when a key up event has been dequeued. Raises the <see cref="KeyUp"/> event.
     ///     Called when a key up event has been dequeued. Raises the <see cref="KeyUp"/> event.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
-    ///     Drivers that do not support key release events will call this method after <see cref="RaiseKeyDownEvent"/> processing
+    ///     Drivers that do not support key release events will call this method after <see cref="RaiseKeyDownEvent"/>
+    ///     processing
     ///     is complete.
     ///     is complete.
     /// </remarks>
     /// </remarks>
     /// <param name="key">The key event data.</param>
     /// <param name="key">The key event data.</param>
@@ -89,7 +89,10 @@ public interface IInputProcessor
     /// <summary>
     /// <summary>
     ///     Adds a mouse input event to the input queue. For unit tests.
     ///     Adds a mouse input event to the input queue. For unit tests.
     /// </summary>
     /// </summary>
+    /// <param name="app">
+    ///     The application instance to use. Used to use Invoke to raise the mouse
+    ///     event in the case where this method is not called on the main thread.
+    /// </param>
     /// <param name="mouseEvent"></param>
     /// <param name="mouseEvent"></param>
-    void EnqueueMouseEvent (MouseEventArgs mouseEvent);
-
+    void EnqueueMouseEvent (IApplication? app,  MouseEventArgs mouseEvent);
 }
 }

+ 1 - 1
Terminal.Gui/Drivers/InputProcessorImpl.cs

@@ -122,7 +122,7 @@ public abstract class InputProcessorImpl<TInputRecord> : IInputProcessor, IDispo
     public event EventHandler<MouseEventArgs>? MouseEvent;
     public event EventHandler<MouseEventArgs>? MouseEvent;
 
 
     /// <inheritdoc />
     /// <inheritdoc />
-    public virtual void EnqueueMouseEvent (MouseEventArgs mouseEvent)
+    public virtual void EnqueueMouseEvent (IApplication? app, MouseEventArgs mouseEvent)
     {
     {
         // Base implementation: For drivers where TInputRecord cannot represent mouse events
         // Base implementation: For drivers where TInputRecord cannot represent mouse events
         // (e.g., ConsoleKeyInfo), derived classes should override this method.
         // (e.g., ConsoleKeyInfo), derived classes should override this method.

+ 10 - 8
Terminal.Gui/Drivers/OutputBase.cs

@@ -90,14 +90,16 @@ public abstract class OutputBase
             }
             }
         }
         }
 
 
-        foreach (SixelToRender s in Application.Sixel)
-        {
-            if (!string.IsNullOrWhiteSpace (s.SixelData))
-            {
-                SetCursorPositionImpl (s.ScreenPosition.X, s.ScreenPosition.Y);
-                Console.Out.Write (s.SixelData);
-            }
-        }
+        // BUGBUG: The Sixel impl depends on the legacy static Application object
+        // BUGBUG: Disabled for now
+        //foreach (SixelToRender s in  Application.Sixel)
+        //{
+        //    if (!string.IsNullOrWhiteSpace (s.SixelData))
+        //    {
+        //        SetCursorPositionImpl (s.ScreenPosition.X, s.ScreenPosition.Y);
+        //        Console.Out.Write (s.SixelData);
+        //    }
+        //}
 
 
         SetCursorVisibility (savedVisibility ?? CursorVisibility.Default);
         SetCursorVisibility (savedVisibility ?? CursorVisibility.Default);
         _cachedCursorVisibility = savedVisibility;
         _cachedCursorVisibility = savedVisibility;

+ 1 - 1
Terminal.Gui/Drivers/WindowsDriver/WindowsInputProcessor.cs

@@ -18,7 +18,7 @@ internal class WindowsInputProcessor : InputProcessorImpl<InputRecord>
     }
     }
 
 
     /// <inheritdoc />
     /// <inheritdoc />
-    public override void EnqueueMouseEvent (MouseEventArgs mouseEvent)
+    public override void EnqueueMouseEvent (IApplication? app, MouseEventArgs mouseEvent)
     {
     {
         InputQueue.Enqueue (new ()
         InputQueue.Enqueue (new ()
         {
         {

+ 3 - 2
Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs

@@ -149,7 +149,7 @@ internal partial class WindowsOutput : OutputBase, IOutput
             // Force 16 colors if not in virtual terminal mode.
             // Force 16 colors if not in virtual terminal mode.
             // BUGBUG: This is bad. It does not work if the app was crated without
             // BUGBUG: This is bad. It does not work if the app was crated without
             // BUGBUG: Apis.
             // BUGBUG: Apis.
-            ApplicationImpl.Instance.Force16Colors = true;
+            //ApplicationImpl.Instance.Force16Colors = true;
 
 
         }
         }
 
 
@@ -357,7 +357,8 @@ internal partial class WindowsOutput : OutputBase, IOutput
     {
     {
         // BUGBUG: This is bad. It does not work if the app was crated without
         // BUGBUG: This is bad. It does not work if the app was crated without
         // BUGBUG: Apis.
         // BUGBUG: Apis.
-        bool force16Colors = ApplicationImpl.Instance.Force16Colors;
+        // bool force16Colors = ApplicationImpl.Instance.Force16Colors;
+        bool force16Colors = false;
 
 
         if (force16Colors)
         if (force16Colors)
         {
         {

+ 6 - 3
Terminal.Gui/FileServices/IFileOperations.cs

@@ -9,28 +9,31 @@ namespace Terminal.Gui.FileServices;
 public interface IFileOperations
 public interface IFileOperations
 {
 {
     /// <summary>Specifies how to handle file/directory deletion attempts in <see cref="FileDialog"/>.</summary>
     /// <summary>Specifies how to handle file/directory deletion attempts in <see cref="FileDialog"/>.</summary>
+    /// <param name="app"></param>
     /// <param name="toDelete"></param>
     /// <param name="toDelete"></param>
     /// <returns><see langword="true"/> if operation was completed or <see langword="false"/> if cancelled</returns>
     /// <returns><see langword="true"/> if operation was completed or <see langword="false"/> if cancelled</returns>
     /// <remarks>
     /// <remarks>
     ///     Ensure you use a try/catch block with appropriate error handling (e.g. showing a <see cref="MessageBox"/>
     ///     Ensure you use a try/catch block with appropriate error handling (e.g. showing a <see cref="MessageBox"/>
     /// </remarks>
     /// </remarks>
-    bool Delete (IEnumerable<IFileSystemInfo> toDelete);
+    bool Delete (IApplication? app, IEnumerable<IFileSystemInfo> toDelete);
 
 
     /// <summary>Specifies how to handle 'new directory' operation in <see cref="FileDialog"/>.</summary>
     /// <summary>Specifies how to handle 'new directory' operation in <see cref="FileDialog"/>.</summary>
+    /// <param name="app"></param>
     /// <param name="fileSystem"></param>
     /// <param name="fileSystem"></param>
     /// <param name="inDirectory">The parent directory in which the new directory should be created</param>
     /// <param name="inDirectory">The parent directory in which the new directory should be created</param>
     /// <returns>The newly created directory or null if cancelled.</returns>
     /// <returns>The newly created directory or null if cancelled.</returns>
     /// <remarks>
     /// <remarks>
     ///     Ensure you use a try/catch block with appropriate error handling (e.g. showing a <see cref="MessageBox"/>
     ///     Ensure you use a try/catch block with appropriate error handling (e.g. showing a <see cref="MessageBox"/>
     /// </remarks>
     /// </remarks>
-    IFileSystemInfo New (IFileSystem fileSystem, IDirectoryInfo inDirectory);
+    IFileSystemInfo New (IApplication? app, IFileSystem fileSystem, IDirectoryInfo inDirectory);
 
 
     /// <summary>Specifies how to handle file/directory rename attempts in <see cref="FileDialog"/>.</summary>
     /// <summary>Specifies how to handle file/directory rename attempts in <see cref="FileDialog"/>.</summary>
+    /// <param name="app"></param>
     /// <param name="fileSystem"></param>
     /// <param name="fileSystem"></param>
     /// <param name="toRename"></param>
     /// <param name="toRename"></param>
     /// <returns>The new name for the file or null if cancelled</returns>
     /// <returns>The new name for the file or null if cancelled</returns>
     /// <remarks>
     /// <remarks>
     ///     Ensure you use a try/catch block with appropriate error handling (e.g. showing a <see cref="MessageBox"/>
     ///     Ensure you use a try/catch block with appropriate error handling (e.g. showing a <see cref="MessageBox"/>
     /// </remarks>
     /// </remarks>
-    IFileSystemInfo Rename (IFileSystem fileSystem, IFileSystemInfo toRename);
+    IFileSystemInfo Rename (IApplication? app, IFileSystem fileSystem, IFileSystemInfo toRename);
 }
 }

+ 95 - 83
Terminal.Gui/Input/InputBindings.cs

@@ -1,19 +1,15 @@
-namespace Terminal.Gui.Input;
+using System.Collections.Concurrent;
+
+namespace Terminal.Gui.Input;
 
 
 /// <summary>
 /// <summary>
 ///     Abstract class for <see cref="KeyBindings"/> and <see cref="MouseBindings"/>.
 ///     Abstract class for <see cref="KeyBindings"/> and <see cref="MouseBindings"/>.
+///     This class is thread-safe for all public operations.
 /// </summary>
 /// </summary>
 /// <typeparam name="TEvent">The type of the event (e.g. <see cref="Key"/> or <see cref="MouseFlags"/>).</typeparam>
 /// <typeparam name="TEvent">The type of the event (e.g. <see cref="Key"/> or <see cref="MouseFlags"/>).</typeparam>
 /// <typeparam name="TBinding">The binding type (e.g. <see cref="KeyBinding"/>).</typeparam>
 /// <typeparam name="TBinding">The binding type (e.g. <see cref="KeyBinding"/>).</typeparam>
-public abstract class InputBindings<TEvent, TBinding> where TBinding : IInputBinding, new () where TEvent : notnull
+public abstract class InputBindings<TEvent, TBinding> where TBinding : IInputBinding, new() where TEvent : notnull
 {
 {
-    /// <summary>
-    ///     The bindings.
-    /// </summary>
-    private readonly Dictionary<TEvent, TBinding> _bindings;
-
-    private readonly Func<Command [], TEvent, TBinding> _constructBinding;
-
     /// <summary>
     /// <summary>
     ///     Initializes a new instance.
     ///     Initializes a new instance.
     /// </summary>
     /// </summary>
@@ -26,11 +22,11 @@ public abstract class InputBindings<TEvent, TBinding> where TBinding : IInputBin
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Tests whether <paramref name="eventArgs"/> is valid or not.
+    ///     The bindings.
     /// </summary>
     /// </summary>
-    /// <param name="eventArgs"></param>
-    /// <returns></returns>
-    public abstract bool IsValid (TEvent eventArgs);
+    private readonly ConcurrentDictionary<TEvent, TBinding> _bindings;
+
+    private readonly Func<Command [], TEvent, TBinding> _constructBinding;
 
 
     /// <summary>Adds a <typeparamref name="TEvent"/> bound to <typeparamref name="TBinding"/> to the collection.</summary>
     /// <summary>Adds a <typeparamref name="TEvent"/> bound to <typeparamref name="TBinding"/> to the collection.</summary>
     /// <param name="eventArgs"></param>
     /// <param name="eventArgs"></param>
@@ -42,24 +38,21 @@ public abstract class InputBindings<TEvent, TBinding> where TBinding : IInputBin
             throw new ArgumentException (@"Invalid newEventArgs", nameof (eventArgs));
             throw new ArgumentException (@"Invalid newEventArgs", nameof (eventArgs));
         }
         }
 
 
-#pragma warning disable CS8601 // Possible null reference assignment.
-        if (TryGet (eventArgs, out TBinding _))
+        // IMPORTANT: Add a COPY of the eventArgs. This is needed because ConfigurationManager.Apply uses DeepMemberWiseCopy
+        // IMPORTANT: update the memory referenced by the key, and Dictionary uses caching for performance, and thus
+        // IMPORTANT: Apply will update the Dictionary with the new eventArgs, but the old eventArgs will still be in the dictionary.
+        // IMPORTANT: See the ConfigurationManager.Illustrate_DeepMemberWiseCopy_Breaks_Dictionary test for details.
+        if (!_bindings.TryAdd (eventArgs, binding))
         {
         {
             throw new InvalidOperationException (@$"A binding for {eventArgs} exists ({binding}).");
             throw new InvalidOperationException (@$"A binding for {eventArgs} exists ({binding}).");
         }
         }
-#pragma warning restore CS8601 // Possible null reference assignment.
-
-        // IMPORTANT: Add a COPY of the eventArgs. This is needed because ConfigurationManager.Apply uses DeepMemberWiseCopy 
-        // IMPORTANT: update the memory referenced by the key, and Dictionary uses caching for performance, and thus 
-        // IMPORTANT: Apply will update the Dictionary with the new eventArgs, but the old eventArgs will still be in the dictionary.
-        // IMPORTANT: See the ConfigurationManager.Illustrate_DeepMemberWiseCopy_Breaks_Dictionary test for details.
-        _bindings.Add (eventArgs, binding);
     }
     }
 
 
     /// <summary>
     /// <summary>
     ///     <para>Adds a new <typeparamref name="TEvent"/> that will trigger the commands in <paramref name="commands"/>.</para>
     ///     <para>Adds a new <typeparamref name="TEvent"/> that will trigger the commands in <paramref name="commands"/>.</para>
     ///     <para>
     ///     <para>
-    ///         If the <typeparamref name="TEvent"/> is already bound to a different set of <see cref="Command"/>s it will be rebound
+    ///         If the <typeparamref name="TEvent"/> is already bound to a different set of <see cref="Command"/>s it will be
+    ///         rebound
     ///         <paramref name="commands"/>.
     ///         <paramref name="commands"/>.
     ///     </para>
     ///     </para>
     /// </summary>
     /// </summary>
@@ -77,31 +70,32 @@ public abstract class InputBindings<TEvent, TBinding> where TBinding : IInputBin
             throw new ArgumentException (@"At least one command must be specified", nameof (commands));
             throw new ArgumentException (@"At least one command must be specified", nameof (commands));
         }
         }
 
 
-        if (TryGet (eventArgs, out TBinding? binding))
+        if (!IsValid (eventArgs))
         {
         {
-            throw new InvalidOperationException (@$"A binding for {eventArgs} exists ({binding}).");
+            throw new ArgumentException (@"Invalid newEventArgs", nameof (eventArgs));
         }
         }
 
 
-        Add (eventArgs, _constructBinding (commands, eventArgs));
-    }
+        TBinding binding = _constructBinding (commands, eventArgs);
 
 
-    /// <summary>
-    ///     Gets the bindings.
-    /// </summary>
-    /// <returns></returns>
-    public IEnumerable<KeyValuePair<TEvent, TBinding>> GetBindings () { return _bindings; }
+        if (!_bindings.TryAdd (eventArgs, binding))
+        {
+            throw new InvalidOperationException (@$"A binding for {eventArgs} exists ({binding}).");
+        }
+    }
 
 
     /// <summary>Removes all <typeparamref name="TEvent"/> objects from the collection.</summary>
     /// <summary>Removes all <typeparamref name="TEvent"/> objects from the collection.</summary>
     public void Clear () { _bindings.Clear (); }
     public void Clear () { _bindings.Clear (); }
 
 
     /// <summary>
     /// <summary>
-    ///     Removes all bindings that trigger the given command set. Views can have multiple different <typeparamref name="TEvent"/>
+    ///     Removes all bindings that trigger the given command set. Views can have multiple different
+    ///     <typeparamref name="TEvent"/>
     ///     bound to
     ///     bound to
     ///     the same command sets and this method will clear all of them.
     ///     the same command sets and this method will clear all of them.
     /// </summary>
     /// </summary>
     /// <param name="command"></param>
     /// <param name="command"></param>
     public void Clear (params Command [] command)
     public void Clear (params Command [] command)
     {
     {
+        // ToArray() creates a snapshot to avoid modification during enumeration
         KeyValuePair<TEvent, TBinding> [] kvps = _bindings
         KeyValuePair<TEvent, TBinding> [] kvps = _bindings
                                                  .Where (kvp => kvp.Value.Commands.SequenceEqual (command))
                                                  .Where (kvp => kvp.Value.Commands.SequenceEqual (command))
                                                  .ToArray ();
                                                  .ToArray ();
@@ -125,16 +119,29 @@ public abstract class InputBindings<TEvent, TBinding> where TBinding : IInputBin
         throw new InvalidOperationException ($"{eventArgs} is not bound.");
         throw new InvalidOperationException ($"{eventArgs} is not bound.");
     }
     }
 
 
-    /// <summary>Gets the commands bound with the specified <typeparamref name="TEvent"/>.</summary>
-    /// <remarks></remarks>
-    /// <param name="eventArgs">The <typeparamref name="TEvent"/> to check.</param>
-    /// <param name="binding">
-    ///     When this method returns, contains the commands bound with the <typeparamref name="TEvent"/>, if the <typeparamref name="TEvent"/> is
-    ///     not
-    ///     found; otherwise, null. This parameter is passed uninitialized.
-    /// </param>
-    /// <returns><see langword="true"/> if the <typeparamref name="TEvent"/> is bound; otherwise <see langword="false"/>.</returns>
-    public bool TryGet (TEvent eventArgs, out TBinding? binding) { return _bindings.TryGetValue (eventArgs, out binding); }
+    /// <summary>Gets all <typeparamref name="TEvent"/> bound to the set of commands specified by <paramref name="commands"/>.</summary>
+    /// <param name="commands">The set of commands to search.</param>
+    /// <returns>
+    ///     The <typeparamref name="TEvent"/>s bound to the set of commands specified by <paramref name="commands"/>. An empty
+    ///     list if
+    ///     the
+    ///     set of commands was not found.
+    /// </returns>
+    public IEnumerable<TEvent> GetAllFromCommands (params Command [] commands)
+    {
+        // ToList() creates a snapshot to ensure thread-safe enumeration
+        return _bindings.Where (a => a.Value.Commands.SequenceEqual (commands)).Select (a => a.Key).ToList ();
+    }
+
+    /// <summary>
+    ///     Gets the bindings.
+    /// </summary>
+    /// <returns></returns>
+    public IEnumerable<KeyValuePair<TEvent, TBinding>> GetBindings ()
+    {
+        // ConcurrentDictionary provides a snapshot enumeration that is safe for concurrent access
+        return _bindings;
+    }
 
 
     /// <summary>Gets the array of <see cref="Command"/>s bound to <paramref name="eventArgs"/> if it exists.</summary>
     /// <summary>Gets the array of <see cref="Command"/>s bound to <paramref name="eventArgs"/> if it exists.</summary>
     /// <param name="eventArgs">The <typeparamref name="TEvent"/> to check.</param>
     /// <param name="eventArgs">The <typeparamref name="TEvent"/> to check.</param>
@@ -163,17 +170,16 @@ public abstract class InputBindings<TEvent, TBinding> where TBinding : IInputBin
     /// </returns>
     /// </returns>
     public TEvent? GetFirstFromCommands (params Command [] commands) { return _bindings.FirstOrDefault (a => a.Value.Commands.SequenceEqual (commands)).Key; }
     public TEvent? GetFirstFromCommands (params Command [] commands) { return _bindings.FirstOrDefault (a => a.Value.Commands.SequenceEqual (commands)).Key; }
 
 
-    /// <summary>Gets all <typeparamref name="TEvent"/> bound to the set of commands specified by <paramref name="commands"/>.</summary>
-    /// <param name="commands">The set of commands to search.</param>
-    /// <returns>
-    ///     The <typeparamref name="TEvent"/>s bound to the set of commands specified by <paramref name="commands"/>. An empty list if
-    ///     the
-    ///     set of commands was not found.
-    /// </returns>
-    public IEnumerable<TEvent> GetAllFromCommands (params Command [] commands)
-    {
-        return _bindings.Where (a => a.Value.Commands.SequenceEqual (commands)).Select (a => a.Key);
-    }
+    /// <summary>
+    ///     Tests whether <paramref name="eventArgs"/> is valid or not.
+    /// </summary>
+    /// <param name="eventArgs"></param>
+    /// <returns></returns>
+    public abstract bool IsValid (TEvent eventArgs);
+
+    /// <summary>Removes a <typeparamref name="TEvent"/> from the collection.</summary>
+    /// <param name="eventArgs"></param>
+    public void Remove (TEvent eventArgs) { _bindings.TryRemove (eventArgs, out _); }
 
 
     /// <summary>Replaces a <typeparamref name="TEvent"/> combination already bound to a set of <see cref="Command"/>s.</summary>
     /// <summary>Replaces a <typeparamref name="TEvent"/> combination already bound to a set of <see cref="Command"/>s.</summary>
     /// <remarks></remarks>
     /// <remarks></remarks>
@@ -188,15 +194,28 @@ public abstract class InputBindings<TEvent, TBinding> where TBinding : IInputBin
             throw new ArgumentException (@"Invalid newEventArgs", nameof (newEventArgs));
             throw new ArgumentException (@"Invalid newEventArgs", nameof (newEventArgs));
         }
         }
 
 
-        if (TryGet (oldEventArgs, out TBinding? binding))
-        {
-            Remove (oldEventArgs);
-            Add (newEventArgs, binding!);
-        }
-        else
+        // Thread-safe: Handle the case where oldEventArgs == newEventArgs
+        if (EqualityComparer<TEvent>.Default.Equals (oldEventArgs, newEventArgs))
         {
         {
-            Add (newEventArgs, binding!);
+            // Same key - nothing to do, binding stays as-is
+            return;
         }
         }
+
+        // Thread-safe: Get the binding from oldEventArgs, or create default if it doesn't exist
+        // This is atomic - either gets existing or adds new
+        TBinding binding = _bindings.GetOrAdd (oldEventArgs, _ => new TBinding ());
+
+        // Thread-safe: Atomically add/update newEventArgs with the binding from oldEventArgs
+        // The updateValueFactory is only called if the key already exists, ensuring we don't
+        // accidentally overwrite a binding that was added by another thread
+        _bindings.AddOrUpdate (
+            newEventArgs,
+            binding, // Add this binding if newEventArgs doesn't exist
+            (_, _) => binding);
+
+        // Thread-safe: Remove oldEventArgs only after newEventArgs has been set
+        // This ensures we don't lose the binding if another thread is reading it
+        _bindings.TryRemove (oldEventArgs, out _);
     }
     }
 
 
     /// <summary>Replaces the commands already bound to a combination of <typeparamref name="TEvent"/>.</summary>
     /// <summary>Replaces the commands already bound to a combination of <typeparamref name="TEvent"/>.</summary>
@@ -209,28 +228,21 @@ public abstract class InputBindings<TEvent, TBinding> where TBinding : IInputBin
     /// <param name="newCommands">The set of commands to replace the old ones with.</param>
     /// <param name="newCommands">The set of commands to replace the old ones with.</param>
     public void ReplaceCommands (TEvent eventArgs, params Command [] newCommands)
     public void ReplaceCommands (TEvent eventArgs, params Command [] newCommands)
     {
     {
-#pragma warning disable CS8601 // Possible null reference assignment.
-        if (TryGet (eventArgs, out TBinding _))
-        {
-            Remove (eventArgs);
-            Add (eventArgs, newCommands);
-        }
-        else
-        {
-            Add (eventArgs, newCommands);
-        }
-#pragma warning restore CS8601 // Possible null reference assignment.
-    }
+        TBinding newBinding = _constructBinding (newCommands, eventArgs);
 
 
-    /// <summary>Removes a <typeparamref name="TEvent"/> from the collection.</summary>
-    /// <param name="eventArgs"></param>
-    public void Remove (TEvent eventArgs)
-    {
-        if (!TryGet (eventArgs, out _))
-        {
-            return;
-        }
-
-        _bindings.Remove (eventArgs);
+        // Thread-safe: Add or update atomically
+        _bindings.AddOrUpdate (eventArgs, newBinding, (_, _) => newBinding);
     }
     }
+
+    /// <summary>Gets the commands bound with the specified <typeparamref name="TEvent"/>.</summary>
+    /// <remarks></remarks>
+    /// <param name="eventArgs">The <typeparamref name="TEvent"/> to check.</param>
+    /// <param name="binding">
+    ///     When this method returns, contains the commands bound with the <typeparamref name="TEvent"/>, if the
+    ///     <typeparamref name="TEvent"/> is
+    ///     not
+    ///     found; otherwise, null. This parameter is passed uninitialized.
+    /// </param>
+    /// <returns><see langword="true"/> if the <typeparamref name="TEvent"/> is bound; otherwise <see langword="false"/>.</returns>
+    public bool TryGet (TEvent eventArgs, out TBinding? binding) { return _bindings.TryGetValue (eventArgs, out binding); }
 }
 }

+ 1 - 1
Terminal.Gui/ViewBase/Runnable.cs

@@ -92,7 +92,7 @@ public class Runnable<TResult> : View, IRunnable<TResult>
     ///         // Or check if user wants to save first
     ///         // Or check if user wants to save first
     ///         if (HasUnsavedChanges ())
     ///         if (HasUnsavedChanges ())
     ///         {
     ///         {
-    ///             int result = MessageBox.Query ("Save?", "Save changes?", "Yes", "No", "Cancel");
+    ///             int result = MessageBox.Query (App, "Save?", "Save changes?", "Yes", "No", "Cancel");
     ///             if (result == 2) return true;  // Cancel stopping
     ///             if (result == 2) return true;  // Cancel stopping
     ///             if (result == 0) Save ();
     ///             if (result == 0) Save ();
     ///         }
     ///         }

+ 2 - 1
Terminal.Gui/ViewBase/RunnableWrapper.cs

@@ -8,7 +8,8 @@ namespace Terminal.Gui.ViewBase;
 /// <typeparam name="TResult">The type of result data returned when the session completes.</typeparam>
 /// <typeparam name="TResult">The type of result data returned when the session completes.</typeparam>
 /// <remarks>
 /// <remarks>
 ///     <para>
 ///     <para>
-///         This class enables any View to be run as a blocking session with <see cref="IApplication.Run"/>
+///         This class enables any View to be run as a blocking session with
+///         <see cref="IApplication.Run(Func{Exception, bool}, string)"/>
 ///         without requiring the View to implement <see cref="IRunnable{TResult}"/> or derive from
 ///         without requiring the View to implement <see cref="IRunnable{TResult}"/> or derive from
 ///         <see cref="Runnable{TResult}"/>.
 ///         <see cref="Runnable{TResult}"/>.
 ///     </para>
 ///     </para>

+ 1 - 0
Terminal.Gui/ViewBase/View.Diagnostics.cs

@@ -2,6 +2,7 @@
 
 
 public partial class View
 public partial class View
 {
 {
+    // TODO: Make this a configuration property
     /// <summary>Gets or sets whether diagnostic information will be drawn. This is a bit-field of <see cref="ViewDiagnosticFlags"/>.e <see cref="View"/> diagnostics.</summary>
     /// <summary>Gets or sets whether diagnostic information will be drawn. This is a bit-field of <see cref="ViewDiagnosticFlags"/>.e <see cref="View"/> diagnostics.</summary>
     /// <remarks>
     /// <remarks>
     /// <para>
     /// <para>

+ 2 - 2
Terminal.Gui/ViewBase/View.Drawing.Attribute.cs

@@ -104,7 +104,7 @@ public partial class View
 
 
     /// <summary>
     /// <summary>
     ///     Selects the specified Attribute
     ///     Selects the specified Attribute
-    ///     as the Attribute to use for subsequent calls to <see cref="AddRune(System.Text.Rune)"/> and <see cref="AddStr"/>.
+    ///     as the Attribute to use for subsequent calls to <see cref="AddRune(System.Text.Rune)"/> and <see cref="AddStr(string)"/>.
     /// </summary>
     /// </summary>
     /// <param name="attribute">THe Attribute to set.</param>
     /// <param name="attribute">THe Attribute to set.</param>
     /// <returns>The previously set Attribute.</returns>
     /// <returns>The previously set Attribute.</returns>
@@ -112,7 +112,7 @@ public partial class View
 
 
     /// <summary>
     /// <summary>
     ///     Selects the Attribute associated with the specified <see cref="VisualRole"/>
     ///     Selects the Attribute associated with the specified <see cref="VisualRole"/>
-    ///     as the Attribute to use for subsequent calls to <see cref="AddRune(System.Text.Rune)"/> and <see cref="AddStr"/>.
+    ///     as the Attribute to use for subsequent calls to <see cref="AddRune(System.Text.Rune)"/> and <see cref="AddStr(string)"/>.
     ///     <para>
     ///     <para>
     ///         Calls <see cref="GetAttributeForRole"/> to get the Attribute associated with the specified role, which will
     ///         Calls <see cref="GetAttributeForRole"/> to get the Attribute associated with the specified role, which will
     ///         raise <see cref="OnGettingAttributeForRole"/>/<see cref="GettingAttributeForRole"/>.
     ///         raise <see cref="OnGettingAttributeForRole"/>/<see cref="GettingAttributeForRole"/>.

+ 13 - 3
Terminal.Gui/Views/Button.cs

@@ -1,4 +1,3 @@
-
 #nullable disable
 #nullable disable
 namespace Terminal.Gui.Views;
 namespace Terminal.Gui.Views;
 
 
@@ -24,6 +23,9 @@ namespace Terminal.Gui.Views;
 /// </remarks>
 /// </remarks>
 public class Button : View, IDesignable
 public class Button : View, IDesignable
 {
 {
+    private static ShadowStyle _defaultShadow = ShadowStyle.Opaque; // Resources/config.json overrides
+    private static MouseState _defaultHighlightStates = MouseState.In | MouseState.Pressed | MouseState.PressedOutside; // Resources/config.json overrides
+
     private readonly Rune _leftBracket;
     private readonly Rune _leftBracket;
     private readonly Rune _leftDefault;
     private readonly Rune _leftDefault;
     private readonly Rune _rightBracket;
     private readonly Rune _rightBracket;
@@ -34,13 +36,21 @@ public class Button : View, IDesignable
     ///     Gets or sets whether <see cref="Button"/>s are shown with a shadow effect by default.
     ///     Gets or sets whether <see cref="Button"/>s are shown with a shadow effect by default.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.Opaque;
+    public static ShadowStyle DefaultShadow
+    {
+        get => _defaultShadow;
+        set => _defaultShadow = value;
+    }
 
 
     /// <summary>
     /// <summary>
     ///     Gets or sets the default Highlight Style.
     ///     Gets or sets the default Highlight Style.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static MouseState DefaultHighlightStates { get; set; } = MouseState.In | MouseState.Pressed | MouseState.PressedOutside;
+    public static MouseState DefaultHighlightStates
+    {
+        get => _defaultHighlightStates;
+        set => _defaultHighlightStates = value;
+    }
 
 
     /// <summary>Initializes a new instance of <see cref="Button"/>.</summary>
     /// <summary>Initializes a new instance of <see cref="Button"/>.</summary>
     public Button ()
     public Button ()

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

@@ -281,8 +281,8 @@ public class CharMap : View, IDesignable
         }
         }
     }
     }
 
 
-    private void CopyCodePoint () { Clipboard.Contents = $"U+{SelectedCodePoint:x5}"; }
-    private void CopyGlyph () { Clipboard.Contents = $"{new Rune (SelectedCodePoint)}"; }
+    private void CopyCodePoint () { App?.Clipboard?.SetClipboardData($"U+{SelectedCodePoint:x5}"); }
+    private void CopyGlyph () { App?.Clipboard?.SetClipboardData($"{new Rune (SelectedCodePoint)}"); }
 
 
     private bool? Move (ICommandContext? commandContext, int cpOffset)
     private bool? Move (ICommandContext? commandContext, int cpOffset)
     {
     {
@@ -335,7 +335,7 @@ public class CharMap : View, IDesignable
     [RequiresDynamicCode ("AOT")]
     [RequiresDynamicCode ("AOT")]
     private void ShowDetails ()
     private void ShowDetails ()
     {
     {
-        if (!Application.Initialized)
+        if (App is not { Initialized: true })
         {
         {
             // Some unit tests invoke Accept without Init
             // Some unit tests invoke Accept without Init
             return;
             return;
@@ -380,15 +380,15 @@ public class CharMap : View, IDesignable
                                    try
                                    try
                                    {
                                    {
                                        decResponse = await client.GetCodepointDec (SelectedCodePoint).ConfigureAwait (false);
                                        decResponse = await client.GetCodepointDec (SelectedCodePoint).ConfigureAwait (false);
-                                       Application.Invoke ((_) => waitIndicator.RequestStop ());
+                                       App?.Invoke ((_) => (s as Dialog)?.RequestStop ());
                                    }
                                    }
                                    catch (HttpRequestException e)
                                    catch (HttpRequestException e)
                                    {
                                    {
                                        getCodePointError = errorLabel.Text = e.Message;
                                        getCodePointError = errorLabel.Text = e.Message;
-                                       Application.Invoke ((_) => waitIndicator.RequestStop ());
+                                       App?.Invoke ((_) => (s as Dialog)?.RequestStop ());
                                    }
                                    }
                                };
                                };
-        Application.Run (waitIndicator);
+        App?.Run (waitIndicator);
         waitIndicator.Dispose ();
         waitIndicator.Dispose ();
 
 
         var name = string.Empty;
         var name = string.Empty;
@@ -521,7 +521,7 @@ public class CharMap : View, IDesignable
 
 
         dlg.Add (json);
         dlg.Add (json);
 
 
-        Application.Run (dlg);
+        App?.Run (dlg);
         dlg.Dispose ();
         dlg.Dispose ();
     }
     }
 
 

+ 7 - 3
Terminal.Gui/Views/CheckBox.cs

@@ -1,5 +1,3 @@
-
-
 namespace Terminal.Gui.Views;
 namespace Terminal.Gui.Views;
 
 
 /// <summary>Shows a checkbox that can be cycled between two or three states.</summary>
 /// <summary>Shows a checkbox that can be cycled between two or three states.</summary>
@@ -10,11 +8,17 @@ namespace Terminal.Gui.Views;
 /// </remarks>
 /// </remarks>
 public class CheckBox : View
 public class CheckBox : View
 {
 {
+    private static MouseState _defaultHighlightStates = MouseState.PressedOutside | MouseState.Pressed | MouseState.In; // Resources/config.json overrides
+
     /// <summary>
     /// <summary>
     ///     Gets or sets the default Highlight Style.
     ///     Gets or sets the default Highlight Style.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static MouseState DefaultHighlightStates { get; set; } = MouseState.PressedOutside | MouseState.Pressed | MouseState.In;
+    public static MouseState DefaultHighlightStates
+    {
+        get => _defaultHighlightStates;
+        set => _defaultHighlightStates = value;
+    }
 
 
     /// <summary>
     /// <summary>
     ///     Initializes a new instance of <see cref="CheckBox"/>.
     ///     Initializes a new instance of <see cref="CheckBox"/>.

+ 35 - 4
Terminal.Gui/Views/CollectionNavigation/CollectionNavigator.cs

@@ -1,5 +1,5 @@
 #nullable disable
 #nullable disable
-using System.Collections;
+using System.Collections;
 
 
 namespace Terminal.Gui.Views;
 namespace Terminal.Gui.Views;
 
 
@@ -7,6 +7,9 @@ namespace Terminal.Gui.Views;
 /// <remarks>This implementation is based on a static <see cref="Collection"/> of objects.</remarks>
 /// <remarks>This implementation is based on a static <see cref="Collection"/> of objects.</remarks>
 internal class CollectionNavigator : CollectionNavigatorBase, IListCollectionNavigator
 internal class CollectionNavigator : CollectionNavigatorBase, IListCollectionNavigator
 {
 {
+    private readonly object _collectionLock = new ();
+    private IList _collection;
+
     /// <summary>Constructs a new CollectionNavigator.</summary>
     /// <summary>Constructs a new CollectionNavigator.</summary>
     public CollectionNavigator () { }
     public CollectionNavigator () { }
 
 
@@ -15,11 +18,39 @@ internal class CollectionNavigator : CollectionNavigatorBase, IListCollectionNav
     public CollectionNavigator (IList collection) { Collection = collection; }
     public CollectionNavigator (IList collection) { Collection = collection; }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    public IList Collection { get; set; }
+    public IList Collection
+    {
+        get
+        {
+            lock (_collectionLock)
+            {
+                return _collection;
+            }
+        }
+        set
+        {
+            lock (_collectionLock)
+            {
+                _collection = value;
+            }
+        }
+    }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    protected override object ElementAt (int idx) { return Collection [idx]; }
+    protected override object ElementAt (int idx)
+    {
+        lock (_collectionLock)
+        {
+            return Collection [idx];
+        }
+    }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    protected override int GetCollectionLength () { return Collection.Count; }
+    protected override int GetCollectionLength ()
+    {
+        lock (_collectionLock)
+        {
+            return Collection.Count;
+        }
+    }
 }
 }

+ 38 - 10
Terminal.Gui/Views/CollectionNavigation/CollectionNavigatorBase.cs

@@ -1,10 +1,9 @@
-
-
 namespace Terminal.Gui.Views;
 namespace Terminal.Gui.Views;
 
 
 /// <inheritdoc/>
 /// <inheritdoc/>
 internal abstract class CollectionNavigatorBase : ICollectionNavigator
 internal abstract class CollectionNavigatorBase : ICollectionNavigator
 {
 {
+    private readonly object _lock = new ();
     private DateTime _lastKeystroke = DateTime.Now;
     private DateTime _lastKeystroke = DateTime.Now;
     private string _searchString = "";
     private string _searchString = "";
 
 
@@ -14,10 +13,20 @@ internal abstract class CollectionNavigatorBase : ICollectionNavigator
     /// <inheritdoc/>
     /// <inheritdoc/>
     public string SearchString
     public string SearchString
     {
     {
-        get => _searchString;
+        get
+        {
+            lock (_lock)
+            {
+                return _searchString;
+            }
+        }
         private set
         private set
         {
         {
-            _searchString = value;
+            lock (_lock)
+            {
+                _searchString = value;
+            }
+
             OnSearchStringChanged (new (value));
             OnSearchStringChanged (new (value));
         }
         }
     }
     }
@@ -40,15 +49,22 @@ internal abstract class CollectionNavigatorBase : ICollectionNavigator
             // but if we find none then we must fallback on cycling
             // but if we find none then we must fallback on cycling
             // d instead and discard the candidate state
             // d instead and discard the candidate state
             var candidateState = "";
             var candidateState = "";
-            TimeSpan elapsedTime = DateTime.Now - _lastKeystroke;
+            TimeSpan elapsedTime;
+            string currentSearchString;
+
+            lock (_lock)
+            {
+                elapsedTime = DateTime.Now - _lastKeystroke;
+                currentSearchString = _searchString;
+            }
 
 
             Logging.Debug ($"CollectionNavigator began processing '{keyStruck}', it has been {elapsedTime} since last keystroke");
             Logging.Debug ($"CollectionNavigator began processing '{keyStruck}', it has been {elapsedTime} since last keystroke");
 
 
             // is it a second or third (etc) keystroke within a short time
             // is it a second or third (etc) keystroke within a short time
-            if (SearchString.Length > 0 && elapsedTime < TimeSpan.FromMilliseconds (TypingDelay))
+            if (currentSearchString.Length > 0 && elapsedTime < TimeSpan.FromMilliseconds (TypingDelay))
             {
             {
                 // "dd" is a candidate
                 // "dd" is a candidate
-                candidateState = SearchString + keyStruck;
+                candidateState = currentSearchString + keyStruck;
                 Logging.Debug ($"Appending, search is now for '{candidateState}'");
                 Logging.Debug ($"Appending, search is now for '{candidateState}'");
             }
             }
             else
             else
@@ -72,7 +88,11 @@ internal abstract class CollectionNavigatorBase : ICollectionNavigator
             if (idxCandidate is { })
             if (idxCandidate is { })
             {
             {
                 // found "dd" so candidate search string is accepted
                 // found "dd" so candidate search string is accepted
-                _lastKeystroke = DateTime.Now;
+                lock (_lock)
+                {
+                    _lastKeystroke = DateTime.Now;
+                }
+
                 SearchString = candidateState;
                 SearchString = candidateState;
 
 
                 Logging.Debug ($"Found collection item that matched search:{idxCandidate}");
                 Logging.Debug ($"Found collection item that matched search:{idxCandidate}");
@@ -82,7 +102,11 @@ internal abstract class CollectionNavigatorBase : ICollectionNavigator
 
 
             //// nothing matches "dd" so discard it as a candidate
             //// nothing matches "dd" so discard it as a candidate
             //// and just cycle "d" instead
             //// and just cycle "d" instead
-            _lastKeystroke = DateTime.Now;
+            lock (_lock)
+            {
+                _lastKeystroke = DateTime.Now;
+            }
+
             idxCandidate = GetNextMatchingItem (currentIndex, candidateState);
             idxCandidate = GetNextMatchingItem (currentIndex, candidateState);
 
 
             Logging.Debug ($"CollectionNavigator searching (any match) matched:{idxCandidate}");
             Logging.Debug ($"CollectionNavigator searching (any match) matched:{idxCandidate}");
@@ -206,6 +230,10 @@ internal abstract class CollectionNavigatorBase : ICollectionNavigator
     private void ClearSearchString ()
     private void ClearSearchString ()
     {
     {
         SearchString = "";
         SearchString = "";
-        _lastKeystroke = DateTime.Now;
+
+        lock (_lock)
+        {
+            _lastKeystroke = DateTime.Now;
+        }
     }
     }
 }
 }

+ 2 - 2
Terminal.Gui/Views/Color/ColorPicker.Prompt.cs

@@ -37,7 +37,7 @@ public partial class ColorPicker
                         {
                         {
                             accept = true;
                             accept = true;
                             e.Handled = true;
                             e.Handled = true;
-                            Application.RequestStop ();
+                            (s as View)?.App?.RequestStop ();
                         };
                         };
 
 
         var btnCancel = new Button
         var btnCancel = new Button
@@ -51,7 +51,7 @@ public partial class ColorPicker
         btnCancel.Accepting += (s, e) =>
         btnCancel.Accepting += (s, e) =>
                             {
                             {
                                 e.Handled = true;
                                 e.Handled = true;
-                                Application.RequestStop ();
+                                (s as View)?.App ?.RequestStop ();
                             };
                             };
 
 
         d.Add (btnOk);
         d.Add (btnOk);

+ 37 - 7
Terminal.Gui/Views/Dialog.cs

@@ -1,4 +1,3 @@
-
 namespace Terminal.Gui.Views;
 namespace Terminal.Gui.Views;
 
 
 /// <summary>
 /// <summary>
@@ -23,6 +22,13 @@ namespace Terminal.Gui.Views;
 /// </remarks>
 /// </remarks>
 public class Dialog : Window, IRunnable<int?>
 public class Dialog : Window, IRunnable<int?>
 {
 {
+    private static LineStyle _defaultBorderStyle = LineStyle.Heavy; // Resources/config.json overrides
+    private static Alignment _defaultButtonAlignment = Alignment.End; // Resources/config.json overrides
+    private static AlignmentModes _defaultButtonAlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems; // Resources/config.json overrides
+    private static int _defaultMinimumHeight = 80; // Resources/config.json overrides
+    private static int _defaultMinimumWidth = 80; // Resources/config.json overrides
+    private static ShadowStyle _defaultShadow = ShadowStyle.Transparent; // Resources/config.json overrides
+
     /// <summary>
     /// <summary>
     ///     Initializes a new instance of the <see cref="Dialog"/> class with no <see cref="Button"/>s.
     ///     Initializes a new instance of the <see cref="Dialog"/> class with no <see cref="Button"/>s.
     /// </summary>
     /// </summary>
@@ -136,37 +142,61 @@ public class Dialog : Window, IRunnable<int?>
     /// </summary>
     /// </summary>
 
 
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public new static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Heavy;
+    public new static LineStyle DefaultBorderStyle
+    {
+        get => _defaultBorderStyle;
+        set => _defaultBorderStyle = value;
+    }
 
 
     /// <summary>The default <see cref="Alignment"/> for <see cref="Dialog"/>.</summary>
     /// <summary>The default <see cref="Alignment"/> for <see cref="Dialog"/>.</summary>
     /// <remarks>This property can be set in a Theme.</remarks>
     /// <remarks>This property can be set in a Theme.</remarks>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static Alignment DefaultButtonAlignment { get; set; } = Alignment.End;
+    public static Alignment DefaultButtonAlignment
+    {
+        get => _defaultButtonAlignment;
+        set => _defaultButtonAlignment = value;
+    }
 
 
     /// <summary>The default <see cref="AlignmentModes"/> for <see cref="Dialog"/>.</summary>
     /// <summary>The default <see cref="AlignmentModes"/> for <see cref="Dialog"/>.</summary>
     /// <remarks>This property can be set in a Theme.</remarks>
     /// <remarks>This property can be set in a Theme.</remarks>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static AlignmentModes DefaultButtonAlignmentModes { get; set; } = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems;
+    public static AlignmentModes DefaultButtonAlignmentModes
+    {
+        get => _defaultButtonAlignmentModes;
+        set => _defaultButtonAlignmentModes = value;
+    }
 
 
     /// <summary>
     /// <summary>
     ///     Defines the default minimum Dialog height, as a percentage of the container width. Can be configured via
     ///     Defines the default minimum Dialog height, as a percentage of the container width. Can be configured via
     ///     <see cref="ConfigurationManager"/>.
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static int DefaultMinimumHeight { get; set; } = 80;
+    public static int DefaultMinimumHeight
+    {
+        get => _defaultMinimumHeight;
+        set => _defaultMinimumHeight = value;
+    }
 
 
     /// <summary>
     /// <summary>
     ///     Defines the default minimum Dialog width, as a percentage of the container width. Can be configured via
     ///     Defines the default minimum Dialog width, as a percentage of the container width. Can be configured via
     ///     <see cref="ConfigurationManager"/>.
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static int DefaultMinimumWidth { get; set; } = 80;
+    public static int DefaultMinimumWidth
+    {
+        get => _defaultMinimumWidth;
+        set => _defaultMinimumWidth = value;
+    }
 
 
     /// <summary>
     /// <summary>
     ///     Gets or sets whether all <see cref="Window"/>s are shown with a shadow effect by default.
     ///     Gets or sets whether all <see cref="Window"/>s are shown with a shadow effect by default.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public new static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.Transparent;
+    public new static ShadowStyle DefaultShadow
+    {
+        get => _defaultShadow;
+        set => _defaultShadow = value;
+    }
 
 
 
 
     // Dialogs are Modal and Focus is indicated by their Border. The following code ensures the
     // Dialogs are Modal and Focus is indicated by their Border. The following code ensures the

+ 9 - 9
Terminal.Gui/Views/FileDialogs/DefaultFileOperations.cs

@@ -7,7 +7,7 @@ namespace Terminal.Gui.Views;
 public class DefaultFileOperations : IFileOperations
 public class DefaultFileOperations : IFileOperations
 {
 {
     /// <inheritdoc/>
     /// <inheritdoc/>
-    public bool Delete (IEnumerable<IFileSystemInfo> toDelete)
+    public bool Delete (IApplication app, IEnumerable<IFileSystemInfo> toDelete)
     {
     {
         // Default implementation does not allow deleting multiple files
         // Default implementation does not allow deleting multiple files
         if (toDelete.Count () != 1)
         if (toDelete.Count () != 1)
@@ -18,7 +18,7 @@ public class DefaultFileOperations : IFileOperations
         IFileSystemInfo d = toDelete.Single ();
         IFileSystemInfo d = toDelete.Single ();
         string adjective = d.Name;
         string adjective = d.Name;
 
 
-        int result = MessageBox.Query (
+        int? result = MessageBox.Query (app,
                                        string.Format (Strings.fdDeleteTitle, adjective),
                                        string.Format (Strings.fdDeleteTitle, adjective),
                                        string.Format (Strings.fdDeleteBody, adjective),
                                        string.Format (Strings.fdDeleteBody, adjective),
                                        Strings.btnYes,
                                        Strings.btnYes,
@@ -43,14 +43,14 @@ public class DefaultFileOperations : IFileOperations
         }
         }
         catch (Exception ex)
         catch (Exception ex)
         {
         {
-            MessageBox.ErrorQuery (Strings.fdDeleteFailedTitle, ex.Message, Strings.btnOk);
+            MessageBox.ErrorQuery (app, Strings.fdDeleteFailedTitle, ex.Message, Strings.btnOk);
         }
         }
 
 
         return false;
         return false;
     }
     }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    public IFileSystemInfo Rename (IFileSystem fileSystem, IFileSystemInfo toRename)
+    public IFileSystemInfo Rename (IApplication app, IFileSystem fileSystem, IFileSystemInfo toRename)
     {
     {
         // Don't allow renaming C: or D: or / (on linux) etc
         // Don't allow renaming C: or D: or / (on linux) etc
         if (toRename is IDirectoryInfo dir && dir.Parent is null)
         if (toRename is IDirectoryInfo dir && dir.Parent is null)
@@ -95,7 +95,7 @@ public class DefaultFileOperations : IFileOperations
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {
-                    MessageBox.ErrorQuery (Strings.fdRenameFailedTitle, ex.Message, "Ok");
+                    MessageBox.ErrorQuery (app, Strings.fdRenameFailedTitle, ex.Message, "Ok");
                 }
                 }
             }
             }
         }
         }
@@ -104,7 +104,7 @@ public class DefaultFileOperations : IFileOperations
     }
     }
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    public IFileSystemInfo New (IFileSystem fileSystem, IDirectoryInfo inDirectory)
+    public IFileSystemInfo New (IApplication app, IFileSystem fileSystem, IDirectoryInfo inDirectory)
     {
     {
         if (Prompt (Strings.fdNewTitle, "", out string named))
         if (Prompt (Strings.fdNewTitle, "", out string named))
         {
         {
@@ -122,7 +122,7 @@ public class DefaultFileOperations : IFileOperations
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {
-                    MessageBox.ErrorQuery (Strings.fdNewFailed, ex.Message, "Ok");
+                    MessageBox.ErrorQuery (app, Strings.fdNewFailed, ex.Message, "Ok");
                 }
                 }
             }
             }
         }
         }
@@ -138,7 +138,7 @@ public class DefaultFileOperations : IFileOperations
         btnOk.Accepting += (s, e) =>
         btnOk.Accepting += (s, e) =>
                          {
                          {
                              confirm = true;
                              confirm = true;
-                             Application.RequestStop ();
+                             (s as View)?.App?.RequestStop ();
                              // When Accepting is handled, set e.Handled to true to prevent further processing.
                              // When Accepting is handled, set e.Handled to true to prevent further processing.
                              e.Handled = true;
                              e.Handled = true;
                          };
                          };
@@ -147,7 +147,7 @@ public class DefaultFileOperations : IFileOperations
         btnCancel.Accepting += (s, e) =>
         btnCancel.Accepting += (s, e) =>
                              {
                              {
                                  confirm = false;
                                  confirm = false;
-                                 Application.RequestStop ();
+                                 (s as View)?.App?.RequestStop ();
                                  // When Accepting is handled, set e.Handled to true to prevent further processing.
                                  // When Accepting is handled, set e.Handled to true to prevent further processing.
                                  e.Handled = true;
                                  e.Handled = true;
                              };
                              };

+ 10 - 10
Terminal.Gui/Views/FileDialogs/FileDialog.cs

@@ -108,7 +108,7 @@ public class FileDialog : Dialog, IDesignable
 
 
                                     if (Modal)
                                     if (Modal)
                                     {
                                     {
-                                        Application.RequestStop ();
+                                        (s as View)?.App?.RequestStop ();
                                     }
                                     }
                                 };
                                 };
 
 
@@ -468,7 +468,6 @@ public class FileDialog : Dialog, IDesignable
         Style.IconProvider.IsOpenGetter = _treeView.IsExpanded;
         Style.IconProvider.IsOpenGetter = _treeView.IsExpanded;
 
 
         _treeView.AddObjects (_treeRoots.Keys);
         _treeView.AddObjects (_treeRoots.Keys);
-#if MENU_V1
 
 
         // if filtering on file type is configured then create the ComboBox and establish
         // if filtering on file type is configured then create the ComboBox and establish
         // initial filtering by extension(s)
         // initial filtering by extension(s)
@@ -479,6 +478,7 @@ public class FileDialog : Dialog, IDesignable
             // Fiddle factor
             // Fiddle factor
             int width = AllowedTypes.Max (a => a.ToString ()!.Length) + 6;
             int width = AllowedTypes.Max (a => a.ToString ()!.Length) + 6;
 
 
+#if MENU_V1
             _allowedTypeMenu = new (
             _allowedTypeMenu = new (
                                     "<placeholder>",
                                     "<placeholder>",
                                     _allowedTypeMenuItems = AllowedTypes.Select (
                                     _allowedTypeMenuItems = AllowedTypes.Select (
@@ -512,8 +512,8 @@ public class FileDialog : Dialog, IDesignable
                                                   };
                                                   };
 
 
             Add (_allowedTypeMenuBar);
             Add (_allowedTypeMenuBar);
-        }
 #endif
 #endif
+        }
 
 
         // if no path has been provided
         // if no path has been provided
         if (_tbPath.Text.Length <= 0)
         if (_tbPath.Text.Length <= 0)
@@ -849,7 +849,7 @@ public class FileDialog : Dialog, IDesignable
     {
     {
         IFileSystemInfo [] toDelete = GetFocusedFiles ()!;
         IFileSystemInfo [] toDelete = GetFocusedFiles ()!;
 
 
-        if (FileOperationsHandler.Delete (toDelete))
+        if (FileOperationsHandler.Delete (App, toDelete))
         {
         {
             RefreshState ();
             RefreshState ();
         }
         }
@@ -879,7 +879,7 @@ public class FileDialog : Dialog, IDesignable
 
 
         if (Modal)
         if (Modal)
         {
         {
-            Application.RequestStop ();
+            App?.RequestStop ();
         }
         }
     }
     }
 
 
@@ -1039,7 +1039,7 @@ public class FileDialog : Dialog, IDesignable
     private void New ()
     private void New ()
     {
     {
         {
         {
-            IFileSystemInfo created = FileOperationsHandler.New (_fileSystem!, State!.Directory);
+            IFileSystemInfo created = FileOperationsHandler.New (App, _fileSystem!, State!.Directory);
 
 
             if (created is { })
             if (created is { })
             {
             {
@@ -1174,13 +1174,13 @@ public class FileDialog : Dialog, IDesignable
         PushState (State, false, false, false);
         PushState (State, false, false, false);
     }
     }
 
 
-    private void Rename ()
+    private void Rename (IApplication? app)
     {
     {
         IFileSystemInfo [] toRename = GetFocusedFiles ()!;
         IFileSystemInfo [] toRename = GetFocusedFiles ()!;
 
 
         if (toRename?.Length == 1)
         if (toRename?.Length == 1)
         {
         {
-            IFileSystemInfo newNamed = FileOperationsHandler.Rename (_fileSystem!, toRename.Single ());
+            IFileSystemInfo newNamed = FileOperationsHandler.Rename (app, _fileSystem!, toRename.Single ());
 
 
             if (newNamed is { })
             if (newNamed is { })
             {
             {
@@ -1230,7 +1230,7 @@ public class FileDialog : Dialog, IDesignable
         PopoverMenu? contextMenu = new (
         PopoverMenu? contextMenu = new (
                                         [
                                         [
                                             new (Strings.fdCtxNew, string.Empty, New),
                                             new (Strings.fdCtxNew, string.Empty, New),
-                                            new (Strings.fdCtxRename, string.Empty, Rename),
+                                            new (Strings.fdCtxRename, string.Empty, () => Rename (App)),
                                             new (Strings.fdCtxDelete, string.Empty, Delete)
                                             new (Strings.fdCtxDelete, string.Empty, Delete)
                                         ]);
                                         ]);
 
 
@@ -1327,7 +1327,7 @@ public class FileDialog : Dialog, IDesignable
 
 
         if (keyEvent.KeyCode == (KeyCode.CtrlMask | KeyCode.R))
         if (keyEvent.KeyCode == (KeyCode.CtrlMask | KeyCode.R))
         {
         {
-            Rename ();
+            Rename (App);
 
 
             return true;
             return true;
         }
         }

+ 9 - 5
Terminal.Gui/Views/FrameView.cs

@@ -1,5 +1,3 @@
-
-
 namespace Terminal.Gui.Views;
 namespace Terminal.Gui.Views;
 
 
 // TODO: FrameView is mis-named, really. It's far more about it being a TabGroup than a frame. 
 // TODO: FrameView is mis-named, really. It's far more about it being a TabGroup than a frame. 
@@ -19,6 +17,8 @@ namespace Terminal.Gui.Views;
 /// <seealso cref="Window"/>
 /// <seealso cref="Window"/>
 public class FrameView : View
 public class FrameView : View
 {
 {
+    private static LineStyle _defaultBorderStyle = LineStyle.Rounded; // Resources/config.json overrides
+
     /// <summary>
     /// <summary>
     ///     Initializes a new instance of the <see cref="FrameView"/> class.
     ///     Initializes a new instance of the <see cref="FrameView"/> class.
     ///     layout.
     ///     layout.
@@ -31,13 +31,17 @@ public class FrameView : View
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     The default <see cref="LineStyle"/> for <see cref="FrameView"/>'s border. The default is
-    ///     <see cref="LineStyle.Single"/>.
+    ///     Defines the default border styling for <see cref="FrameView"/>. Can be configured via
+    ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
     ///     This property can be set in a Theme to change the default <see cref="LineStyle"/> for all
     ///     This property can be set in a Theme to change the default <see cref="LineStyle"/> for all
     ///     <see cref="FrameView"/>s.
     ///     <see cref="FrameView"/>s.
     /// </remarks>
     /// </remarks>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Rounded;
+    public static LineStyle DefaultBorderStyle
+    {
+        get => _defaultBorderStyle;
+        set => _defaultBorderStyle = value;
+    }
 }
 }

+ 0 - 1
Terminal.Gui/Views/GraphView/GraphView.cs

@@ -8,7 +8,6 @@ public class GraphView : View, IDesignable
     /// <summary>Creates a new graph with a 1 to 1 graph space with absolute layout.</summary>
     /// <summary>Creates a new graph with a 1 to 1 graph space with absolute layout.</summary>
     public GraphView ()
     public GraphView ()
     {
     {
-        App = ApplicationImpl.Instance;
         CanFocus = true;
         CanFocus = true;
 
 
         AxisX = new ();
         AxisX = new ();

+ 4 - 4
Terminal.Gui/Views/Menu/MenuBar.cs

@@ -591,7 +591,7 @@ public class MenuBar : Menu, IDesignable
                                                            {
                                                            {
                                                                Title = "_File Settings...",
                                                                Title = "_File Settings...",
                                                                HelpText = "More file settings",
                                                                HelpText = "More file settings",
-                                                               Action = () => MessageBox.Query (
+                                                               Action = () => MessageBox.Query (App,
                                                                                                 "File Settings",
                                                                                                 "File Settings",
                                                                                                 "This is the File Settings Dialog\n",
                                                                                                 "This is the File Settings Dialog\n",
                                                                                                 "_Ok",
                                                                                                 "_Ok",
@@ -665,12 +665,12 @@ public class MenuBar : Menu, IDesignable
                                     new MenuItem
                                     new MenuItem
                                     {
                                     {
                                         Title = "_Online Help...",
                                         Title = "_Online Help...",
-                                        Action = () => MessageBox.Query ("Online Help", "https://gui-cs.github.io/Terminal.Gui", "Ok")
+                                        Action = () => MessageBox.Query (App, "Online Help", "https://gui-cs.github.io/Terminal.Gui", "Ok")
                                     },
                                     },
                                     new MenuItem
                                     new MenuItem
                                     {
                                     {
                                         Title = "About...",
                                         Title = "About...",
-                                        Action = () => MessageBox.Query ("About", "Something About Mary.", "Ok")
+                                        Action = () => MessageBox.Query (App, "About", "Something About Mary.", "Ok")
                                     }
                                     }
                                 ]
                                 ]
                                )
                                )
@@ -734,7 +734,7 @@ public class MenuBar : Menu, IDesignable
                 {
                 {
                     Title = "_Deeper Detail",
                     Title = "_Deeper Detail",
                     Text = "Deeper Detail",
                     Text = "Deeper Detail",
-                    Action = () => { MessageBox.Query ("Deeper Detail", "Lots of details", "_Ok"); }
+                    Action = () => { MessageBox.Query (App, "Deeper Detail", "Lots of details", "_Ok"); }
                 };
                 };
 
 
                 var belowLineDetail = new MenuItem
                 var belowLineDetail = new MenuItem

+ 412 - 178
Terminal.Gui/Views/MessageBox.cs

@@ -1,59 +1,109 @@
-#nullable disable
-
 namespace Terminal.Gui.Views;
 namespace Terminal.Gui.Views;
 
 
 /// <summary>
 /// <summary>
-///     MessageBox displays a modal message to the user, with a title, a message and a series of options that the user
-///     can choose from.
+///     Displays a modal message box with a title, message, and buttons. Returns the index of the selected button,
+///     or <see langword="null"/> if the user cancels with <see cref="Application.QuitKey"/>.
 /// </summary>
 /// </summary>
-/// <para>
-///     The difference between the <see cref="Query(string, string, string[])"/> and
-///     <see cref="ErrorQuery(string, string, string[])"/> method is the default set of colors used for the message box.
-/// </para>
-/// <para>
-///     The following example pops up a <see cref="MessageBox"/> with the specified title and text, plus two
-///     <see cref="Button"/>s. The value -1 is returned when the user cancels the <see cref="MessageBox"/> by pressing the
-///     ESC key.
-/// </para>
-/// <example>
-///     <code lang="c#">
-/// var n = MessageBox.Query ("Quit Demo", "Are you sure you want to quit this demo?", "Yes", "No");
-/// if (n == 0)
-///    quit = true;
-/// else
-///    quit = false;
-/// </code>
-/// </example>
+/// <remarks>
+///     <para>
+///         MessageBox provides static methods for displaying modal dialogs with customizable buttons and messages.
+///         All methods return <see langword="int?"/> where the value is the 0-based index of the button pressed,
+///         or <see langword="null"/> if the user pressed <see cref="Application.QuitKey"/> (typically Esc).
+///     </para>
+///     <para>
+///         <see cref="Query(IApplication?, string, string, string[])"/> uses the default Dialog color scheme.
+///         <see cref="ErrorQuery(IApplication?, string, string, string[])"/> uses the Error color scheme.
+///     </para>
+///     <para>
+///         <b>Important:</b> All MessageBox methods require an <see cref="IApplication"/> instance to be passed.
+///         This enables proper modal dialog management and respects the application's lifecycle. Pass your
+///         application instance (from <see cref="Application.Create()"/>) or use the legacy
+///         <see cref="ApplicationImpl.Instance"/> if using the static Application pattern.
+///     </para>
+///     <para>
+///         Example using instance-based pattern:
+///         <code>
+///     IApplication app = Application.Create();
+///     app.Init();
+///     
+///     int? result = MessageBox.Query(app, "Quit Demo", "Are you sure you want to quit?", "Yes", "No");
+///     if (result == 0) // User clicked "Yes"
+///         app.RequestStop();
+///     else if (result == null) // User pressed Esc
+///         // Handle cancellation
+///         
+///     app.Shutdown();
+///     </code>
+///     </para>
+///     <para>
+///         Example using legacy static pattern:
+///         <code>
+///     Application.Init();
+///     
+///     int? result = MessageBox.Query(ApplicationImpl.Instance, "Quit Demo", "Are you sure?", "Yes", "No");
+///     if (result == 0) // User clicked "Yes"
+///         Application.RequestStop();
+///     
+///     Application.Shutdown();
+///     </code>
+///     </para>
+///     <para>
+///         The <see cref="Clicked"/> property provides a global variable alternative for web-based consoles
+///         without SynchronizationContext. However, using the return value is preferred as it's more thread-safe
+///         and follows modern async patterns.
+///     </para>
+/// </remarks>
 public static class MessageBox
 public static class MessageBox
 {
 {
+    private static LineStyle _defaultBorderStyle = LineStyle.Heavy; // Resources/config.json overrides
+    private static Alignment _defaultButtonAlignment = Alignment.Center; // Resources/config.json overrides
+    private static int _defaultMinimumWidth = 0; // Resources/config.json overrides
+    private static int _defaultMinimumHeight = 0; // Resources/config.json overrides
+
     /// <summary>
     /// <summary>
     ///     Defines the default border styling for <see cref="MessageBox"/>. Can be configured via
     ///     Defines the default border styling for <see cref="MessageBox"/>. Can be configured via
     ///     <see cref="ConfigurationManager"/>.
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Heavy;
+    public static LineStyle DefaultBorderStyle
+    {
+        get => _defaultBorderStyle;
+        set => _defaultBorderStyle = value;
+    }
 
 
     /// <summary>The default <see cref="Alignment"/> for <see cref="Dialog"/>.</summary>
     /// <summary>The default <see cref="Alignment"/> for <see cref="Dialog"/>.</summary>
     /// <remarks>This property can be set in a Theme.</remarks>
     /// <remarks>This property can be set in a Theme.</remarks>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static Alignment DefaultButtonAlignment { get; set; } = Alignment.Center;
+    public static Alignment DefaultButtonAlignment
+    {
+        get => _defaultButtonAlignment;
+        set => _defaultButtonAlignment = value;
+    }
 
 
     /// <summary>
     /// <summary>
     ///     Defines the default minimum MessageBox width, as a percentage of the screen width. Can be configured via
     ///     Defines the default minimum MessageBox width, as a percentage of the screen width. Can be configured via
     ///     <see cref="ConfigurationManager"/>.
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static int DefaultMinimumWidth { get; set; } = 0;
+    public static int DefaultMinimumWidth
+    {
+        get => _defaultMinimumWidth;
+        set => _defaultMinimumWidth = value;
+    }
 
 
     /// <summary>
     /// <summary>
     ///     Defines the default minimum Dialog height, as a percentage of the screen width. Can be configured via
     ///     Defines the default minimum Dialog height, as a percentage of the screen width. Can be configured via
     ///     <see cref="ConfigurationManager"/>.
     ///     <see cref="ConfigurationManager"/>.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static int DefaultMinimumHeight { get; set; } = 0;
+    public static int DefaultMinimumHeight
+    {
+        get => _defaultMinimumHeight;
+        set => _defaultMinimumHeight = value;
+    }
+
     /// <summary>
     /// <summary>
-    ///     The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox. This is useful for web
-    ///     based console where there is no SynchronizationContext or TaskScheduler.
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed <see cref="Application.QuitKey"/>.
     /// </summary>
     /// </summary>
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
@@ -65,55 +115,97 @@ public static class MessageBox
     ///         non-global alternative for custom dialog implementations.
     ///         non-global alternative for custom dialog implementations.
     ///     </para>
     ///     </para>
     /// </remarks>
     /// </remarks>
-    public static int Clicked { get; private set; } = -1;
+    public static int? Clicked { get; private set; }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons.
+    ///     Displays an error <see cref="MessageBox"/> with fixed dimensions.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
     /// <param name="width">Width for the MessageBox.</param>
     /// <param name="width">Width for the MessageBox.</param>
     /// <param name="height">Height for the MessageBox.</param>
     /// <param name="height">Height for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="message">Message to display. May contain multiple lines and will be word-wrapped.</param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    ///     Use <see cref="ErrorQuery(string, string, string[])"/> instead; it automatically sizes the MessageBox based on
-    ///     the contents.
+    ///     Consider using <see cref="ErrorQuery(IApplication?, string, string, string[])"/> which automatically sizes the
+    ///     MessageBox.
     /// </remarks>
     /// </remarks>
-    public static int ErrorQuery (int width, int height, string title, string message, params string [] buttons)
+    public static int? ErrorQuery (
+        IApplication? app,
+        int width,
+        int height,
+        string title,
+        string message,
+        params string [] buttons
+    )
     {
     {
-        return QueryFull (true, width, height, title, message, 0, true, buttons);
+        return QueryFull (
+                          app,
+                          true,
+                          width,
+                          height,
+                          title,
+                          message,
+                          0,
+                          true,
+                          buttons);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons to show
-    ///     to the user.
+    ///     Displays an auto-sized error <see cref="MessageBox"/>.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
-    /// <param name="title">Title for the query.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
+    /// <param name="title">Title for the MessageBox.</param>
+    /// <param name="message">Message to display. May contain multiple lines and will be word-wrapped.</param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    ///     The message box will be vertically and horizontally centered in the container and the size will be
-    ///     automatically determined from the size of the title, message. and buttons.
+    ///     The MessageBox is centered and auto-sized based on title, message, and buttons.
     /// </remarks>
     /// </remarks>
-    public static int ErrorQuery (string title, string message, params string [] buttons) { return QueryFull (true, 0, 0, title, message, 0, true, buttons); }
+    public static int? ErrorQuery (IApplication? app, string title, string message, params string [] buttons)
+    {
+        return QueryFull (
+                          app,
+                          true,
+                          0,
+                          0,
+                          title,
+                          message,
+                          0,
+                          true,
+                          buttons);
+    }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons.
+    ///     Displays an error <see cref="MessageBox"/> with fixed dimensions and a default button.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
     /// <param name="width">Width for the MessageBox.</param>
     /// <param name="width">Width for the MessageBox.</param>
     /// <param name="height">Height for the MessageBox.</param>
     /// <param name="height">Height for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="defaultButton">Index of the default button.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="message">Message to display. May contain multiple lines and will be word-wrapped.</param>
+    /// <param name="defaultButton">Index of the default button (0-based).</param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    ///     Use <see cref="ErrorQuery(string, string, string[])"/> instead; it automatically sizes the MessageBox based on
-    ///     the contents.
+    ///     Consider using <see cref="ErrorQuery(IApplication?, string, string, int, string[])"/> which automatically sizes the
+    ///     MessageBox.
     /// </remarks>
     /// </remarks>
-    public static int ErrorQuery (
+    public static int? ErrorQuery (
+        IApplication? app,
         int width,
         int width,
         int height,
         int height,
         string title,
         string title,
@@ -122,44 +214,73 @@ public static class MessageBox
         params string [] buttons
         params string [] buttons
     )
     )
     {
     {
-        return QueryFull (true, width, height, title, message, defaultButton, true, buttons);
+        return QueryFull (
+                          app,
+                          true,
+                          width,
+                          height,
+                          title,
+                          message,
+                          defaultButton,
+                          true,
+                          buttons);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons to show
-    ///     to the user.
+    ///     Displays an auto-sized error <see cref="MessageBox"/> with a default button.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
     /// <param name="title">Title for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="defaultButton">Index of the default button.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="message">Message to display. May contain multiple lines and will be word-wrapped.</param>
+    /// <param name="defaultButton">Index of the default button (0-based).</param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    ///     The message box will be vertically and horizontally centered in the container and the size will be
-    ///     automatically determined from the size of the title, message. and buttons.
+    ///     The MessageBox is centered and auto-sized based on title, message, and buttons.
     /// </remarks>
     /// </remarks>
-    public static int ErrorQuery (string title, string message, int defaultButton = 0, params string [] buttons)
+    public static int? ErrorQuery (IApplication? app, string title, string message, int defaultButton = 0, params string [] buttons)
     {
     {
-        return QueryFull (true, 0, 0, title, message, defaultButton, true, buttons);
+        return QueryFull (
+                          app,
+                          true,
+                          0,
+                          0,
+                          title,
+                          message,
+                          defaultButton,
+                          true,
+                          buttons);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons to show
-    ///     to the user.
+    ///     Displays an error <see cref="MessageBox"/> with fixed dimensions, a default button, and word-wrap control.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
-    /// <param name="width">Width for the window.</param>
-    /// <param name="height">Height for the window.</param>
-    /// <param name="title">Title for the query.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="defaultButton">Index of the default button.</param>
-    /// <param name="wrapMessage">If wrap the message or not.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
+    /// <param name="width">Width for the MessageBox.</param>
+    /// <param name="height">Height for the MessageBox.</param>
+    /// <param name="title">Title for the MessageBox.</param>
+    /// <param name="message">Message to display. May contain multiple lines.</param>
+    /// <param name="defaultButton">Index of the default button (0-based).</param>
+    /// <param name="wrapMessage">
+    ///     If <see langword="true"/>, word-wraps the message; otherwise displays as-is with multi-line
+    ///     support.
+    /// </param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    ///     Use <see cref="ErrorQuery(string, string, string[])"/> instead; it automatically sizes the MessageBox based on
-    ///     the contents.
+    ///     Consider using <see cref="ErrorQuery(IApplication?, string, string, int, bool, string[])"/> which automatically
+    ///     sizes the MessageBox.
     /// </remarks>
     /// </remarks>
-    public static int ErrorQuery (
+    public static int? ErrorQuery (
+        IApplication? app,
         int width,
         int width,
         int height,
         int height,
         string title,
         string title,
@@ -169,24 +290,40 @@ public static class MessageBox
         params string [] buttons
         params string [] buttons
     )
     )
     {
     {
-        return QueryFull (true, width, height, title, message, defaultButton, wrapMessage, buttons);
+        return QueryFull (
+                          app,
+                          true,
+                          width,
+                          height,
+                          title,
+                          message,
+                          defaultButton,
+                          wrapMessage,
+                          buttons);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents an error <see cref="MessageBox"/> with the specified title and message and a list of buttons to show
-    ///     to the user.
+    ///     Displays an auto-sized error <see cref="MessageBox"/> with a default button and word-wrap control.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
-    /// <param name="title">Title for the query.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="defaultButton">Index of the default button.</param>
-    /// <param name="wrapMessage">If wrap the message or not. The default is <see langword="true"/></param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
+    /// <param name="title">Title for the MessageBox.</param>
+    /// <param name="message">Message to display. May contain multiple lines.</param>
+    /// <param name="defaultButton">Index of the default button (0-based).</param>
+    /// <param name="wrapMessage">
+    ///     If <see langword="true"/>, word-wraps the message; otherwise displays as-is with multi-line
+    ///     support.
+    /// </param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    ///     The message box will be vertically and horizontally centered in the container and the size will be
-    ///     automatically determined from the size of the title, message. and buttons.
+    ///     The MessageBox is centered and auto-sized based on title, message, and buttons.
     /// </remarks>
     /// </remarks>
-    public static int ErrorQuery (
+    public static int? ErrorQuery (
+        IApplication? app,
         string title,
         string title,
         string message,
         string message,
         int defaultButton = 0,
         int defaultButton = 0,
@@ -194,67 +331,100 @@ public static class MessageBox
         params string [] buttons
         params string [] buttons
     )
     )
     {
     {
-        return QueryFull (true, 0, 0, title, message, defaultButton, wrapMessage, buttons);
+        return QueryFull (
+                          app,
+                          true,
+                          0,
+                          0,
+                          title,
+                          message,
+                          defaultButton,
+                          wrapMessage,
+                          buttons);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents a <see cref="MessageBox"/> with the specified title and message and a list of buttons.
+    ///     Displays a <see cref="MessageBox"/> with fixed dimensions.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
     /// <param name="width">Width for the MessageBox.</param>
     /// <param name="width">Width for the MessageBox.</param>
     /// <param name="height">Height for the MessageBox.</param>
     /// <param name="height">Height for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="message">Message to display. May contain multiple lines and will be word-wrapped.</param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    ///     Use <see cref="Query(string, string, string[])"/> instead; it automatically sizes the MessageBox based on
-    ///     the contents.
+    ///     Consider using <see cref="Query(IApplication?, string, string, string[])"/> which automatically sizes the
+    ///     MessageBox.
     /// </remarks>
     /// </remarks>
-    public static int Query (int width, int height, string title, string message, params string [] buttons)
+    public static int? Query (IApplication? app, int width, int height, string title, string message, params string [] buttons)
     {
     {
-        return QueryFull (false, width, height, title, message, 0, true, buttons);
+        return QueryFull (
+                          app,
+                          false,
+                          width,
+                          height,
+                          title,
+                          message,
+                          0,
+                          true,
+                          buttons);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents a <see cref="MessageBox"/> with the specified title and message and a list of buttons.
+    ///     Displays an auto-sized <see cref="MessageBox"/>.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
     /// <param name="title">Title for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="message">Message to display. May contain multiple lines and will be word-wrapped.</param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    /// <para>
-    ///     The message box will be vertically and horizontally centered in the container and the size will be
-    ///     automatically determined from the size of the title, message. and buttons.
-    /// </para>
-    /// <para>
-    ///     Use <see cref="Query(string, string, string[])"/> instead; it automatically sizes the MessageBox based on
-    ///     the contents.
-    /// </para>
+    ///     The MessageBox is centered and auto-sized based on title, message, and buttons.
     /// </remarks>
     /// </remarks>
-    public static int Query (string title, string message, params string [] buttons) { return QueryFull (false, 0, 0, title, message, 0, true, buttons); }
+    public static int? Query (IApplication? app, string title, string message, params string [] buttons)
+    {
+        return QueryFull (
+                          app,
+                          false,
+                          0,
+                          0,
+                          title,
+                          message,
+                          0,
+                          true,
+                          buttons);
+    }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents a <see cref="MessageBox"/> with the specified title and message and a list of buttons.
+    ///     Displays a <see cref="MessageBox"/> with fixed dimensions and a default button.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
-    /// <param name="width">Width for the window.</param>
-    /// <param name="height">Height for the window.</param>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
+    /// <param name="width">Width for the MessageBox.</param>
+    /// <param name="height">Height for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="defaultButton">Index of the default button.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="message">Message to display. May contain multiple lines and will be word-wrapped.</param>
+    /// <param name="defaultButton">Index of the default button (0-based).</param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    /// <para>
-    ///     The message box will be vertically and horizontally centered in the container and the size will be
-    ///     automatically determined from the size of the title, message. and buttons.
-    /// </para>
-    /// <para>
-    ///     Use <see cref="Query(string, string, string[])"/> instead; it automatically sizes the MessageBox based on
-    ///     the contents.
-    /// </para>
+    ///     Consider using <see cref="Query(IApplication?, string, string, int, string[])"/> which automatically sizes the
+    ///     MessageBox.
     /// </remarks>
     /// </remarks>
-    public static int Query (
+    public static int? Query (
+        IApplication? app,
         int width,
         int width,
         int height,
         int height,
         string title,
         string title,
@@ -263,43 +433,73 @@ public static class MessageBox
         params string [] buttons
         params string [] buttons
     )
     )
     {
     {
-        return QueryFull (false, width, height, title, message, defaultButton, true, buttons);
+        return QueryFull (
+                          app,
+                          false,
+                          width,
+                          height,
+                          title,
+                          message,
+                          defaultButton,
+                          true,
+                          buttons);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents a <see cref="MessageBox"/> with the specified title and message and a list of buttons.
+    ///     Displays an auto-sized <see cref="MessageBox"/> with a default button.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
     /// <param name="title">Title for the MessageBox.</param>
     /// <param name="title">Title for the MessageBox.</param>
-    /// <param name="message">Message to display; might contain multiple lines. The message will be word=wrapped by default.</param>
-    /// <param name="defaultButton">Index of the default button.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="message">Message to display. May contain multiple lines and will be word-wrapped.</param>
+    /// <param name="defaultButton">Index of the default button (0-based).</param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    ///     The message box will be vertically and horizontally centered in the container and the size will be
-    ///     automatically determined from the size of the message and buttons.
+    ///     The MessageBox is centered and auto-sized based on title, message, and buttons.
     /// </remarks>
     /// </remarks>
-    public static int Query (string title, string message, int defaultButton = 0, params string [] buttons)
+    public static int? Query (IApplication? app, string title, string message, int defaultButton = 0, params string [] buttons)
     {
     {
-        return QueryFull (false, 0, 0, title, message, defaultButton, true, buttons);
+        return QueryFull (
+                          app,
+                          false,
+                          0,
+                          0,
+                          title,
+                          message,
+                          defaultButton,
+                          true,
+                          buttons);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents a <see cref="MessageBox"/> with the specified title and message and a list of buttons to show
-    ///     to the user.
+    ///     Displays a <see cref="MessageBox"/> with fixed dimensions, a default button, and word-wrap control.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
-    /// <param name="width">Width for the window.</param>
-    /// <param name="height">Height for the window.</param>
-    /// <param name="title">Title for the query.</param>
-    /// <param name="message">Message to display, might contain multiple lines.</param>
-    /// <param name="defaultButton">Index of the default button.</param>
-    /// <param name="wrapMessage">If wrap the message or not.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
+    /// <param name="width">Width for the MessageBox.</param>
+    /// <param name="height">Height for the MessageBox.</param>
+    /// <param name="title">Title for the MessageBox.</param>
+    /// <param name="message">Message to display. May contain multiple lines.</param>
+    /// <param name="defaultButton">Index of the default button (0-based).</param>
+    /// <param name="wrapMessage">
+    ///     If <see langword="true"/>, word-wraps the message; otherwise displays as-is with multi-line
+    ///     support.
+    /// </param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
     /// <remarks>
     /// <remarks>
-    ///     Use <see cref="Query(string, string, string[])"/> instead; it automatically sizes the MessageBox based on the
-    ///     contents.
+    ///     Consider using <see cref="Query(IApplication?, string, string, int, bool, string[])"/> which automatically sizes
+    ///     the MessageBox.
     /// </remarks>
     /// </remarks>
-    public static int Query (
+    public static int? Query (
+        IApplication? app,
         int width,
         int width,
         int height,
         int height,
         string title,
         string title,
@@ -309,20 +509,40 @@ public static class MessageBox
         params string [] buttons
         params string [] buttons
     )
     )
     {
     {
-        return QueryFull (false, width, height, title, message, defaultButton, wrapMessage, buttons);
+        return QueryFull (
+                          app,
+                          false,
+                          width,
+                          height,
+                          title,
+                          message,
+                          defaultButton,
+                          wrapMessage,
+                          buttons);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    ///     Presents a <see cref="MessageBox"/> with the specified title and message and a list of buttons to show
-    ///     to the user.
+    ///     Displays an auto-sized <see cref="MessageBox"/> with a default button and word-wrap control.
     /// </summary>
     /// </summary>
-    /// <returns>The index of the selected button, or -1 if the user pressed <see cref="Application.QuitKey"/> to close the MessageBox.</returns>
-    /// <param name="title">Title for the query.</param>
-    /// <param name="message">Message to display, might contain multiple lines.</param>
-    /// <param name="defaultButton">Index of the default button.</param>
-    /// <param name="wrapMessage">If wrap the message or not.</param>
-    /// <param name="buttons">Array of buttons to add.</param>
-    public static int Query (
+    /// <param name="app">The application instance. If <see langword="null"/>, uses <see cref="IApplication.TopRunnable"/>.</param>
+    /// <param name="title">Title for the MessageBox.</param>
+    /// <param name="message">Message to display. May contain multiple lines.</param>
+    /// <param name="defaultButton">Index of the default button (0-based).</param>
+    /// <param name="wrapMessage">
+    ///     If <see langword="true"/>, word-wraps the message; otherwise displays as-is with multi-line
+    ///     support.
+    /// </param>
+    /// <param name="buttons">Array of button labels.</param>
+    /// <returns>
+    ///     The index of the selected button, or <see langword="null"/> if the user pressed
+    ///     <see cref="Application.QuitKey"/>.
+    /// </returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="app"/> is <see langword="null"/>.</exception>
+    /// <remarks>
+    ///     The MessageBox is centered and auto-sized based on title, message, and buttons.
+    /// </remarks>
+    public static int? Query (
+        IApplication? app,
         string title,
         string title,
         string message,
         string message,
         int defaultButton = 0,
         int defaultButton = 0,
@@ -330,10 +550,20 @@ public static class MessageBox
         params string [] buttons
         params string [] buttons
     )
     )
     {
     {
-        return QueryFull (false, 0, 0, title, message, defaultButton, wrapMessage, buttons);
+        return QueryFull (
+                          app,
+                          false,
+                          0,
+                          0,
+                          title,
+                          message,
+                          defaultButton,
+                          wrapMessage,
+                          buttons);
     }
     }
 
 
-    private static int QueryFull (
+    private static int? QueryFull (
+        IApplication? app,
         bool useErrorColors,
         bool useErrorColors,
         int width,
         int width,
         int height,
         int height,
@@ -344,6 +574,8 @@ public static class MessageBox
         params string [] buttons
         params string [] buttons
     )
     )
     {
     {
+        ArgumentNullException.ThrowIfNull (app);
+
         // Create button array for Dialog
         // Create button array for Dialog
         var count = 0;
         var count = 0;
         List<Button> buttonList = new ();
         List<Button> buttonList = new ();
@@ -384,8 +616,9 @@ public static class MessageBox
                                        e.Handled = true;
                                        e.Handled = true;
                                    }
                                    }
 
 
-                                   Application.RequestStop ();
-                               };
+                                       (s as View)?.App?.RequestStop ();
+                                   };
+                }
 
 
                 buttonList.Add (b);
                 buttonList.Add (b);
                 count++;
                 count++;
@@ -395,20 +628,21 @@ public static class MessageBox
         var d = new Dialog
         var d = new Dialog
         {
         {
             Title = title,
             Title = title,
-            ButtonAlignment = MessageBox.DefaultButtonAlignment,
+            ButtonAlignment = DefaultButtonAlignment,
             ButtonAlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems,
             ButtonAlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems,
-            BorderStyle = MessageBox.DefaultBorderStyle,
-            Buttons = buttonList.ToArray (),
+            BorderStyle = DefaultBorderStyle,
+            Buttons = buttonList.ToArray ()
         };
         };
 
 
-        d.Width = Dim.Auto (DimAutoStyle.Auto,
-                            minimumContentDim: Dim.Func (_ => (int)((Application.Screen.Width - d.GetAdornmentsThickness ().Horizontal) * (DefaultMinimumWidth / 100f))),
-                            maximumContentDim: Dim.Func (_ => (int)((Application.Screen.Width - d.GetAdornmentsThickness ().Horizontal) * 0.9f)));
-
-        d.Height = Dim.Auto (DimAutoStyle.Auto,
-                             minimumContentDim: Dim.Func (_ => (int)((Application.Screen.Height - d.GetAdornmentsThickness ().Vertical) * (DefaultMinimumHeight / 100f))),
-                             maximumContentDim: Dim.Func (_ => (int)((Application.Screen.Height - d.GetAdornmentsThickness ().Vertical) * 0.9f)));
+        d.Width = Dim.Auto (
+                            DimAutoStyle.Auto,
+                            Dim.Func (_ => (int)((app.Screen.Width - d.GetAdornmentsThickness ().Horizontal) * (DefaultMinimumWidth / 100f))),
+                            Dim.Func (_ => (int)((app.Screen.Width - d.GetAdornmentsThickness ().Horizontal) * 0.9f)));
 
 
+        d.Height = Dim.Auto (
+                             DimAutoStyle.Auto,
+                             Dim.Func (_ => (int)((app.Screen.Height - d.GetAdornmentsThickness ().Vertical) * (DefaultMinimumHeight / 100f))),
+                             Dim.Func (_ => (int)((app.Screen.Height - d.GetAdornmentsThickness ().Vertical) * 0.9f)));
 
 
         if (width != 0)
         if (width != 0)
         {
         {
@@ -422,7 +656,7 @@ public static class MessageBox
 
 
         d.SchemeName = useErrorColors ? SchemeManager.SchemesToSchemeName (Schemes.Error) : SchemeManager.SchemesToSchemeName (Schemes.Dialog);
         d.SchemeName = useErrorColors ? SchemeManager.SchemesToSchemeName (Schemes.Error) : SchemeManager.SchemesToSchemeName (Schemes.Dialog);
 
 
-        d.HotKeySpecifier = new Rune ('\xFFFF');
+        d.HotKeySpecifier = new ('\xFFFF');
         d.Text = message;
         d.Text = message;
         d.TextAlignment = Alignment.Center;
         d.TextAlignment = Alignment.Center;
         d.VerticalTextAlignment = Alignment.Start;
         d.VerticalTextAlignment = Alignment.Start;
@@ -430,8 +664,8 @@ public static class MessageBox
         d.TextFormatter.MultiLine = !wrapMessage;
         d.TextFormatter.MultiLine = !wrapMessage;
 
 
         // Run the modal; do not shut down the mainloop driver when done
         // Run the modal; do not shut down the mainloop driver when done
-        Application.Run (d);
-        
+        app.Run (d);
+
         // Use Dialog.Result instead of manually tracking with Clicked
         // Use Dialog.Result instead of manually tracking with Clicked
         // Dialog automatically extracts which button was clicked in OnIsRunningChanging
         // Dialog automatically extracts which button was clicked in OnIsRunningChanging
         int result = d.Result ?? -1;
         int result = d.Result ?? -1;

+ 1 - 1
Terminal.Gui/Views/Selectors/SelectorBase.cs

@@ -425,7 +425,7 @@ public abstract class SelectorBase : View, IOrientation
             maxNaturalCheckBoxWidth = SubViews.OfType<CheckBox> ().Max (
             maxNaturalCheckBoxWidth = SubViews.OfType<CheckBox> ().Max (
                                                              v =>
                                                              v =>
                                                              {
                                                              {
-                                                                 v.SetRelativeLayout (Application.Screen.Size);
+                                                                 v.SetRelativeLayout (App?.Screen.Size ?? new Size (2048, 2048));
                                                                  v.Layout ();
                                                                  v.Layout ();
                                                                  return v.Frame.Width;
                                                                  return v.Frame.Width;
                                                              });
                                                              });

+ 8 - 2
Terminal.Gui/Views/StatusBar.cs

@@ -9,6 +9,8 @@ namespace Terminal.Gui.Views;
 /// </summary>
 /// </summary>
 public class StatusBar : Bar, IDesignable
 public class StatusBar : Bar, IDesignable
 {
 {
+    private static LineStyle _defaultSeparatorLineStyle = LineStyle.Single; // Resources/config.json overrides
+
     /// <inheritdoc/>
     /// <inheritdoc/>
     public StatusBar () : this ([]) { }
     public StatusBar () : this ([]) { }
 
 
@@ -55,7 +57,11 @@ public class StatusBar : Bar, IDesignable
     ///     Gets or sets the default Line Style for the separators between the shortcuts of the StatusBar.
     ///     Gets or sets the default Line Style for the separators between the shortcuts of the StatusBar.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static LineStyle DefaultSeparatorLineStyle { get; set; } = LineStyle.Single;
+    public static LineStyle DefaultSeparatorLineStyle
+    {
+        get => _defaultSeparatorLineStyle;
+        set => _defaultSeparatorLineStyle = value;
+    }
 
 
     /// <inheritdoc />
     /// <inheritdoc />
     protected override void OnSubViewLayout (LayoutEventArgs args)
     protected override void OnSubViewLayout (LayoutEventArgs args)
@@ -160,7 +166,7 @@ public class StatusBar : Bar, IDesignable
 
 
         return true;
         return true;
 
 
-        void OnButtonClicked (object? sender, EventArgs? e) { MessageBox.Query ("Hi", $"You clicked {sender}"); }
+        void OnButtonClicked (object? sender, EventArgs? e) { MessageBox.Query (App, "Hi", $"You clicked {sender}"); }
     }
     }
 
 
     /// <inheritdoc />
     /// <inheritdoc />

+ 2 - 2
Terminal.Gui/Views/TableView/TableView.cs

@@ -1534,7 +1534,7 @@ public class TableView : View, IDesignable
     /// <param name="width"></param>
     /// <param name="width"></param>
     private void ClearLine (int row, int width)
     private void ClearLine (int row, int width)
     {
     {
-        if (Application.Screen.Height == 0)
+        if (App?.Screen.Height == 0)
         {
         {
             return;
             return;
         }
         }
@@ -1810,7 +1810,7 @@ public class TableView : View, IDesignable
                 }
                 }
             }
             }
 
 
-            if (Application.Screen.Height > 0)
+            if (App?.Screen.Height > 0)
             {
             {
                 AddRuneAt (c, row, rune);
                 AddRuneAt (c, row, rune);
             }
             }

+ 5 - 5
Terminal.Gui/Views/TextInput/TextField.cs

@@ -617,7 +617,7 @@ public class TextField : View, IDesignable
             return;
             return;
         }
         }
 
 
-        Clipboard.Contents = SelectedText;
+        App?.Clipboard?.SetClipboardData (SelectedText);
     }
     }
 
 
     /// <summary>Cut the selected text to the clipboard.</summary>
     /// <summary>Cut the selected text to the clipboard.</summary>
@@ -628,7 +628,7 @@ public class TextField : View, IDesignable
             return;
             return;
         }
         }
 
 
-        Clipboard.Contents = SelectedText;
+        App?.Clipboard?.SetClipboardData (SelectedText);
         List<string> newText = DeleteSelectedText ();
         List<string> newText = DeleteSelectedText ();
         Text = StringExtensions.ToString (newText);
         Text = StringExtensions.ToString (newText);
         Adjust ();
         Adjust ();
@@ -1079,7 +1079,7 @@ public class TextField : View, IDesignable
             return;
             return;
         }
         }
 
 
-        string cbTxt = Clipboard.Contents.Split ("\n") [0] ?? "";
+        string cbTxt = App?.Clipboard?.GetClipboardData ()?.Split ("\n") [0];
 
 
         if (string.IsNullOrEmpty (cbTxt))
         if (string.IsNullOrEmpty (cbTxt))
         {
         {
@@ -1731,9 +1731,9 @@ public class TextField : View, IDesignable
 
 
     private void SetClipboard (IEnumerable<string> text)
     private void SetClipboard (IEnumerable<string> text)
     {
     {
-        if (!Secret)
+        if (!Secret && App?.Clipboard is { })
         {
         {
-            Clipboard.Contents = StringExtensions.ToString (text.ToList ());
+            App.Clipboard.SetClipboardData (StringExtensions.ToString (text.ToList ()));
         }
         }
     }
     }
 
 

+ 4 - 4
Terminal.Gui/Views/TextInput/TextView.cs

@@ -1960,7 +1960,7 @@ public class TextView : View, IDesignable
         }
         }
 
 
         SetWrapModel ();
         SetWrapModel ();
-        string? contents = Clipboard.Contents;
+        string? contents = App?.Clipboard?.GetClipboardData ();
 
 
         if (_copyWithoutSelection && contents!.FirstOrDefault (x => x is '\n' or '\r') == 0)
         if (_copyWithoutSelection && contents!.FirstOrDefault (x => x is '\n' or '\r') == 0)
         {
         {
@@ -2363,7 +2363,7 @@ public class TextView : View, IDesignable
         OnUnwrappedCursorPosition ();
         OnUnwrappedCursorPosition ();
     }
     }
 
 
-    private void AppendClipboard (string text) { Clipboard.Contents += text; }
+    private void AppendClipboard (string text) { App?.Clipboard?.SetClipboardData (App?.Clipboard?.GetClipboardData () + text); }
 
 
     private PopoverMenu CreateContextMenu ()
     private PopoverMenu CreateContextMenu ()
     {
     {
@@ -3842,7 +3842,7 @@ public class TextView : View, IDesignable
 
 
             List<Cell> currentLine = GetCurrentLine ();
             List<Cell> currentLine = GetCurrentLine ();
 
 
-            if (currentLine.Count > 0 && currentLine[CurrentColumn - 1].Grapheme == "\t")
+            if (currentLine.Count > 0 && currentLine [CurrentColumn - 1].Grapheme == "\t")
             {
             {
                 _historyText.Add (new () { new (currentLine) }, CursorPosition);
                 _historyText.Add (new () { new (currentLine) }, CursorPosition);
 
 
@@ -4470,7 +4470,7 @@ public class TextView : View, IDesignable
     {
     {
         if (text is { })
         if (text is { })
         {
         {
-            Clipboard.Contents = text;
+            App?.Clipboard?.SetClipboardData (text);
         }
         }
     }
     }
 
 

+ 13 - 4
Terminal.Gui/Views/Window.cs

@@ -1,5 +1,3 @@
-
-
 namespace Terminal.Gui.Views;
 namespace Terminal.Gui.Views;
 
 
 /// <summary>
 /// <summary>
@@ -18,6 +16,9 @@ namespace Terminal.Gui.Views;
 /// <seealso cref="FrameView"/>
 /// <seealso cref="FrameView"/>
 public class Window : Toplevel
 public class Window : Toplevel
 {
 {
+    private static ShadowStyle _defaultShadow = ShadowStyle.None; // Resources/config.json overrides
+    private static LineStyle _defaultBorderStyle = LineStyle.Single; // Resources/config.json overrides
+
     /// <summary>
     /// <summary>
     ///     Initializes a new instance of the <see cref="Window"/> class.
     ///     Initializes a new instance of the <see cref="Window"/> class.
     /// </summary>
     /// </summary>
@@ -35,7 +36,11 @@ public class Window : Toplevel
     ///     Gets or sets whether all <see cref="Window"/>s are shown with a shadow effect by default.
     ///     Gets or sets whether all <see cref="Window"/>s are shown with a shadow effect by default.
     /// </summary>
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None;
+    public static ShadowStyle DefaultShadow
+    {
+        get => _defaultShadow;
+        set => _defaultShadow = value;
+    }
 
 
     // TODO: enable this
     // TODO: enable this
     ///// <summary>
     ///// <summary>
@@ -56,5 +61,9 @@ public class Window : Toplevel
     ///     s.
     ///     s.
     /// </remarks>
     /// </remarks>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
+    public static LineStyle DefaultBorderStyle
+    {
+        get => _defaultBorderStyle;
+        set => _defaultBorderStyle = value;
+    }
 }
 }

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

@@ -487,7 +487,7 @@ public class Wizard : Dialog
 
 
                 if (IsCurrentTop)
                 if (IsCurrentTop)
                 {
                 {
-                    Application.RequestStop (this);
+                    (sender as View)?.App?.RequestStop (this);
                     e.Handled = true;
                     e.Handled = true;
                 }
                 }
 
 

+ 12 - 11
Tests/IntegrationTests/FluentTests/FileDialogFluentTests.cs

@@ -60,10 +60,10 @@ public class FileDialogFluentTests
     public void CancelFileDialog_QuitKey_Quits (TestDriver d)
     public void CancelFileDialog_QuitKey_Quits (TestDriver d)
     {
     {
         SaveDialog? sd = null;
         SaveDialog? sd = null;
-        using var c = With.A (() => NewSaveDialog (out sd), 100, 20, d)
-            .ScreenShot ("Save dialog", _out)
-            .EnqueueKeyEvent (Application.QuitKey)
-            .AssertTrue (sd!.Canceled);
+        using GuiTestContext c = With.A (() => NewSaveDialog (out sd), 100, 20, d, logWriter: _out)
+                                     .ScreenShot ("Save dialog", _out)
+                                     .EnqueueKeyEvent (Application.QuitKey)
+                                     .AssertTrue (sd!.Canceled);
     }
     }
 
 
     [Theory]
     [Theory]
@@ -93,7 +93,7 @@ public class FileDialogFluentTests
     public void CancelFileDialog_UsingCancelButton_AltC (TestDriver d)
     public void CancelFileDialog_UsingCancelButton_AltC (TestDriver d)
     {
     {
         SaveDialog? sd = null;
         SaveDialog? sd = null;
-        using var c = With.A (() => NewSaveDialog (out sd), 100, 20, d)
+        using var c = With.A (() => NewSaveDialog (out sd), 100, 20, d, _out)
                           .ScreenShot ("Save dialog", _out)
                           .ScreenShot ("Save dialog", _out)
                           .EnqueueKeyEvent (Key.C.WithAlt)
                           .EnqueueKeyEvent (Key.C.WithAlt)
                           .AssertTrue (sd!.Canceled);
                           .AssertTrue (sd!.Canceled);
@@ -132,12 +132,13 @@ public class FileDialogFluentTests
     {
     {
         SaveDialog? sd = null;
         SaveDialog? sd = null;
         MockFileSystem? fs = null;
         MockFileSystem? fs = null;
-        using var c = With.A (() => NewSaveDialog (out sd, out fs, modal: false), 100, 20, d)
-                          .ScreenShot ("Save dialog", _out)
-                          .Focus<Button> (b => b.Text == "_Save")
-                          .EnqueueKeyEvent (Key.Enter)
-                          .AssertFalse (sd!.Canceled)
-                          .AssertEqual (GetFileSystemRoot (fs!), sd!.FileName);
+        using GuiTestContext c = With.A (() => NewSaveDialog (out sd, out fs, modal: false), 100, 20, d)
+                                     .ScreenShot ("Save dialog", _out)
+                                     .Focus<Button> (b => b.Text == "_Save")
+                                     .EnqueueKeyEvent (Key.Enter)
+                                     .AssertFalse (sd!.Canceled)
+                                     .AssertEqual (GetFileSystemRoot (fs!), sd!.FileName)
+                                     ;
     }
     }
 
 
     private string GetFileSystemRoot (IFileSystem fs)
     private string GetFileSystemRoot (IFileSystem fs)

+ 1 - 1
Tests/IntegrationTests/FluentTests/GuiTestContextTests.cs

@@ -18,7 +18,7 @@ public class GuiTestContextTests (ITestOutputHelper outputHelper)
     {
     {
         using var context = new GuiTestContext (d, _out, TimeSpan.FromSeconds (10));
         using var context = new GuiTestContext (d, _out, TimeSpan.FromSeconds (10));
 
 
-        Assert.NotEqual (Rectangle.Empty, Application.Screen);
+        Assert.NotEqual (Rectangle.Empty, context.App?.Screen);
     }
     }
 
 
     [Theory]
     [Theory]

+ 1 - 1
Tests/StressTests/ScenariosStressTests.cs

@@ -110,7 +110,7 @@ public class ScenariosStressTests
             _output.WriteLine ($"Initialized == {a.Value}");
             _output.WriteLine ($"Initialized == {a.Value}");
         }
         }
 
 
-        void OnApplicationOnIteration (object? s, IterationEventArgs a)
+        void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
         {
         {
             iterationCount++;
             iterationCount++;
 
 

+ 1 - 6
Tests/TerminalGuiFluentTesting/GuiTestContext.Input.cs

@@ -64,7 +64,7 @@ public partial class GuiTestContext
             {
             {
                 mouseEvent.Position = mouseEvent.ScreenPosition;
                 mouseEvent.Position = mouseEvent.ScreenPosition;
 
 
-                app.Driver.InputProcessor.EnqueueMouseEvent (mouseEvent);
+                app.Driver.InputProcessor.EnqueueMouseEvent (app, mouseEvent);
             }
             }
             else
             else
             {
             {
@@ -205,11 +205,6 @@ public partial class GuiTestContext
             App.Driver.EnqueueKeyEvent (key);
             App.Driver.EnqueueKeyEvent (key);
             WaitUntil (() => keyReceived);
             WaitUntil (() => keyReceived);
         }
         }
-        else
-        {
-            Fail ("Expected Application.Driver to be non-null.");
-        }
-
 
 
         return this;
         return this;
 
 

+ 33 - 21
Tests/TerminalGuiFluentTesting/GuiTestContext.cs

@@ -68,7 +68,7 @@ public partial class GuiTestContext : IDisposable
 
 
         try
         try
         {
         {
-            InitializeApplication ();
+            App?.Init (GetDriverName ());
             _booting.Release ();
             _booting.Release ();
 
 
             // After Init, Application.Screen should be set by the driver
             // After Init, Application.Screen should be set by the driver
@@ -119,21 +119,36 @@ public partial class GuiTestContext : IDisposable
                              {
                              {
                                  try
                                  try
                                  {
                                  {
-                                     InitializeApplication ();
-
-                                     _booting.Release ();
-
-                                     Toplevel t = topLevelBuilder ();
-                                     t.Closed += (s, e) => { Finished = true; };
-                                     App?.Run (t); // This will block, but it's on a background thread now
+                                     try
+                                     {
+                                         App?.Init (GetDriverName ());
+                                     }
+                                     catch (Exception e)
+                                     {
+                                         Logging.Error(e.Message);
+                                         _runCancellationTokenSource.Cancel ();
+                                     }
+                                     finally
+                                     {
+                                         _booting.Release ();
+                                     }
 
 
-                                     t.Dispose ();
-                                     Logging.Trace ("Application.Run completed");
-                                     App?.Shutdown ();
-                                     _runCancellationTokenSource.Cancel ();
+                                     if (App is { Initialized: true })
+                                     {
+                                         Toplevel t = topLevelBuilder ();
+                                         t.Closed += (s, e) => { Finished = true; };
+                                         App?.Run (t); // This will block, but it's on a background thread now
+
+                                         t.Dispose ();
+                                         Logging.Trace ("Application.Run completed");
+                                         App?.Shutdown ();
+                                         _runCancellationTokenSource.Cancel ();
+                                     }
                                  }
                                  }
                                  catch (OperationCanceledException)
                                  catch (OperationCanceledException)
-                                 { }
+                                 {
+                                     Logging.Trace ("OperationCanceledException");
+                                 }
                                  catch (Exception ex)
                                  catch (Exception ex)
                                  {
                                  {
                                      _backgroundException = ex;
                                      _backgroundException = ex;
@@ -142,7 +157,6 @@ public partial class GuiTestContext : IDisposable
                                  finally
                                  finally
                                  {
                                  {
                                      CleanupApplication ();
                                      CleanupApplication ();
-
                                      if (_logWriter != null)
                                      if (_logWriter != null)
                                      {
                                      {
                                          WriteOutLogs (_logWriter);
                                          WriteOutLogs (_logWriter);
@@ -165,11 +179,6 @@ public partial class GuiTestContext : IDisposable
         }
         }
     }
     }
 
 
-    private void InitializeApplication ()
-    {
-        App?.Init (GetDriverName ());
-    }
-
 
 
     /// <summary>
     /// <summary>
     ///     Common initialization for both constructors.
     ///     Common initialization for both constructors.
@@ -316,7 +325,7 @@ public partial class GuiTestContext : IDisposable
             throw new NotSupportedException ("Cannot WaitIteration during Invoke");
             throw new NotSupportedException ("Cannot WaitIteration during Invoke");
         }
         }
 
 
-        Logging.Trace ($"WaitIteration started");
+        //Logging.Trace ($"WaitIteration started");
         if (action is null)
         if (action is null)
         {
         {
             action = (app) => { };
             action = (app) => { };
@@ -358,8 +367,9 @@ public partial class GuiTestContext : IDisposable
         GuiTestContext? c = null;
         GuiTestContext? c = null;
         var sw = Stopwatch.StartNew ();
         var sw = Stopwatch.StartNew ();
 
 
-        //Logging.Trace ($"WaitUntil started with timeout {_timeout}");
+        Logging.Trace ($"WaitUntil started with timeout {_timeout}");
 
 
+        int count = 0;
         while (!condition ())
         while (!condition ())
         {
         {
             if (sw.Elapsed > _timeout)
             if (sw.Elapsed > _timeout)
@@ -368,8 +378,10 @@ public partial class GuiTestContext : IDisposable
             }
             }
 
 
             c = WaitIteration ();
             c = WaitIteration ();
+            count++;
         }
         }
 
 
+        Logging.Trace ($"WaitUntil completed after {sw.ElapsedMilliseconds}ms and {count} iterations");
         return c ?? this;
         return c ?? this;
     }
     }
 
 

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä