Skip to content

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

@pbalduino

Description

@pbalduino

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

See docs/road/road_to_gui.md for complete roadmap.

Metadata

Metadata

Assignees

Labels

GUIGraphical user interface componentsenhancementNew feature or request

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions