URI: 
       tChange ltk_widget to use a vtable - ltk - Socket-based GUI for X11 (WIP)
  HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 75115e459d76c7f38fe5e743f90b2c4f0d21055a
   DIR parent 5d21899cd0709d59584964aed6e94c536f08c911
  HTML 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:
         M box.c                               |      48 +++++++++++++++++--------------
         M button.c                            |      15 +++++++++++----
         M draw.c                              |      11 ++++++++---
         M grid.c                              |      32 +++++++++++++++++--------------
         M label.c                             |       8 ++++++--
         M ltk.h                               |      33 ++++++++++++++++++-------------
         M ltkd.c                              |      71 ++++++++++++-------------------
         M scrollbar.c                         |      12 ++++++++----
       
       8 files changed, 124 insertions(+), 106 deletions(-)
       ---
   DIR diff --git a/box.c b/box.c
       t@@ -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,
       t@@ -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;
       t@@ -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);
        }
        
       t@@ -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;
       t@@ -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;
                        }
                }
       t@@ -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);
        }
       t@@ -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;
                        }
   DIR diff --git a/button.c b/button.c
       t@@ -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;
       t@@ -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);
   DIR diff --git a/draw.c b/draw.c
       t@@ -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,
       t@@ -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);
   DIR diff --git a/grid.c b/grid.c
       t@@ -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,
       t@@ -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);
                }
        }
        
       t@@ -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;
       t@@ -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);
                                }
                        }
                }
       t@@ -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);
                                        }
                                }
        
       t@@ -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);
        }
   DIR diff --git a/label.c b/label.c
       t@@ -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;
       t@@ -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);
   DIR diff --git a/ltk.h b/ltk.h
       t@@ -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);
       t@@ -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;
       t@@ -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);
   DIR diff --git a/ltkd.c b/ltkd.c
       t@@ -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;
        }
       t@@ -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
       t@@ -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) {
       t@@ -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);
       t@@ -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;
       t@@ -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);
        }
       t@@ -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);
       t@@ -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);
        }
       t@@ -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);
        }
       t@@ -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;
        }
   DIR diff --git a/scrollbar.c b/scrollbar.c
       t@@ -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;
       t@@ -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;