-
Notifications
You must be signed in to change notification settings - Fork 1
Description
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
- Port Cairo 2D graphics library to meniOS #396: Cairo (rendering)
- Implement compositor core #403: Compositor (window creation)
- Define window protocol for client-compositor communication #404: Window protocol (client library)
See docs/road/road_to_gui.md for complete roadmap.