menios icon indicating copy to clipboard operation
menios copied to clipboard

Develop core GUI applications (terminal, editor, file manager)

Open pbalduino opened this issue 3 months ago • 0 comments

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:

  1. Terminal Emulator - Run shell commands
  2. Text Editor - Edit text files
  3. File Manager - Browse filesystem
  4. Calculator - Basic calculator
  5. 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.

pbalduino avatar Oct 30 '25 22:10 pbalduino