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:
| 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(-)
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 = <k_box_draw,
+	.destroy = <k_box_destroy,
+	.resize = <k_recalculate_box,
+	.child_size_change = <k_box_child_size_change,
+	.remove_child = <k_box_remove,
+	.mouse_press = <k_box_mouse_press,
+	.mouse_release = <k_box_mouse_release,
+	.motion_notify = <k_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, <k_box_draw,
-	    NULL, <k_box_destroy, 0, LTK_BOX);
-	box->widget.mouse_press = <k_box_mouse_press;
-	box->widget.mouse_release = <k_box_mouse_release;
-	box->widget.motion_notify = <k_box_motion_notify;
-	box->widget.resize = <k_recalculate_box;
-	box->widget.child_size_change = <k_box_child_size_change;
-	box->widget.remove_child = <k_box_remove;
+	ltk_fill_widget_defaults(&box->widget, id, window, &vtable, 0, LTK_BOX);
 
 	box->sc = ltk_scrollbar_create(window, orient, <k_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 = <k_button_mouse_release,
+    .change_state = <k_button_change_state,
+    .draw = <k_button_draw,
+    .destroy = <k_button_destroy,
+    .resize = <k_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,
-	    <k_button_draw, <k_button_change_state, <k_button_destroy, 1, LTK_BUTTON);
-	button->widget.mouse_release = <k_button_mouse_release;
-	button->widget.resize = <k_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 = <k_draw_draw,
+	.resize = <k_draw_resize,
+	.destroy = <k_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,
-	    <k_draw_draw, NULL, <k_draw_destroy, 1, LTK_DRAW);
-	draw->widget.resize = <k_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 = <k_grid_draw,
+	.destroy = <k_grid_destroy,
+	.resize = <k_recalculate_grid,
+	.child_size_change = <k_grid_child_size_change,
+	.remove_child = <k_grid_ungrid,
+	.mouse_press = <k_grid_mouse_press,
+	.mouse_release = <k_grid_mouse_release,
+	.motion_notify = <k_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, <k_grid_draw,
-	    NULL, <k_grid_destroy, 0, LTK_GRID);
-	grid->widget.mouse_press = <k_grid_mouse_press;
-	grid->widget.mouse_release = <k_grid_mouse_release;
-	grid->widget.motion_notify = <k_grid_motion_notify;
-	grid->widget.resize = <k_recalculate_grid;
-	grid->widget.child_size_change = <k_grid_child_size_change;
-	grid->widget.remove_child = <k_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 = <k_label_draw,
+	.destroy = <k_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,
-	    <k_label_draw, NULL, <k_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 = <k_scrollbar_draw,
+	.mouse_press = <k_scrollbar_mouse_press,
+	.motion_notify = <k_scrollbar_motion_notify,
+	.destroy = <k_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, <k_scrollbar_draw,
-	    NULL, <k_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 = <k_scrollbar_motion_notify;
-	sc->widget.mouse_press = <k_scrollbar_mouse_press;
 	/* This cannot be 0 because that leads to divide-by-zero */
 	sc->virtual_size = 1;
 	sc->cur_pos = 0;