commit 488ed473efaa6153752374f9c27f67fe45dc4823
parent 480c476bee3efca10facb5ff2be6863bf112b72a
Author: lumidify <nobody@lumidify.org>
Date: Thu, 23 Jun 2022 12:37:01 +0200
Standardize error handling
Diffstat:
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();