Window stack

This commit is contained in:
Thierry 2026-04-22 21:15:46 +02:00
parent 64ea01f46b
commit 703b2ec3f0
No known key found for this signature in database

117
src/app.c
View file

@ -22,14 +22,20 @@ static struct tex fb_as_tex(void) {
}; };
} }
#define APP_STACK_SIZE 10
struct app_instance { struct app_instance {
struct app_template *template; struct app_template *template;
struct rect pos; struct rect pos;
void *app; void *app;
struct tex framebuf; struct tex framebuf;
} app_stack[10]; struct app_instance *next_app;
size_t app_stack_size = 0; struct app_instance *prev_app;
};
// Soon dynamic allocation
struct app_instance apps[32];
size_t free_idx = 0;
struct app_instance *app_root = NULL;
struct tex app_background; struct tex app_background;
@ -75,41 +81,43 @@ void app_init_global(void) {
} }
static struct app_instance *app_find(void *app) { static struct app_instance *app_find(void *app) {
for (int i = (int)app_stack_size - 1; i >= 0; i--) {
if (app_stack[i].app == app) { if (app_root->app == app) {
return app_stack + i; return app_root;
}
for (struct app_instance *cursor = app_root->next_app; cursor != app_root; cursor = cursor->next_app) {
if (cursor->app == app) {
return cursor;
} }
} }
return NULL; return NULL;
} }
static void app_redraw_below(struct rect uncovered, size_t idx) { static void app_redraw_below(struct rect uncovered, struct app_instance *ins) {
ASSERT(idx < app_stack_size);
struct tex fb_tex = fb_as_tex(); struct tex fb_tex = fb_as_tex();
tex_blit(&fb_tex, &app_background, &uncovered, &uncovered); tex_blit(&fb_tex, &app_background, &uncovered, &uncovered);
for (size_t i = 0; i < idx; i++) { for (struct app_instance *cursor = ins->next_app; cursor != ins; cursor = cursor->next_app) {
struct app_instance *ins = &app_stack[i];
struct rect local_src = uncovered; struct rect local_src = uncovered;
struct rect local_dst = uncovered; struct rect local_dst = uncovered;
rect_clamp(&local_src, &ins->pos); rect_clamp(&local_src, &cursor->pos);
rect_clamp(&local_dst, &ins->pos); rect_clamp(&local_dst, &cursor->pos);
rect_translate(&local_src, -ins->pos.x, -ins->pos.y); rect_translate(&local_src, -cursor->pos.x, -cursor->pos.y);
tex_blit(&fb_tex, &ins->framebuf, &local_src, &local_dst); tex_blit(&fb_tex, &cursor->framebuf, &local_src, &local_dst);
} }
fb_damage(uncovered); fb_damage(uncovered);
} }
static void app_redraw_above(struct rect uncovered, size_t idx) { static void app_redraw_above(struct rect uncovered, struct app_instance *ins) {
ASSERT(idx < app_stack_size); ASSERT(ins != NULL);
struct tex fb_tex = fb_as_tex(); struct tex fb_tex = fb_as_tex();
for (size_t i = idx + 1; i < app_stack_size; i++) { for (struct app_instance *cursor = ins->prev_app; cursor != ins; cursor = cursor->prev_app) {
struct app_instance *ins = &app_stack[i];
struct rect local_src = uncovered; struct rect local_src = uncovered;
struct rect local_dst = uncovered; struct rect local_dst = uncovered;
rect_clamp(&local_src, &ins->pos); rect_clamp(&local_src, &cursor->pos);
rect_clamp(&local_dst, &ins->pos); rect_clamp(&local_dst, &cursor->pos);
rect_translate(&local_src, -ins->pos.x, -ins->pos.y); rect_translate(&local_src, -cursor->pos.x, -cursor->pos.y);
tex_blit(&fb_tex, &ins->framebuf, &local_src, &local_dst); tex_blit(&fb_tex, &cursor->framebuf, &local_src, &local_dst);
} }
fb_damage(uncovered); fb_damage(uncovered);
} }
@ -142,9 +150,8 @@ void app_draw_rect(void *self, struct color col, const struct rect *rect) {
tex_fill_region(&my_view, col, rect); tex_fill_region(&my_view, col, rect);
struct rect rect_global = app_rect_local_to_global(ins, rect); struct rect rect_global = app_rect_local_to_global(ins, rect);
size_t own_idx = (ins - app_stack); if (ins != app_root) {
if (own_idx < app_stack_size - 1) { app_redraw_above(rect_global, ins);
app_redraw_above(rect_global, own_idx);
} }
fb_damage(rect_global); fb_damage(rect_global);
} }
@ -162,9 +169,8 @@ void app_draw_texture(void *self, const struct tex *tex, int x, int y) {
struct rect rect_local = RECT_XYWH(x, y, tex->width, tex->height); struct rect rect_local = RECT_XYWH(x, y, tex->width, tex->height);
struct rect rect_global = app_rect_local_to_global(ins, &rect_local); struct rect rect_global = app_rect_local_to_global(ins, &rect_local);
size_t own_idx = (ins - app_stack); if (ins != app_root) {
if (own_idx < app_stack_size - 1) { app_redraw_above(rect_global, ins);
app_redraw_above(rect_global, own_idx);
} }
fb_damage(rect_global); fb_damage(rect_global);
} }
@ -189,9 +195,10 @@ bool app_push(struct app_template *template, void *arg, struct rect *pos) {
}; };
struct ppn ppn; struct ppn ppn;
ASSERT(ram_alloc_buffer(&ppn, req)); ASSERT(ram_alloc_buffer(&ppn, req));
ASSERT(app_stack_size < APP_STACK_SIZE);
// TODO this structure should be locked // TODO this structure should be locked
app_stack[app_stack_size++] = (struct app_instance){ // 32 = length of apps[]
ASSERT(free_idx < 32);
apps[free_idx] = (struct app_instance){
.template = template, .template = template,
.pos = actual_pos, .pos = actual_pos,
.app = app, .app = app,
@ -200,14 +207,23 @@ bool app_push(struct app_template *template, void *arg, struct rect *pos) {
RECT_HEIGHT(actual_pos), RECT_HEIGHT(actual_pos),
ppn_to_pointer(ppn) ppn_to_pointer(ppn)
), ),
.next_app = app_root != NULL ? app_root : &apps[free_idx],
.prev_app = app_root != NULL ? app_root->prev_app : &apps[free_idx]
}; };
if (app_root != NULL) {
app_root->prev_app->next_app = &apps[free_idx];
app_root->prev_app = &apps[free_idx];
}
app_root = &apps[free_idx];
free_idx++;
template->init(app); template->init(app);
fb_refresh(); fb_refresh();
return true; return true;
} }
void *app_top(void) { void *app_top(void) {
return (app_stack_size == 0) ? NULL : app_stack + app_stack_size - 1; return app_root;
} }
void app_pop(void) { void app_pop(void) {
@ -219,64 +235,65 @@ void app_pop(void) {
ins->template->destroy(ins->app); ins->template->destroy(ins->app);
ram_free(ppn_from_aligned_pa(pa_from_pointer(ins->framebuf.data))); ram_free(ppn_from_aligned_pa(pa_from_pointer(ins->framebuf.data)));
// we know `app_stack_size` is at least 1 here, so the decrement is safe app_redraw_below(uncovered, ins);
app_redraw_below(uncovered, app_stack_size - 1); if (ins == ins->next_app) {
app_stack_size--; app_root = NULL;
return;
}
ins->next_app->prev_app = ins->prev_app;
ins->prev_app->next_app = ins->next_app;
app_root = ins->next_app;
} }
void app_translate(size_t app_idx, int dx, int dy) { void app_translate(struct app_instance *ins, int dx, int dy) {
// TODO could optimize the uncovered // TODO could optimize the uncovered
ASSERT(app_idx < app_stack_size);
struct app_instance *ins = &app_stack[app_idx];
const struct rect uncovered = ins->pos; const struct rect uncovered = ins->pos;
rect_translate(&ins->pos, dx, dy); rect_translate(&ins->pos, dx, dy);
struct tex fb_tex = fb_as_tex(); struct tex fb_tex = fb_as_tex();
// draw everything below, and then the current window // draw everything below, and then the current window
app_redraw_below(uncovered, app_idx); app_redraw_below(uncovered, ins);
tex_blit(&fb_tex, &ins->framebuf, NULL, &ins->pos); tex_blit(&fb_tex, &ins->framebuf, NULL, &ins->pos);
fb_damage(ins->pos); fb_damage(ins->pos);
} }
void app_key_event_listener(struct key_event event) { void app_key_event_listener(struct key_event event) {
if (app_stack_size == 0) { if (app_root == NULL) {
return; return;
} }
struct app_instance *ins = app_top(); struct app_instance *ins = app_top();
if (event.code == KEY_ARROW_LEFT && (event.mod & KEY_MOD_SHIFT)) { if (event.code == KEY_ARROW_LEFT && (event.mod & KEY_MOD_SHIFT)) {
if (event.pressed) { if (event.pressed) {
app_translate(app_stack_size - 1, -10, 0); app_translate(ins, -10, 0);
} }
return; return;
} }
if (event.code == KEY_ARROW_RIGHT && (event.mod & KEY_MOD_SHIFT)) { if (event.code == KEY_ARROW_RIGHT && (event.mod & KEY_MOD_SHIFT)) {
if (event.pressed) { if (event.pressed) {
app_translate(app_stack_size - 1, 10, 0); app_translate(ins, 10, 0);
} }
return; return;
} }
if (event.code == KEY_ARROW_UP && (event.mod & KEY_MOD_SHIFT)) { if (event.code == KEY_ARROW_UP && (event.mod & KEY_MOD_SHIFT)) {
if (event.pressed) { if (event.pressed) {
app_translate(app_stack_size - 1, 0, -10); app_translate(ins, 0, -10);
} }
return; return;
} }
if (event.code == KEY_ARROW_DOWN && (event.mod & KEY_MOD_SHIFT)) { if (event.code == KEY_ARROW_DOWN && (event.mod & KEY_MOD_SHIFT)) {
if (event.pressed) { if (event.pressed) {
app_translate(app_stack_size - 1, 0, 10); app_translate(ins, 0, 10);
} }
return; return;
} }
if (event.code == KEY_TAB && (event.mod & KEY_MOD_SHIFT)) { if (event.code == KEY_TAB && (event.mod & KEY_MOD_SHIFT)) {
// select lowest app to be the current one now (natural rotation, easy for now) // select next app to be the current one now (natural rotation, easy for now)
if (event.pressed && app_stack_size >= 2) { if (event.pressed) {
struct app_instance lowest = app_stack[0]; app_root = app_root->next_app;
memmove(app_stack, app_stack + 1, (app_stack_size - 1) * sizeof(struct app_instance));
app_stack[app_stack_size - 1] = lowest;
// redraw this new top window // redraw this new top window
struct tex fb_tex = fb_as_tex(); struct tex fb_tex = fb_as_tex();
tex_blit(&fb_tex, &lowest.framebuf, NULL, &lowest.pos); tex_blit(&fb_tex, &app_root->framebuf, NULL, &app_root->pos);
fb_damage(lowest.pos); fb_damage(app_root->pos);
} }
return; return;
} }