ltk

Socket-based GUI for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 75115e459d76c7f38fe5e743f90b2c4f0d21055a
parent 5d21899cd0709d59584964aed6e94c536f08c911
Author: lumidify <nobody@lumidify.org>
Date:   Mon, 22 Feb 2021 19:54:14 +0100

Change ltk_widget to use a vtable

This avoids storing the functions pointers
separately for each instance of a widget.

Diffstat:
Mbox.c | 48++++++++++++++++++++++++++----------------------
Mbutton.c | 15+++++++++++----
Mdraw.c | 11++++++++---
Mgrid.c | 32++++++++++++++++++--------------
Mlabel.c | 8++++++--
Mltk.h | 33+++++++++++++++++++--------------
Mltkd.c | 71++++++++++++++++++++++++++++-------------------------------------------
Mscrollbar.c | 12++++++++----
8 files changed, 124 insertions(+), 106 deletions(-)

diff --git a/box.c b/box.c @@ -52,6 +52,17 @@ static int ltk_box_mouse_press(ltk_widget *self, XEvent event); static int ltk_box_mouse_release(ltk_widget *self, XEvent event); static int ltk_box_motion_notify(ltk_widget *self, XEvent event); +static struct ltk_widget_vtable vtable = { + .draw = &ltk_box_draw, + .destroy = &ltk_box_destroy, + .resize = &ltk_recalculate_box, + .child_size_change = &ltk_box_child_size_change, + .remove_child = &ltk_box_remove, + .mouse_press = &ltk_box_mouse_press, + .mouse_release = &ltk_box_mouse_release, + .motion_notify = &ltk_box_motion_notify +}; + static int ltk_box_cmd_add( ltk_window *window, char **tokens, @@ -84,23 +95,16 @@ ltk_box_draw(ltk_widget *self, ltk_rect clip) { ptr = box->widgets[i]; /* FIXME: Maybe continue immediately if widget is obviously outside of clipping rect */ - ptr->draw(ptr, real_clip); + ptr->vtable->draw(ptr, real_clip); } - box->sc->widget.draw((ltk_widget *)box->sc, real_clip); + box->sc->widget.vtable->draw((ltk_widget *)box->sc, real_clip); } static ltk_box * ltk_box_create(ltk_window *window, const char *id, ltk_orientation orient) { ltk_box *box = ltk_malloc(sizeof(ltk_box)); - ltk_fill_widget_defaults(&box->widget, id, window, &ltk_box_draw, - NULL, &ltk_box_destroy, 0, LTK_BOX); - box->widget.mouse_press = &ltk_box_mouse_press; - box->widget.mouse_release = &ltk_box_mouse_release; - box->widget.motion_notify = &ltk_box_motion_notify; - box->widget.resize = &ltk_recalculate_box; - box->widget.child_size_change = &ltk_box_child_size_change; - box->widget.remove_child = &ltk_box_remove; + ltk_fill_widget_defaults(&box->widget, id, window, &vtable, 0, LTK_BOX); box->sc = ltk_scrollbar_create(window, orient, &ltk_box_scroll, box); box->widgets = NULL; @@ -118,13 +122,13 @@ ltk_box_destroy(ltk_widget *self, int shallow) { if (!shallow) { for (size_t i = 0; i < box->num_widgets; i++) { ptr = box->widgets[i]; - ptr->destroy(ptr, shallow); + ptr->vtable->destroy(ptr, shallow); } } ltk_free(box->widgets); ltk_remove_widget(box->widget.id); ltk_free(box->widget.id); - box->sc->widget.destroy((ltk_widget *)box->sc, 0); + box->sc->widget.vtable->destroy((ltk_widget *)box->sc, 0); ltk_free(box); } @@ -151,8 +155,8 @@ ltk_recalculate_box(ltk_widget *self) { ptr->rect.y = box->widget.rect.y + box->widget.rect.h - ptr->rect.h - sc_rect->h; else ptr->rect.y = box->widget.rect.y + (box->widget.rect.h - ptr->rect.h) / 2; - if (ptr->resize) - ptr->resize(ptr); + if (ptr->vtable->resize) + ptr->vtable->resize(ptr); cur_pos += ptr->rect.w; } else { ptr->rect.y = cur_pos - box->sc->cur_pos; @@ -164,8 +168,8 @@ ltk_recalculate_box(ltk_widget *self) { ptr->rect.x = box->widget.rect.x + box->widget.rect.w - ptr->rect.w - sc_rect->w; else ptr->rect.x = box->widget.rect.x + (box->widget.rect.w - ptr->rect.w) / 2; - if (ptr->resize) - ptr->resize(ptr); + if (ptr->vtable->resize) + ptr->vtable->resize(ptr); cur_pos += ptr->rect.h; } } @@ -214,8 +218,8 @@ ltk_box_child_size_change(ltk_widget *self, ltk_widget *widget) { size_changed = 1; } - if (size_changed && box->widget.parent && box->widget.parent->child_size_change) - box->widget.parent->child_size_change(box->widget.parent, (ltk_widget *)box); + if (size_changed && box->widget.parent && box->widget.parent->vtable->child_size_change) + box->widget.parent->vtable->child_size_change(box->widget.parent, (ltk_widget *)box); else ltk_recalculate_box((ltk_widget *)box); } @@ -279,16 +283,16 @@ ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_widget *self, char ** if (box->widgets[j]->ideal_h + sc_h > box->widget.ideal_h) box->widget.ideal_h = box->widgets[j]->ideal_h + sc_h; } - if (box->widget.parent && box->widget.parent->resize) - box->widget.parent->resize(box->widget.parent); + if (box->widget.parent && box->widget.parent->vtable->resize) + box->widget.parent->vtable->resize(box->widget.parent); } else if (box->orient == LTK_VERTICAL && widget->ideal_w + sc_w == box->widget.ideal_w) { box->widget.ideal_w = 0; for (size_t j = 0; j < box->num_widgets; j++) { if (box->widgets[j]->ideal_w + sc_w > box->widget.ideal_w) box->widget.ideal_w = box->widgets[j]->ideal_w + sc_w; } - if (box->widget.parent && box->widget.parent->resize) - box->widget.parent->resize(box->widget.parent); + if (box->widget.parent && box->widget.parent->vtable->resize) + box->widget.parent->vtable->resize(box->widget.parent); } return 0; } diff --git a/button.c b/button.c @@ -42,6 +42,16 @@ static int ltk_button_mouse_release(ltk_widget *self, XEvent event); static ltk_button *ltk_button_create(ltk_window *window, const char *id, const char *text); static void ltk_button_destroy(ltk_widget *self, int shallow); +static void ltk_button_change_state(ltk_widget *self); +static void ltk_button_resize(ltk_widget *self); + +static struct ltk_widget_vtable vtable = { + .mouse_release = &ltk_button_mouse_release, + .change_state = &ltk_button_change_state, + .draw = &ltk_button_draw, + .destroy = &ltk_button_destroy, + .resize = &ltk_button_resize +}; static struct { int border_width; @@ -244,10 +254,7 @@ ltk_button_create(ltk_window *window, const char *id, const char *text) { char *text_copy; ltk_button *button = ltk_malloc(sizeof(ltk_button)); - ltk_fill_widget_defaults(&button->widget, id, window, - &ltk_button_draw, &ltk_button_change_state, &ltk_button_destroy, 1, LTK_BUTTON); - button->widget.mouse_release = &ltk_button_mouse_release; - button->widget.resize = &ltk_button_resize; + ltk_fill_widget_defaults(&button->widget, id, window, &vtable, 1, LTK_BUTTON); uint16_t font_size = window->theme.font_size; text_copy = ltk_strdup(text); button->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1); diff --git a/draw.c b/draw.c @@ -45,6 +45,13 @@ static void ltk_draw_clear(ltk_window *window, ltk_draw *draw); static void ltk_draw_set_color(ltk_window *window, ltk_draw *draw, const char *color); static void ltk_draw_line(ltk_window *window, ltk_draw *draw, int x1, int y1, int x2, int y2); static void ltk_draw_rect(ltk_window *window, ltk_draw *draw, int x, int y, int w, int h, int fill); + +static struct ltk_widget_vtable vtable = { + .draw = &ltk_draw_draw, + .resize = &ltk_draw_resize, + .destroy = &ltk_draw_destroy, +}; + static int ltk_draw_cmd_clear( ltk_window *window, char **tokens, @@ -85,9 +92,7 @@ static ltk_draw * ltk_draw_create(ltk_window *window, const char *id, int w, int h, const char *color) { ltk_draw *draw = ltk_malloc(sizeof(ltk_draw)); - ltk_fill_widget_defaults(&draw->widget, id, window, - &ltk_draw_draw, NULL, &ltk_draw_destroy, 1, LTK_DRAW); - draw->widget.resize = &ltk_draw_resize; + ltk_fill_widget_defaults(&draw->widget, id, window, &vtable, 1, LTK_DRAW); draw->widget.rect.w = w; draw->widget.rect.h = h; draw->pix = XCreatePixmap(window->dpy, window->xwindow, w, h, window->depth); diff --git a/grid.c b/grid.c @@ -60,6 +60,17 @@ static int ltk_grid_mouse_press(ltk_widget *self, XEvent event); static int ltk_grid_mouse_release(ltk_widget *self, XEvent event); static int ltk_grid_motion_notify(ltk_widget *self, XEvent event); +static struct ltk_widget_vtable vtable = { + .draw = &ltk_grid_draw, + .destroy = &ltk_grid_destroy, + .resize = &ltk_recalculate_grid, + .child_size_change = &ltk_grid_child_size_change, + .remove_child = &ltk_grid_ungrid, + .mouse_press = &ltk_grid_mouse_press, + .mouse_release = &ltk_grid_mouse_release, + .motion_notify = &ltk_grid_motion_notify +}; + static int ltk_grid_cmd_add( ltk_window *window, char **tokens, @@ -106,7 +117,7 @@ ltk_grid_draw(ltk_widget *self, ltk_rect clip) { if (!grid->widget_grid[i]) continue; ltk_widget *ptr = grid->widget_grid[i]; - ptr->draw(ptr, clip); + ptr->vtable->draw(ptr, clip); } } @@ -114,14 +125,7 @@ static ltk_grid * ltk_grid_create(ltk_window *window, const char *id, int rows, int columns) { ltk_grid *grid = ltk_malloc(sizeof(ltk_grid)); - ltk_fill_widget_defaults(&grid->widget, id, window, &ltk_grid_draw, - NULL, &ltk_grid_destroy, 0, LTK_GRID); - grid->widget.mouse_press = &ltk_grid_mouse_press; - grid->widget.mouse_release = &ltk_grid_mouse_release; - grid->widget.motion_notify = &ltk_grid_motion_notify; - grid->widget.resize = &ltk_recalculate_grid; - grid->widget.child_size_change = &ltk_grid_child_size_change; - grid->widget.remove_child = &ltk_grid_ungrid; + ltk_fill_widget_defaults(&grid->widget, id, window, &vtable, 0, LTK_GRID); grid->rows = rows; grid->columns = columns; @@ -170,7 +174,7 @@ ltk_grid_destroy(ltk_widget *self, int shallow) { grid->widget_grid[r * grid->columns + c] = NULL; } } - ptr->destroy(ptr, shallow); + ptr->vtable->destroy(ptr, shallow); } } } @@ -248,8 +252,8 @@ ltk_recalculate_grid(ltk_widget *self) { ptr->rect.h = grid->row_pos[end_row] - grid->row_pos[i]; } if (orig_width != ptr->rect.w || orig_height != ptr->rect.h) { - if (ptr->resize) { - ptr->resize(ptr); + if (ptr->vtable->resize) { + ptr->vtable->resize(ptr); } } @@ -291,8 +295,8 @@ ltk_grid_child_size_change(ltk_widget *self, ltk_widget *widget) { grid->row_heights[widget->row] = widget->rect.h; size_changed = 1; } - if (size_changed && grid->widget.parent && grid->widget.parent->child_size_change) - grid->widget.parent->child_size_change(grid->widget.parent, (ltk_widget *)grid); + if (size_changed && grid->widget.parent && grid->widget.parent->vtable->child_size_change) + grid->widget.parent->vtable->child_size_change(grid->widget.parent, (ltk_widget *)grid); else ltk_recalculate_grid((ltk_widget *)grid); } diff --git a/label.c b/label.c @@ -42,6 +42,11 @@ static ltk_label *ltk_label_create(ltk_window *window, const char *id, const char *text); static void ltk_label_destroy(ltk_widget *self, int shallow); +static struct ltk_widget_vtable vtable = { + .draw = &ltk_label_draw, + .destroy = &ltk_label_destroy +}; + static struct { LtkColor text_color; LtkColor bg_color; @@ -98,8 +103,7 @@ ltk_label_create(ltk_window *window, const char *id, const char *text) { char *text_copy; ltk_label *label = ltk_malloc(sizeof(ltk_label)); - ltk_fill_widget_defaults(&label->widget, id, window, - &ltk_label_draw, NULL, &ltk_label_destroy, 1, LTK_LABEL); + ltk_fill_widget_defaults(&label->widget, id, window, &vtable, 1, LTK_LABEL); uint16_t font_size = window->theme.font_size; text_copy = ltk_strdup(text); label->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1); diff --git a/ltk.h b/ltk.h @@ -71,20 +71,36 @@ typedef enum { struct ltk_window; +struct ltk_widget_vtable; + typedef struct ltk_widget { struct ltk_window *window; struct ltk_widget *active_widget; struct ltk_widget *parent; char *id; + struct ltk_widget_vtable *vtable; + ltk_rect rect; unsigned int ideal_w; unsigned int ideal_h; + ltk_widget_type type; + ltk_widget_state state; + unsigned int sticky; + unsigned short row; + unsigned short column; + unsigned short row_span; + unsigned short column_span; + unsigned char needs_redraw; +} ltk_widget; + +struct ltk_widget_vtable { void (*key_press) (struct ltk_widget *, XEvent); void (*key_release) (struct ltk_widget *, XEvent); int (*mouse_press) (struct ltk_widget *, XEvent); int (*mouse_release) (struct ltk_widget *, XEvent); + int (*mouse_wheel) (struct ltk_widget *, XEvent); int (*motion_notify) (struct ltk_widget *, XEvent); void (*mouse_leave) (struct ltk_widget *, XEvent); void (*mouse_enter) (struct ltk_widget *, XEvent); @@ -96,16 +112,7 @@ typedef struct ltk_widget { void (*child_size_change) (struct ltk_widget *, struct ltk_widget *); int (*remove_child) (struct ltk_window *, struct ltk_widget *, struct ltk_widget *, char **); - - ltk_widget_type type; - ltk_widget_state state; - unsigned int sticky; - unsigned short row; - unsigned short column; - unsigned short row_span; - unsigned short column_span; - unsigned char needs_redraw; -} ltk_widget; +}; typedef struct { int border_width; @@ -159,10 +166,8 @@ void ltk_queue_event(ltk_window *window, ltk_event_type type, const char *id, co int ltk_collide_rect(ltk_rect rect, int x, int y); void ltk_window_set_active_widget(ltk_window *window, ltk_widget *widget); void ltk_window_set_pressed_widget(ltk_window *window, ltk_widget *widget); -void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window * window, - void (*draw) (ltk_widget *, ltk_rect), void (*change_state) (ltk_widget *), - void (*destroy) (ltk_widget *, int), unsigned int needs_redraw, - ltk_widget_type type); +void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window, + struct ltk_widget_vtable *vtable, unsigned int needs_redraw, ltk_widget_type type); void ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event); void ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event); void ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event); diff --git a/ltkd.c b/ltkd.c @@ -432,8 +432,8 @@ ltk_set_root_widget_cmd( ltk_window_invalidate_rect(window, widget->rect); widget->rect.w = window->rect.w; widget->rect.h = window->rect.h; - if (widget->resize) - widget->resize(widget); + if (widget->vtable->resize) + widget->vtable->resize(widget); return 0; } @@ -516,7 +516,7 @@ ltk_redraw_window(ltk_window *window) { if (!window->root_widget) return; ptr = window->root_widget; if (ptr) - ptr->draw(ptr, window->dirty_rect); + ptr->vtable->draw(ptr, window->dirty_rect); } static void @@ -532,10 +532,10 @@ ltk_window_other_event(ltk_window *window, XEvent event) { window->rect.w = w; window->rect.h = h; ltk_window_invalidate_rect(window, window->rect); - if (ptr && ptr->resize) { + if (ptr && ptr->vtable->resize) { ptr->rect.w = w; ptr->rect.h = h; - ptr->resize(ptr); + ptr->vtable->resize(ptr); } } } else if (event.type == Expose && event.xexpose.count == 0) { @@ -617,7 +617,7 @@ ltk_destroy_widget_hash(void) { for (k = kh_begin(widget_hash); k != kh_end(widget_hash); k++) { if (kh_exist(widget_hash, k)) { ptr = kh_value(widget_hash, k); - ptr->destroy(ptr, 1); + ptr->vtable->destroy(ptr, 1); } } kh_destroy(widget, widget_hash); @@ -699,33 +699,18 @@ ltk_collide_rect(ltk_rect rect, int x, int y) { void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window, - void (*draw) (ltk_widget *, ltk_rect), void (*change_state) (ltk_widget *), - void (*destroy) (ltk_widget *, int), unsigned int needs_redraw, - ltk_widget_type type) { - if (id) { + struct ltk_widget_vtable *vtable, unsigned int needs_redraw, ltk_widget_type type) { + if (id) widget->id = ltk_strdup(id); - } else { + else widget->id = NULL; - } widget->window = window; widget->active_widget = NULL; widget->parent = NULL; widget->type = type; - widget->key_press = NULL; - widget->key_release = NULL; - widget->mouse_press = NULL; - widget->mouse_release = NULL; - widget->motion_notify = NULL; - widget->mouse_enter = NULL; - widget->mouse_leave = NULL; - - widget->resize = NULL; - widget->draw = draw; - widget->change_state = change_state; - widget->destroy = destroy; - widget->child_size_change = NULL; - widget->remove_child = NULL; + /* FIXME: possibly check that draw and destroy aren't NULL */ + widget->vtable = vtable; widget->needs_redraw = needs_redraw; widget->state = LTK_NORMAL; @@ -746,8 +731,8 @@ ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window, static void ltk_widget_change_state(ltk_widget *widget) { - if (widget->change_state) - widget->change_state(widget); + if (widget->vtable->change_state) + widget->vtable->change_state(widget); if (widget->needs_redraw) ltk_window_invalidate_rect(widget->window, widget->rect); } @@ -792,8 +777,8 @@ ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event) { if (!widget || widget->state == LTK_DISABLED) return; int default_handler = 1; - if (widget->mouse_press) - default_handler = widget->mouse_press(widget, event); + if (widget->vtable->mouse_press) + default_handler = widget->vtable->mouse_press(widget, event); if (default_handler) { if (event.xbutton.button == 1) ltk_window_set_pressed_widget(widget->window, widget); @@ -805,8 +790,8 @@ ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) { if (!widget || widget->state == LTK_DISABLED) return; int default_handler = 1; - if (widget->mouse_release) - default_handler = widget->mouse_release(widget, event); + if (widget->vtable->mouse_release) + default_handler = widget->vtable->mouse_release(widget, event); if (default_handler) ltk_window_set_pressed_widget(widget->window, NULL); } @@ -823,19 +808,19 @@ ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event) { (widget->state == LTK_ACTIVE && widget->window->active_widget != widget)) && !widget->window->pressed_widget) { widget->state = LTK_ACTIVE; - if (widget->change_state) - widget->change_state(widget); - if (widget->mouse_enter) - widget->mouse_enter(widget, event); + if (widget->vtable->change_state) + widget->change_statevtable->(widget); + if (widget->vtable->mouse_enter) + widget->mouse_entervtable->(widget, event); ltk_window_remove_active_widget(widget->window); ltk_window_set_active_widget(widget); } */ int default_handler = 1; - if (widget->window->pressed_widget && widget->window->pressed_widget->motion_notify) - default_handler = widget->window->pressed_widget->motion_notify(widget->window->pressed_widget, event); - else if (widget->motion_notify) - default_handler = widget->motion_notify(widget, event); + if (widget->window->pressed_widget && widget->window->pressed_widget->vtable->motion_notify) + default_handler = widget->window->pressed_widget->vtable->motion_notify(widget->window->pressed_widget, event); + else if (widget->vtable->motion_notify) + default_handler = widget->vtable->motion_notify(widget, event); if (default_handler) ltk_window_set_active_widget(widget->window, widget); } @@ -1223,12 +1208,12 @@ ltk_widget_destroy( ltk_remove_widget(tokens[1]); /* widget->parent->remove_child should never be NULL because of the fact that the widget is set as parent, but let's just check anyways... */ - if (widget->parent && widget->parent->remove_child) { - err = widget->parent->remove_child( + if (widget->parent && widget->parent->vtable->remove_child) { + err = widget->parent->vtable->remove_child( window, widget, widget->parent, errstr ); } - widget->destroy(widget, shallow); + widget->vtable->destroy(widget, shallow); return err; } diff --git a/scrollbar.c b/scrollbar.c @@ -41,6 +41,13 @@ static int ltk_scrollbar_mouse_press(ltk_widget *self, XEvent event); static int ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event); static void ltk_scrollbar_destroy(ltk_widget *self, int shallow); +static struct ltk_widget_vtable vtable = { + .draw = &ltk_scrollbar_draw, + .mouse_press = &ltk_scrollbar_mouse_press, + .motion_notify = &ltk_scrollbar_motion_notify, + .destroy = &ltk_scrollbar_destroy +}; + static struct { int size; /* width or height, depending on orientation */ LtkColor bg_normal; @@ -228,11 +235,8 @@ ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event) { ltk_scrollbar * ltk_scrollbar_create(ltk_window *window, ltk_orientation orient, void (*callback)(ltk_widget *), void *data) { ltk_scrollbar *sc = ltk_malloc(sizeof(ltk_scrollbar)); - ltk_fill_widget_defaults((ltk_widget *)sc, NULL, window, &ltk_scrollbar_draw, - NULL, &ltk_scrollbar_destroy, 1, LTK_UNKNOWN); + ltk_fill_widget_defaults((ltk_widget *)sc, NULL, window, &vtable, 1, LTK_UNKNOWN); sc->last_mouse_x = sc->last_mouse_y = 0; - sc->widget.motion_notify = &ltk_scrollbar_motion_notify; - sc->widget.mouse_press = &ltk_scrollbar_mouse_press; /* This cannot be 0 because that leads to divide-by-zero */ sc->virtual_size = 1; sc->cur_pos = 0;