ltk

GUI toolkit for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/ltk.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
Log | Files | Refs | README | LICENSE

commit 210aa3d51d8dcc1e36c73d3404e032937271e0d6
parent 71f3528512ae0666e68994bd70dccb933bed55f8
Author: lumidify <nobody@lumidify.org>
Date:   Wed,  1 May 2024 21:24:44 +0200

Restructure configuration parsing for keybindings

It's still really ugly.

Diffstat:
MMakefile | 1-
Msrc/ltk/config.c | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/ltk/config.h | 40++++++++++++++++++++++++++--------------
Msrc/ltk/entry.c | 209+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/ltk/entry.h | 16+++++++++-------
Dsrc/ltk/keys.h | 78------------------------------------------------------------------------------
Msrc/ltk/ltk.c | 66++----------------------------------------------------------------
Asrc/ltk/sort_search.h | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ltk/window.c | 155+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/ltk/window.h | 17+++++++++--------
10 files changed, 416 insertions(+), 400 deletions(-)

diff --git a/Makefile b/Makefile @@ -117,7 +117,6 @@ HDR_LTK = \ src/ltk/label.h \ src/ltk/config.h \ src/ltk/array.h \ - src/ltk/keys.h \ src/ltk/clipboard_xlib.h \ src/ltk/clipboard.h \ src/ltk/txtbuf.h \ diff --git a/src/ltk/config.c b/src/ltk/config.c @@ -21,10 +21,122 @@ #include <limits.h> #include "util.h" -#include "keys.h" #include "memory.h" #include "config.h" +#include "sort_search.h" + +#include "entry.h" +#include "window.h" + +GEN_SORT_SEARCH_HELPERS(keybinding, ltk_keybinding_cb, text) +//GEN_SORT_SEARCH_HELPERS(theme, ltk_theme_parseinfo, key) +LTK_ARRAY_INIT_IMPL(keypress, ltk_keypress_cfg) +LTK_ARRAY_INIT_IMPL(keyrelease, ltk_keyrelease_cfg) + +static struct { + const char *name; + void (*get_parseinfo)( + ltk_keybinding_cb **press_cbs_ret, size_t *press_len_ret, + ltk_keybinding_cb **release_cbs_ret, size_t *release_len_ret, + ltk_array(keypress) **presses_ret, ltk_array(keyrelease) **releases_ret + ); +} keybinding_handlers[] = { + {"entry", &ltk_entry_get_keybinding_parseinfo}, + {"window", &ltk_window_get_keybinding_parseinfo}, +}; + +static int +register_keypress(ltk_array(keypress) *bindings, ltk_keybinding_cb *arr, size_t arrlen, const char *func_name, size_t func_len, ltk_keypress_binding b) { + ltk_keybinding_cb *cb = keybinding_get_entry(arr, arrlen, func_name, func_len); + if (!cb) + return 1; + ltk_keypress_cfg cfg = {b, *cb}; + ltk_array_append(keypress, bindings, cfg); + return 0; +} + +static int +register_keyrelease(ltk_array(keyrelease) *bindings, ltk_keybinding_cb *arr, size_t arrlen, const char *func_name, size_t func_len, ltk_keyrelease_binding b) { + ltk_keybinding_cb *cb = keybinding_get_entry(arr, arrlen, func_name, func_len); + if (!cb) + return 1; + ltk_keyrelease_cfg cfg = {b, *cb}; + ltk_array_append(keyrelease, bindings, cfg); + return 0; +} + +static int +handle_keypress_binding(const char *widget_name, size_t wlen, const char *name, size_t nlen, ltk_keypress_binding b) { + ltk_keybinding_cb *press_cbs = NULL, *release_cbs = NULL; + size_t press_len = 0, release_len = 0; + ltk_array(keypress) *presses = NULL; + ltk_array(keyrelease) *releases = NULL; + for (size_t i = 0; i < LENGTH(keybinding_handlers); i++) { + if (str_array_equal(keybinding_handlers[i].name, widget_name, wlen)) { + keybinding_handlers[i].get_parseinfo( + &press_cbs, &press_len, &release_cbs, &release_len, &presses, &releases + ); + if (!press_cbs || !presses) + return 1; + return register_keypress(presses, press_cbs, press_len, name, nlen, b); + } + } + return 1; +} + +static int +handle_keyrelease_binding(const char *widget_name, size_t wlen, const char *name, size_t nlen, ltk_keyrelease_binding b) { + ltk_keybinding_cb *press_cbs = NULL, *release_cbs = NULL; + size_t press_len = 0, release_len = 0; + ltk_array(keypress) *presses = NULL; + ltk_array(keyrelease) *releases = NULL; + for (size_t i = 0; i < LENGTH(keybinding_handlers); i++) { + if (str_array_equal(keybinding_handlers[i].name, widget_name, wlen)) { + keybinding_handlers[i].get_parseinfo( + &press_cbs, &press_len, &release_cbs, &release_len, &presses, &releases + ); + if (!release_cbs || !releases) + return 1; + return register_keyrelease(releases, release_cbs, release_len, name, nlen, b); + } + } + return 1; +} + +static void +sort_keybindings(void) { + ltk_keybinding_cb *press_cbs = NULL, *release_cbs = NULL; + size_t press_len = 0, release_len = 0; + ltk_array(keypress) *presses = NULL; + ltk_array(keyrelease) *releases = NULL; + for (size_t i = 0; i < LENGTH(keybinding_handlers); i++) { + keybinding_handlers[i].get_parseinfo( + &press_cbs, &press_len, &release_cbs, &release_len, &presses, &releases + ); + if (press_cbs) + keybinding_sort(press_cbs, press_len); + if (release_cbs) + keybinding_sort(release_cbs, release_len); + } +} + +static void +destroy_keypress_cfg(ltk_keypress_cfg cfg) { + ltk_free(cfg.b.text); + ltk_free(cfg.b.rawtext); +} + +void +ltk_keypress_bindings_destroy(ltk_array(keypress) *arr) { + ltk_array_destroy_deep(keypress, arr, &destroy_keypress_cfg); +} + +void +ltk_keyrelease_bindings_destroy(ltk_array(keyrelease) *arr) { + ltk_array_destroy(keyrelease, arr); +} +static void sort_keysyms(void); static int parse_keysym(char *text, size_t len, ltk_keysym *sym_ret); ltk_config *global_config = NULL; @@ -361,8 +473,6 @@ parse_keybinding( struct token *tok, char *widget, size_t len, - keypress_binding_handler press_handler, - keyrelease_binding_handler release_handler, char **errstr) { char *msg = NULL; *tok = next_token(s); @@ -379,7 +489,7 @@ parse_keybinding( size_t nlen; if (parse_keypress_binding(s, tok, &b, &name, &nlen, errstr)) return 1; - if (press_handler(widget, len, name, nlen, b)) { + if (handle_keypress_binding(widget, len, name, nlen, b)) { msg = "Invalid key binding"; goto error; } @@ -395,7 +505,7 @@ parse_keybinding( msg = "Text and rawtext may only be specified for keypress bindings"; goto error; } - if (release_handler(widget, len, name, nlen, (ltk_keyrelease_binding){b.sym, b.mods, b.flags})) { + if (handle_keyrelease_binding(widget, len, name, nlen, (ltk_keyrelease_binding){b.sym, b.mods, b.flags})) { msg = "Invalid key binding"; goto error; } @@ -502,8 +612,6 @@ load_from_text( const char *filename, char *file_contents, size_t len, - keypress_binding_handler press_handler, - keyrelease_binding_handler release_handler, char **errstr) { ltk_config *config = ltk_malloc(sizeof(ltk_config)); config->mappings = NULL; @@ -629,7 +737,7 @@ load_from_text( char *widget = secttok.text + strlen("key-binding:"); size_t len = secttok.len - strlen("key-binding:"); while (1) { - if ((ret = parse_keybinding(&s, &tok, widget, len, press_handler, release_handler, errstr)) > 0) { + if ((ret = parse_keybinding(&s, &tok, widget, len, errstr)) > 0) { goto errornomsg; } else if (ret < 0) { start_of_line = 1; @@ -715,19 +823,17 @@ errornomsg: } int -ltk_config_parsefile( - const char *filename, - keypress_binding_handler press_handler, - keyrelease_binding_handler release_handler, - char **errstr) { +ltk_config_parsefile(const char *filename, char **errstr) { unsigned long len = 0; char *ferrstr = NULL; + sort_keysyms(); + sort_keybindings(); char *file_contents = ltk_read_file(filename, &len, &ferrstr); if (!file_contents) { *errstr = ltk_print_fmt("Unable to open file \"%s\": %s", filename, ferrstr); return 1; } - int ret = load_from_text(filename, file_contents, len, press_handler, release_handler, errstr); + int ret = load_from_text(filename, file_contents, len, errstr); ltk_free(file_contents); return ret; } @@ -750,22 +856,15 @@ const char *default_config = "[general]\n" /* FIXME: improve this configuration */ int -ltk_config_load_default( - keypress_binding_handler press_handler, - keyrelease_binding_handler release_handler, - char **errstr) { +ltk_config_load_default(char **errstr) { + sort_keysyms(); + sort_keybindings(); char *config_copied = ltk_strdup(default_config); - int ret = load_from_text("<default config>", config_copied, strlen(config_copied), press_handler, release_handler, errstr); + int ret = load_from_text("<default config>", config_copied, strlen(config_copied), errstr); ltk_free(config_copied); return ret; } -void -ltk_keypress_binding_destroy(ltk_keypress_binding b) { - ltk_free(b.text); - ltk_free(b.rawtext); -} - /* FIXME: which additional ones are needed here? */ static struct keysym_mapping { char *name; @@ -859,11 +958,16 @@ static struct keysym_mapping { {"undo", LTK_KEY_UNDO}, }; -GEN_CB_MAP_HELPERS(keysym_map, struct keysym_mapping, name) +GEN_SORT_SEARCH_HELPERS(keysym, struct keysym_mapping, name) + +static void +sort_keysyms(void) { + keysym_sort(keysym_map, LENGTH(keysym_map)); +} static int parse_keysym(char *keysym_str, size_t len, ltk_keysym *sym) { - struct keysym_mapping *km = keysym_map_get_entry(keysym_str, len); + struct keysym_mapping *km = keysym_get_entry(keysym_map, LENGTH(keysym_map), keysym_str, len); if (!km) return 1; *sym = km->keysym; diff --git a/src/ltk/config.h b/src/ltk/config.h @@ -19,6 +19,8 @@ #include <stddef.h> +#include "array.h" +#include "widget.h" #include "eventdefs.h" typedef enum{ @@ -66,24 +68,34 @@ typedef struct { ltk_general_config general; } ltk_config; -typedef int (*keypress_binding_handler)(const char *widget_name, size_t wlen, const char *name, size_t nlen, ltk_keypress_binding b); -typedef int (*keyrelease_binding_handler)(const char *widget_name, size_t wlen, const char *name, size_t nlen, ltk_keyrelease_binding b); +typedef int (*ltk_keybinding_func)(ltk_widget *, ltk_key_event *); + +typedef struct { + char *text; + ltk_keybinding_func func; +} ltk_keybinding_cb; + +typedef struct { + ltk_keypress_binding b; + ltk_keybinding_cb cb; +} ltk_keypress_cfg; + +typedef struct { + ltk_keyrelease_binding b; + ltk_keybinding_cb cb; +} ltk_keyrelease_cfg; + +LTK_ARRAY_INIT_DECL(keypress, ltk_keypress_cfg) +LTK_ARRAY_INIT_DECL(keyrelease, ltk_keyrelease_cfg) void ltk_config_cleanup(void); ltk_config *ltk_config_get(void); int ltk_config_get_language_index(char *lang, size_t *idx_ret); ltk_language_mapping *ltk_config_get_language_mapping(size_t idx); -int ltk_config_parsefile( - const char *filename, - keypress_binding_handler press_handler, - keyrelease_binding_handler release_handler, - char **errstr -); -int ltk_config_load_default( - keypress_binding_handler press_handler, - keyrelease_binding_handler release_handler, - char **errstr -); -void ltk_keypress_binding_destroy(ltk_keypress_binding b); +int ltk_config_parsefile(const char *filename, char **errstr); +int ltk_config_load_default(char **errstr); + +void ltk_keypress_bindings_destroy(ltk_array(keypress) *arr); +void ltk_keyrelease_bindings_destroy(ltk_array(keyrelease) *arr); #endif /* LTK_CONFIG_H */ diff --git a/src/ltk/entry.c b/src/ltk/entry.c @@ -31,7 +31,6 @@ #include "event.h" #include "eventdefs.h" #include "graphics.h" -#include "keys.h" #include "ltk.h" #include "memory.h" #include "rect.h" @@ -40,6 +39,7 @@ #include "txtbuf.h" #include "util.h" #include "widget.h" +#include "config.h" #define MAX_ENTRY_BORDER_WIDTH 10000 #define MAX_ENTRY_PADDING 50000 @@ -63,31 +63,27 @@ typedef void (*cb_func)(ltk_entry *, ltk_key_event *); /* FIXME: configure mouse actions, e.g. select-word-under-pointer, move-cursor-to-pointer */ -static void cursor_to_beginning(ltk_entry *entry, ltk_key_event *event); -static void cursor_to_end(ltk_entry *entry, ltk_key_event *event); -static void cursor_left(ltk_entry *entry, ltk_key_event *event); -static void cursor_right(ltk_entry *entry, ltk_key_event *event); -static void expand_selection_left(ltk_entry *entry, ltk_key_event *event); -static void expand_selection_right(ltk_entry *entry, ltk_key_event *event); -static void selection_to_primary(ltk_entry *entry, ltk_key_event *event); -static void selection_to_clipboard(ltk_entry *entry, ltk_key_event *event); -static void switch_selection_side(ltk_entry *entry, ltk_key_event *event); -static void paste_primary(ltk_entry *entry, ltk_key_event *event); -static void paste_clipboard(ltk_entry *entry, ltk_key_event *event); -static void select_all(ltk_entry *entry, ltk_key_event *event); -static void delete_char_backwards(ltk_entry *entry, ltk_key_event *event); -static void delete_char_forwards(ltk_entry *entry, ltk_key_event *event); -static void edit_external(ltk_entry *entry, ltk_key_event *event); +static int cursor_to_beginning(ltk_widget *self, ltk_key_event *event); +static int cursor_to_end(ltk_widget *self, ltk_key_event *event); +static int cursor_left(ltk_widget *self, ltk_key_event *event); +static int cursor_right(ltk_widget *self, ltk_key_event *event); +static int expand_selection_left(ltk_widget *self, ltk_key_event *event); +static int expand_selection_right(ltk_widget *self, ltk_key_event *event); +static int selection_to_primary(ltk_widget *self, ltk_key_event *event); +static int selection_to_clipboard(ltk_widget *self, ltk_key_event *event); +static int switch_selection_side(ltk_widget *self, ltk_key_event *event); +static int paste_primary(ltk_widget *self, ltk_key_event *event); +static int paste_clipboard(ltk_widget *self, ltk_key_event *event); +static int select_all(ltk_widget *self, ltk_key_event *event); +static int delete_char_backwards(ltk_widget *self, ltk_key_event *event); +static int delete_char_forwards(ltk_widget *self, ltk_key_event *event); +static int edit_external(ltk_widget *self, ltk_key_event *event); + static void recalc_ideal_size(ltk_entry *entry); static void ensure_cursor_shown(ltk_entry *entry); static void insert_text(ltk_entry *entry, char *text, size_t len, int move_cursor); -struct key_cb { - char *text; - cb_func func; -}; - -static struct key_cb cb_map[] = { +static ltk_keybinding_cb cb_map[] = { {"cursor-left", &cursor_left}, {"cursor-right", &cursor_right}, {"cursor-to-beginning", &cursor_to_beginning}, @@ -105,61 +101,29 @@ static struct key_cb cb_map[] = { {"switch-selection-side", &switch_selection_side}, }; -struct keypress_cfg { - ltk_keypress_binding b; - struct key_cb cb; -}; - -struct keyrelease_cfg { - ltk_keyrelease_binding b; - struct key_cb cb; -}; - -LTK_ARRAY_INIT_DECL_STATIC(keypress, struct keypress_cfg) -LTK_ARRAY_INIT_IMPL_STATIC(keypress, struct keypress_cfg) -LTK_ARRAY_INIT_DECL_STATIC(keyrelease, struct keyrelease_cfg) -LTK_ARRAY_INIT_IMPL_STATIC(keyrelease, struct keyrelease_cfg) - +/* FIXME: also support keyreleases */ static ltk_array(keypress) *keypresses = NULL; -static ltk_array(keyrelease) *keyreleases = NULL; -GEN_CB_MAP_HELPERS(cb_map, struct key_cb, text) - -int -ltk_entry_register_keypress(const char *func_name, size_t func_len, ltk_keypress_binding b) { +void +ltk_entry_get_keybinding_parseinfo( + ltk_keybinding_cb **press_cbs_ret, size_t *press_len_ret, + ltk_keybinding_cb **release_cbs_ret, size_t *release_len_ret, + ltk_array(keypress) **presses_ret, ltk_array(keyrelease) **releases_ret +) { + *press_cbs_ret = cb_map; + *press_len_ret = LENGTH(cb_map); + *release_cbs_ret = NULL; + *release_len_ret = 0; if (!keypresses) keypresses = ltk_array_create(keypress, 1); - struct key_cb *cb = cb_map_get_entry(func_name, func_len); - if (!cb) - return 1; - struct keypress_cfg cfg = {b, *cb}; - ltk_array_append(keypress, keypresses, cfg); - return 0; -} - -int -ltk_entry_register_keyrelease(const char *func_name, size_t func_len, ltk_keyrelease_binding b) { - if (!keyreleases) - keyreleases = ltk_array_create(keyrelease, 1); - struct key_cb *cb = cb_map_get_entry(func_name, func_len); - if (!cb) - return 1; - struct keyrelease_cfg cfg = {b, *cb}; - ltk_array_append(keyrelease, keyreleases, cfg); - return 0; -} - -static void -destroy_keypress_cfg(struct keypress_cfg cfg) { - ltk_keypress_binding_destroy(cfg.b); + *presses_ret = keypresses; + *releases_ret = NULL; } void ltk_entry_cleanup(void) { - ltk_array_destroy_deep(keypress, keypresses, &destroy_keypress_cfg); - ltk_array_destroy(keyrelease, keyreleases); + ltk_keypress_bindings_destroy(keypresses); keypresses = NULL; - keyreleases = NULL; } static struct ltk_widget_vtable vtable = { @@ -335,42 +299,50 @@ wipe_selection(ltk_entry *entry) { set_selection(entry, 0, 0); } -static void -cursor_to_beginning(ltk_entry *entry, ltk_key_event *event) { +static int +cursor_to_beginning(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); wipe_selection(entry); entry->pos = 0; ensure_cursor_shown(entry); + return 0; } -static void -cursor_to_end(ltk_entry *entry, ltk_key_event *event) { +static int +cursor_to_end(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); wipe_selection(entry); entry->pos = entry->len; ensure_cursor_shown(entry); + return 0; } -static void -cursor_left(ltk_entry *entry, ltk_key_event *event) { +static int +cursor_left(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); if (entry->sel_start != entry->sel_end) entry->pos = entry->sel_start; else entry->pos = ltk_text_line_move_cursor_visually(entry->tl, entry->pos, -1, NULL); wipe_selection(entry); ensure_cursor_shown(entry); + return 0; } -static void -cursor_right(ltk_entry *entry, ltk_key_event *event) { +static int +cursor_right(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); if (entry->sel_start != entry->sel_end) entry->pos = entry->sel_end; else entry->pos = ltk_text_line_move_cursor_visually(entry->tl, entry->pos, 1, NULL); wipe_selection(entry); ensure_cursor_shown(entry); + return 0; } static void @@ -392,64 +364,79 @@ expand_selection(ltk_entry *entry, int dir) { entry->pos = new; wipe_selection(entry); } - selection_to_primary(entry, NULL); + selection_to_primary(LTK_CAST_WIDGET(entry), NULL); } /* FIXME: different programs have different behaviors when they set the selection */ /* FIXME: sometimes, it might be more useful to wipe the selection when sel_end == sel_start */ -static void -selection_to_primary(ltk_entry *entry, ltk_key_event *event) { +static int +selection_to_primary(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); if (entry->sel_end == entry->sel_start) - return; + return 0; txtbuf *primary = ltk_clipboard_get_primary_buffer(ltk_get_clipboard()); txtbuf_clear(primary); txtbuf_appendn(primary, entry->text + entry->sel_start, entry->sel_end - entry->sel_start); ltk_clipboard_set_primary_selection_owner(ltk_get_clipboard()); + return 0; } -static void -selection_to_clipboard(ltk_entry *entry, ltk_key_event *event) { +static int +selection_to_clipboard(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); if (entry->sel_end == entry->sel_start) - return; + return 0; txtbuf *clip = ltk_clipboard_get_clipboard_buffer(ltk_get_clipboard()); txtbuf_clear(clip); txtbuf_appendn(clip, entry->text + entry->sel_start, entry->sel_end - entry->sel_start); ltk_clipboard_set_clipboard_selection_owner(ltk_get_clipboard()); + return 0; } -static void -switch_selection_side(ltk_entry *entry, ltk_key_event *event) { + +static int +switch_selection_side(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); entry->sel_side = !entry->sel_side; + return 0; } -static void -paste_primary(ltk_entry *entry, ltk_key_event *event) { +static int +paste_primary(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); txtbuf *buf = ltk_clipboard_get_primary_text(ltk_get_clipboard()); if (buf) insert_text(entry, buf->text, buf->len, 1); + return 0; } -static void -paste_clipboard(ltk_entry *entry, ltk_key_event *event) { +static int +paste_clipboard(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); txtbuf *buf = ltk_clipboard_get_clipboard_text(ltk_get_clipboard()); if (buf) insert_text(entry, buf->text, buf->len, 1); + return 0; } -static void -expand_selection_left(ltk_entry *entry, ltk_key_event *event) { +static int +expand_selection_left(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); expand_selection(entry, -1); + return 0; } -static void -expand_selection_right(ltk_entry *entry, ltk_key_event *event) { +static int +expand_selection_right(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); expand_selection(entry, 1); + return 0; } static void @@ -466,35 +453,41 @@ delete_text(ltk_entry *entry, size_t start, size_t end) { ltk_window_invalidate_widget_rect(entry->widget.window, &entry->widget); } -static void -delete_char_backwards(ltk_entry *entry, ltk_key_event *event) { +static int +delete_char_backwards(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); if (entry->sel_start != entry->sel_end) { delete_text(entry, entry->sel_start, entry->sel_end); } else { size_t new = prev_utf8(entry->text, entry->pos); delete_text(entry, new, entry->pos); } + return 0; } -static void -delete_char_forwards(ltk_entry *entry, ltk_key_event *event) { +static int +delete_char_forwards(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); if (entry->sel_start != entry->sel_end) { delete_text(entry, entry->sel_start, entry->sel_end); } else { size_t new = next_utf8(entry->text, entry->len, entry->pos); delete_text(entry, entry->pos, new); } + return 0; } -static void -select_all(ltk_entry *entry, ltk_key_event *event) { +static int +select_all(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); set_selection(entry, 0, entry->len); if (entry->len) - selection_to_primary(entry, NULL); + selection_to_primary(LTK_CAST_WIDGET(entry), NULL); entry->sel_side = 0; + return 0; } static void @@ -579,9 +572,10 @@ ltk_entry_cmd_return(ltk_widget *self, char *text, size_t len) { insert_text(e, text, len, 0); } -static void -edit_external(ltk_entry *entry, ltk_key_event *event) { +static int +edit_external(ltk_widget *self, ltk_key_event *event) { (void)event; + ltk_entry *entry = LTK_CAST_ENTRY(self); ltk_config *config = ltk_config_get(); /* FIXME: allow arguments to key mappings - this would allow to have different key mappings for different editors instead of just one command */ @@ -592,8 +586,11 @@ edit_external(ltk_entry *entry, ltk_key_event *event) { /* FIXME: change interface to not require length of cmd */ ltk_call_cmd(LTK_CAST_WIDGET(entry), config->general.line_editor, strlen(config->general.line_editor), entry->text, entry->len); } + return 0; } +/* FIXME: return values of callbacks are currently ignored - could this be used for anything useful? */ +/* -> maybe if multiple bindings are configured for the same key? */ static int ltk_entry_key_press(ltk_widget *self, ltk_key_event *event) { ltk_entry *entry = LTK_CAST_ENTRY(self); @@ -607,7 +604,7 @@ ltk_entry_key_press(ltk_widget *self, ltk_key_event *event) { (b.mods == (event->modmask & ~LTK_MOD_SHIFT) && ((b.text && event->mapped && !strcmp(b.text, event->mapped)) || (b.rawtext && event->text && !strcmp(b.rawtext, event->text))))) { - ltk_array_get(keypresses, i).cb.func(entry, event); + ltk_array_get(keypresses, i).cb.func(LTK_CAST_WIDGET(entry), event); self->dirty = 1; ltk_window_invalidate_widget_rect(self->window, self); return 1; @@ -641,7 +638,7 @@ ltk_entry_mouse_press(ltk_widget *self, ltk_button_event *event) { } if (event->button == LTK_BUTTONL) { if (event->type == LTK_3BUTTONPRESS_EVENT) { - select_all(e, NULL); + select_all(LTK_CAST_WIDGET(e), NULL); } else if (event->type == LTK_2BUTTONPRESS_EVENT) { /* FIXME: use proper unicode stuff */ /* Note: If pango is used to determine what a word is, maybe at least @@ -695,7 +692,7 @@ ltk_entry_mouse_press(ltk_widget *self, ltk_button_event *event) { (see behavior in ledit) */ wipe_selection(e); e->pos = xy_to_pos(e, event->x, event->y, 1); - paste_primary(e, NULL); + paste_primary(LTK_CAST_WIDGET(e), NULL); } return 0; } @@ -705,7 +702,7 @@ ltk_entry_mouse_release(ltk_widget *self, ltk_button_event *event) { ltk_entry *e = LTK_CAST_ENTRY(self); if (event->button == LTK_BUTTONL) { e->selecting = 0; - selection_to_primary(e, NULL); + selection_to_primary(LTK_CAST_WIDGET(e), NULL); } return 0; } diff --git a/src/ltk/entry.h b/src/ltk/entry.h @@ -38,15 +38,17 @@ typedef struct { char selecting; } ltk_entry; +ltk_entry *ltk_entry_create(ltk_window *window, char *text); + +/* FIXME: these should be private to ltk */ +void ltk_entry_cleanup(void); +void ltk_entry_get_keybinding_parseinfo( + ltk_keybinding_cb **press_cbs_ret, size_t *press_len_ret, + ltk_keybinding_cb **release_cbs_ret, size_t *release_len_ret, + ltk_array(keypress) **presses_ret, ltk_array(keyrelease) **releases_ret +); int ltk_entry_ini_handler(ltk_renderdata *data, const char *prop, const char *value); int ltk_entry_fill_theme_defaults(ltk_renderdata *data); void ltk_entry_uninitialize_theme(ltk_renderdata *data); -/* FIXME: document that pointers inside binding are taken over! */ -int ltk_entry_register_keypress(const char *func_name, size_t func_len, ltk_keypress_binding b); -int ltk_entry_register_keyrelease(const char *func_name, size_t func_len, ltk_keyrelease_binding b); -void ltk_entry_cleanup(void); - -ltk_entry *ltk_entry_create(ltk_window *window, char *text); - #endif /* LTK_ENTRY_H */ diff --git a/src/ltk/keys.h b/src/ltk/keys.h @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2023-2024 lumidify <nobody@lumidify.org> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LTK_KEYS_H -#define LTK_KEYS_H - -#include <stddef.h> - -#include "util.h" - -/* FIXME: replace with proper string type */ -struct ltk_search_cmp_helper { - const char *text; - size_t len; -}; - -/* FIXME: documentation */ -#define GEN_CB_MAP_HELPERS(name, typename, cmp_entry) \ - \ -static int name##_sorted = 0; \ - \ -/* \ - * IMPORTANT: The text passed to *_get_entry may not be nul-terminated, \ - * so ltk_search_cmp_helper has to be used for the bsearch comparison \ - * helper. \ - */ \ - \ -static int \ -name##_search_helper(const void *keyv, const void *entryv) { \ - struct ltk_search_cmp_helper *key = (struct ltk_search_cmp_helper *)keyv; \ - typename *entry = (typename *)entryv; \ - int ret = strncmp(key->text, entry->cmp_entry, key->len); \ - if (ret == 0) { \ - if (entry->cmp_entry[key->len] == '\0') \ - return 0; \ - else \ - return -1; \ - } \ - return ret; \ -} \ - \ -static int \ -name##_sort_helper(const void *entry1v, const void *entry2v) { \ - typename *entry1 = (typename *)entry1v; \ - typename *entry2 = (typename *)entry2v; \ - return strcmp(entry1->cmp_entry, entry2->cmp_entry); \ -} \ - \ -static typename * \ -name##_get_entry(const char *text, size_t len) { \ - /* just in case */ \ - if (!name##_sorted) { \ - qsort( \ - name, LENGTH(name), \ - sizeof(name[0]), &name##_sort_helper); \ - name##_sorted = 1; \ - } \ - struct ltk_search_cmp_helper tmp = {.len = len, .text = text}; \ - return bsearch( \ - &tmp, name, LENGTH(name), \ - sizeof(name[0]), &name##_search_helper \ - ); \ -} - -#endif /* LTK_KEYS_H */ diff --git a/src/ltk/ltk.c b/src/ltk/ltk.c @@ -90,8 +90,6 @@ static void ltk_handle_event(ltk_event *event); static void ltk_load_theme(const char *path); static void ltk_uninitialize_theme(void); static int ltk_ini_handler(void *renderdata, const char *widget, const char *prop, const char *value); -static int handle_keypress_binding(const char *widget_name, size_t wlen, const char *name, size_t nlen, ltk_keypress_binding b); -static int handle_keyrelease_binding(const char *widget_name, size_t wlen, const char *name, size_t nlen, ltk_keyrelease_binding b); static short running = 1; @@ -100,8 +98,6 @@ typedef struct { int (*ini_handler)(ltk_renderdata *, const char *, const char *); int (*fill_theme_defaults)(ltk_renderdata *); void (*uninitialize_theme)(ltk_renderdata *); - int (*register_keypress)(const char *, size_t, ltk_keypress_binding); - int (*register_keyrelease)(const char *, size_t, ltk_keyrelease_binding); void (*cleanup)(void); } ltk_widget_funcs; @@ -112,8 +108,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = NULL, .fill_theme_defaults = NULL, .uninitialize_theme = NULL, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, }, { @@ -121,8 +115,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = &ltk_button_ini_handler, .fill_theme_defaults = &ltk_button_fill_theme_defaults, .uninitialize_theme = &ltk_button_uninitialize_theme, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, }, { @@ -130,8 +122,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = &ltk_entry_ini_handler, .fill_theme_defaults = &ltk_entry_fill_theme_defaults, .uninitialize_theme = &ltk_entry_uninitialize_theme, - .register_keypress = &ltk_entry_register_keypress, - .register_keyrelease = &ltk_entry_register_keyrelease, .cleanup = &ltk_entry_cleanup, }, { @@ -139,8 +129,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = NULL, .fill_theme_defaults = NULL, .uninitialize_theme = NULL, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, }, { @@ -148,8 +136,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = &ltk_label_ini_handler, .fill_theme_defaults = &ltk_label_fill_theme_defaults, .uninitialize_theme = &ltk_label_uninitialize_theme, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, }, { @@ -158,8 +144,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = NULL, .fill_theme_defaults = NULL, .uninitialize_theme = NULL, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, }, { @@ -167,8 +151,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = &ltk_menu_ini_handler, .fill_theme_defaults = &ltk_menu_fill_theme_defaults, .uninitialize_theme = &ltk_menu_uninitialize_theme, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, }, { @@ -176,8 +158,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = &ltk_menuentry_ini_handler, .fill_theme_defaults = &ltk_menuentry_fill_theme_defaults, .uninitialize_theme = &ltk_menuentry_uninitialize_theme, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, }, { @@ -185,8 +165,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = &ltk_submenu_ini_handler, .fill_theme_defaults = &ltk_submenu_fill_theme_defaults, .uninitialize_theme = &ltk_submenu_uninitialize_theme, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, }, { @@ -194,8 +172,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = &ltk_submenuentry_ini_handler, .fill_theme_defaults = &ltk_submenuentry_fill_theme_defaults, .uninitialize_theme = &ltk_submenuentry_uninitialize_theme, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, /* This "widget" is only needed to have separate styles for regular @@ -213,18 +189,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = &ltk_scrollbar_ini_handler, .fill_theme_defaults = &ltk_scrollbar_fill_theme_defaults, .uninitialize_theme = &ltk_scrollbar_uninitialize_theme, - .register_keypress = NULL, - .register_keyrelease = NULL, - .cleanup = NULL, - }, - { - /* Handler for general widget key bindings. */ - .name = "widget", - .ini_handler = NULL, - .fill_theme_defaults = NULL, - .uninitialize_theme = NULL, - .register_keypress = NULL, - .register_keyrelease = NULL, .cleanup = NULL, }, { @@ -233,8 +197,6 @@ static ltk_widget_funcs widget_funcs[] = { .ini_handler = &ltk_window_ini_handler, .fill_theme_defaults = &ltk_window_fill_theme_defaults, .uninitialize_theme = &ltk_window_uninitialize_theme, - .register_keypress = &ltk_window_register_keypress, - .register_keyrelease = &ltk_window_register_keyrelease, .cleanup = &ltk_window_cleanup, } }; @@ -259,12 +221,12 @@ ltk_init(void) { char *config_path = ltk_strcat_useful(ltk_dir, "/ltk.cfg"); char *theme_path; char *errstr = NULL; - if (ltk_config_parsefile(config_path, &handle_keypress_binding, &handle_keyrelease_binding, &errstr)) { + if (ltk_config_parsefile(config_path, &errstr)) { if (errstr) { ltk_warn("Unable to load config: %s\n", errstr); ltk_free0(errstr); } - if (ltk_config_load_default(&handle_keypress_binding, &handle_keyrelease_binding, &errstr)) { + if (ltk_config_load_default(&errstr)) { /* FIXME: I guess errstr isn't freed here, but whatever */ /* FIXME: return error instead of dying */ ltk_fatal("Unable to load default config: %s\n", errstr); @@ -588,30 +550,6 @@ ltk_uninitialize_theme(void) { } } -static int -handle_keypress_binding(const char *widget_name, size_t wlen, const char *name, size_t nlen, ltk_keypress_binding b) { - for (size_t i = 0; i < LENGTH(widget_funcs); i++) { - if (str_array_equal(widget_funcs[i].name, widget_name, wlen)) { - if (!widget_funcs[i].register_keypress) - return 1; - return widget_funcs[i].register_keypress(name, nlen, b); - } - } - return 1; -} - -static int -handle_keyrelease_binding(const char *widget_name, size_t wlen, const char *name, size_t nlen, ltk_keyrelease_binding b) { - for (size_t i = 0; i < LENGTH(widget_funcs); i++) { - if (str_array_equal(widget_funcs[i].name, widget_name, wlen)) { - if (!widget_funcs[i].register_keyrelease) - return 1; - return widget_funcs[i].register_keyrelease(name, nlen, b); - } - } - return 1; -} - int ltk_call_cmd(ltk_widget *caller, const char *cmd, size_t cmdlen, const char *text, size_t textlen) { /* FIXME: support environment variable $TMPDIR */ diff --git a/src/ltk/sort_search.h b/src/ltk/sort_search.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 lumidify <nobody@lumidify.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef LTK_SORT_SEARCH_H +#define LTK_SORT_SEARCH_H + +#include <stdlib.h> +#include <stddef.h> +#include <string.h> + +struct ltk_search_cmp_helper { + const char *text; + size_t len; +}; + +/* FIXME: documentation */ +#define GEN_SORT_SEARCH_HELPERS(name, typename, cmp_entry) \ + \ +/* \ + * IMPORTANT: The text passed to *_get_entry may not be nul-terminated, \ + * so ltk_search_cmp_helper has to be used for the bsearch comparison \ + * helper. \ + */ \ + \ +static int \ +name##_search_helper(const void *keyv, const void *entryv) { \ + struct ltk_search_cmp_helper *key = (struct ltk_search_cmp_helper *)keyv; \ + typename *entry = (typename *)entryv; \ + int ret = strncmp(key->text, entry->cmp_entry, key->len); \ + if (ret == 0) { \ + if (entry->cmp_entry[key->len] == '\0') \ + return 0; \ + else \ + return -1; \ + } \ + return ret; \ +} \ + \ +static int \ +name##_sort_helper(const void *entry1v, const void *entry2v) { \ + typename *entry1 = (typename *)entry1v; \ + typename *entry2 = (typename *)entry2v; \ + return strcmp(entry1->cmp_entry, entry2->cmp_entry); \ +} \ + \ +static void \ +name##_sort(typename *arr, size_t arrlen) { \ + qsort( \ + arr, arrlen, \ + sizeof(typename), &name##_sort_helper \ + ); \ +} \ + \ +static typename * \ +name##_get_entry(typename *arr, size_t arrlen, const char *text, size_t len) { \ + struct ltk_search_cmp_helper tmp = {.text = text, .len = len}; \ + return bsearch( \ + &tmp, arr, arrlen, \ + sizeof(typename), &name##_search_helper \ + ); \ +} + +#endif /* LTK_SORT_SEARCH_H */ diff --git a/src/ltk/window.c b/src/ltk/window.c @@ -21,12 +21,12 @@ #include "ltk.h" #include "util.h" -#include "keys.h" #include "array.h" #include "theme.h" #include "widget.h" #include "window.h" #include "memory.h" +#include "config.h" #include "eventdefs.h" #define MAX_WINDOW_FONT_SIZE 20000 @@ -67,24 +67,19 @@ static struct ltk_widget_vtable vtable = { .invalid_signal = LTK_WINDOW_SIGNAL_INVALID, }; -static int cb_focus_active(ltk_window *window, ltk_key_event *event, int handled); -static int cb_unfocus_active(ltk_window *window, ltk_key_event *event, int handled); -static int cb_move_prev(ltk_window *window, ltk_key_event *event, int handled); -static int cb_move_next(ltk_window *window, ltk_key_event *event, int handled); -static int cb_move_left(ltk_window *window, ltk_key_event *event, int handled); -static int cb_move_right(ltk_window *window, ltk_key_event *event, int handled); -static int cb_move_up(ltk_window *window, ltk_key_event *event, int handled); -static int cb_move_down(ltk_window *window, ltk_key_event *event, int handled); -static int cb_set_pressed(ltk_window *window, ltk_key_event *event, int handled); -static int cb_unset_pressed(ltk_window *window, ltk_key_event *event, int handled); -static int cb_remove_popups(ltk_window *window, ltk_key_event *event, int handled); - -struct key_cb { - char *func_name; - int (*callback)(ltk_window *, ltk_key_event *, int handled); -}; - -static struct key_cb cb_map[] = { +static int cb_focus_active(ltk_widget *self, ltk_key_event *event); +static int cb_unfocus_active(ltk_widget *self, ltk_key_event *event); +static int cb_move_prev(ltk_widget *self, ltk_key_event *event); +static int cb_move_next(ltk_widget *self, ltk_key_event *event); +static int cb_move_left(ltk_widget *self, ltk_key_event *event); +static int cb_move_right(ltk_widget *self, ltk_key_event *event); +static int cb_move_up(ltk_widget *self, ltk_key_event *event); +static int cb_move_down(ltk_widget *self, ltk_key_event *event); +static int cb_set_pressed(ltk_widget *self, ltk_key_event *event); +static int cb_unset_pressed(ltk_widget *self, ltk_key_event *event); +static int cb_remove_popups(ltk_widget *self, ltk_key_event *event); + +static ltk_keybinding_cb cb_map[] = { {"focus-active", &cb_focus_active}, {"move-down", &cb_move_down}, {"move-left", &cb_move_left}, @@ -98,25 +93,26 @@ static struct key_cb cb_map[] = { {"unset-pressed", &cb_unset_pressed}, }; -struct keypress_cfg { - ltk_keypress_binding b; - struct key_cb cb; -}; - -struct keyrelease_cfg { - ltk_keyrelease_binding b; - struct key_cb cb; -}; - -LTK_ARRAY_INIT_DECL_STATIC(keypress, struct keypress_cfg) -LTK_ARRAY_INIT_IMPL_STATIC(keypress, struct keypress_cfg) -LTK_ARRAY_INIT_DECL_STATIC(keyrelease, struct keyrelease_cfg) -LTK_ARRAY_INIT_IMPL_STATIC(keyrelease, struct keyrelease_cfg) - static ltk_array(keypress) *keypresses = NULL; static ltk_array(keyrelease) *keyreleases = NULL; -GEN_CB_MAP_HELPERS(cb_map, struct key_cb, func_name) +void +ltk_window_get_keybinding_parseinfo( + ltk_keybinding_cb **press_cbs_ret, size_t *press_len_ret, + ltk_keybinding_cb **release_cbs_ret, size_t *release_len_ret, + ltk_array(keypress) **presses_ret, ltk_array(keyrelease) **releases_ret +) { + *press_cbs_ret = cb_map; + *press_len_ret = LENGTH(cb_map); + *release_cbs_ret = cb_map; + *release_len_ret = LENGTH(cb_map); + if (!keypresses) + keypresses = ltk_array_create(keypress, 1); + if (!keyreleases) + keyreleases = ltk_array_create(keyrelease, 1); + *presses_ret = keypresses; + *releases_ret = keyreleases; +} /* needed for passing keyboard events down the hierarchy */ static ltk_widget **widget_stack = NULL; @@ -153,44 +149,13 @@ ltk_window_get_theme(void) { return &theme; } -/* FIXME: most of this is duplicated code */ - -int -ltk_window_register_keypress(const char *func_name, size_t func_len, ltk_keypress_binding b) { - if (!keypresses) - keypresses = ltk_array_create(keypress, 1); - struct key_cb *cb = cb_map_get_entry(func_name, func_len); - if (!cb) - return 1; - struct keypress_cfg cfg = {b, *cb}; - ltk_array_append(keypress, keypresses, cfg); - return 0; -} - -int -ltk_window_register_keyrelease(const char *func_name, size_t func_len, ltk_keyrelease_binding b) { - if (!keyreleases) - keyreleases = ltk_array_create(keyrelease, 1); - struct key_cb *cb = cb_map_get_entry(func_name, func_len); - if (!cb) - return 1; - struct keyrelease_cfg cfg = {b, *cb}; - ltk_array_append(keyrelease, keyreleases, cfg); - return 0; -} - -static void -destroy_keypress_cfg(struct keypress_cfg cfg) { - ltk_keypress_binding_destroy(cfg.b); -} - void ltk_window_cleanup(void) { - ltk_array_destroy_deep(keypress, keypresses, &destroy_keypress_cfg); - ltk_array_destroy(keyrelease, keyreleases); - free(widget_stack); + ltk_keypress_bindings_destroy(keypresses); + ltk_keyrelease_bindings_destroy(keyreleases); keypresses = NULL; keyreleases = NULL; + ltk_free(widget_stack); widget_stack = NULL; } @@ -244,13 +209,13 @@ ltk_window_key_press_event(ltk_widget *self, ltk_key_event *event) { continue; } else if (b->text) { if (event->mapped && !strcmp(b->text, event->mapped)) - handled |= ltk_array_get(keypresses, i).cb.callback(window, event, handled); + handled |= ltk_array_get(keypresses, i).cb.func(LTK_CAST_WIDGET(window), event); } else if (b->rawtext) { if (event->text && !strcmp(b->text, event->text)) - handled |= ltk_array_get(keypresses, i).cb.callback(window, event, handled); + handled |= ltk_array_get(keypresses, i).cb.func(LTK_CAST_WIDGET(window), event); } else if (b->sym != LTK_KEY_NONE) { if (event->sym == b->sym) - handled |= ltk_array_get(keypresses, i).cb.callback(window, event, handled); + handled |= ltk_array_get(keypresses, i).cb.func(LTK_CAST_WIDGET(window), event); } } return 1; @@ -280,7 +245,7 @@ ltk_window_key_release_event(ltk_widget *self, ltk_key_event *event) { if (b->mods != event->modmask || (!(b->flags & LTK_KEY_BINDING_RUN_ALWAYS) && handled)) { continue; } else if (b->sym != LTK_KEY_NONE && event->sym == b->sym) { - handled |= ltk_array_get(keyreleases, i).cb.callback(window, event, handled); + handled |= ltk_array_get(keyreleases, i).cb.func(LTK_CAST_WIDGET(window), event); } } return 1; @@ -1226,9 +1191,9 @@ gen_widget_stack(ltk_widget *bottom) { widget type, but what if the program using ltk wants to catch keyboard events even if the widget doesn't do that by default? */ static int -cb_focus_active(ltk_window *window, ltk_key_event *event, int handled) { +cb_focus_active(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); if (window->active_widget && !(window->active_widget->state & LTK_FOCUSED)) { /* FIXME: maybe also set widgets above in hierarchy? */ ltk_widget_state old_state = window->active_widget->state; @@ -1240,9 +1205,9 @@ cb_focus_active(ltk_window *window, ltk_key_event *event, int handled) { } static int -cb_unfocus_active(ltk_window *window, ltk_key_event *event, int handled) { +cb_unfocus_active(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); if (window->active_widget && (window->active_widget->state & LTK_FOCUSED) && (window->active_widget->vtable->flags & LTK_NEEDS_KEYBOARD)) { ltk_widget_state old_state = window->active_widget->state; window->active_widget->state &= ~LTK_FOCUSED; @@ -1253,51 +1218,51 @@ cb_unfocus_active(ltk_window *window, ltk_key_event *event, int handled) { } static int -cb_move_prev(ltk_window *window, ltk_key_event *event, int handled) { +cb_move_prev(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); return prev_child(window); } static int -cb_move_next(ltk_window *window, ltk_key_event *event, int handled) { +cb_move_next(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); return next_child(window); } static int -cb_move_left(ltk_window *window, ltk_key_event *event, int handled) { +cb_move_left(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); return left_top_child(window, 1); } static int -cb_move_right(ltk_window *window, ltk_key_event *event, int handled) { +cb_move_right(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); return right_bottom_child(window, 1); } static int -cb_move_up(ltk_window *window, ltk_key_event *event, int handled) { +cb_move_up(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); return left_top_child(window, 0); } static int -cb_move_down(ltk_window *window, ltk_key_event *event, int handled) { +cb_move_down(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); return right_bottom_child(window, 0); } static int -cb_set_pressed(ltk_window *window, ltk_key_event *event, int handled) { +cb_set_pressed(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); if (window->active_widget && (window->active_widget->state & LTK_FOCUSED)) { /* FIXME: only set pressed if needs keyboard? */ ltk_window_set_pressed_widget(window, window->active_widget, 0); @@ -1307,9 +1272,9 @@ cb_set_pressed(ltk_window *window, ltk_key_event *event, int handled) { } static int -cb_unset_pressed(ltk_window *window, ltk_key_event *event, int handled) { +cb_unset_pressed(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); if (window->pressed_widget) { ltk_window_set_pressed_widget(window, NULL, 1); return 1; @@ -1318,9 +1283,9 @@ cb_unset_pressed(ltk_window *window, ltk_key_event *event, int handled) { } static int -cb_remove_popups(ltk_window *window, ltk_key_event *event, int handled) { +cb_remove_popups(ltk_widget *self, ltk_key_event *event) { (void)event; - (void)handled; + ltk_window *window = LTK_CAST_WINDOW(self); if (window->popups_num > 0) { ltk_window_unregister_all_popups(window); return 1; diff --git a/src/ltk/window.h b/src/ltk/window.h @@ -61,11 +61,6 @@ typedef struct ltk_window { char popups_locked; } ltk_window; -int ltk_window_fill_theme_defaults(ltk_renderdata *data); -int ltk_window_ini_handler(ltk_renderdata *data, const char *prop, const char *value); -void ltk_window_uninitialize_theme(ltk_renderdata *data); -ltk_window_theme *ltk_window_get_theme(void); - /* FIXME: should be private to ltk */ ltk_window *ltk_window_create_intern(ltk_renderdata *data, const char *title, int x, int y, unsigned int w, unsigned int h); void ltk_window_destroy_intern(ltk_window *window); @@ -90,9 +85,15 @@ void ltk_window_unregister_popup(ltk_window *window, ltk_widget *popup); void ltk_window_unregister_all_popups(ltk_window *window); /* FIXME: these should be private to ltk */ -/* FIXME: document that pointers inside binding are taken over! */ -int ltk_window_register_keypress(const char *func_name, size_t func_len, ltk_keypress_binding b); -int ltk_window_register_keyrelease(const char *func_name, size_t func_len, ltk_keyrelease_binding b); void ltk_window_cleanup(void); +void ltk_window_get_keybinding_parseinfo( + ltk_keybinding_cb **press_cbs_ret, size_t *press_len_ret, + ltk_keybinding_cb **release_cbs_ret, size_t *release_len_ret, + ltk_array(keypress) **presses_ret, ltk_array(keyrelease) **releases_ret +); +int ltk_window_fill_theme_defaults(ltk_renderdata *data); +int ltk_window_ini_handler(ltk_renderdata *data, const char *prop, const char *value); +void ltk_window_uninitialize_theme(ltk_renderdata *data); +ltk_window_theme *ltk_window_get_theme(void); #endif /* LTK_WINDOW_H */