Develop core GUI applications (terminal, editor, file manager)
Summary
Develop core GUI applications to demonstrate and validate the GUI stack, including a terminal emulator, text editor, file manager, and calculator.
Goals
Create essential GUI applications:
- Terminal Emulator - Run shell commands
- Text Editor - Edit text files
- File Manager - Browse filesystem
- Calculator - Basic calculator
- Image Viewer - Display PNG/JPEG images (optional)
Implementation
1. Terminal Emulator
```c // GUI terminal that runs /bin/mosh struct terminal { struct window *window; char grid[80][25]; // Character grid int cursor_x, cursor_y; int pty_fd; // Pseudo-terminal };
void terminal_init(struct terminal *term) { term->window = compositor_create_window(640, 400, "Terminal"); term->pty_fd = pty_open(); // Fork mosh
// Main loop
while (1) {
// Read from PTY
char buf[256];
ssize_t n = read(term->pty_fd, buf, sizeof(buf));
for (int i = 0; i < n; i++) {
terminal_putchar(term, buf[i]);
}
// Render
terminal_render(term);
// Handle keyboard
struct input_event evt;
if (get_key_event(&evt)) {
char ch = keycode_to_char(evt.key.keycode);
write(term->pty_fd, &ch, 1);
}
}
}
void terminal_render(struct terminal *term) { cairo_t *cr = cairo_create(term->window->surface);
// Black background
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
// Render text grid
cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);
cairo_select_font_face(cr, "Monospace", ...);
cairo_set_font_size(cr, 14);
for (int y = 0; y < 25; y++) {
for (int x = 0; x < 80; x++) {
if (term->grid[x][y]) {
cairo_move_to(cr, x * 8, y * 16);
char str[2] = { term->grid[x][y], 0 };
cairo_show_text(cr, str);
}
}
}
// Draw cursor
cairo_rectangle(cr, term->cursor_x * 8, term->cursor_y * 16, 8, 16);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_stroke(cr);
cairo_destroy(cr);
window_commit(term->window);
} ```
2. Text Editor
```c struct editor { struct window *window; char **lines; // Text buffer int num_lines; int cursor_line, cursor_col; int scroll_offset; char *filename; int modified; };
void editor_render(struct editor *ed) { cairo_t *cr = cairo_create(ed->window->surface);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_select_font_face(cr, "Monospace", ...);
int y = 20;
for (int i = ed->scroll_offset;
i < ed->num_lines && y < ed->window->height;
i++, y += 16) {
cairo_move_to(cr, 10, y);
cairo_show_text(cr, ed->lines[i]);
}
// Draw cursor
int cursor_y = (ed->cursor_line - ed->scroll_offset) * 16 + 20;
int cursor_x = ed->cursor_col * 8 + 10;
cairo_move_to(cr, cursor_x, cursor_y);
cairo_line_to(cr, cursor_x, cursor_y - 16);
cairo_stroke(cr);
cairo_destroy(cr);
window_commit(ed->window);
}
// Handle Ctrl+S to save void editor_save(struct editor *ed) { FILE *f = fopen(ed->filename, "w"); for (int i = 0; i < ed->num_lines; i++) { fprintf(f, "%s\n", ed->lines[i]); } fclose(f); ed->modified = 0; } ```
3. File Manager
```c struct file_manager { struct window *window; char current_path[256]; struct dirent *entries; int num_entries; int selected; };
void filemgr_render(struct filemgr *fm) { cairo_t *cr = cairo_create(fm->window->surface);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
// Draw path
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_move_to(cr, 10, 20);
cairo_show_text(cr, fm->current_path);
// Draw files
int y = 50;
for (int i = 0; i < fm->num_entries; i++) {
if (i == fm->selected) {
cairo_rectangle(cr, 5, y - 15, fm->window->width - 10, 20);
cairo_set_source_rgb(cr, 0.7, 0.7, 1.0);
cairo_fill(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
}
// Draw icon based on type
if (fm->entries[i].d_type == DT_DIR) {
draw_icon(cr, 10, y - 12, "folder.png");
} else {
draw_icon(cr, 10, y - 12, "file.png");
}
cairo_move_to(cr, 35, y);
cairo_show_text(cr, fm->entries[i].d_name);
y += 25;
}
cairo_destroy(cr);
window_commit(fm->window);
}
// Double-click to open void filemgr_open(struct filemgr *fm, int index) { if (fm->entries[index].d_type == DT_DIR) { // Navigate to directory chdir(fm->entries[index].d_name); getcwd(fm->current_path, sizeof(fm->current_path)); filemgr_refresh(fm); } else { // Open file with default application char cmd[512]; snprintf(cmd, sizeof(cmd), "/bin/editor %s/%s", fm->current_path, fm->entries[index].d_name); system(cmd); } } ```
4. Calculator
```c struct calculator { struct window *window; char display[32]; double accumulator; char operation; };
void calc_render(struct calc *c) { cairo_t *cr = cairo_create(c->window->surface);
// Background
cairo_set_source_rgb(cr, 0.9, 0.9, 0.9);
cairo_paint(cr);
// Display
cairo_rectangle(cr, 10, 10, 260, 40);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_select_font_face(cr, "Sans", ...);
cairo_set_font_size(cr, 24);
cairo_move_to(cr, 20, 40);
cairo_show_text(cr, c->display);
// Number buttons
const char *labels[] = {
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "=", "+"
};
for (int i = 0; i < 16; i++) {
int x = (i % 4) * 65 + 10;
int y = (i / 4) * 50 + 60;
draw_button(cr, x, y, 60, 45, labels[i]);
}
cairo_destroy(cr);
window_commit(c->window);
} ```
Timeline
- Terminal Emulator: 2 weeks
- Text Editor: 2 weeks
- File Manager: 2 weeks
- Calculator: 1 week
Total: 6-8 weeks (can be done in parallel)
Definition of Done
- [ ] Terminal emulator runs and is usable
- [ ] Text editor can open, edit, and save files
- [ ] File manager can browse directories
- [ ] Calculator performs basic math
- [ ] All apps have professional UI
- [ ] Apps demonstrate GUI capabilities
Dependencies
- #396: Cairo (rendering)
- #403: Compositor (window creation)
- #404: Window protocol (client library)
See docs/road/road_to_gui.md for complete roadmap.