# How Ghostty Handles Terminal Window Resizing and Grid Reflow

> Discover how Ghostty expertly manages terminal window resizing and grid reflow. Learn about its atomic updates, buffer reallocation, and flicker-free rendering process.

- Repository: [Ghostty/ghostty](https://github.com/ghostty-org/ghostty)
- Tags: internals
- Published: 2026-05-01

---

**Ghostty processes terminal window resizing through a coordinated pipeline that atomically updates PTY dimensions, reallocates internal grid buffers, and triggers renderer reflow to prevent visual flicker.**

Ghostty, the cross-platform terminal emulator written in Zig, implements a sophisticated resize handling mechanism that bridges UI events with the underlying pseudo-terminal (PTY). When the operating system reports a window size change, the terminal grid reflow occurs atomically across the **Termio** layer, ensuring the rendered output always matches the new dimensions.

## The Resize Event Pipeline

Ghostty's resize handling follows a strict five-stage pipeline that separates UI events from computational updates and rendering.

### Capture and Coalescing in the Termio Thread

When the GTK or macOS frontend detects a size change, it posts a `resize` message to the termio thread. According to the Ghostty source code in `src/termio/Thread.zig`, the thread loop coalesces rapid successive events to avoid redundant calculations:

```zig
while (true) {
    const msg = cb.io.wait();
    switch (msg) {
        .resize => |size| {
            // Stores only the latest size during the debounce interval
            thread.coalesce_data.resize = size;
        },
        .timer => {
            if (thread.coalesce_data.resize) |sz| {
                thread.coalesce_data.resize = null;
                cb.io.resize(&cb.data, sz) catch |err| log.warn("resize error {}", .{err});
            }
        },
        // … other messages …
    }
}

```

This debouncing mechanism collapses multiple rapid resize events into a single `Termio.resize` call.

### State Update and PTY Synchronization

Once coalesced, the `resize` function in `src/termio/Termio.zig` (lines 62-101) performs three critical operations:

- Stores the new `renderer.Size` containing pixel and cell dimensions
- Calculates the grid size using the `grid()` method
- Invokes `backend.resize` to synchronize the underlying PTY file descriptors

The implementation ensures the operating system's view of the terminal size stays locked to Ghostty's internal state.

### Grid Reallocation Under Mutex Lock

Inside the critical section guarded by `renderer_state.mutex`, Ghostty calls `terminal.resize` as implemented in `src/terminal/c/terminal.zig` (lines 467-484). This function:

- Reallocates the logical grid buffers to match new cell counts
- Updates pixel dimensions for font rendering calculations
- Clears any pending "synchronized output" mode (SM?2026) to force immediate visual updates
- Handles edge cases including zero-size windows and dimension overflow

The mutex ensures grid reflow happens atomically without race conditions between the terminal state and the rendering thread.

### Renderer Notification and Redraw

After updating the grid, the termio thread enqueues a resize message and wakes the renderer. As found in `src/termio/Termio.zig` (lines 99-102):

```zig
renderer_mailbox.push(.{ .resize = size }, .{ .forever = {} });
renderer_wakeup.notify();

```

The renderer thread consumes this message, recomputes cell layout based on the new grid dimensions, and redraws the entire screen surface.

## Size Reporting and Synchronization

### In-Band Size Reports

When configured, Ghostty emits in-band size reports using CSI sequences. The `sizeReportLocked` function in `src/termio/Termio.zig` (lines 12-20) formats and sends OSC 1337-style reports (`CSI = 3 ; … c`) to applications requesting window dimension notifications.

### Forced Resize Fallback

In `src/termio/stream_handler.zig` (line 723), Ghostty implements a consistency check: if the terminal reports dimensions differing from the UI window size, the system forces the UI to adopt the terminal's size. This prevents desynchronization between the PTY state and the visual window bounds.

## Practical Code Examples

### Manual Resize Invocation

For testing or custom UI integrations, developers can trigger the resize pipeline directly:

```zig
const newSize = renderer.Size{
    .cols = 120,
    .rows = 35,
    .cell = .{ .width = 8, .height = 16 },
};
try termio.resize(td, newSize);

```

This call executes the full sequence: PTY resize, grid reallocation, and renderer notification.

### Understanding the Coalescing Behavior

The debounce logic in `src/termio/Thread.zig` ensures that during animated window resizes, only the final dimensions trigger expensive grid reallocation operations. This optimization prevents memory thrashing and reduces CPU usage during continuous resize events.

## Summary

- **Event Coalescing**: Rapid resize events collapse into single updates via `src/termio/Thread.zig` to optimize performance
- **Atomic Updates**: Grid reallocation occurs under `renderer_state.mutex` in `src/terminal/c/terminal.zig` to prevent race conditions
- **PTY Synchronization**: `backend.resize` in `src/termio/Termio.zig` ensures the operating system's pseudo-terminal matches the UI dimensions
- **Renderer Integration**: The mailbox push pattern decouples terminal state updates from GPU rendering operations
- **Consistency Guarantees**: Fallback logic in `src/termio/stream_handler.zig` resynchronizes the UI if terminal reports diverge from window bounds

## Frequently Asked Questions

### How does Ghostty prevent flicker during window resizing?

Ghostty guards grid reallocation with a mutex (`renderer_state.mutex`) and clears synchronized output mode before updating dimensions. This ensures the terminal buffer atomically switches to the new size before the renderer redraws, eliminating intermediate frames that could cause visual tearing.

### What happens if I resize the window rapidly?

The termio thread coalesces multiple resize events into a single operation. In `src/termio/Thread.zig`, intermediate sizes are stored temporarily in `coalesce_data` and only the final dimensions processed after a brief debounce interval, preventing redundant grid reallocations and PTY updates.

### Does Ghostty support in-band size reporting to applications?

Yes. When enabled, Ghostty emits CSI sequences via `sizeReportLocked` in `src/termio/Termio.zig`, sending OSC 1337-style notifications that allow terminal applications to react programmatically to dimension changes without relying on SIGWINCH signals alone.

### How does Ghostty handle size mismatches between the UI and PTY?

If the terminal reports dimensions different from the window size, the stream handler in `src/termio/stream_handler.zig` (line 723) forces the UI to adopt the terminal's size. This ensures consistency between the logical grid and the visual window, preventing display corruption or input coordinate misalignment.