commit 4f891285a531b95894eb8ecb397d91f84285bfaa
parent 7d8235cc4e3c173b19461ff5eaf5991a43f15994
Author: lumidify <nobody@lumidify.org>
Date: Mon, 22 Feb 2021 22:05:56 +0100
Move some functions from ltkd.c to widget.c and rect.c
Diffstat:
21 files changed, 396 insertions(+), 335 deletions(-)
diff --git a/Makefile b/Makefile
@@ -37,6 +37,8 @@ OBJ = \
src/util.o \
src/memory.o \
src/color.o \
+ src/rect.o \
+ src/widget.o \
src/ltkd.o \
src/ini.o \
src/grid.o \
@@ -59,6 +61,8 @@ HDR = \
src/ini.h \
src/khash.h \
src/label.h \
+ src/rect.h \
+ src/widget.h \
src/ltk.h \
src/memory.h \
src/scrollbar.h \
diff --git a/src/box.c b/src/box.c
@@ -32,6 +32,8 @@
#include "memory.h"
#include "color.h"
+#include "rect.h"
+#include "widget.h"
#include "ltk.h"
#include "util.h"
#include "scrollbar.h"
diff --git a/src/box.h b/src/box.h
@@ -24,7 +24,7 @@
#ifndef _LTK_BOX_H_
#define _LTK_BOX_H_
-/* Requires the following includes: "scrollbar.h" "ltk.h" */
+/* Requires the following includes: "scrollbar.h", "rect.h", "widget.h", "ltk.h" */
typedef struct {
ltk_widget widget;
diff --git a/src/button.c b/src/button.c
@@ -32,6 +32,8 @@
#include "memory.h"
#include "color.h"
+#include "rect.h"
+#include "widget.h"
#include "ltk.h"
#include "util.h"
#include "text.h"
diff --git a/src/button.h b/src/button.h
@@ -24,7 +24,7 @@
#ifndef _LTK_BUTTON_H_
#define _LTK_BUTTON_H_
-/* Requires the following includes: <X11/Xlib.h>, "ltk.h", "color.h", "text.h" */
+/* Requires the following includes: <X11/Xlib.h>, "rect.h", "widget.h", "ltk.h", "color.h", "text.h" */
typedef struct {
ltk_widget widget;
diff --git a/src/draw.c b/src/draw.c
@@ -32,6 +32,8 @@
#include "memory.h"
#include "color.h"
+#include "rect.h"
+#include "widget.h"
#include "ltk.h"
#include "util.h"
#include "draw.h"
diff --git a/src/draw.h b/src/draw.h
@@ -24,7 +24,7 @@
#ifndef _LTK_DRAW_H_
#define _LTK_DRAW_H_
-/* Requires the following includes: <X11/Xlib.h>, "ltk.h" */
+/* Requires the following includes: <X11/Xlib.h>, "rect.h", "widget.h", "ltk.h" */
typedef struct {
ltk_widget widget;
diff --git a/src/grid.c b/src/grid.c
@@ -39,6 +39,8 @@
#include "memory.h"
#include "color.h"
+#include "rect.h"
+#include "widget.h"
#include "ltk.h"
#include "util.h"
#include "grid.h"
diff --git a/src/grid.h b/src/grid.h
@@ -24,7 +24,7 @@
#ifndef _LTK_GRID_H_
#define _LTK_GRID_H_
-/* Requires the following includes: "ltk.h" */
+/* Requires the following includes: "rect.h", "widget.h", "ltk.h" */
/*
* Struct to represent a grid widget.
diff --git a/src/label.c b/src/label.c
@@ -32,6 +32,8 @@
#include "memory.h"
#include "color.h"
+#include "rect.h"
+#include "widget.h"
#include "ltk.h"
#include "util.h"
#include "text.h"
diff --git a/src/label.h b/src/label.h
@@ -24,7 +24,7 @@
#ifndef _LTK_LABEL_H_
#define _LTK_LABEL_H_
-/* Requires the following includes: <X11/Xlib.h>, "ltk.h", "color.h", "text.h" */
+/* Requires the following includes: <X11/Xlib.h>, "rect.h", "widget.h", "ltk.h", "color.h", "text.h" */
typedef struct {
ltk_widget widget;
diff --git a/src/ltk.h b/src/ltk.h
@@ -24,7 +24,7 @@
#ifndef _LTK_H_
#define _LTK_H_
-/* Requires the following includes: <X11/Xlib.h>, <X11/Xutil.h>, <stdarg.h> */
+/* Requires the following includes: <X11/Xlib.h>, <X11/Xutil.h>, "widget.h" */
typedef enum {
LTK_EVENT_RESIZE = 1 << 0,
@@ -33,88 +33,6 @@ typedef enum {
} ltk_event_type;
typedef struct {
- int x;
- int y;
- int w;
- int h;
-} ltk_rect;
-
-typedef enum {
- LTK_STICKY_LEFT = 1 << 0,
- LTK_STICKY_RIGHT = 1 << 1,
- LTK_STICKY_TOP = 1 << 2,
- LTK_STICKY_BOTTOM = 1 << 3
-} ltk_sticky_mask;
-
-typedef enum {
- LTK_VERTICAL,
- LTK_HORIZONTAL
-} ltk_orientation;
-
-typedef enum {
- LTK_NORMAL,
- LTK_PRESSED,
- LTK_ACTIVE,
- LTK_DISABLED
-} ltk_widget_state;
-
-typedef enum {
- /* for e.g. scrollbar, which can't be directly accessed by users */
- LTK_UNKNOWN,
- LTK_GRID,
- LTK_BUTTON,
- LTK_DRAW,
- LTK_LABEL,
- LTK_WIDGET,
- LTK_BOX
-} ltk_widget_type;
-
-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);
-
- void (*resize) (struct ltk_widget *);
- void (*draw) (struct ltk_widget *, ltk_rect);
- void (*change_state) (struct ltk_widget *);
- void (*destroy) (struct ltk_widget *, int);
-
- void (*child_size_change) (struct ltk_widget *, struct ltk_widget *);
- int (*remove_child) (struct ltk_window *, struct ltk_widget *, struct ltk_widget *, char **);
-};
-
-typedef struct {
int border_width;
uint16_t font_size;
char *font;
@@ -158,23 +76,11 @@ typedef struct ltk_window {
struct ltk_event_queue *last_event;
} ltk_window;
-ltk_rect ltk_rect_intersect(ltk_rect r1, ltk_rect r2);
-ltk_rect ltk_rect_union(ltk_rect r1, ltk_rect r2);
void ltk_window_invalidate_rect(ltk_window *window, ltk_rect rect);
int ltk_create_xcolor(ltk_window *window, const char *hex, XColor *col);
void ltk_queue_event(ltk_window *window, ltk_event_type type, const char *id, const char *data);
-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,
- 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);
-int ltk_widget_id_free(const char *id);
-ltk_widget *ltk_get_widget(const char *id, ltk_widget_type type, char **errstr);
-void ltk_set_widget(ltk_widget *widget, const char *id);
-void ltk_remove_widget(const char *id);
void ltk_quit(ltk_window *window);
#endif
diff --git a/src/ltkd.c b/src/ltkd.c
@@ -1,5 +1,5 @@
/* FIXME: backslashes should be parsed properly! */
-/* FIXME Figure out how to properly print window id */
+/* FIXME: Figure out how to properly print window id */
/* FIXME: PROPERLY CLEANUP ALL THEMES */
/* FIXME: error checking in tokenizer (is this necessary?) */
/* FIXME: parsing doesn't work properly with bs? */
@@ -51,6 +51,8 @@
#include "memory.h"
#include "color.h"
+#include "rect.h"
+#include "widget.h"
#include "ltk.h"
#include "util.h"
#include "text.h"
@@ -90,16 +92,12 @@ static struct ltk_sock_info {
struct token_list tokens; /* current tokens */
} sockets[MAX_SOCK_CONNS];
-KHASH_MAP_INIT_STR(widget, ltk_widget *)
-static khash_t(widget) *widget_hash = NULL;
-
static int ltk_mainloop(ltk_window *window);
static char *get_sock_path(char *basedir, Window id);
static FILE *open_log(char *dir);
static void daemonize(void);
static ltk_window *ltk_create_window(const char *title, int x, int y,
unsigned int w, unsigned int h);
-static void ltk_destroy_widget_hash(void);
static void ltk_destroy_window(ltk_window *window);
static void ltk_redraw_window(ltk_window *window);
static void ltk_window_other_event(ltk_window *window, XEvent event);
@@ -116,7 +114,6 @@ static void process_commands(ltk_window *window, struct ltk_sock_info *sock);
static int add_client(int fd);
static int listen_sock(const char *sock_path);
static int accept_sock(int listenfd);
-static int ltk_widget_destroy(ltk_window *window, char **tokens, size_t num_tokens, char **errstr);
static short maxsocket = -1;
static short running = 1;
@@ -147,8 +144,7 @@ int main(int argc, char *argv[]) {
ltk_logfile = open_log(ltk_dir);
if (!ltk_logfile) ltk_fatal_errno("Unable to open log file.\n");
- widget_hash = kh_init(widget);
- if (!widget_hash) ltk_fatal_errno("Unable to initialize widget hash table.\n");
+ ltk_widgets_init();
/* FIXME: set window size properly - I only run it in a tiling WM
anyways, so it doesn't matter, but still... */
@@ -386,8 +382,7 @@ ltk_cleanup(void) {
ltk_free(sockets[i].tokens.tokens);
}
- if (widget_hash)
- ltk_destroy_widget_hash();
+ ltk_widgets_cleanup();
if (main_window)
ltk_destroy_window(main_window);
}
@@ -438,32 +433,6 @@ ltk_set_root_widget_cmd(
return 0;
}
-/* FIXME */
-#undef MAX
-#undef MIN
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-ltk_rect
-ltk_rect_intersect(ltk_rect r1, ltk_rect r2) {
- ltk_rect i;
- i.x = MAX(r1.x, r2.x);
- i.y = MAX(r1.y, r2.y);
- i.w = MIN(r1.x + r1.w, r2.x + r2.w) - i.x;
- i.h = MIN(r1.y + r1.h, r2.y + r2.h) - i.y;
- return i;
-}
-
-ltk_rect
-ltk_rect_union(ltk_rect r1, ltk_rect r2) {
- ltk_rect u;
- u.x = MIN(r1.x, r2.x);
- u.y = MIN(r1.y, r2.y);
- u.w = MAX(r1.x + r1.w, r2.x + r2.w) - u.x;
- u.h = MAX(r1.y + r1.h, r2.y + r2.h) - u.y;
- return u;
-}
-
void
ltk_window_invalidate_rect(ltk_window *window, ltk_rect rect) {
if (window->dirty_rect.w == 0 && window->dirty_rect.h == 0)
@@ -611,19 +580,6 @@ ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int
}
static void
-ltk_destroy_widget_hash(void) {
- khint_t k;
- ltk_widget *ptr;
- 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->vtable->destroy(ptr, 1);
- }
- }
- kh_destroy(widget, widget_hash);
-}
-
-static void
ltk_destroy_window(ltk_window *window) {
XDestroyWindow(window->dpy, window->xwindow);
ltk_cleanup_text();
@@ -691,52 +647,6 @@ ltk_load_theme(ltk_window *window, const char *path) {
}
}
-int
-ltk_collide_rect(ltk_rect rect, int x, int y) {
- return (rect.x <= x && (rect.x + rect.w) >= x && rect.y <= y
- && (rect.y + rect.h) >= y);
-}
-
-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) {
- if (id)
- widget->id = ltk_strdup(id);
- else
- widget->id = NULL;
- widget->window = window;
- widget->active_widget = NULL;
- widget->parent = NULL;
- widget->type = type;
-
- /* FIXME: possibly check that draw and destroy aren't NULL */
- widget->vtable = vtable;
-
- widget->needs_redraw = needs_redraw;
- widget->state = LTK_NORMAL;
- widget->row = 0;
- widget->rect.x = 0;
- widget->rect.y = 0;
- widget->rect.w = 0;
- widget->rect.h = 0;
- widget->ideal_w = 0;
- widget->ideal_h = 0;
-
- widget->row = 0;
- widget->column = 0;
- widget->row_span = 0;
- widget->column_span = 0;
- widget->sticky = 0;
-}
-
-static void
-ltk_widget_change_state(ltk_widget *widget) {
- if (widget->vtable->change_state)
- widget->vtable->change_state(widget);
- if (widget->needs_redraw)
- ltk_window_invalidate_rect(widget->window, widget->rect);
-}
-
void
ltk_window_set_active_widget(ltk_window *window, ltk_widget *widget) {
if (window->active_widget == widget)
@@ -772,59 +682,6 @@ ltk_window_set_pressed_widget(ltk_window *window, ltk_widget *widget) {
}
}
-void
-ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event) {
- if (!widget || widget->state == LTK_DISABLED)
- return;
- int default_handler = 1;
- 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);
- }
-}
-
-void
-ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) {
- if (!widget || widget->state == LTK_DISABLED)
- return;
- int default_handler = 1;
- if (widget->vtable->mouse_release)
- default_handler = widget->vtable->mouse_release(widget, event);
- if (default_handler)
- ltk_window_set_pressed_widget(widget->window, NULL);
-}
-
-/* FIXME: ONLY SET ACTIVE WIDGET AT BOTTOM OF HIERARCHY
- -> Don't first set parent as active widget and then child */
-void
-ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event) {
- if (!widget || widget->state == LTK_DISABLED)
- return;
- /* FIXME: THIS WHOLE STATE HANDLING IS STILL PARTIALLY BROKEN */
- /*
- if (((widget->state == LTK_NORMAL) ||
- (widget->state == LTK_ACTIVE && widget->window->active_widget != widget)) &&
- !widget->window->pressed_widget) {
- widget->state = LTK_ACTIVE;
- 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->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);
-}
-
static void
ltk_handle_event(ltk_window *window, XEvent event) {
ltk_widget *root_widget = window->root_widget;
@@ -851,53 +708,6 @@ ltk_handle_event(ltk_window *window, XEvent event) {
}
}
-int
-ltk_widget_id_free(const char *id) {
- khint_t k;
- k = kh_get(widget, widget_hash, id);
- if (k != kh_end(widget_hash)) {
- return 0;
- }
- return 1;
-}
-
-ltk_widget *
-ltk_get_widget(const char *id, ltk_widget_type type, char **errstr) {
- khint_t k;
- ltk_widget *widget;
- k = kh_get(widget, widget_hash, id);
- if (k == kh_end(widget_hash)) {
- *errstr = "Widget with given ID doesn't exist.\n";
- return NULL;
- }
- widget = kh_value(widget_hash, k);
- if (type != LTK_WIDGET && widget->type != type) {
- *errstr = "Widget with given ID has wrong type.\n";
- return NULL;
- }
- return widget;
-}
-
-void
-ltk_set_widget(ltk_widget *widget, const char *id) {
- int ret;
- khint_t k;
- /* apparently, khash requires the string to stay accessible */
- /* FIXME: How is this freed? */
- char *tmp = ltk_strdup(id);
- k = kh_put(widget, widget_hash, tmp, &ret);
- kh_value(widget_hash, k) = widget;
-}
-
-void
-ltk_remove_widget(const char *id) {
- khint_t k;
- k = kh_get(widget, widget_hash, id);
- if (k != kh_end(widget_hash)) {
- kh_del(widget, widget_hash, k);
- }
-}
-
/* Push a token onto `token_list`, resizing the buffer if necessary.
Returns -1 on error, 0 otherwise.
Note: The token is not copied, it is only added directly. */
@@ -1178,42 +988,3 @@ process_commands(ltk_window *window, struct ltk_sock_info *sock) {
sock->read_cur = 0;
}
}
-
-static int
-ltk_widget_destroy(
- ltk_window *window,
- char **tokens,
- size_t num_tokens,
- char **errstr) {
- int err = 0, shallow = 1;
- if (num_tokens != 2 && num_tokens != 3) {
- *errstr = "Invalid number of arguments.\n";
- return 1;
- }
- if (num_tokens == 3) {
- if (strcmp(tokens[2], "deep") == 0) {
- shallow = 0;
- } else if (strcmp(tokens[2], "shallow") == 0) {
- shallow = 1;
- } else {
- *errstr = "Invalid argument: must be 'shallow' or 'deep'.\n";
- return 1;
- }
- }
- ltk_widget *widget = ltk_get_widget(tokens[1], LTK_WIDGET, errstr);
- if (!widget) {
- *errstr = "Invalid widget ID.\n";
- return 1;
- }
- 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->vtable->remove_child) {
- err = widget->parent->vtable->remove_child(
- window, widget, widget->parent, errstr
- );
- }
- widget->vtable->destroy(widget, shallow);
-
- return err;
-}
diff --git a/src/rect.c b/src/rect.c
@@ -0,0 +1,33 @@
+#include "rect.h"
+
+/* FIXME */
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+ltk_rect
+ltk_rect_intersect(ltk_rect r1, ltk_rect r2) {
+ ltk_rect i;
+ i.x = MAX(r1.x, r2.x);
+ i.y = MAX(r1.y, r2.y);
+ i.w = MIN(r1.x + r1.w, r2.x + r2.w) - i.x;
+ i.h = MIN(r1.y + r1.h, r2.y + r2.h) - i.y;
+ return i;
+}
+
+ltk_rect
+ltk_rect_union(ltk_rect r1, ltk_rect r2) {
+ ltk_rect u;
+ u.x = MIN(r1.x, r2.x);
+ u.y = MIN(r1.y, r2.y);
+ u.w = MAX(r1.x + r1.w, r2.x + r2.w) - u.x;
+ u.h = MAX(r1.y + r1.h, r2.y + r2.h) - u.y;
+ return u;
+}
+
+int
+ltk_collide_rect(ltk_rect rect, int x, int y) {
+ return (rect.x <= x && (rect.x + rect.w) >= x && rect.y <= y
+ && (rect.y + rect.h) >= y);
+}
diff --git a/src/rect.h b/src/rect.h
@@ -0,0 +1,15 @@
+#ifndef _LTK_RECT_H_
+#define _LTK_RECT_H_
+
+typedef struct {
+ int x;
+ int y;
+ int w;
+ int h;
+} ltk_rect;
+
+ltk_rect ltk_rect_intersect(ltk_rect r1, ltk_rect r2);
+ltk_rect ltk_rect_union(ltk_rect r1, ltk_rect r2);
+int ltk_collide_rect(ltk_rect rect, int x, int y);
+
+#endif /* _LTK_RECT_H_ */
diff --git a/src/scrollbar.c b/src/scrollbar.c
@@ -32,6 +32,8 @@
#include "memory.h"
#include "color.h"
+#include "rect.h"
+#include "widget.h"
#include "ltk.h"
#include "util.h"
#include "scrollbar.h"
diff --git a/src/scrollbar.h b/src/scrollbar.h
@@ -24,7 +24,7 @@
#ifndef _LTK_SCROLLBAR_H_
#define _LTK_SCROLLBAR_H_
-/* Requires: "ltk.h" */
+/* Requires: "rect.h", "widget.h", "ltk.h" */
typedef struct {
ltk_widget widget;
diff --git a/src/text_pango.c b/src/text_pango.c
@@ -12,6 +12,8 @@
#include "memory.h"
#include "color.h"
+#include "rect.h"
+#include "widget.h"
#include "ltk.h"
#include "util.h"
#include "text.h"
diff --git a/src/text_stb.c b/src/text_stb.c
@@ -37,6 +37,8 @@
#include "memory.h"
#include "color.h"
+#include "rect.h"
+#include "widget.h"
#include "ltk.h"
#include "util.h"
#include "text.h"
diff --git a/src/widget.c b/src/widget.c
@@ -0,0 +1,221 @@
+#include <stdarg.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "rect.h"
+#include "widget.h"
+#include "color.h"
+#include "ltk.h"
+#include "memory.h"
+#include "util.h"
+#include "khash.h"
+
+static void ltk_destroy_widget_hash(void);
+
+KHASH_MAP_INIT_STR(widget, ltk_widget *)
+static khash_t(widget) *widget_hash = NULL;
+
+static void
+ltk_destroy_widget_hash(void) {
+ khint_t k;
+ ltk_widget *ptr;
+ 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->vtable->destroy(ptr, 1);
+ }
+ }
+ kh_destroy(widget, widget_hash);
+}
+
+void
+ltk_widgets_init() {
+ widget_hash = kh_init(widget);
+ if (!widget_hash) ltk_fatal_errno("Unable to initialize widget hash table.\n");
+}
+
+void
+ltk_widgets_cleanup() {
+ if (widget_hash)
+ ltk_destroy_widget_hash();
+}
+
+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) {
+ if (id)
+ widget->id = ltk_strdup(id);
+ else
+ widget->id = NULL;
+ widget->window = window;
+ widget->active_widget = NULL;
+ widget->parent = NULL;
+ widget->type = type;
+
+ /* FIXME: possibly check that draw and destroy aren't NULL */
+ widget->vtable = vtable;
+
+ widget->needs_redraw = needs_redraw;
+ widget->state = LTK_NORMAL;
+ widget->row = 0;
+ widget->rect.x = 0;
+ widget->rect.y = 0;
+ widget->rect.w = 0;
+ widget->rect.h = 0;
+ widget->ideal_w = 0;
+ widget->ideal_h = 0;
+
+ widget->row = 0;
+ widget->column = 0;
+ widget->row_span = 0;
+ widget->column_span = 0;
+ widget->sticky = 0;
+}
+
+void
+ltk_widget_change_state(ltk_widget *widget) {
+ if (widget->vtable->change_state)
+ widget->vtable->change_state(widget);
+ if (widget->needs_redraw)
+ ltk_window_invalidate_rect(widget->window, widget->rect);
+}
+
+void
+ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event) {
+ if (!widget || widget->state == LTK_DISABLED)
+ return;
+ int default_handler = 1;
+ 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);
+ }
+}
+
+void
+ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) {
+ if (!widget || widget->state == LTK_DISABLED)
+ return;
+ int default_handler = 1;
+ if (widget->vtable->mouse_release)
+ default_handler = widget->vtable->mouse_release(widget, event);
+ if (default_handler)
+ ltk_window_set_pressed_widget(widget->window, NULL);
+}
+
+/* FIXME: ONLY SET ACTIVE WIDGET AT BOTTOM OF HIERARCHY
+ -> Don't first set parent as active widget and then child */
+void
+ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event) {
+ if (!widget || widget->state == LTK_DISABLED)
+ return;
+ /* FIXME: THIS WHOLE STATE HANDLING IS STILL PARTIALLY BROKEN */
+ /*
+ if (((widget->state == LTK_NORMAL) ||
+ (widget->state == LTK_ACTIVE && widget->window->active_widget != widget)) &&
+ !widget->window->pressed_widget) {
+ widget->state = LTK_ACTIVE;
+ if (widget->vtable->change_state)
+ widget->vtable->change_state(widget);
+ if (widget->vtable->mouse_enter)
+ widget->vtable->mouse_enter(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->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);
+}
+
+int
+ltk_widget_id_free(const char *id) {
+ khint_t k;
+ k = kh_get(widget, widget_hash, id);
+ if (k != kh_end(widget_hash)) {
+ return 0;
+ }
+ return 1;
+}
+
+ltk_widget *
+ltk_get_widget(const char *id, ltk_widget_type type, char **errstr) {
+ khint_t k;
+ ltk_widget *widget;
+ k = kh_get(widget, widget_hash, id);
+ if (k == kh_end(widget_hash)) {
+ *errstr = "Widget with given ID doesn't exist.\n";
+ return NULL;
+ }
+ widget = kh_value(widget_hash, k);
+ if (type != LTK_WIDGET && widget->type != type) {
+ *errstr = "Widget with given ID has wrong type.\n";
+ return NULL;
+ }
+ return widget;
+}
+
+void
+ltk_set_widget(ltk_widget *widget, const char *id) {
+ int ret;
+ khint_t k;
+ /* apparently, khash requires the string to stay accessible */
+ /* FIXME: How is this freed? */
+ char *tmp = ltk_strdup(id);
+ k = kh_put(widget, widget_hash, tmp, &ret);
+ kh_value(widget_hash, k) = widget;
+}
+
+void
+ltk_remove_widget(const char *id) {
+ khint_t k;
+ k = kh_get(widget, widget_hash, id);
+ if (k != kh_end(widget_hash)) {
+ kh_del(widget, widget_hash, k);
+ }
+}
+
+int
+ltk_widget_destroy(
+ ltk_window *window,
+ char **tokens,
+ size_t num_tokens,
+ char **errstr) {
+ int err = 0, shallow = 1;
+ if (num_tokens != 2 && num_tokens != 3) {
+ *errstr = "Invalid number of arguments.\n";
+ return 1;
+ }
+ if (num_tokens == 3) {
+ if (strcmp(tokens[2], "deep") == 0) {
+ shallow = 0;
+ } else if (strcmp(tokens[2], "shallow") == 0) {
+ shallow = 1;
+ } else {
+ *errstr = "Invalid argument: must be 'shallow' or 'deep'.\n";
+ return 1;
+ }
+ }
+ ltk_widget *widget = ltk_get_widget(tokens[1], LTK_WIDGET, errstr);
+ if (!widget) {
+ *errstr = "Invalid widget ID.\n";
+ return 1;
+ }
+ 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->vtable->remove_child) {
+ err = widget->parent->vtable->remove_child(
+ window, widget, widget->parent, errstr
+ );
+ }
+ widget->vtable->destroy(widget, shallow);
+
+ return err;
+}
diff --git a/src/widget.h b/src/widget.h
@@ -0,0 +1,95 @@
+/* Requires the following includes: <X11/Xlib.h>, <X11/Xutil.h>, "rect.h" */
+
+#ifndef _LTK_WIDGET_H_
+#define _LTK_WIDGET_H_
+
+typedef enum {
+ LTK_STICKY_LEFT = 1 << 0,
+ LTK_STICKY_RIGHT = 1 << 1,
+ LTK_STICKY_TOP = 1 << 2,
+ LTK_STICKY_BOTTOM = 1 << 3
+} ltk_sticky_mask;
+
+typedef enum {
+ LTK_VERTICAL,
+ LTK_HORIZONTAL
+} ltk_orientation;
+
+typedef enum {
+ LTK_NORMAL,
+ LTK_PRESSED,
+ LTK_ACTIVE,
+ LTK_DISABLED
+} ltk_widget_state;
+
+typedef enum {
+ /* for e.g. scrollbar, which can't be directly accessed by users */
+ LTK_UNKNOWN,
+ LTK_GRID,
+ LTK_BUTTON,
+ LTK_DRAW,
+ LTK_LABEL,
+ LTK_WIDGET,
+ LTK_BOX
+} ltk_widget_type;
+
+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);
+
+ void (*resize) (struct ltk_widget *);
+ void (*draw) (struct ltk_widget *, ltk_rect);
+ void (*change_state) (struct ltk_widget *);
+ void (*destroy) (struct ltk_widget *, int);
+
+ void (*child_size_change) (struct ltk_widget *, struct ltk_widget *);
+ int (*remove_child) (struct ltk_window *, struct ltk_widget *, struct ltk_widget *, char **);
+};
+
+int ltk_widget_destroy(struct ltk_window *window, char **tokens, size_t num_tokens, char **errstr);
+void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, struct ltk_window *window,
+ struct ltk_widget_vtable *vtable, unsigned int needs_redraw, ltk_widget_type type);
+void ltk_widget_change_state(ltk_widget *widget);
+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);
+int ltk_widget_id_free(const char *id);
+ltk_widget *ltk_get_widget(const char *id, ltk_widget_type type, char **errstr);
+void ltk_set_widget(ltk_widget *widget, const char *id);
+void ltk_remove_widget(const char *id);
+void ltk_widgets_cleanup();
+void ltk_widgets_init();
+
+#endif /* _LTK_WIDGET_H_ */