This is the integration step that turns the ported crates into a working
terminal: `cargo run` now opens a GTK window running the user's shell.
ghostty-core ports App.zig, Surface.zig (split into keyboard, mouse,
binding, clipboard and config submodules), surface_mouse.zig and
global.zig, and implements the runtime traits. perform_binding_action
handles every binding action.
Cross-crate integration:
- The core<->runtime traits (CoreApp, CoreSurface, RtApp, RtSurface,
Waker) move from apprt-gtk into ghostty_apprt::runtime_api so the core
stays runtime-agnostic; Scrollbar/RendererHealth stand-ins are replaced
by the real terminal/renderer types.
- termio now uses ghostty_renderer::state::{State, SharedState}; the
renderer calls kitty_update; image-storage-limit is applied at init
and on config change.
- The search thread locks the terminal through a TerminalLock trait so
it can share the render state mutex; termio's Wakeup gained a hook to
wake the renderer thread.
- apprt-gtk: GL proc addresses are resolved through libepoxy's
epoxy_glFoo pointer variables (plain glFoo symbols resolved to null),
default DPI fixed to 96, libadwaita version read without GTK init so
--version works headless.
The root binary dispatches +actions to ghostty-cli (list-fonts,
show-face and new-window are now wired) and otherwise runs the GTK app
with the real core.
Verified at runtime on Wayland and X11: shell prompt and colored output
render, child exit closes the window cleanly. Not yet verified: keyboard
and mouse input, clipboard, IME, tabs and splits (no key injection was
possible in this environment). GHOSTTY_DEBUG_SCREENSHOT=<png> dumps the
renderer's last frame for headless checks.
Test Plan:
- cargo test --workspace (2890 passed)
- cargo clippy --workspace --all-targets -- -D warnings
- GSETTINGS_BACKEND=memory GHOSTTY_RESOURCES_DIR=/usr/share/ghostty \
cargo run
121 lines
3.0 KiB
Rust
121 lines
3.0 KiB
Rust
//! Backend implementations (`termio/backend.zig`). A backend is responsible
|
|
//! for owning the pty behavior and providing read/write capabilities.
|
|
|
|
use std::sync::Arc;
|
|
|
|
use ghostty_renderer::size::{GridSize, ScreenSize};
|
|
use ghostty_terminal::terminal::Terminal;
|
|
|
|
use crate::exec::{self, Exec};
|
|
use crate::sinks::SurfaceMailbox;
|
|
use crate::state::SharedState;
|
|
use crate::termio::Output;
|
|
|
|
/// The kinds of backends.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum Kind {
|
|
Exec,
|
|
}
|
|
|
|
/// Configuration for the various backend types.
|
|
pub enum Config {
|
|
/// Exec uses posix exec to run a command with a pty.
|
|
Exec(exec::Config),
|
|
}
|
|
|
|
/// Backend implementations.
|
|
pub enum Backend {
|
|
Exec(Exec),
|
|
}
|
|
|
|
impl Backend {
|
|
pub fn new(config: Config) -> Result<Backend, exec::Error> {
|
|
match config {
|
|
Config::Exec(cfg) => Ok(Backend::Exec(Exec::new(cfg)?)),
|
|
}
|
|
}
|
|
|
|
pub fn kind(&self) -> Kind {
|
|
match self {
|
|
Backend::Exec(_) => Kind::Exec,
|
|
}
|
|
}
|
|
|
|
pub fn init_terminal(&mut self, t: &mut Terminal) {
|
|
match self {
|
|
Backend::Exec(e) => e.init_terminal(t),
|
|
}
|
|
}
|
|
|
|
pub fn thread_enter(
|
|
&mut self,
|
|
output: Arc<Output>,
|
|
surface_mailbox: Arc<dyn SurfaceMailbox>,
|
|
renderer_state: SharedState,
|
|
) -> Result<ThreadData, exec::Error> {
|
|
match self {
|
|
Backend::Exec(e) => Ok(ThreadData::Exec(e.thread_enter(
|
|
output,
|
|
surface_mailbox,
|
|
renderer_state,
|
|
)?)),
|
|
}
|
|
}
|
|
|
|
pub fn thread_exit(&mut self, td: &mut ThreadData) {
|
|
match (self, td) {
|
|
(Backend::Exec(e), ThreadData::Exec(td)) => e.thread_exit(td),
|
|
}
|
|
}
|
|
|
|
pub fn focus_gained(&mut self, td: &mut ThreadData, focused: bool) {
|
|
match (self, td) {
|
|
(Backend::Exec(e), ThreadData::Exec(td)) => e.focus_gained(td, focused),
|
|
}
|
|
}
|
|
|
|
pub fn resize(
|
|
&mut self,
|
|
grid_size: GridSize,
|
|
screen_size: ScreenSize,
|
|
) -> Result<(), exec::Error> {
|
|
match self {
|
|
Backend::Exec(e) => e.resize(grid_size, screen_size),
|
|
}
|
|
}
|
|
|
|
pub fn queue_write(&mut self, td: &mut ThreadData, data: &[u8], linefeed: bool) {
|
|
match (self, td) {
|
|
(Backend::Exec(e), ThreadData::Exec(td)) => e.queue_write(td, data, linefeed),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Termio thread data. See `termio::ThreadData` for docs.
|
|
pub enum ThreadData {
|
|
Exec(exec::ThreadData),
|
|
}
|
|
|
|
impl ThreadData {
|
|
pub fn kind(&self) -> Kind {
|
|
match self {
|
|
ThreadData::Exec(_) => Kind::Exec,
|
|
}
|
|
}
|
|
|
|
pub fn as_exec(&self) -> &exec::ThreadData {
|
|
match self {
|
|
ThreadData::Exec(e) => e,
|
|
}
|
|
}
|
|
|
|
pub fn as_exec_mut(&mut self) -> &mut exec::ThreadData {
|
|
match self {
|
|
ThreadData::Exec(e) => e,
|
|
}
|
|
}
|
|
|
|
/// `ThreadData.changeConfig`: nothing to do for the exec backend.
|
|
pub fn change_config(&mut self, _config: &crate::termio::DerivedConfig) {}
|
|
}
|