diff --git a/userspace/applications/wm/cterm.c b/userspace/applications/wm/cterm.c index 3132943a..fea9f9a4 100644 --- a/userspace/applications/wm/cterm.c +++ b/userspace/applications/wm/cterm.c @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -16,8 +15,10 @@ #define FONT_WIDTH 8 #define FONT_HEIGHT 8 -void canvas_ctx_draw_character(struct canvas_ctx *ctx, int xs, int ys, const char ch) { - char *bitmap = font8x8_basic[ch]; +extern char font8x8_basic[128][8]; + +static void canvas_ctx_draw_character(struct canvas_ctx *ctx, int xs, int ys, const char ch) { + char *bitmap = font8x8_basic[(int)ch]; if(canvas_ctx_get_format(ctx) != LIBCANVAS_FORMAT_RGB24) return; unsigned long *data = (unsigned long *)canvas_ctx_get_surface(ctx); @@ -30,7 +31,7 @@ void canvas_ctx_draw_character(struct canvas_ctx *ctx, int xs, int ys, const cha } } -void canvas_ctx_draw_text(struct canvas_ctx *ctx, int xs, int ys, const char *s) { +static void canvas_ctx_draw_text(struct canvas_ctx *ctx, int xs, int ys, const char *s) { int x = xs, y = ys; while(*s) { canvas_ctx_draw_character(ctx, x, y, *s); @@ -44,25 +45,10 @@ void canvas_ctx_draw_text(struct canvas_ctx *ctx, int xs, int ys, const char *s) #define LINE_BUFFER_LEN 128 struct cterm_state { - int cwidth, cheight; // in number of characters - int cx, cy; - int root_width, root_height; - int root_x, root_y; - char *buffer; - size_t buffer_len; int in_fd, out_fd; - char line_buffer[LINE_BUFFER_LEN]; - size_t line_buffer_len; }; void cterm_init(struct cterm_state *state) { - state->cwidth = 0; - state->cheight = 0; - state->cx = 0; - state->cy = 0; - state->buffer = 0; - state->buffer_len = 0; - char path[128] = { 0 }; snprintf(path, sizeof(path), "/pipes/cterm:%d:in", getpid()); @@ -97,122 +83,9 @@ int cterm_app_redraw(struct g_application *app) { return 0; } -#if 0 - -void cterm_draw_buffer(struct cterm_state *state); -void cterm_draw(struct cterm_state *state) { - // window decorations - canvas_ctx_fill_rect(state->ctx, 0, 0, - state->sprite.width, state->sprite.height, - canvas_color_rgb(0x32, 0x36, 0x39)); - canvas_ctx_stroke_rect(state->ctx, 0, 0, - state->sprite.width - 1, state->sprite.height - 1, - canvas_color_rgb(0x20, 0x21, 0x24)); - - { - const char *title = "Terminal"; - int x_title = (state->sprite.width - strlen(title) * FONT_WIDTH) / 2; - canvas_ctx_draw_text(state->ctx, x_title, 10, title); - } - - // calculate root widget - state->root_x = 1; - state->root_y = FONT_HEIGHT + 15; - state->root_width = state->sprite.width - state->root_x - 1; - state->root_height = state->sprite.height - state->root_y - 1; - - // calculate characters and buffer - state->cwidth = state->root_width / FONT_WIDTH; - state->cheight = state->root_height / FONT_HEIGHT; - size_t new_len = state->cwidth * state->cheight; - if(new_len != state->buffer_len) { - state->buffer = realloc(state->buffer, new_len); - if(new_len > state->buffer_len) { - memset(state->buffer + state->buffer_len, 0, new_len - state->buffer_len); - } - state->buffer_len = new_len; - } - cterm_draw_buffer(state); -} - -void cterm_draw_buffer(struct cterm_state *state) { - canvas_ctx_fill_rect(state->ctx, state->root_x, state->root_y, - state->root_width, state->root_height, - canvas_color_rgb(0, 0, 0)); - for(int y = 0; y < state->cheight; y++) { - for(int x = 0; x < state->cwidth; x++) { - canvas_ctx_draw_character(state->ctx, - state->root_x + x * FONT_WIDTH, state->root_y + y * FONT_HEIGHT, - state->buffer[y * state->cwidth + x]); - } - } -} - -void cterm_newline(struct cterm_state *state) { - state->cx = 0; - if(state->cy == state->cheight - 1) { - // scroll - for(int y = 0; y < state->cheight - 1; y++) { - for(int x = 0; x < state->cwidth; x++) { - state->buffer[y * state->cwidth + x] - = state->buffer[(y + 1) * state->cwidth + x]; - } - } - for(int x = 0; x < state->cwidth; x++) { - state->buffer[(state->cheight - 1) * state->cwidth + x] = 0; - } - cterm_draw_buffer(state); - } else { - state->cy++; - } -} - -void cterm_advance(struct cterm_state *state) { - state->cx++; - if(state->cx == state->cwidth) { - cterm_newline(state); - } -} - -void cterm_add_character(struct cterm_state *state, char ch) { - if(ch == '\n') { - cterm_newline(state); - } else { - state->buffer[state->cy * state->cwidth + state->cx] = ch; - canvas_ctx_draw_character(state->ctx, - state->root_x + state->cx * FONT_WIDTH, - state->root_y + state->cy * FONT_HEIGHT, - ch); - cterm_advance(state); - } -} - -void cterm_type(struct cterm_state *state, char ch) { - cterm_add_character(state, ch); - if(ch == '\n' || state->line_buffer_len == LINE_BUFFER_LEN - 2) { - state->line_buffer[state->line_buffer_len++] = '\n'; - write(state->in_fd, state->line_buffer, state->line_buffer_len); - state->line_buffer_len = 0; - } else { - state->line_buffer[state->line_buffer_len++] = ch; - } -} - -int cterm_read_buf(struct cterm_state *state) { - char buf[4096]; - int retval = read(state->out_fd, buf, sizeof(buf)); - if(retval <= 0) return retval; - for(int i = 0; i < retval; i++) { - cterm_add_character(state, buf[i]); - } - return retval; -} - -#endif - int main(int argc, char **argv) { - #if 0 - cterm_draw(&state); + struct cterm_state state = { 0 }; + cterm_init(&state); // spawn main struct startup_info s_info = { @@ -222,18 +95,17 @@ int main(int argc, char **argv) { }; char *spawn_argv[] = {"/hd0/main", NULL}; spawnxv(&s_info, "/hd0/main", (char **)spawn_argv); - #endif - - struct cterm_state state = { 0 }; - cterm_init(&state); struct g_application *app = g_application_create(INIT_WIDTH, INIT_HEIGHT); g_application_set_userdata(app, &state); g_application_set_redraw_cb(app, cterm_app_redraw); struct g_termbox *tb = g_termbox_create(); - g_widget_move_resize(tb, 0, 15, INIT_WIDTH, INIT_HEIGHT - 15); - g_application_add_widget(app, tb); + const int title_height = 20; + g_widget_move_resize((struct g_widget *)tb, 0, title_height, INIT_WIDTH, INIT_HEIGHT - title_height); + g_termbox_bind_in_fd(tb, state.in_fd); + g_termbox_bind_out_fd(tb, state.out_fd); + g_application_add_widget(app, (struct g_widget *)tb); return g_application_run(app); } diff --git a/userspace/libraries/libgui/gapplication.c b/userspace/libraries/libgui/gapplication.c index 47487c89..068b2d1a 100644 --- a/userspace/libraries/libgui/gapplication.c +++ b/userspace/libraries/libgui/gapplication.c @@ -59,23 +59,30 @@ void g_application_destroy(struct g_application *app) { int g_application_redraw(struct g_application *app) { app->sprite.source = (unsigned long *)canvas_ctx_get_surface(app->ctx); int needs_redraw = 0; + if (app->redraw_cb) { + if (app->redraw_cb(app)) + needs_redraw = 1; + } for(size_t i = 0; i < app->widgets_len; i++) { if(app->widgets[i]->redraw_fn(app->widgets[i], app)) { + canvas_ctx_bitblit(app->ctx, app->widgets[i]->ctx, + app->widgets[i]->x, app->widgets[i]->y); needs_redraw = 1; } } - if (app->redraw_cb) { - if (app->redraw_cb(app)) - needs_redraw = 1; - } return needs_redraw; } static int g_application_on_key(struct g_application *app, int ch) { if (app->key_cb) { - return app->key_cb(app, ch); + app->key_cb(app, ch); } - return 0; + for(size_t i = 0; i < app->widgets_len; i++) { + if(app->widgets[i]->on_key_fn) { + app->widgets[i]->on_key_fn(app->widgets[i], ch); + } + } + return 1; } int g_application_run(struct g_application *app) { @@ -160,7 +167,7 @@ int g_application_run(struct g_application *app) { break; } case ATOM_KEYBOARD_EVENT_TYPE: { - needs_redraw = g_application_on_key(app, atom.keyboard_event.ch); + g_application_on_key(app, atom.keyboard_event.ch); struct wm_atom respond_atom = { .type = ATOM_RESPOND_TYPE, diff --git a/userspace/libraries/libgui/gtermbox.c b/userspace/libraries/libgui/gtermbox.c index 08af66da..2028034b 100644 --- a/userspace/libraries/libgui/gtermbox.c +++ b/userspace/libraries/libgui/gtermbox.c @@ -1,25 +1,204 @@ #include #include #include +#include #include #include + #include "gui.h" #include "priv/gwidget-impl.h" +#include + +#define FONT_WIDTH 8 +#define FONT_HEIGHT 8 + +#define LINE_BUFFER_LEN 128 + +static void canvas_ctx_draw_character(struct canvas_ctx *ctx, int xs, int ys, const char ch) { + char *bitmap = font8x8_basic[(int)ch]; + switch(canvas_ctx_get_format(ctx)) { + case LIBCANVAS_FORMAT_ARGB32: + // fallthrough + case LIBCANVAS_FORMAT_RGB24: { + unsigned long *data = (unsigned long *)canvas_ctx_get_surface(ctx); + for (int x = 0; x < FONT_WIDTH; x++) { + for (int y = 0; y < FONT_HEIGHT; y++) { + if (bitmap[y] & 1 << x) { + data[(ys + y) * canvas_ctx_get_width(ctx) + (xs + x)] = 0xffffffff; + } + } + } + break; + } + } +} + +struct g_termbox_data { + int cx, cy; // character placement position + int cwidth, cheight; // size in number of characters + + char *buffer; + size_t buffer_len; + + int in_fd, out_fd; + + char line_buffer[LINE_BUFFER_LEN]; + size_t line_buffer_len; +}; + static void g_termbox_deinit(struct g_widget *widget) { - + free(widget->widget_data); +} + +static void g_termbox_resize(struct g_widget *widget, int w, int h) { + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + data->cwidth = w / FONT_WIDTH; + data->cheight = h / FONT_HEIGHT; + size_t new_len = data->cwidth * data->cheight; + if(new_len != data->buffer_len) { + data->buffer = realloc(data->buffer, new_len); + if(new_len > data->buffer_len) { + memset(data->buffer + data->buffer_len, 0, new_len - data->buffer_len); + } + data->buffer_len = new_len; + } +} + +static void g_termbox_newline(struct g_widget *widget) { + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + data->cx = 0; + if(data->cy == data->cheight - 1) { + // scroll + for(int y = 0; y < data->cheight - 1; y++) { + for(int x = 0; x < data->cwidth; x++) { + data->buffer[y * data->cwidth + x] + = data->buffer[(y + 1) * data->cwidth + x]; + } + } + for(int x = 0; x < data->cwidth; x++) { + data->buffer[(data->cheight - 1) * data->cwidth + x] = 0; + } + } else { + data->cy++; + } +} + +static void g_termbox_advance(struct g_widget *widget) { + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + data->cx++; + if(data->cx == data->cwidth) { + g_termbox_newline(widget); + } +} + +static void g_termbox_add_character(struct g_widget *widget, char ch) { + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + if(ch == '\n') { + g_termbox_newline(widget); + } else { + data->buffer[data->cy * data->cwidth + data->cx] = ch; + canvas_ctx_draw_character(widget->ctx, + data->cx * FONT_WIDTH, + data->cy * FONT_HEIGHT, + ch); + g_termbox_advance(widget); + } +} + +static void g_termbox_type(struct g_widget *widget, int ch) { + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + g_termbox_add_character(widget, ch); + if(ch == '\n' || data->line_buffer_len == LINE_BUFFER_LEN - 2) { + data->line_buffer[data->line_buffer_len++] = '\n'; + write(data->in_fd, data->line_buffer, data->line_buffer_len); + data->line_buffer_len = 0; + } else { + data->line_buffer[data->line_buffer_len++] = ch; + } +} + +static int g_termbox_read_buf(struct g_widget *widget) { + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + char buf[4096]; + int retval = read(data->out_fd, buf, sizeof(buf)); + if(retval <= 0) return retval; + for(int i = 0; i < retval; i++) { + g_termbox_add_character(widget, buf[i]); + } + return retval; } static int g_termbox_redraw(struct g_widget *widget, struct g_application *app) { + g_widget_init_ctx(widget); + canvas_ctx_fill_rect(widget->ctx, 0, 0, widget->width, widget->height, canvas_color_rgb(0, 0, 0)); - return 0; + + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + + if(data->out_fd != -1) { + g_termbox_read_buf(widget); + } + + for(int y = 0; y < data->cheight; y++) { + for(int x = 0; x < data->cwidth; x++) { + canvas_ctx_draw_character(widget->ctx, + x * FONT_WIDTH, y * FONT_HEIGHT, + data->buffer[y * data->cwidth + x]); + } + } + + return 1; +} + +static int g_termbox_on_key(struct g_widget *widget, int ch) { + g_termbox_type(widget, ch); + return 1; } struct g_termbox *g_termbox_create() { struct g_widget *termbox = calloc(1, sizeof(struct g_widget)); + if(!termbox) return 0; + + struct g_termbox_data *data = calloc(1, sizeof(struct g_termbox_data)); + if(!data) return 0; + data->in_fd = -1; + data->out_fd = -1; + + termbox->widget_data = data; termbox->deinit_fn = g_termbox_deinit; + termbox->resize_fn = g_termbox_resize; termbox->redraw_fn = g_termbox_redraw; + termbox->on_key_fn = g_termbox_on_key; return (struct g_termbox *)termbox; } + +// getters + +int g_termbox_in_fd(struct g_termbox *tb) { + struct g_widget *widget = (struct g_widget *)tb; + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + return data->in_fd; +} + +int g_termbox_out_fd(struct g_termbox *tb) { + struct g_widget *widget = (struct g_widget *)tb; + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + return data->out_fd; +} + +// setters + +void g_termbox_bind_in_fd(struct g_termbox *tb, int in_fd) { + struct g_widget *widget = (struct g_widget *)tb; + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + data->in_fd = in_fd; +} + +void g_termbox_bind_out_fd(struct g_termbox *tb, int out_fd) { + struct g_widget *widget = (struct g_widget *)tb; + struct g_termbox_data *data = (struct g_termbox_data *)widget->widget_data; + data->out_fd = out_fd; +} diff --git a/userspace/libraries/libgui/gui/termbox.h b/userspace/libraries/libgui/gui/termbox.h index bd5e8e72..f83b7e25 100644 --- a/userspace/libraries/libgui/gui/termbox.h +++ b/userspace/libraries/libgui/gui/termbox.h @@ -3,3 +3,9 @@ struct g_termbox; struct g_termbox *g_termbox_create(); + +int g_termbox_in_fd(struct g_termbox *); +int g_termbox_out_fd(struct g_termbox *); + +void g_termbox_bind_in_fd(struct g_termbox *, int); +void g_termbox_bind_out_fd(struct g_termbox *, int); diff --git a/userspace/libraries/libgui/gwidget.c b/userspace/libraries/libgui/gwidget.c index 7ab9336f..d7a70829 100644 --- a/userspace/libraries/libgui/gwidget.c +++ b/userspace/libraries/libgui/gwidget.c @@ -2,9 +2,15 @@ #include #include #include -#include "priv/coords.h" -#include "priv/gwidget-impl.h" #include "gui.h" +#include "priv/gwidget-impl.h" + +void g_widget_init_ctx(struct g_widget *widget) { + if(widget->ctx == 0) { + widget->ctx = canvas_ctx_create(widget->width, widget->height, + LIBCANVAS_FORMAT_ARGB32); + } +} // getters struct canvas_ctx *g_widget_ctx(struct g_widget *widget) { @@ -36,9 +42,15 @@ void g_widget_set_y(struct g_widget *widget, unsigned int val) { } void g_widget_set_width(struct g_widget *widget, unsigned val) { widget->width = val; + if(widget->resize_fn) { + widget->resize_fn(widget, widget->width, widget->height); + } } void g_widget_set_height(struct g_widget *widget, unsigned val) { widget->height = val; + if(widget->resize_fn) { + widget->resize_fn(widget, widget->width, widget->height); + } } void g_widget_set_z_index(struct g_widget *widget, unsigned val) { widget->z_index = val; @@ -49,5 +61,8 @@ void g_widget_move_resize(struct g_widget *widget, unsigned int x, widget->y = y; widget->width = width; widget->height = height; + if(widget->resize_fn) { + widget->resize_fn(widget, widget->width, widget->height); + } } diff --git a/userspace/libraries/libgui/priv/gwidget-impl.h b/userspace/libraries/libgui/priv/gwidget-impl.h index ff83ac4d..ee060546 100644 --- a/userspace/libraries/libgui/priv/gwidget-impl.h +++ b/userspace/libraries/libgui/priv/gwidget-impl.h @@ -2,7 +2,9 @@ typedef int (*g_widget_redraw_fn)(struct g_widget *widget, struct g_application *app); +typedef void (*g_widget_resize_fn)(struct g_widget *widget, int w, int h); typedef void (*g_widget_deinit_fn)(struct g_widget *widget); +typedef int (*g_widget_on_key_fn)(struct g_widget *widget, int ch); struct g_widget { unsigned int x, y, width, height, z_index; @@ -10,9 +12,13 @@ struct g_widget { void *widget_data; g_widget_deinit_fn deinit_fn; + g_widget_resize_fn resize_fn; g_widget_redraw_fn redraw_fn; + g_widget_on_key_fn on_key_fn; }; static inline int g_widget_cmp_z_index(const void *a, const void *b) { return ((struct g_widget *)b)->z_index - ((struct g_widget *)a)->z_index; } + +void g_widget_init_ctx(struct g_widget *widget);