Files
Terminal.Gui/docfx/docs/drivers.md
Tig 0f72cf8a74 Fixes #4425 - ApplicationImpl internal (#4426)
* Pulled from v2_release

* Refactor migration guide for Terminal.Gui v2

Restructured and expanded the migration guide to provide a comprehensive resource for transitioning from Terminal.Gui v1 to v2. Key updates include:

- Added a Table of Contents for easier navigation.
- Summarized major architectural changes in v2, including the instance-based application model, IRunnable architecture, and 24-bit TrueColor support.
- Updated examples to reflect new patterns, such as initializers replacing constructors and explicit disposal using `IDisposable`.
- Documented changes to the layout system, including the removal of `Absolute`/`Computed` styles and the introduction of `Viewport`.
- Standardized event patterns to use `object sender, EventArgs args`.
- Detailed updates to the Keyboard, Mouse, and Navigation APIs, including configurable key bindings and viewport-relative mouse coordinates.
- Replaced legacy components like `ScrollView` and `ContextMenu` with built-in scrolling and `PopoverMenu`.
- Clarified disposal rules and introduced best practices for resource management.
- Provided a complete migration example and a summary of breaking changes.

This update aims to simplify the migration process by addressing breaking changes, introducing new features, and aligning with modern .NET conventions.

* Refactor to use Application.Instance for lifecycle management

Replaced all occurrences of `ApplicationImpl.Instance` with the new `Application.Instance` property across the codebase to align with the updated application lifecycle model.

Encapsulated the `ApplicationImpl` class by making it `internal`, ensuring it is no longer directly accessible outside its assembly. Introduced the `[Obsolete]` `Application.Instance` property as a backward-compatible singleton for the legacy static `Application` model, while encouraging the use of `Application.Create()` for new code.

Updated `MessageBox` methods to use `Application.Instance` for consistent modal dialog management. Improved documentation to reflect these changes and emphasize the transition to the instance-based application model.

Performed code cleanup in multiple classes to ensure consistency and maintainability. These changes maintain backward compatibility while preparing the codebase for the eventual removal of the legacy `ApplicationImpl` class.

* Fix doc bug

* - Removed obsolete `.cd` class diagram files.
- Introduced `IRunnable` interface for decoupling component execution.
- Added fluent API for running dialogs and retrieving results.
- Enhanced `View` with `App` and `Driver` properties for better decoupling.
- Improved testability with support for mock and real applications.
- Implemented `IDisposable` for proper resource cleanup.
- Replaced `RunnableSessionStack` with `SessionStack` for session management.
- Updated driver architecture to align with the new model.
- Scoped `IKeyboard` to application contexts for modularity.
- Updated documentation with migration strategies and best practices.

These changes modernize the library, improve maintainability, and align with current development practices.
2025-12-01 14:40:31 -07:00

225 lines
9.6 KiB
Markdown

# Cross-Platform Driver Model
## Overview
The driver model is the mechanism by which Terminal.Gui supports multiple platforms. Windows, Mac, Linux, and unit test environments are all supported through a modular, component-based architecture.
Terminal.Gui v2 uses a sophisticated driver architecture that separates concerns and enables platform-specific optimizations while maintaining a consistent API. The architecture is based on the **Component Factory** pattern and uses **multi-threading** to ensure responsive input handling.
## Available Drivers
Terminal.Gui provides console driver implementations optimized for different platforms:
- **DotNetDriver (`dotnet`)** - A cross-platform driver that uses the .NET `System.Console` API. Works on all platforms (Windows, macOS, Linux). Best for maximum compatibility.
- **WindowsDriver (`windows`)** - A Windows-optimized driver that uses native Windows Console APIs for enhanced performance and platform-specific features.
- **UnixDriver (`unix`)** - A Unix/Linux/macOS-optimized driver that uses platform-specific APIs for better integration and performance.
- **FakeDriver (`fake`)** - A mock driver designed for unit testing. Simulates console behavior without requiring a real terminal.
### Automatic Driver Selection
The appropriate driver is automatically selected based on the platform when you call `Application.Init()`:
- **Windows** (Win32NT, Win32S, Win32Windows) → `WindowsDriver`
- **Unix/Linux/macOS** → `UnixDriver`
### Explicit Driver Selection
You can explicitly specify a driver in three ways:
```csharp
// Method 1: Set ForceDriver property before Init
Application.ForceDriver = "dotnet";
Application.Init();
// Method 2: Pass driver name to Init
Application.Init(driverName: "unix");
// Method 3: Pass a custom IDriver instance
var customDriver = new MyCustomDriver();
Application.Init(driver: customDriver);
```
Valid driver names: `"dotnet"`, `"windows"`, `"unix"`, `"fake"`
## Architecture
### Component Factory Pattern
The v2 driver architecture uses the **Component Factory** pattern to create platform-specific components. Each driver has a corresponding factory:
- `NetComponentFactory` - Creates components for DotNetDriver
- `WindowsComponentFactory` - Creates components for WindowsDriver
- `UnixComponentFactory` - Creates components for UnixDriver
- `FakeComponentFactory` - Creates components for FakeDriver
### Core Components
Each driver is composed of specialized components, each with a single responsibility:
#### IInput<T>
Reads raw console input events from the terminal. The generic type `T` represents the platform-specific input type:
- `ConsoleKeyInfo` for DotNetDriver and FakeDriver
- `WindowsConsole.InputRecord` for WindowsDriver
- `char` for UnixDriver
Runs on a dedicated input thread to avoid blocking the UI.
#### IOutput
Renders the output buffer to the terminal. Handles:
- Writing text and ANSI escape sequences
- Setting cursor position
- Managing cursor visibility
- Detecting terminal window size
#### IInputProcessor
Translates raw console input into Terminal.Gui events:
- Converts raw input to `Key` events (handles keyboard input)
- Parses ANSI escape sequences (mouse events, special keys)
- Generates `MouseEventArgs` for mouse input
- Handles platform-specific key mappings
#### IOutputBuffer
Manages the screen buffer and drawing operations:
- Maintains the `Contents` array (what should be displayed)
- Provides methods like `AddRune()`, `AddStr()`, `Move()`, `FillRect()`
- Handles clipping regions
- Tracks dirty regions for efficient rendering
#### IWindowSizeMonitor
Detects terminal size changes and raises `SizeChanged` events when the terminal is resized.
#### DriverFacade<T>
A unified facade that implements `IDriver` and coordinates all the components. This is what gets assigned to `Application.Driver`.
### Threading Model
The driver architecture employs a **multi-threaded design** for optimal responsiveness:
```
┌─────────────────────────────────────────────┐
│ IApplication.Init() │
│ Creates MainLoopCoordinator<T> with │
│ ComponentFactory<T> │
└────────────────┬────────────────────────────┘
├──────────────────┬───────────────────┐
│ │ │
┌────────▼────────┐ ┌──────▼─────────┐ ┌──────▼──────────┐
│ Input Thread │ │ Main UI Thread│ │ Driver │
│ │ │ │ │ Facade │
│ IInput │ │ ApplicationMain│ │ │
│ reads console │ │ Loop processes │ │ Coordinates all │
│ input async │ │ events, layout,│ │ components │
│ into queue │ │ and rendering │ │ │
└─────────────────┘ └────────────────┘ └─────────────────┘
```
- **Input Thread**: Started by `MainLoopCoordinator`, runs `IInput.Run()` which continuously reads console input and queues it into a thread-safe `ConcurrentQueue<T>`.
- **Main UI Thread**: Runs `ApplicationMainLoop.Iteration()` which:
1. Processes input from the queue via `IInputProcessor`
2. Executes timeout callbacks
3. Checks for UI changes (layout/drawing)
4. Renders updates via `IOutput`
This separation ensures that input is never lost and the UI remains responsive during intensive operations.
### Initialization Flow
When you call `Application.Init()`:
1. **IApplication.Init()** is invoked
2. Creates a `MainLoopCoordinator<T>` with the appropriate `ComponentFactory<T>`
3. **MainLoopCoordinator.StartAsync()** begins:
- Starts the input thread which creates `IInput<T>`
- Initializes the main UI loop which creates `IOutput`
- Creates `DriverFacade<T>` and assigns to `IApplication.Driver`
- Waits for both threads to be ready
4. Returns control to the application
### Shutdown Flow
When `IApplication.Shutdown()` is called:
1. Cancellation token is triggered
2. Input thread exits its read loop
3. `IOutput` is disposed
4. Main thread waits for input thread to complete
5. All resources are cleaned up
## Component Interfaces
### IDriver
The main driver interface that the framework uses internally. Provides:
- **Screen Management**: `Screen`, `Cols`, `Rows`, `Contents`
- **Drawing Operations**: `AddRune()`, `AddStr()`, `Move()`, `FillRect()`
- **Cursor Management**: `SetCursorVisibility()`, `UpdateCursor()`
- **Attribute Management**: `CurrentAttribute`, `SetAttribute()`, `MakeColor()`
- **Clipping**: `Clip` property
- **Events**: `KeyDown`, `KeyUp`, `MouseEvent`, `SizeChanged`
- **Platform Features**: `SupportsTrueColor`, `Force16Colors`, `Clipboard`
**Note:** The driver is internal to Terminal.Gui. View classes should not access `Driver` directly. Instead:
- Use @Terminal.Gui.App.Application.Screen to get screen dimensions
- Use @Terminal.Gui.ViewBase.View.Move for positioning (with viewport-relative coordinates)
- Use @Terminal.Gui.ViewBase.View.AddRune and @Terminal.Gui.ViewBase.View.AddStr for drawing
- ViewBase infrastructure classes (in `Terminal.Gui/ViewBase/`) can access Driver when needed for framework implementation
## Platform-Specific Details
### DotNetDriver (NetComponentFactory)
- Uses `System.Console` for all I/O operations
- Input: Reads `ConsoleKeyInfo` via `Console.ReadKey()`
- Output: Uses `Console.Write()` and ANSI escape sequences
- Works on all platforms but may have limited features
- Best for maximum compatibility and simple applications
### WindowsDriver (WindowsComponentFactory)
- Uses Windows Console API via P/Invoke
- Input: Reads `InputRecord` structs via `ReadConsoleInput`
- Output: Uses Windows Console API for optimal performance
- Supports Windows-specific features and better performance
- Automatically selected on Windows platforms
#### Visual Studio Debug Console Support
When running in Visual Studio's debug console (`VSDebugConsole.exe`), WindowsDriver detects the `VSAPPIDNAME` environment variable and automatically adjusts its behavior:
- Disables the alternative screen buffer (which is not supported in VS debug console)
- Preserves the original console colors on startup
- Restores the original colors and clears the screen on shutdown
This ensures Terminal.Gui applications can be debugged directly in Visual Studio without rendering issues.
### UnixDriver (UnixComponentFactory)
- Uses Unix/Linux terminal APIs
- Input: Reads raw `char` data from terminal
- Output: Uses ANSI escape sequences
- Supports Unix-specific features
- Automatically selected on Unix/Linux/macOS platforms
### FakeDriver (FakeComponentFactory)
- Simulates console behavior for unit testing
- Uses `FakeConsole` for all operations
- Allows injection of predefined input
- Captures output for verification
- Always used when `IApplication.ForceDriver` is `fake`
**Important:** View subclasses should not access `Application.Driver`. Use the View APIs instead:
- `View.Move(col, row)` for positioning
- `View.AddRune()` and `View.AddStr()` for drawing
- `View.App.Screen` for screen dimensions
## See Also
- @Terminal.Gui.Drivers - API Reference
- @Terminal.Gui.App.IApplication - Application interface
- @Terminal.Gui.App.MainLoopCoordinator`1 - Main loop coordination