ltk

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

commit 488ed473efaa6153752374f9c27f67fe45dc4823
parent 480c476bee3efca10facb5ff2be6863bf112b72a
Author: lumidify <nobody@lumidify.org>
Date:   Thu, 23 Jun 2022 12:37:01 +0200

Standardize error handling

Diffstat:
Msrc/box.c | 97+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/box.h | 5++++-
Msrc/button.c | 18+++++++++++-------
Msrc/button.h | 5++++-
Asrc/err.c | 28++++++++++++++++++++++++++++
Asrc/err.h | 31+++++++++++++++++++++++++++++++
Msrc/grid.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/grid.h | 10++++++----
Msrc/label.c | 18+++++++++++-------
Msrc/label.h | 11+++++++----
Msrc/ltkd.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/menu.c | 218++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/menu.h | 10+++++-----
Msrc/util.c | 5++---
Msrc/util.h | 2+-
Msrc/widget.c | 38++++++++++++++++++++++----------------
Msrc/widget.h | 10++++++----
17 files changed, 472 insertions(+), 279 deletions(-)

diff --git a/src/box.c b/src/box.c @@ -36,9 +36,9 @@ static void ltk_box_destroy(ltk_widget *self, int shallow); static void ltk_recalculate_box(ltk_widget *self); static void ltk_box_child_size_change(ltk_widget *self, ltk_widget *widget); /* FIXME: Why is sticky unsigned short? */ -static int ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short sticky, char **errstr); -static int ltk_box_remove(ltk_widget *widget, ltk_widget *self, char **errstr); -/* static int ltk_box_clear(ltk_window *window, ltk_box *box, int shallow, char **errstr); */ +static int ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short sticky, ltk_error *err); +static int ltk_box_remove(ltk_widget *widget, ltk_widget *self, ltk_error *err); +/* static int ltk_box_clear(ltk_window *window, ltk_box *box, int shallow, ltk_error *err); */ static void ltk_box_scroll(ltk_widget *self); static int ltk_box_mouse_press(ltk_widget *self, ltk_button_event *event); static ltk_widget *ltk_box_get_child_at_pos(ltk_widget *self, int x, int y); @@ -67,24 +67,24 @@ static int ltk_box_cmd_add( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err); static int ltk_box_cmd_remove( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err); /* static int ltk_box_cmd_clear ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err); */ static int ltk_box_cmd_create( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err); static void ltk_box_draw(ltk_widget *self, ltk_rect clip) { @@ -229,9 +229,9 @@ ltk_box_child_size_change(ltk_widget *self, ltk_widget *widget) { } static int -ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short sticky, char **errstr) { +ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short sticky, ltk_error *err) { if (widget->parent) { - *errstr = "Widget already inside a container.\n"; + err->type = ERR_WIDGET_IN_CONTAINER; return 1; } if (box->num_widgets >= box->num_alloc) { @@ -263,12 +263,12 @@ ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short } static int -ltk_box_remove(ltk_widget *widget, ltk_widget *self, char **errstr) { +ltk_box_remove(ltk_widget *widget, ltk_widget *self, ltk_error *err) { ltk_box *box = (ltk_box *)self; int sc_w = box->sc->widget.rect.w; int sc_h = box->sc->widget.rect.h; if (widget->parent != (ltk_widget *)box) { - *errstr = "Widget isn't contained in given box.\n"; + err->type = ERR_WIDGET_NOT_IN_CONTAINER; return 1; } widget->parent = NULL; @@ -303,7 +303,7 @@ ltk_box_remove(ltk_widget *widget, ltk_widget *self, char **errstr) { } } - *errstr = "Widget isn't contained in given box.\n"; + err->type = ERR_WIDGET_NOT_IN_CONTAINER; return 1; } @@ -347,20 +347,24 @@ ltk_box_cmd_add( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { const char *c; ltk_box *box; ltk_widget *widget; int sticky = 0; if (num_tokens != 4 && num_tokens != 5) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - box = (ltk_box *)ltk_get_widget(tokens[1], LTK_BOX, errstr); - widget = ltk_get_widget(tokens[3], LTK_WIDGET, errstr); - if (!box || !widget) { - *errstr = "Invalid widget ID.\n"; + box = (ltk_box *)ltk_get_widget(tokens[1], LTK_BOX, err); + widget = ltk_get_widget(tokens[3], LTK_WIDGET, err); + if (!box) { + err->arg = 1; + return 1; + } else if (!widget) { + err->arg = 3; return 1; } @@ -375,13 +379,18 @@ ltk_box_cmd_add( } else if (*c == 'w') { sticky |= LTK_STICKY_LEFT; } else { - *errstr = "Invalid sticky specification.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 4; return 1; } } } - return ltk_box_add(window, widget, box, sticky, errstr); + if (ltk_box_add(window, widget, box, sticky, err)) { + err->arg = 3; + return 1; + } + return 0; } /* box <box id> remove <widget id> */ @@ -390,23 +399,31 @@ ltk_box_cmd_remove( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_box *box; ltk_widget *widget; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - box = (ltk_box *)ltk_get_widget(tokens[1], LTK_BOX, errstr); - widget = ltk_get_widget(tokens[3], LTK_WIDGET, errstr); - if (!box || !widget) { - *errstr = "Invalid widget ID.\n"; + box = (ltk_box *)ltk_get_widget(tokens[1], LTK_BOX, err); + widget = ltk_get_widget(tokens[3], LTK_WIDGET, err); + if (!box) { + err->arg = 1; + return 1; + } else if (!widget) { + err->arg = 3; return 1; } - return ltk_box_remove(widget, (ltk_widget *)box, errstr); + if (ltk_box_remove(widget, (ltk_widget *)box, err)) { + err->arg = 3; + return 1; + } + return 0; } /* box <box id> create <orientation> */ @@ -415,16 +432,19 @@ ltk_box_cmd_create( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { ltk_box *box; ltk_orientation orient; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } + /* FIXME: race condition */ if (!ltk_widget_id_free(tokens[1])) { - *errstr = "Widget ID already taken.\n"; + err->type = ERR_WIDGET_ID_IN_USE; + err->arg = 1; return 1; } if (!strcmp(tokens[3], "horizontal")) { @@ -432,7 +452,8 @@ ltk_box_cmd_create( } else if (!strcmp(tokens[3], "vertical")) { orient = LTK_VERTICAL; } else { - *errstr = "Invalid orientation.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 3; return 1; } box = (ltk_box *)ltk_box_create(window, tokens[1], orient); @@ -447,19 +468,21 @@ ltk_box_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { if (num_tokens < 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (strcmp(tokens[2], "add") == 0) { - return ltk_box_cmd_add(window, tokens, num_tokens, errstr); + return ltk_box_cmd_add(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "remove") == 0) { - return ltk_box_cmd_remove(window, tokens, num_tokens, errstr); + return ltk_box_cmd_remove(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "create") == 0) { - return ltk_box_cmd_create(window, tokens, num_tokens, errstr); + return ltk_box_cmd_create(window, tokens, num_tokens, err); } else { - *errstr = "Invalid command.\n"; + err->type = ERR_INVALID_COMMAND; + err->arg = -1; return 1; } diff --git a/src/box.h b/src/box.h @@ -17,8 +17,11 @@ #ifndef _LTK_BOX_H_ #define _LTK_BOX_H_ +/* FIXME: include everything here */ /* Requires the following includes: "scrollbar.h", "rect.h", "widget.h", "ltk.h" */ +#include "err.h" + typedef struct { ltk_widget widget; ltk_scrollbar *sc; @@ -30,6 +33,6 @@ typedef struct { ltk_orientation orient; } ltk_box; -int ltk_box_cmd(ltk_window *window, char **tokens, size_t num_tokens, char **errstr); +int ltk_box_cmd(ltk_window *window, char **tokens, size_t num_tokens, ltk_error *); #endif /* _LTK_BOX_H_ */ diff --git a/src/button.c b/src/button.c @@ -212,14 +212,16 @@ ltk_button_cmd_create( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { ltk_button *button; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (!ltk_widget_id_free(tokens[1])) { - *errstr = "Widget ID already taken.\n"; + err->type = ERR_WIDGET_ID_IN_USE; + err->arg = 1; return 1; } button = ltk_button_create(window, tokens[1], tokens[3]); @@ -234,15 +236,17 @@ ltk_button_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { if (num_tokens < 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (strcmp(tokens[2], "create") == 0) { - return ltk_button_cmd_create(window, tokens, num_tokens, errstr); + return ltk_button_cmd_create(window, tokens, num_tokens, err); } else { - *errstr = "Invalid command.\n"; + err->type = ERR_INVALID_COMMAND; + err->arg = -1; return 1; } diff --git a/src/button.h b/src/button.h @@ -19,6 +19,8 @@ /* Requires the following includes: <X11/Xlib.h>, "rect.h", "widget.h", "ltk.h", "color.h", "text.h" */ +#include "err.h" + typedef struct { ltk_widget widget; ltk_text_line *tl; @@ -32,6 +34,7 @@ int ltk_button_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error * +); #endif /* _LTK_BUTTON_H_ */ diff --git a/src/err.c b/src/err.c @@ -0,0 +1,28 @@ +#include "err.h" + +static const char *errtable[] = { + "None", + "Widget already in container", + "Widget not in container", + "Widget id already in use", + "Invalid number of arguments", + "Invalid argument", + "Invalid index", + "Invalid widget id", + "Invalid widget type", + "Invalid command", + "Menu is not submenu", + "Menu entry already contains submenu", + "Invalid grid position", +}; + +#define LENGTH(X) (sizeof(X) / sizeof(X[0])) + +const char * +errtype_to_string(ltk_errtype type) { + if (type < 0 || type >= LENGTH(errtable)) { + /* that's a funny error, now isn't it? */ + return "Invalid error"; + } + return errtable[type]; +} diff --git a/src/err.h b/src/err.h @@ -0,0 +1,31 @@ +#ifndef LTK_ERR_H +#define LTK_ERR_H + +/* WARNING: THIS NEEDS TO BE KEPT IN SYNC WITH THE TABLE IN err.c! */ +/* (also, the explicit value setting is redundant, but just in case) */ +typedef enum { + ERR_NONE = 0, + ERR_WIDGET_IN_CONTAINER = 1, + ERR_WIDGET_NOT_IN_CONTAINER = 2, + ERR_WIDGET_ID_IN_USE = 3, + ERR_INVALID_NUMBER_OF_ARGUMENTS = 4, + ERR_INVALID_ARGUMENT = 5, + ERR_INVALID_INDEX = 6, + ERR_INVALID_WIDGET_ID = 7, + ERR_INVALID_WIDGET_TYPE = 8, + ERR_INVALID_COMMAND = 9, + /* widget specific */ + ERR_MENU_NOT_SUBMENU = 10, + ERR_MENU_ENTRY_CONTAINS_SUBMENU = 11, + ERR_GRID_INVALID_POSITION = 12, +} ltk_errtype; + +typedef struct { + ltk_errtype type; + /* corresponding argument, -1 if none */ + int arg; +} ltk_error; + +const char *errtype_to_string(ltk_errtype type); + +#endif /* LTK_ERR_H */ diff --git a/src/grid.c b/src/grid.c @@ -46,8 +46,8 @@ static void ltk_grid_destroy(ltk_widget *self, int shallow); static void ltk_recalculate_grid(ltk_widget *self); static void ltk_grid_child_size_change(ltk_widget *self, ltk_widget *widget); static int ltk_grid_add(ltk_window *window, ltk_widget *widget, ltk_grid *grid, - int row, int column, int row_span, int column_span, unsigned short sticky, char **errstr); -static int ltk_grid_ungrid(ltk_widget *widget, ltk_widget *self, char **errstr); + int row, int column, int row_span, int column_span, unsigned short sticky, ltk_error *err); +static int ltk_grid_ungrid(ltk_widget *widget, ltk_widget *self, ltk_error *err); static int ltk_grid_find_nearest_column(ltk_grid *grid, int x); static int ltk_grid_find_nearest_row(ltk_grid *grid, int y); static ltk_widget *ltk_grid_get_child_at_pos(ltk_widget *self, int x, int y); @@ -76,27 +76,27 @@ static int ltk_grid_cmd_add( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err); static int ltk_grid_cmd_ungrid( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err); static int ltk_grid_cmd_create( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err); static int ltk_grid_cmd_set_row_weight( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err); static int ltk_grid_cmd_set_column_weight( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err); static void ltk_grid_set_row_weight(ltk_grid *grid, int row, int weight) { @@ -317,13 +317,13 @@ ltk_grid_child_size_change(ltk_widget *self, ltk_widget *widget) { /* FIXME: Check if widget already exists at position */ static int ltk_grid_add(ltk_window *window, ltk_widget *widget, ltk_grid *grid, - int row, int column, int row_span, int column_span, unsigned short sticky, char **errstr) { + int row, int column, int row_span, int column_span, unsigned short sticky, ltk_error *err) { if (widget->parent) { - *errstr = "Widget already inside a container.\n"; + err->type = ERR_WIDGET_IN_CONTAINER; return 1; } if (row + row_span > grid->rows || column + column_span > grid->columns) { - *errstr = "Invalid row or column.\n"; + err->type = ERR_GRID_INVALID_POSITION; return 1; } widget->sticky = sticky; @@ -344,10 +344,10 @@ ltk_grid_add(ltk_window *window, ltk_widget *widget, ltk_grid *grid, } static int -ltk_grid_ungrid(ltk_widget *widget, ltk_widget *self, char **errstr) { +ltk_grid_ungrid(ltk_widget *widget, ltk_widget *self, ltk_error *err) { ltk_grid *grid = (ltk_grid *)self; if (widget->parent != (ltk_widget *)grid) { - *errstr = "Widget isn't gridded in given grid.\n"; + err->type = ERR_WIDGET_NOT_IN_CONTAINER; return 1; } widget->parent = NULL; @@ -402,7 +402,7 @@ ltk_grid_cmd_add( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { const char *c; ltk_grid *grid; ltk_widget *widget; @@ -410,33 +410,42 @@ ltk_grid_cmd_add( int row, column, row_span, column_span, sticky = 0; if (num_tokens != 8 && num_tokens != 9) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - grid = (ltk_grid *)ltk_get_widget(tokens[1], LTK_GRID, errstr); - widget = ltk_get_widget(tokens[3], LTK_WIDGET, errstr); - if (!grid || !widget) { - *errstr = "Invalid widget ID.\n"; + grid = (ltk_grid *)ltk_get_widget(tokens[1], LTK_GRID, err); + widget = ltk_get_widget(tokens[3], LTK_WIDGET, err); + if (!grid) { + err->arg = 1; + return 1; + } else if (!widget) { + err->arg = 3; return 1; } + row = ltk_strtonum(tokens[4], 0, grid->rows - 1, &errstr_num); if (errstr_num) { - *errstr = "Invalid row number.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 4; return 1; } column = ltk_strtonum(tokens[5], 0, grid->columns - 1, &errstr_num); if (errstr_num) { - *errstr = "Invalid row number.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 5; return 1; } row_span = ltk_strtonum(tokens[6], 1, grid->rows, &errstr_num); if (errstr_num) { - *errstr = "Invalid row span.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 6; return 1; } column_span = ltk_strtonum(tokens[7], 1, grid->columns, &errstr_num); if (errstr_num) { - *errstr = "Invalid column span.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 7; return 1; } @@ -451,13 +460,19 @@ ltk_grid_cmd_add( } else if (*c == 'w') { sticky |= LTK_STICKY_LEFT; } else { - *errstr = "Invalid sticky specification.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 8; return 1; } } } - return ltk_grid_add(window, widget, grid, row, column, row_span, column_span, sticky, errstr); + /* FIXME: better error reporting for invalid grid position */ + if (ltk_grid_add(window, widget, grid, row, column, row_span, column_span, sticky, err)) { + err->arg = err->type == ERR_WIDGET_IN_CONTAINER ? 3 : -1; + return 1; + } + return 0; } /* grid <grid id> remove <widget id> */ @@ -466,18 +481,29 @@ ltk_grid_cmd_ungrid( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_grid *grid; ltk_widget *widget; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; + return 1; + } + grid = (ltk_grid *)ltk_get_widget(tokens[1], LTK_GRID, err); + widget = ltk_get_widget(tokens[3], LTK_WIDGET, err); + if (!grid) { + err->arg = 1; + return 1; + } else if (!widget) { + err->arg = 3; return 1; } - grid = (ltk_grid *)ltk_get_widget(tokens[1], LTK_GRID, errstr); - widget = ltk_get_widget(tokens[3], LTK_WIDGET, errstr); - if (!grid || !widget) return 1; - return ltk_grid_ungrid(widget, (ltk_widget *)grid, errstr); + if (ltk_grid_ungrid(widget, (ltk_widget *)grid, err)) { + err->arg = 3; + return 1; + } + return 0; } /* grid <grid id> create <rows> <columns> */ @@ -486,26 +512,30 @@ ltk_grid_cmd_create( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { int rows, columns; ltk_grid *grid; const char *errstr_num; if (num_tokens != 5) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (!ltk_widget_id_free(tokens[1])) { - *errstr = "Widget ID already taken.\n"; + err->type = ERR_WIDGET_ID_IN_USE; + err->arg = 1; return 1; } rows = ltk_strtonum(tokens[3], 1, 64, &errstr_num); if (errstr_num) { - *errstr = "Invalid number of rows.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 3; return 1; } columns = ltk_strtonum(tokens[4], 1, 64, &errstr_num); if (errstr_num) { - *errstr = "Invalid number of columns.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 4; return 1; } grid = ltk_grid_create(window, tokens[1], rows, columns); @@ -520,25 +550,31 @@ ltk_grid_cmd_set_row_weight( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_grid *grid; int row, weight; const char *errstr_num; if (num_tokens != 5) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; + return 1; + } + grid = (ltk_grid *)ltk_get_widget(tokens[1], LTK_GRID, err); + if (!grid) { + err->arg = 1; return 1; } - grid = (ltk_grid *)ltk_get_widget(tokens[1], LTK_GRID, errstr); - if (!grid) return 1; row = ltk_strtonum(tokens[3], 0, grid->rows, &errstr_num); if (errstr_num) { - *errstr = "Invalid row number.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 3; return 1; } weight = ltk_strtonum(tokens[4], 0, 64, &errstr_num); if (errstr_num) { - *errstr = "Invalid row weight.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 4; return 1; } ltk_grid_set_row_weight(grid, row, weight); @@ -552,25 +588,31 @@ ltk_grid_cmd_set_column_weight( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_grid *grid; int column, weight; const char *errstr_num; if (num_tokens != 5) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; + return 1; + } + grid = (ltk_grid *)ltk_get_widget(tokens[1], LTK_GRID, err); + if (!grid) { + err->arg = 1; return 1; } - grid = (ltk_grid *)ltk_get_widget(tokens[1], LTK_GRID, errstr); - if (!grid) return 1; column = ltk_strtonum(tokens[3], 0, grid->columns, &errstr_num); if (errstr_num) { - *errstr = "Invalid column number.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 3; return 1; } weight = ltk_strtonum(tokens[4], 0, 64, &errstr_num); if (errstr_num) { - *errstr = "Invalid column weight.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 4; return 1; } ltk_grid_set_column_weight(grid, column, weight); @@ -584,23 +626,25 @@ ltk_grid_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { if (num_tokens < 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (strcmp(tokens[2], "add") == 0) { - return ltk_grid_cmd_add(window, tokens, num_tokens, errstr); + return ltk_grid_cmd_add(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "ungrid") == 0) { - return ltk_grid_cmd_ungrid(window, tokens, num_tokens, errstr); + return ltk_grid_cmd_ungrid(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "create") == 0) { - return ltk_grid_cmd_create(window, tokens, num_tokens, errstr); + return ltk_grid_cmd_create(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "set-row-weight") == 0) { - return ltk_grid_cmd_set_row_weight(window, tokens, num_tokens, errstr); + return ltk_grid_cmd_set_row_weight(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "set-column-weight") == 0) { - return ltk_grid_cmd_set_column_weight(window, tokens, num_tokens, errstr); + return ltk_grid_cmd_set_column_weight(window, tokens, num_tokens, err); } else { - *errstr = "Invalid command.\n"; + err->type = ERR_INVALID_COMMAND; + err->arg = -1; return 1; } diff --git a/src/grid.h b/src/grid.h @@ -14,11 +14,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _LTK_GRID_H_ -#define _LTK_GRID_H_ +#ifndef LTK_GRID_H +#define LTK_GRID_H /* Requires the following includes: "rect.h", "widget.h", "ltk.h" */ +#include "err.h" + /* * Struct to represent a grid widget. */ @@ -35,6 +37,6 @@ typedef struct { int *column_pos; } ltk_grid; -int ltk_grid_cmd(ltk_window *window, char **tokens, size_t num_tokens, char **errstr); +int ltk_grid_cmd(ltk_window *window, char **tokens, size_t num_tokens, ltk_error *err); -#endif +#endif /* LTK_GRID_H */ diff --git a/src/label.c b/src/label.c @@ -151,14 +151,16 @@ ltk_label_cmd_create( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { ltk_label *label; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (!ltk_widget_id_free(tokens[1])) { - *errstr = "Widget ID already taken.\n"; + err->type = ERR_WIDGET_ID_IN_USE; + err->arg = 1; return 1; } label = ltk_label_create(window, tokens[1], tokens[3]); @@ -173,15 +175,17 @@ ltk_label_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { if (num_tokens < 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (strcmp(tokens[2], "create") == 0) { - return ltk_label_cmd_create(window, tokens, num_tokens, errstr); + return ltk_label_cmd_create(window, tokens, num_tokens, err); } else { - *errstr = "Invalid command.\n"; + err->type = ERR_INVALID_COMMAND; + err->arg = -1; return 1; } diff --git a/src/label.h b/src/label.h @@ -14,11 +14,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _LTK_LABEL_H_ -#define _LTK_LABEL_H_ +#ifndef LTK_LABEL_H +#define LTK_LABEL_H /* Requires the following includes: <X11/Xlib.h>, "rect.h", "widget.h", "ltk.h", "color.h", "text.h" */ +#include "err.h" + typedef struct { ltk_widget widget; ltk_text_line *tl; @@ -32,6 +34,7 @@ int ltk_label_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr); + ltk_error *err +); -#endif /* _LTK_LABEL_H_ */ +#endif /* LTK_LABEL_H */ diff --git a/src/ltkd.c b/src/ltkd.c @@ -126,8 +126,9 @@ static int push_token(struct token_list *tl, char *token); static int read_sock(struct ltk_sock_info *sock); static int write_sock(struct ltk_sock_info *sock); static int queue_sock_write(struct ltk_sock_info *sock, const char *str, int len); +static int queue_sock_write_fmt(struct ltk_sock_info *sock, const char *fmt, ...); static int tokenize_command(struct ltk_sock_info *sock); -static int ltk_set_root_widget_cmd(ltk_window *window, char **tokens, int num_tokens, char **errstr); +static int ltk_set_root_widget_cmd(ltk_window *window, char **tokens, int num_tokens, ltk_error *err); 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); @@ -471,14 +472,18 @@ ltk_set_root_widget_cmd( ltk_window *window, char **tokens, int num_tokens, - char **errstr) { + ltk_error *err) { ltk_widget *widget; if (num_tokens != 2) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; + return 1; + } + widget = ltk_get_widget(tokens[1], LTK_WIDGET, err); + if (!widget) { + err->arg = 1; return 1; } - widget = ltk_get_widget(tokens[1], LTK_WIDGET, errstr); - if (!widget) return 1; window->root_widget = widget; ltk_window_invalidate_rect(window, widget->rect); widget->rect.w = window->rect.w; @@ -1050,8 +1055,7 @@ static int read_sock(struct ltk_sock_info *sock) { int nread; char *old = sock->read; - int ret = ltk_grow_string(&sock->read, &sock->read_alloc, sock->read_len + READ_BLK_SIZE); - if (ret) return -1; /* fixme: errno? */ + ltk_grow_string(&sock->read, &sock->read_alloc, sock->read_len + READ_BLK_SIZE); /* move tokens to new addresses - this was added as an afterthought and really needs to be cleaned up */ if (sock->read != old) { @@ -1097,25 +1101,28 @@ write_sock(struct ltk_sock_info *sock) { return 0; } -/* Queue `str` to be written to the socket. If len is < 0, it is set to `strlen(str)`. - Returns -1 on error, 0 otherwise. - Note: The string must include all '\n', etc. as defined in the protocol. This - function just adds the given string verbatim. */ -static int -queue_sock_write(struct ltk_sock_info *sock, const char *str, int len) { +static void +move_write_pos(struct ltk_sock_info *sock) { if (sock->write_cur > 0) { memmove(sock->to_write, sock->to_write + sock->write_cur, sock->write_len - sock->write_cur); sock->write_len -= sock->write_cur; sock->write_cur = 0; } +} +/* Queue `str` to be written to the socket. If len is < 0, it is set to `strlen(str)`. + Returns -1 on error, 0 otherwise. + Note: The string must include all '\n', etc. as defined in the protocol. This + function just adds the given string verbatim. */ +static int +queue_sock_write(struct ltk_sock_info *sock, const char *str, int len) { + move_write_pos(sock); if (len < 0) len = strlen(str); - if (sock->write_alloc - sock->write_len < len && - ltk_grow_string(&sock->to_write, &sock->write_alloc, sock->write_len + len)) - return -1; + if (sock->write_alloc - sock->write_len < len) + ltk_grow_string(&sock->to_write, &sock->write_alloc, sock->write_len + len); (void)strncpy(sock->to_write + sock->write_len, str, len); sock->write_len += len; @@ -1125,6 +1132,28 @@ queue_sock_write(struct ltk_sock_info *sock, const char *str, int len) { return 0; } +static int +queue_sock_write_fmt(struct ltk_sock_info *sock, const char *fmt, ...) { + move_write_pos(sock); + va_list args; + va_start(args, fmt); + int len = vsnprintf(sock->to_write + sock->write_len, sock->write_alloc - sock->write_len, fmt, args); + if (len < 0) { + ltk_fatal("Unable to print formatted text to socket.\n"); + } else if (len >= sock->write_alloc - sock->write_len) { + va_end(args); + va_start(args, fmt); + /* snprintf always writes '\0', even though we don't actually need it here */ + ltk_grow_string(&sock->to_write, &sock->write_alloc, sock->write_len + len + 1); + vsnprintf(sock->to_write + sock->write_len, sock->write_alloc - sock->write_len, fmt, args); + } + va_end(args); + sock->write_len += len; + sock_write_available = 1; + + return 0; +} + /* Tokenize the current read buffer in `sock`. Returns 0 immediately if the end of a command was encountered, 1 otherwise. */ static int @@ -1169,7 +1198,7 @@ static void process_commands(ltk_window *window, struct ltk_sock_info *sock) { char **tokens; int num_tokens; - char *errstr; + ltk_error errdetail = {ERR_NONE, -1}; int err; while (!tokenize_command(sock)) { err = 0; @@ -1178,36 +1207,34 @@ process_commands(ltk_window *window, struct ltk_sock_info *sock) { if (num_tokens < 1) continue; if (strcmp(tokens[0], "grid") == 0) { - err = ltk_grid_cmd(window, tokens, num_tokens, &errstr); + err = ltk_grid_cmd(window, tokens, num_tokens, &errdetail); } else if (strcmp(tokens[0], "box") == 0) { - err = ltk_box_cmd(window, tokens, num_tokens, &errstr); + err = ltk_box_cmd(window, tokens, num_tokens, &errdetail); } else if (strcmp(tokens[0], "button") == 0) { - err = ltk_button_cmd(window, tokens, num_tokens, &errstr); + err = ltk_button_cmd(window, tokens, num_tokens, &errdetail); } else if (strcmp(tokens[0], "label") == 0) { - err = ltk_label_cmd(window, tokens, num_tokens, &errstr); + err = ltk_label_cmd(window, tokens, num_tokens, &errdetail); } else if (strcmp(tokens[0], "menu") == 0) { - err = ltk_menu_cmd(window, tokens, num_tokens, &errstr); + err = ltk_menu_cmd(window, tokens, num_tokens, &errdetail); } else if (strcmp(tokens[0], "submenu") == 0) { - err = ltk_menu_cmd(window, tokens, num_tokens, &errstr); + err = ltk_menu_cmd(window, tokens, num_tokens, &errdetail); } else if (strcmp(tokens[0], "menuentry") == 0) { - err = ltk_menuentry_cmd(window, tokens, num_tokens, &errstr); + err = ltk_menuentry_cmd(window, tokens, num_tokens, &errdetail); } else if (strcmp(tokens[0], "set-root-widget") == 0) { - err = ltk_set_root_widget_cmd(window, tokens, num_tokens, &errstr); -/* - } else if (strcmp(tokens[0], "draw") == 0) { - err = ltk_draw_cmd(window, tokens, num_tokens, &errstr); -*/ + err = ltk_set_root_widget_cmd(window, tokens, num_tokens, &errdetail); } else if (strcmp(tokens[0], "quit") == 0) { ltk_quit(window); } else if (strcmp(tokens[0], "destroy") == 0) { - err = ltk_widget_destroy_cmd(window, tokens, num_tokens, &errstr); + err = ltk_widget_destroy_cmd(window, tokens, num_tokens, &errdetail); } else { - errstr = "Invalid command.\n"; + errdetail.type = ERR_INVALID_COMMAND; + errdetail.arg = -1; err = 1; } sock->tokens.num_tokens = 0; if (err) { - if (queue_sock_write(sock, errstr, -1) < 0) + const char *errmsg = errtype_to_string(errdetail.type); + if (queue_sock_write_fmt(sock, "err %d arg %d msg \"%s\"\n", errdetail.type, errdetail.arg, errmsg) < 0) ltk_fatal("Unable to queue socket write.\n"); } } diff --git a/src/menu.c b/src/menu.c @@ -111,10 +111,10 @@ static void ltk_menuentry_destroy(ltk_widget *self, int shallow); static void ltk_menuentry_change_state(ltk_widget *self, ltk_widget_state old_state); static int ltk_menuentry_mouse_release(ltk_widget *self, ltk_button_event *event); static void ltk_menuentry_recalc_ideal_size(ltk_menuentry *entry); -static void ltk_menuentry_attach_submenu(ltk_menuentry *e, ltk_menu *submenu, char **errstr); +static int ltk_menuentry_attach_submenu(ltk_menuentry *e, ltk_menu *submenu, ltk_error *err); static void ltk_menuentry_detach_submenu(ltk_menuentry *e); -static int ltk_menu_remove_child(ltk_widget *widget, ltk_widget *self, char **errstr); +static int ltk_menu_remove_child(ltk_widget *widget, ltk_widget *self, ltk_error *err); #define IN_SUBMENU(e) (e->widget.parent && e->widget.parent->vtable->type == LTK_MENU && ((ltk_menu *)e->widget.parent)->is_submenu) @@ -305,7 +305,6 @@ ltk_menuentry_change_state(ltk_widget *self, ltk_widget_state old_state) { } else if (((self->state & LTK_PRESSED) || ((self->state & LTK_ACTIVE) && (in_submenu || submenus_opened))) && e->submenu && e->submenu->widget.hidden) { - printf("popup: %s, %d, %d, %d\n", self->id, submenus_opened, self->state, self->parent->hidden); popup_active_menu(e); if (self->parent && self->parent->vtable->type == LTK_MENU) ((ltk_menu *)self->parent)->popup_submenus = 1; @@ -389,7 +388,6 @@ ltk_menu_draw(ltk_widget *self, ltk_rect clip) { ltk_menuentry_draw(&menu->entries[i]->widget, clip_final); i++; } else { - ltk_widget *widget = &menu->entries[i]->widget; ltk_menuentry_draw(&menu->entries[i]->widget, clip_final); } } @@ -460,7 +458,6 @@ ltk_menu_resize(ltk_widget *self) { int mbw = t->border_width; int cur_abs_x = -(int)menu->x_scroll_offset + rect.x + start_x + t->pad; int cur_abs_y = -(int)menu->y_scroll_offset + rect.y + start_y + t->pad; - printf("%d, %d\n", self->rect.x, self->rect.w); for (size_t i = 0; i < menu->num_entries; i++) { ltk_menuentry *e = menu->entries[i]; @@ -667,7 +664,6 @@ ltk_menu_hide(ltk_widget *self) { /* FIXME: this is really ugly/hacky */ if (menu->unpopup_submenus_on_hide && self->parent && self->parent->vtable->type == LTK_MENUENTRY && self->parent->parent && self->parent->parent->vtable->type == LTK_MENU) { - printf("hide: %s\n", self->id); ((ltk_menu *)self->parent->parent)->popup_submenus = 0; } menu->unpopup_submenus_on_hide = 1; @@ -951,36 +947,37 @@ ltk_menuentry_destroy(ltk_widget *self, int shallow) { ltk_free(e); } -static void -ltk_menu_insert_entry(ltk_menu *menu, ltk_menuentry *entry, size_t idx, char **errstr) { +static int +ltk_menu_insert_entry(ltk_menu *menu, ltk_menuentry *entry, size_t idx, ltk_error *err) { if (entry->widget.parent) { - *errstr = "Entry already part of other menu.\n"; - return; + err->type = ERR_WIDGET_IN_CONTAINER; + return 1; } if (insert_entry(menu, entry, idx)) { - *errstr = "Illegal index.\n"; - return; + err->type = ERR_INVALID_INDEX; + return 1; } entry->widget.parent = &menu->widget; ltk_menuentry_recalc_ideal_size(entry); recalc_ideal_menu_size(&menu->widget, NULL); menu->widget.dirty = 1; + return 0; } -static void -ltk_menu_add_entry(ltk_menu *menu, ltk_menuentry *entry, char **errstr) { - ltk_menu_insert_entry(menu, entry, menu->num_entries, errstr); +static int +ltk_menu_add_entry(ltk_menu *menu, ltk_menuentry *entry, ltk_error *err) { + return ltk_menu_insert_entry(menu, entry, menu->num_entries, err); } /* FIXME: maybe allow any menu and just change is_submenu (also need to recalculate size then) */ -static void -ltk_menuentry_attach_submenu(ltk_menuentry *e, ltk_menu *submenu, char **errstr) { +static int +ltk_menuentry_attach_submenu(ltk_menuentry *e, ltk_menu *submenu, ltk_error *err) { if (!submenu->is_submenu) { - *errstr = "Not a submenu.\n"; - return; + err->type = ERR_MENU_NOT_SUBMENU; + return 1; } else if (e->submenu) { - *errstr = "Menu entry already has attached submenu.\n"; - return; + err->type = ERR_MENU_ENTRY_CONTAINS_SUBMENU; + return 1; } e->submenu = submenu; ltk_menuentry_recalc_ideal_size(e); @@ -991,6 +988,7 @@ ltk_menuentry_attach_submenu(ltk_menuentry *e, ltk_menu *submenu, char **errstr) } if (!e->widget.hidden) ltk_window_invalidate_rect(e->widget.window, e->widget.rect); + return 0; } /* FIXME: hide all entries when menu hidden? */ @@ -1005,9 +1003,9 @@ shrink_entries(ltk_menu *menu) { } static int -ltk_menu_remove_entry_index(ltk_menu *menu, size_t idx, char **errstr) { +ltk_menu_remove_entry_index(ltk_menu *menu, size_t idx, ltk_error *err) { if (idx >= menu->num_entries) { - *errstr = "Invalid menu entry index.\n"; + err->type = ERR_INVALID_INDEX; return 1; } menu->entries[idx]->widget.parent = NULL; @@ -1033,25 +1031,24 @@ get_entry_with_id(ltk_menu *menu, const char *id) { } static int -ltk_menu_remove_entry_id(ltk_menu *menu, const char *id, char **errstr) { +ltk_menu_remove_entry_id(ltk_menu *menu, const char *id, ltk_error *err) { size_t idx = get_entry_with_id(menu, id); if (idx >= menu->num_entries) { - *errstr = "Invalid menu entry id.\n"; + err->type = ERR_INVALID_WIDGET_ID; return 1; } - ltk_menu_remove_entry_index(menu, idx, errstr); - return 0; + return ltk_menu_remove_entry_index(menu, idx, err); } static int -ltk_menu_remove_child(ltk_widget *child, ltk_widget *self, char **errstr) { +ltk_menu_remove_child(ltk_widget *child, ltk_widget *self, ltk_error *err) { ltk_menu *menu = (ltk_menu *)self; for (size_t i = 0; i < menu->num_entries; i++) { if (&menu->entries[i]->widget == child) { - return ltk_menu_remove_entry_index(menu, i, errstr); + return ltk_menu_remove_entry_index(menu, i, err); } } - *errstr = "Widget not contained in menu.\n"; + err->type = ERR_WIDGET_NOT_IN_CONTAINER; return 1; } @@ -1108,14 +1105,16 @@ ltk_menu_cmd_create( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { ltk_menu *menu; if (num_tokens != 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (!ltk_widget_id_free(tokens[1])) { - *errstr = "Widget ID already taken.\n"; + err->type = ERR_WIDGET_ID_IN_USE; + err->arg = 1; return 1; } if (!strcmp(tokens[0], "menu")) { @@ -1134,36 +1133,36 @@ ltk_menu_cmd_insert_entry( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_menu *menu; ltk_menuentry *e; const char *errstr_num; if (num_tokens != 5) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - /* FIXME: actually use this errstr */ - menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, errstr); + menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, err); if (!menu) { - *errstr = "Invalid widget ID.\n"; + err->arg = 1; return 1; } - e = (ltk_menuentry *)ltk_get_widget(tokens[3], LTK_MENUENTRY, errstr); + e = (ltk_menuentry *)ltk_get_widget(tokens[3], LTK_MENUENTRY, err); if (!e) { - *errstr = "Invalid widget ID.\n"; + err->arg = 3; return 1; } size_t idx = (size_t)ltk_strtonum(tokens[5], 0, (long long)menu->num_entries, &errstr_num); if (errstr_num) { - *errstr = "Invalid index.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 5; return 1; } - *errstr = NULL; - ltk_menu_insert_entry(menu, e, idx, errstr); - if (*errstr) + if (ltk_menu_insert_entry(menu, e, idx, err)) { + err->arg = err->type == ERR_WIDGET_IN_CONTAINER ? 3 : 5; return 1; - + } return 0; } @@ -1173,29 +1172,29 @@ ltk_menu_cmd_add_entry( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_menu *menu; ltk_menuentry *e; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, errstr); + menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, err); if (!menu) { - *errstr = "Invalid widget ID.\n"; + err->arg = 1; return 1; } - e = (ltk_menuentry *)ltk_get_widget(tokens[3], LTK_MENUENTRY, errstr); + e = (ltk_menuentry *)ltk_get_widget(tokens[3], LTK_MENUENTRY, err); if (!e) { - *errstr = "Invalid widget ID.\n"; + err->arg = 3; return 1; } - *errstr = NULL; - ltk_menu_add_entry(menu, e, errstr); - if (*errstr) + if (ltk_menu_add_entry(menu, e, err)) { + err->arg = err->type == ERR_WIDGET_IN_CONTAINER ? 3 : 5; return 1; - + } return 0; } @@ -1205,26 +1204,30 @@ ltk_menu_cmd_remove_entry_index( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_menu *menu; const char *errstr_num; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, errstr); + menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, err); if (!menu) { - *errstr = "Invalid widget ID.\n"; + err->arg = 1; return 1; } size_t idx = (size_t)ltk_strtonum(tokens[3], 0, (long long)menu->num_entries, &errstr_num); if (errstr_num) { - *errstr = "Invalid index.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 3; return 1; } - if (!ltk_menu_remove_entry_index(menu, idx, errstr)) + if (!ltk_menu_remove_entry_index(menu, idx, err)) { + err->arg = 3; return 1; + } return 0; } @@ -1235,20 +1238,23 @@ ltk_menu_cmd_remove_entry_id( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_menu *menu; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, errstr); + menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, err); if (!menu) { - *errstr = "Invalid widget ID.\n"; + err->arg = 1; return 1; } - if (!ltk_menu_remove_entry_id(menu, tokens[3], errstr)) + if (!ltk_menu_remove_entry_id(menu, tokens[3], err)) { + err->arg = 3; return 1; + } return 0; } @@ -1259,16 +1265,17 @@ ltk_menu_cmd_remove_all_entries( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_menu *menu; if (num_tokens != 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, errstr); + menu = (ltk_menu *)ltk_get_widget(tokens[1], LTK_MENU, err); if (!menu) { - *errstr = "Invalid widget ID.\n"; + err->arg = 1; return 1; } ltk_menu_remove_all_entries(menu); @@ -1282,14 +1289,16 @@ ltk_menuentry_cmd_create( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { ltk_menuentry *e; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (!ltk_widget_id_free(tokens[1])) { - *errstr = "Widget ID already taken.\n"; + err->type = ERR_WIDGET_ID_IN_USE; + err->arg = 1; return 1; } e = ltk_menuentry_create(window, tokens[1], tokens[3]); @@ -1304,30 +1313,30 @@ ltk_menuentry_cmd_attach_submenu( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_menuentry *e; ltk_menu *submenu; if (num_tokens != 4) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - e = (ltk_menuentry *)ltk_get_widget(tokens[1], LTK_MENUENTRY, errstr); + e = (ltk_menuentry *)ltk_get_widget(tokens[1], LTK_MENUENTRY, err); if (!e) { - *errstr = "Invalid entry widget ID.\n"; + err->arg = 1; return 1; } - submenu = (ltk_menu *)ltk_get_widget(tokens[3], LTK_MENU, errstr); + submenu = (ltk_menu *)ltk_get_widget(tokens[3], LTK_MENU, err); if (!submenu) { - *errstr = "Invalid submenu widget ID.\n"; + err->arg = 3; return 1; } - *errstr = NULL; - ltk_menuentry_attach_submenu(e, submenu, errstr); - if (*errstr) + if (ltk_menuentry_attach_submenu(e, submenu, err)) { + err->arg = err->type == ERR_MENU_NOT_SUBMENU ? 3 : 1; return 1; - + } return 0; } @@ -1337,16 +1346,17 @@ ltk_menuentry_cmd_detach_submenu( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; ltk_menuentry *e; if (num_tokens != 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } - e = (ltk_menuentry *)ltk_get_widget(tokens[1], LTK_MENUENTRY, errstr); + e = (ltk_menuentry *)ltk_get_widget(tokens[1], LTK_MENUENTRY, err); if (!e) { - *errstr = "Invalid widget ID.\n"; + err->arg = 1; return 1; } @@ -1364,25 +1374,27 @@ ltk_menu_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { if (num_tokens < 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (strcmp(tokens[2], "create") == 0) { - return ltk_menu_cmd_create(window, tokens, num_tokens, errstr); + return ltk_menu_cmd_create(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "insert-entry") == 0) { - return ltk_menu_cmd_insert_entry(window, tokens, num_tokens, errstr); + return ltk_menu_cmd_insert_entry(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "add-entry") == 0) { - return ltk_menu_cmd_add_entry(window, tokens, num_tokens, errstr); + return ltk_menu_cmd_add_entry(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "remove-entry-index") == 0) { - return ltk_menu_cmd_remove_entry_index(window, tokens, num_tokens, errstr); + return ltk_menu_cmd_remove_entry_index(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "remove-entry-id") == 0) { - return ltk_menu_cmd_remove_entry_id(window, tokens, num_tokens, errstr); + return ltk_menu_cmd_remove_entry_id(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "remove-all-entries") == 0) { - return ltk_menu_cmd_remove_all_entries(window, tokens, num_tokens, errstr); + return ltk_menu_cmd_remove_all_entries(window, tokens, num_tokens, err); } else { - *errstr = "Invalid command.\n"; + err->type = ERR_INVALID_COMMAND; + err->arg = -1; return 1; } @@ -1395,19 +1407,21 @@ ltk_menuentry_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { if (num_tokens < 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (strcmp(tokens[2], "create") == 0) { - return ltk_menuentry_cmd_create(window, tokens, num_tokens, errstr); + return ltk_menuentry_cmd_create(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "attach-submenu") == 0) { - return ltk_menuentry_cmd_attach_submenu(window, tokens, num_tokens, errstr); + return ltk_menuentry_cmd_attach_submenu(window, tokens, num_tokens, err); } else if (strcmp(tokens[2], "detach-submenu") == 0) { - return ltk_menuentry_cmd_detach_submenu(window, tokens, num_tokens, errstr); + return ltk_menuentry_cmd_detach_submenu(window, tokens, num_tokens, err); } else { - *errstr = "Invalid command.\n"; + err->type = ERR_INVALID_COMMAND; + err->arg = -1; return 1; } diff --git a/src/menu.h b/src/menu.h @@ -14,8 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _LTK_MENU_H_ -#define _LTK_MENU_H_ +#ifndef LTK_MENU_H +#define LTK_MENU_H #include "ltk.h" #include "text.h" @@ -72,14 +72,14 @@ int ltk_menu_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr + ltk_error *err ); int ltk_menuentry_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr + ltk_error *err ); -#endif /* _LTK_MENU_H_ */ +#endif /* LTK_MENU_H */ diff --git a/src/util.c b/src/util.c @@ -47,14 +47,13 @@ ltk_read_file(const char *path, unsigned long *len) { /* If `needed` is larger than `*alloc_size`, resize `*str` to `max(needed, *alloc_size * 2)`. Aborts program on error. */ -int +void ltk_grow_string(char **str, int *alloc_size, int needed) { - if (needed <= *alloc_size) return 0; + if (needed <= *alloc_size) return; int new_size = needed > (*alloc_size * 2) ? needed : (*alloc_size * 2); char *new = ltk_realloc(*str, new_size); *str = new; *alloc_size = new_size; - return 0; } /* Get the directory to store ltk files in and create it if it doesn't exist yet. diff --git a/src/util.h b/src/util.h @@ -25,7 +25,7 @@ long long ltk_strtonum( ); char *ltk_read_file(const char *path, unsigned long *len); -int ltk_grow_string(char **str, int *alloc_size, int needed); +void ltk_grow_string(char **str, int *alloc_size, int needed); char *ltk_setup_directory(void); char *ltk_strcat_useful(const char *str1, const char *str2); diff --git a/src/widget.c b/src/widget.c @@ -42,12 +42,12 @@ ltk_destroy_widget_hash(void) { hash_locked = 1; khint_t k; ltk_widget *ptr; - char *errstr; + ltk_error err; for (k = kh_begin(widget_hash); k != kh_end(widget_hash); k++) { if (kh_exist(widget_hash, k)) { ptr = kh_value(widget_hash, k); ltk_free((char *)kh_key(widget_hash, k)); - ltk_widget_destroy(ptr, 1, &errstr); + ltk_widget_destroy(ptr, 1, &err); } } kh_destroy(widget, widget_hash); @@ -320,17 +320,17 @@ ltk_widget_id_free(const char *id) { } ltk_widget * -ltk_get_widget(const char *id, ltk_widget_type type, char **errstr) { +ltk_get_widget(const char *id, ltk_widget_type type, ltk_error *err) { 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"; + err->type = ERR_INVALID_WIDGET_ID; return NULL; } widget = kh_value(widget_hash, k); if (type != LTK_WIDGET && widget->vtable->type != type) { - *errstr = "Widget with given ID has wrong type.\n"; + err->type = ERR_INVALID_WIDGET_TYPE; return NULL; } return widget; @@ -359,18 +359,18 @@ ltk_remove_widget(const char *id) { } int -ltk_widget_destroy(ltk_widget *widget, int shallow, char **errstr) { +ltk_widget_destroy(ltk_widget *widget, int shallow, ltk_error *err) { /* 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... */ - int err = 0; + int invalid = 0; if (widget->parent && widget->parent->vtable->remove_child) { - err = widget->parent->vtable->remove_child( - widget, widget->parent, errstr + invalid = widget->parent->vtable->remove_child( + widget, widget->parent, err ); } widget->vtable->destroy(widget, shallow); - return err; + return invalid; } int @@ -378,11 +378,12 @@ ltk_widget_destroy_cmd( ltk_window *window, char **tokens, size_t num_tokens, - char **errstr) { + ltk_error *err) { (void)window; int shallow = 1; if (num_tokens != 2 && num_tokens != 3) { - *errstr = "Invalid number of arguments.\n"; + err->type = ERR_INVALID_NUMBER_OF_ARGUMENTS; + err->arg = -1; return 1; } if (num_tokens == 3) { @@ -391,14 +392,19 @@ ltk_widget_destroy_cmd( } else if (strcmp(tokens[2], "shallow") == 0) { shallow = 1; } else { - *errstr = "Invalid argument: must be 'shallow' or 'deep'.\n"; + err->type = ERR_INVALID_ARGUMENT; + err->arg = 2; return 1; } } - ltk_widget *widget = ltk_get_widget(tokens[1], LTK_WIDGET, errstr); + ltk_widget *widget = ltk_get_widget(tokens[1], LTK_WIDGET, err); if (!widget) { - *errstr = "Invalid widget ID.\n"; + err->arg = 1; return 1; } - return ltk_widget_destroy(widget, shallow, errstr); + if (ltk_widget_destroy(widget, shallow, err)) { + err->arg = -1; + return 1; + } + return 0; } diff --git a/src/widget.h b/src/widget.h @@ -17,11 +17,13 @@ #ifndef LTK_WIDGET_H #define LTK_WIDGET_H +#include "err.h" #include "rect.h" #include "event.h" /* FIXME: SORT OUT INCLUDES PROPERLY! */ + typedef struct ltk_widget ltk_widget; typedef enum { @@ -125,7 +127,7 @@ struct ltk_widget_vtable { struct ltk_widget *(*first_child)(struct ltk_widget *self); void (*child_size_change) (struct ltk_widget *, struct ltk_widget *); - int (*remove_child)(struct ltk_widget *, struct ltk_widget *, char **); + int (*remove_child)(struct ltk_widget *, struct ltk_widget *, ltk_error *); struct ltk_widget *(*get_child_at_pos)(struct ltk_widget *, int x, int y); ltk_widget_type type; @@ -133,8 +135,8 @@ struct ltk_widget_vtable { }; void ltk_widget_hide(ltk_widget *widget); -int ltk_widget_destroy(ltk_widget *widget, int shallow, char **errstr); -int ltk_widget_destroy_cmd(struct ltk_window *window, char **tokens, size_t num_tokens, char **errstr); +int ltk_widget_destroy(ltk_widget *widget, int shallow, ltk_error *err); +int ltk_widget_destroy_cmd(struct ltk_window *window, char **tokens, size_t num_tokens, ltk_error *err); void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, struct ltk_window *window, struct ltk_widget_vtable *vtable, int w, int h); void ltk_widget_change_state(ltk_widget *widget, ltk_widget_state old_state); @@ -144,7 +146,7 @@ void ltk_window_mouse_release_event(ltk_window *window, ltk_button_event *event) void ltk_window_motion_notify_event(ltk_window *window, ltk_motion_event *event); void ltk_window_fake_motion_event(ltk_window *window, int x, int y); int ltk_widget_id_free(const char *id); -ltk_widget *ltk_get_widget(const char *id, ltk_widget_type type, char **errstr); +ltk_widget *ltk_get_widget(const char *id, ltk_widget_type type, ltk_error *err); void ltk_set_widget(ltk_widget *widget, const char *id); void ltk_remove_widget(const char *id); void ltk_widgets_cleanup();