Project 7: Mini-Screen (Single-Window Multiplexer)
Build a minimal multiplexer that runs two PTYs and composites them into one terminal window.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Level 4: Expert |
| Time Estimate | 2-3 weeks |
| Main Programming Language | C (Alternatives: Rust) |
| Alternative Programming Languages | Rust |
| Coolness Level | Level 5: Terminal Sorcery |
| Business Potential | 2: The “Power Tool” |
| Prerequisites | PTYs, screen buffers, event loops |
| Key Topics | pane routing, composite rendering, focus management |
1. Learning Objectives
By completing this project, you will:
- Build a working implementation of mini-screen (single-window multiplexer) and verify it with deterministic outputs.
- Explain the underlying Unix and terminal primitives involved in the project.
- Diagnose common failure modes with logs and targeted tests.
- Extend the project with performance and usability improvements.
2. All Theory Needed (Per-Concept Breakdown)
Multipane Composition and Focus Routing
-
Fundamentals Multipane Composition and Focus Routing is the core contract that makes the project behave like a real terminal tool. It sits at the boundary between raw bytes and structured state, so you must treat it as both a protocol and a data model. The goal of the fundamentals is to understand what assumptions the system makes about ordering, buffering, and ownership, and how those assumptions surface as user-visible behavior. Key terms include: pane buffers, focus, compositor, offsets. In practice, the fastest way to gain intuition is to trace a single input through the pipeline and note where it can be delayed, reordered, or transformed. That exercise reveals why Multipane Composition and Focus Routing needs explicit invariants and why even small mistakes can cascade into broken rendering or stuck input.
-
Deep Dive into the concept A deep understanding of Multipane Composition and Focus Routing requires thinking in terms of state transitions and invariants. You are not just implementing functions; you are enforcing a contract between producers and consumers of bytes, and that contract persists across time. Most failures in this area are caused by violating ordering guarantees, dropping state updates, or misunderstanding how the operating system delivers events. This concept is built from the following pillars: pane buffers, focus, compositor, offsets. A reliable implementation follows a deterministic flow: Render each pane to its own buffer -> Compute layout offsets -> Copy panes into composite buffer -> Route input to focused pane. From a systems perspective, the tricky part is coordinating concurrency without introducing races. Even in a single-threaded loop, multiple events can arrive in the same tick, so you need deterministic ordering. This is why many implementations keep a strict sequence: read, update state, compute diff, render. Another subtlety is error handling and recovery. A robust design treats errors as part of the normal control flow: EOF is expected, partial reads are expected, and transient failures must be retried or gracefully handled. The deep dive should also cover how to observe the system, because without logs and trace points, you cannot reason about correctness. When you design the project, treat each key term as a source of constraints. For example, if a term implies buffering, decide the buffer size and how overflow is handled. If a term implies state, decide how that state is initialized, updated, and reset. Finally, validate your assumptions with deterministic fixtures so you can reproduce bugs. From a systems perspective, the tricky part is coordinating concurrency without introducing races. Even in a single-threaded loop, multiple events can arrive in the same tick, so you need deterministic ordering. This is why many implementations keep a strict sequence: read, update state, compute diff, render. Another subtlety is error handling and recovery. A robust design treats errors as part of the normal control flow: EOF is expected, partial reads are expected, and transient failures must be retried or gracefully handled. The deep dive should also cover how to observe the system, because without logs and trace points, you cannot reason about correctness. From a systems perspective, the tricky part is coordinating concurrency without introducing races. Even in a single-threaded loop, multiple events can arrive in the same tick, so you need deterministic ordering. This is why many implementations keep a strict sequence: read, update state, compute diff, render. Another subtlety is error handling and recovery. A robust design treats errors as part of the normal control flow: EOF is expected, partial reads are expected, and transient failures must be retried or gracefully handled. The deep dive should also cover how to observe the system, because without logs and trace points, you cannot reason about correctness. From a systems perspective, the tricky part is coordinating concurrency without introducing races. Even in a single-threaded loop, multiple events can arrive in the same tick, so you need deterministic ordering. This is why many implementations keep a strict sequence: read, update state, compute diff, render. Another subtlety is error handling and recovery. A robust design treats errors as part of the normal control flow: EOF is expected, partial reads are expected, and transient failures must be retried or gracefully handled. The deep dive should also cover how to observe the system, because without logs and trace points, you cannot reason about correctness.
-
How this fit on projects This concept is the backbone of the project because it defines how data and control flow move through the system.
-
Definitions & key terms
- pane buffers -> per-pane screen buffers storing text and attributes
- focus -> the active pane that receives input
- compositor -> the component that merges pane buffers into a single screen
- offsets -> x/y coordinates that map pane space into global space
-
Mental model diagram (ASCII)
[Input] -> [Multipane Composition and Focus Routing] -> [State] -> [Output]
-
How it works (step-by-step, with invariants and failure modes)
- Render each pane to its own buffer
- Compute layout offsets
- Copy panes into composite buffer
- Route input to focused pane
-
Minimal concrete example
Composite buffer cell (row, col) maps to pane cell with x/y offsets.
-
Common misconceptions
- “You can just write both PTYs to stdout” -> outputs will interleave and corrupt the screen.
-
Check-your-understanding questions
- How do you avoid overlapping pane output?
- How do you route input to only one pane?
-
Check-your-understanding answers
- Use a compositor with offsets and a unified render pass.
- Track focus and forward input only to that pane.
-
Real-world applications
- tmux panes
- tiling terminal UIs
-
Where you’ll apply it
- See Section 3.2 Functional Requirements and Section 5.4 Concepts You Must Understand First.
- Also used in: Project 6: Terminal UI Library (Mini-ncurses), Project 8: Detach/Attach Server Architecture.
-
References
- tmux 3 Ch. 2-3
-
Key insights Multipane Composition and Focus Routing works best when you treat it as a stateful contract with explicit invariants.
-
Summary You now have a concrete mental model for Multipane Composition and Focus Routing and can explain how it affects correctness and usability.
-
Homework/Exercises to practice the concept
- Draw the buffer layout for a split screen.
-
Solutions to the homework/exercises
- Use a 2-pane vertical split and map coordinates.
3. Project Specification
3.1 What You Will Build
A program that launches two PTY-backed shells, renders them side by side, and routes input to the active pane.
3.2 Functional Requirements
- Requirement 1: Launch two PTYs and shells
- Requirement 2: Composite two buffers into one screen
- Requirement 3: Switch focus with a keybinding
- Requirement 4: Route input to focused pane
3.3 Non-Functional Requirements
- Performance: Avoid blocking I/O; batch writes when possible.
- Reliability: Handle partial reads/writes and cleanly recover from disconnects.
- Usability: Provide clear CLI errors, deterministic output, and helpful logs.
3.4 Example Usage / Output
$ ./mini_screen
[mini] 2 panes running
pane0> htop
pane1> tail -f /var/log/syslog
[exit code: 0]
$ ./mini_screen --panes 4
[error] only 2 panes supported in v1
[exit code: 2]
3.5 Data Formats / Schemas / Protocols
Pane buffers stored as rows x cols with cursor state.
3.6 Edge Cases
- Pane output overlaps
- Focus lost after resize
3.7 Real World Outcome
This section defines a deterministic, repeatable outcome. Use fixed inputs and set TZ=UTC where time appears.
3.7.1 How to Run (Copy/Paste)
make
./mini_screen
3.7.2 Golden Path Demo (Deterministic)
The “success” demo below is a fixed scenario with a known outcome. It should always match.
3.7.3 If CLI: provide an exact terminal transcript
$ ./mini_screen
[mini] 2 panes running
pane0> htop
pane1> tail -f /var/log/syslog
[exit code: 0]
Failure Demo (Deterministic)
$ ./mini_screen --panes 4
[error] only 2 panes supported in v1
[exit code: 2]
3.7.8 If TUI
At least one ASCII layout for the UI:
+------------------------------+
| Mini-Screen (Single-Window Multiplexer) |
| [content area] |
| [status / hints] |
+------------------------------+
4. Solution Architecture
4.1 High-Level Design
+-----------+ +-----------+ +-----------+
| Client | <-> | Server | <-> | PTYs |
+-----------+ +-----------+ +-----------+
4.2 Key Components
| Component | Responsibility | Key Decisions | |-----------|----------------|---------------| | Pane manager | Tracks PTYs and buffers. | Fixed pane count for v1. | | Compositor | Merges pane buffers into a single screen. | Use x/y offsets for panes. | | Input router | Sends keys to focused pane. | Capture prefix key for focus switch. |
4.4 Data Structures (No Full Code)
typedef struct { Screen buf; int x, y, w, h; } Pane;
4.4 Algorithm Overview
Key Algorithm: Composite render loop
- Read from PTYs
- Update pane buffers
- Compose into output buffer
- Render diff
Complexity Analysis:
- O(rows*cols) per frame
5. Implementation Guide
5.1 Development Environment Setup
cc --version
make --version
5.2 Project Structure
mini-screen/
|-- src/
| |-- panes.c
| |-- compose.c
| `-- main.c
`-- Makefile
5.3 The Core Question You’re Answering
“How do you multiplex multiple PTYs into one terminal?”
5.4 Concepts You Must Understand First
- pane routing
- Why it matters and how it impacts correctness.
- composite rendering
- Why it matters and how it impacts correctness.
- focus management
- Why it matters and how it impacts correctness.
5.5 Questions to Guide Your Design
- How will you choose the focused pane?
- How do you handle pane resizing?
5.6 Thinking Exercise
Draw a layout tree for two panes and label buffer coordinates.
5.7 The Interview Questions They’ll Ask
- How do you merge two screen buffers?
- What happens if both panes output at once?
5.8 Hints in Layers
- Start with fixed-size panes.
-
Add focus switching after rendering works.
5.9 Books That Will Help
| Topic | Book | Chapter | |——-|——|———| | PTYs | The Linux Programming Interface | Ch. 64 |
5.10 Implementation Phases
Phase 1: Foundation (2-3 weeks)
Goals:
- Establish the core data structures and loop.
- Prove basic I/O or rendering works.
Tasks:
- Implement the core structs and minimal main loop.
- Add logging for key events and errors.
Checkpoint: You can run the tool and see deterministic output.
Phase 2: Core Functionality (2-3 weeks)
Goals:
- Implement the main requirements and pass basic tests.
- Integrate with OS primitives.
Tasks:
- Implement remaining functional requirements.
- Add error handling and deterministic test fixtures.
Checkpoint: All functional requirements are met for the golden path.
Phase 3: Polish & Edge Cases (2-3 weeks)
Goals:
- Handle edge cases and improve UX.
- Optimize rendering or I/O.
Tasks:
- Add edge-case handling and exit codes.
- Improve logs and documentation.
Checkpoint: Failure demos behave exactly as specified.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| I/O model | blocking vs non-blocking | non-blocking | avoids stalls in multiplexed loops |
| Logging | text vs binary | text for v1 | easier to inspect and debug |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Unit Tests | Validate components | parser, buffer, protocol |
| Integration Tests | Validate interactions | end-to-end CLI flow |
| Edge Case Tests | Handle boundary conditions | resize, invalid input |
6.2 Critical Test Cases
- Two panes render correctly
- Input routes to active pane
6.3 Test Data
text
Pane0 prints A, Pane1 prints B; composite shows both in correct regions.
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution | |———|———|———-| | Overlapping output | Wrong offsets | Add x/y offsets per pane. |
7.2 Debugging Strategies
- Draw pane borders to visualize boundaries.
7.3 Performance Traps
-
Rebuilding composite buffer for every byte; batch updates.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add a status line with pane IDs.
- Add key to swap panes.
8.2 Intermediate Extensions
- Add vertical/horizontal split selection.
- Add pane titles.
8.3 Advanced Extensions
- Add dynamic resizing and layout tree.
9. Real-World Connections
9.1 Industry Applications
- tmux
- screen
9.2 Related Open Source Projects
- tmux
9.3 Interview Relevance
- Event loops, terminal I/O, and state machines are common interview topics.
10. Resources
10.1 Essential Reading
- tmux 3 by Brian P. Hogan - Ch. 2-3
10.2 Video Resources
- Pane composition talk.
10.3 Tools & Documentation
- script: script
10.4 Related Projects in This Series
- Project 6: Terminal UI Library (Mini-ncurses) - Builds prerequisites
-
Project 8: Detach/Attach Server Architecture - Extends these ideas
11. Self-Assessment Checklist
11.1 Understanding
- I can explain the core concept without notes
- I can explain how input becomes output in this tool
- I can explain the main failure modes
11.2 Implementation
- All functional requirements are met
- All test cases pass
- Code is clean and well-documented
- Edge cases are handled
11.3 Growth
- I can identify one thing I’d do differently next time
- I’ve documented lessons learned
- I can explain this project in a job interview
12. Submission / Completion Criteria
Minimum Viable Completion:
- Tool runs and passes the golden-path demo
- Deterministic output matches expected snapshot
- Failure demo returns the correct exit code
Full Completion:
- All minimum criteria plus:
- Edge cases handled and tested
- Documentation covers usage and troubleshooting
Excellence (Going Above & Beyond):
- Add at least one advanced extension
- Provide a performance profile and improvement notes