Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Handle resize

A backend’s display can resize out from under you: a user resizes their terminal (crossterm) or drags a window’s edge (software/gl/wgpu). retroglyph surfaces this as an ordinary event rather than something you poll for, and one call resizes the grid to match.

Reacting to Event::Resize

Drain events every tick, same as any other input, and look for Event::Resize. It carries the new size in cells, already converted from whatever the backend measured (a real terminal’s reported columns/rows, or a window’s physical pixel size divided by the font’s cell size):

    fn handle_events<B: Backend>(term: &mut Terminal<B>) -> bool {
        let mut requested_size = None;
        let mut quit = false;
        for event in term.drain_events() {
            match event {
                Event::Key(key) if key.is_down() => {
                    if matches!(key.code, KeyCode::Char('q') | KeyCode::Escape) {
                        quit = true;
                    }
                }
                Event::Close => quit = true,
                Event::Resize(width, height) => requested_size = Some((width, height)),
                _ => {}
            }
        }
        if let Some((width, height)) = requested_size {
            term.resize(width, height);
        }
        !quit
    }

Apply it with Terminal::resize, not Backend::resize directly: Terminal::resize resizes the grid and calls the backend’s own resize to keep Backend::size in sync. Calling Backend::resize on its own only updates what the backend reports; it does not touch the grid, so your next draw call would still be working against the old dimensions.

Draw at term.area(), not a hardcoded size

The part that actually needs a resize handler to matter: never assume a fixed grid size. Read Terminal::area fresh every frame and lay out relative to it, so whatever size the resize handler applies is immediately reflected in the next draw:

let area = term.area();
if area.width() == 0 || area.height() == 0 {
    return;
}

Redraw the whole area on resize, not just what changed

Terminal::present only sends a backend the cells that changed since the last frame, and Terminal::resize preserves overlapping content across the resize rather than clearing it. That combination means a cell your draw code never explicitly touches keeps showing whatever was there before, indefinitely, on any backend that doesn’t clear its own surface on resize. Shrinking a window and then growing it back leaves stale glyphs sitting in what’s now the middle of the frame if your draw code only paints an outline.

The fix isn’t a Terminal method: it’s that a resize-aware draw function fills its entire current area every frame (background first, then whatever’s drawn on top), so every cell’s on-screen content is explained by that frame’s own draw call. See examples/examples/14_resize.rs for a complete example built around exactly this rule, runnable as:

cargo run --example 14_resize --features crossterm
cargo run --example 14_resize --features software

See also

  • Choose a backend, if you’re deciding between a terminal and a windowed backend up front.