diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/libc/inc/errno.h | 6 | ||||
-rw-r--r-- | libs/libgui/gfx.c | 12 | ||||
-rw-r--r-- | libs/libgui/gfx.h | 2 | ||||
-rw-r--r-- | libs/libgui/gui.c | 240 | ||||
-rw-r--r-- | libs/libgui/gui.h | 14 | ||||
-rw-r--r-- | libs/libgui/msg.h | 1 |
6 files changed, 253 insertions, 22 deletions
diff --git a/libs/libc/inc/errno.h b/libs/libc/inc/errno.h index e226aba..133f543 100644 --- a/libs/libc/inc/errno.h +++ b/libs/libc/inc/errno.h @@ -47,6 +47,12 @@ typedef s32 res; #ifdef userspace #define errno (*__errno()) extern u32 *__errno(void); + +#define return_errno(__num) \ + { \ + errno = __num; \ + return -errno; \ + } #endif #endif diff --git a/libs/libgui/gfx.c b/libs/libgui/gfx.c index 259b03f..a0f5b22 100644 --- a/libs/libgui/gfx.c +++ b/libs/libgui/gfx.c @@ -96,13 +96,13 @@ static void draw_rectangle(struct context *ctx, vec2 pos1, vec2 pos2, u32 c) } } -struct context *gfx_new_ctx(struct context *ctx) +struct context *gfx_new_ctx(struct context *ctx, vec2 size, u8 bpp) { - /* struct message msg = { 0 }; */ - assert(0); - /* assert(msg_send(pidof(WM_PATH), GFX_NEW_CONTEXT, ctx) > 0); */ - /* assert(msg_receive(&msg) > 0); */ - /* memcpy(ctx, msg.data, sizeof(*ctx)); */ + ctx->size = size; + ctx->bpp = bpp; + ctx->pitch = size.x * (bpp >> 3); + ctx->bytes = ctx->pitch * ctx->size.y; + ctx->fb = zalloc(ctx->bytes); return ctx; } diff --git a/libs/libgui/gfx.h b/libs/libgui/gfx.h index 8ac01d0..1999b0c 100644 --- a/libs/libgui/gfx.h +++ b/libs/libgui/gfx.h @@ -62,7 +62,7 @@ struct context { u32 bytes; }; -struct context *gfx_new_ctx(struct context *ctx); +struct context *gfx_new_ctx(struct context *ctx, vec2 size, u8 bpp); struct font *gfx_resolve_font(enum font_type font_type); void gfx_write_char(struct context *ctx, vec2 pos, enum font_type font_type, u32 c, char ch); void gfx_write(struct context *ctx, vec2 pos, enum font_type font_type, u32 c, const char *text); diff --git a/libs/libgui/gui.c b/libs/libgui/gui.c index d8435e6..2c6221a 100644 --- a/libs/libgui/gui.c +++ b/libs/libgui/gui.c @@ -7,44 +7,241 @@ #include <libgui/msg.h> #include <list.h> #include <print.h> +#include <random.h> #define WM_PATH "/bin/wm" +struct gui_widget { + u32 id; + vec2 pos; + struct context ctx; + struct list *children; + + struct { + void (*mousemove)(vec2 pos); + } event; +}; + struct gui_window { u32 id; struct context ctx; + struct list *widgets; }; struct list *windows = NULL; -static struct gui_window *win_by_id(u32 id) +/** + * Resolve/find stuff + */ + +static struct gui_window *win_by_id(u32 win_id) { assert(windows); struct node *iterator = windows->head; while (iterator) { struct gui_window *win = iterator->data; - if (win->id == id) + if (win->id == win_id) + return iterator->data; + iterator = iterator->next; + } + + return NULL; +} + +static struct gui_widget *widget_in_widget(struct gui_widget *parent, u32 widget_id) +{ + if (parent->id == widget_id) + return parent; + + if (!parent->children) + return NULL; + + struct node *iterator = parent->children->head; + while (iterator) { + struct gui_widget *widget = iterator->data; + if (widget->id == widget_id) return iterator->data; + + struct gui_widget *sub = widget_in_widget(widget, widget_id); + if (sub && sub->id == widget_id) + return sub; + iterator = iterator->next; } + return NULL; } +static struct gui_widget *widget_in_win(struct gui_window *win, u32 widget_id) +{ + assert(win->widgets); + struct node *iterator = win->widgets->head; + while (iterator) { + struct gui_widget *widget = iterator->data; + if (widget->id == widget_id) + return iterator->data; + + struct gui_widget *sub = widget_in_widget(widget, widget_id); + if (sub && sub->id == widget_id) + return sub; + + iterator = iterator->next; + } + + return NULL; +} + +static struct gui_widget *widget_by_id(u32 win_id, u32 widget_id) +{ + struct gui_window *win = win_by_id(win_id); + return widget_in_win(win, widget_id); +} + /** * GFX wrappers */ -static res fill(u32 id, u32 c) +res gui_fill(u32 win_id, u32 widget_id, u32 c) +{ + struct gui_widget *widget = widget_by_id(win_id, widget_id); + if (!widget) + return_errno(ENOENT); + + gfx_fill(&widget->ctx, c); + + return_errno(EOK); +} + +/** + * Widgets + */ + +static res gui_widget_at(u32 win_id, vec2 pos, struct gui_widget *widget) +{ + struct gui_window *win = win_by_id(win_id); + if (!win) + return_errno(ENOENT); + + struct gui_widget *ret = NULL; + + struct node *iterator = win->widgets->head; + while (iterator) { + struct gui_widget *w = iterator->data; + if (pos.x >= w->pos.x && pos.x <= w->pos.x + w->ctx.size.x && pos.y >= w->pos.y && + pos.y <= w->pos.y + w->ctx.size.y) + ret = widget; + // TODO: Search in children + iterator = iterator->next; + } + + if (widget) { + *widget = *ret; + return_errno(EOK); + } else { + return_errno(ENOENT); + } +} + +static res gui_sync_widget(u32 win_id, u32 widget_id) +{ + struct gui_window *win = win_by_id(win_id); + struct gui_widget *widget = widget_in_win(win, widget_id); + if (!widget) + return_errno(ENOENT); + + gfx_ctx_on_ctx(&win->ctx, &widget->ctx, widget->pos); + + return_errno(EOK); +} + +static struct gui_widget *gui_win_main_widget(struct gui_window *win) +{ + return win->widgets->head->data; +} + +static struct gui_widget *gui_new_plain_widget(vec2 size, vec2 pos, u8 bpp) +{ + struct gui_widget *widget = zalloc(sizeof(*widget)); + struct context *ctx = zalloc(sizeof(*ctx)); + + widget->id = rand(); + widget->pos = pos; + widget->ctx = *gfx_new_ctx(ctx, size, bpp); + widget->children = list_new(); + + return widget; +} + +res gui_add_widget(u32 win_id, u32 widget_id, vec2 size, vec2 pos) +{ + struct gui_widget *parent = widget_by_id(win_id, widget_id); + if (!parent) + return_errno(ENOENT); + + struct gui_widget *child = gui_new_plain_widget(size, pos, parent->ctx.bpp); + list_add(parent->children, child); + + return child->id; +} + +res gui_new_widget(u32 win_id, vec2 size, vec2 pos) +{ + struct gui_window *win = win_by_id(win_id); + if (!win) + return_errno(ENOENT); + + if (!win->widgets->head) + list_add(win->widgets, + gui_new_plain_widget(win->ctx.size, vec2(0, 0), win->ctx.bpp)); + + return gui_add_widget(win->id, gui_win_main_widget(win)->id, size, pos); +} + +res gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u32 func) +{ + if (!func) + return_errno(EFAULT); + + struct gui_widget *widget = widget_by_id(win_id, widget_id); + if (!widget) + return_errno(ENOENT); + + switch (listener) { + case GUI_LISTEN_MOUSEMOVE: + widget->event.mousemove = (void (*)(vec2))func; + break; + default: + return_errno(ENOENT); + } + + return_errno(EOK); +} + +res gui_redraw_widget(u32 win_id, u32 widget_id) +{ + if (gui_sync_widget(win_id, widget_id) != EOK) + return errno; + + if (gui_redraw_window(win_id) != EOK) + return errno; + + return_errno(EOK); +} + +/** + * Window data getters + */ + +vec2 gui_window_size(u32 win_id) { - struct gui_window *win = win_by_id(id); + struct gui_window *win = win_by_id(win_id); if (!win) - return -ENOENT; - gfx_fill(&win->ctx, c); - return EOK; + return vec2(0, 0); + return win->ctx.size; } /** - * Program interface + * Window manager interfaces */ res gui_new_window(void) @@ -63,13 +260,14 @@ res gui_new_window(void) u32 size; res ret = shaccess(msg.shid, (u32 *)&win->ctx.fb, &size); if (ret < 0 || !win->ctx.fb) - return MIN(ret, -EFAULT); + return_errno(-MIN(ret, -EFAULT)); list_add(windows, win); - assert(fill(win->id, COLOR_BLACK) == EOK); - gui_redraw_window(win->id); + win->widgets = list_new(); + return win->id; } - return -EINVAL; + + return_errno(EINVAL); } res gui_redraw_window(u32 id) @@ -79,7 +277,8 @@ res gui_redraw_window(u32 id) msg_receive(&msg, sizeof(msg)) > 0 && msg.header.type == (GUI_REDRAW_WINDOW | MSG_SUCCESS)) return id; - return -EINVAL; + + return_errno(EINVAL); } /** @@ -106,10 +305,21 @@ static res handle_ping(struct message_ping *msg) static res handle_mouse(struct message_mouse *msg) { - if (msg->header.state == MSG_NEED_ANSWER) + if (msg->header.state == MSG_NEED_ANSWER) { msg_send(msg->header.src, msg->header.type | MSG_SUCCESS, msg, sizeof(*msg)); - return errno; + if (errno != EOK) + return errno; + } + + struct gui_widget widget = { 0 }; + if (gui_widget_at(msg->id, msg->pos, &widget) != EOK) + return_errno(EOK); + + if (widget.event.mousemove) + widget.event.mousemove(msg->pos); + + return_errno(EOK); } static void handle_exit(void) diff --git a/libs/libgui/gui.h b/libs/libgui/gui.h index a3f74f8..511033f 100644 --- a/libs/libgui/gui.h +++ b/libs/libgui/gui.h @@ -5,9 +5,23 @@ #include <def.h> #include <errno.h> +#include <libgui/gfx.h> +#include <vec.h> + +enum gui_listener { GUI_LISTEN_MOUSEMOVE }; res gui_new_window(void); res gui_redraw_window(u32 id); + +res gui_fill(u32 win_id, u32 widget_id, u32 c); + +res gui_add_widget(u32 win_id, u32 widget_id, vec2 size, vec2 pos); +res gui_new_widget(u32 win_id, vec2 size, vec2 pos); +res gui_listen_widget(u32 win_id, u32 widget_id, enum gui_listener listener, u32 func); +res gui_redraw_widget(u32 win_id, u32 widget_id); + +vec2 gui_window_size(u32 win_id); + void gui_loop(void); #endif diff --git a/libs/libgui/msg.h b/libs/libgui/msg.h index 7326135..65fc640 100644 --- a/libs/libgui/msg.h +++ b/libs/libgui/msg.h @@ -49,6 +49,7 @@ struct message_destroy_window { struct message_mouse { struct message_header header; + u32 id; vec2 pos; struct { u8 click : 1; |