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 236104387a38581c2d7e0b50dd208d6f2db4e312
parent ffdfc8d4bc5e24eab86b857e637d60c7521bf0b0
Author: lumidify <nobody@lumidify.org>
Date:   Wed, 30 Dec 2020 21:37:51 +0100

Improve error reporting

Diffstat:
Mbutton.c | 44++++++++++++++++++++++++++++----------------
Mbutton.h | 5+++--
Mcolor.c | 3++-
Mdraw.c | 230++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mdraw.h | 5+++--
Mgrid.c | 264+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mgrid.h | 2+-
Mltk.h | 7++++---
Mltkd.c | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mtext_pango.c | 4+++-
Mtext_stb.c | 12++++++------
Mutil.c | 3++-
12 files changed, 403 insertions(+), 292 deletions(-)

diff --git a/button.c b/button.c @@ -196,15 +196,18 @@ ltk_button_mouse_release(ltk_button *button, XEvent event) { static ltk_button * ltk_button_create(ltk_window *window, const char *id, const char *text) { + char *text_copy; ltk_button *button = malloc(sizeof(ltk_button)); - if (!button) ltk_fatal("ERROR: Unable to allocate memory for ltk_button.\n"); + if (!button) ltk_fatal_errno("Unable to allocate memory for ltk_button.\n"); ltk_fill_widget_defaults(&button->widget, id, window, &ltk_button_draw, &ltk_button_change_state, &ltk_button_destroy, 1, LTK_BUTTON); button->widget.mouse_release = &ltk_button_mouse_release; uint16_t font_size = window->theme.font_size; - /* FIXME: check return of strdup */ - button->tl = ltk_text_line_create(window->xwindow, font_size, strdup(text), -1); + text_copy = strdup(text); + if (!text_copy) + ltk_fatal_errno("Unable to allocate button text.\n"); + button->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1); int text_w, text_h; ltk_text_line_get_size(button->tl, &text_w, &text_h); button->widget.rect.w = text_w + theme.border_width * 2 + theme.pad * 2; @@ -218,7 +221,7 @@ ltk_button_create(ltk_window *window, const char *id, const char *text) { static void ltk_button_destroy(ltk_button *button, int shallow) { if (!button) { - (void)printf("WARNING: Tried to destroy NULL button.\n"); + ltk_warn("Tried to destroy NULL button.\n"); return; } ltk_text_line_destroy(button->tl); @@ -228,35 +231,44 @@ ltk_button_destroy(ltk_button *button, int shallow) { } /* button <button id> create <text> */ -static void +static int ltk_button_cmd_create( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_button *button; if (num_tokens != 4) { - (void)fprintf(stderr, "button create: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; + } + if (!ltk_widget_id_free(window, tokens[1])) { + *errstr = "Widget ID already taken.\n"; + return 1; } - if (!ltk_check_widget_id_free(window, tokens[1], "button create")) - return; button = ltk_button_create(window, tokens[1], tokens[3]); ltk_set_widget(window, button, tokens[1]); + + return 0; } /* button <button id> <command> ... */ -void +int ltk_button_cmd( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { if (num_tokens < 3) { - (void)fprintf(stderr, "button: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } if (strcmp(tokens[2], "create") == 0) { - ltk_button_cmd_create(window, tokens, num_tokens); + return ltk_button_cmd_create(window, tokens, num_tokens, errstr); } else { - (void)fprintf(stderr, "button: Invalid command.\n"); + *errstr = "Invalid command.\n"; + return 1; } + + return 0; } diff --git a/button.h b/button.h @@ -35,9 +35,10 @@ typedef struct { void ltk_button_setup_theme_defaults(ltk_window *window); void ltk_button_ini_handler(ltk_window *window, const char *prop, const char *value); -void ltk_button_cmd( +int ltk_button_cmd( ltk_window *window, char **tokens, - size_t num_tokens); + size_t num_tokens, + char **errstr); #endif /* _LTK_BUTTON_H_ */ diff --git a/color.c b/color.c @@ -7,7 +7,8 @@ void ltk_color_create(Display *dpy, int screen, Colormap cm, const char *hex, LtkColor *col) { if (!XParseColor(dpy, cm, hex, &col->xcolor)) { - /* FIXME: better error reporting */ + /* FIXME: better error reporting!!! */ + /* FIXME: remove obsolete ltk_err function */ ltk_err("ltk_color_create"); } XAllocColor(dpy, cm, &col->xcolor); diff --git a/draw.c b/draw.c @@ -40,26 +40,31 @@ static void ltk_draw_clear(ltk_window *window, ltk_draw *draw); static void ltk_draw_set_color(ltk_window *window, ltk_draw *draw, const char *color); static void ltk_draw_line(ltk_window *window, ltk_draw *draw, int x1, int y1, int x2, int y2); static void ltk_draw_rect(ltk_window *window, ltk_draw *draw, int x, int y, int w, int h, int fill); -static void ltk_draw_cmd_clear( +static int ltk_draw_cmd_clear( ltk_window *window, char **tokens, - size_t num_tokens); -static void ltk_draw_cmd_set_color( + size_t num_tokens, + char **errstr); +static int ltk_draw_cmd_set_color( ltk_window *window, char **tokens, - size_t num_tokens); -static void ltk_draw_cmd_line( + size_t num_tokens, + char **errstr); +static int ltk_draw_cmd_line( ltk_window *window, char **tokens, - size_t num_tokens); -static void ltk_draw_cmd_rect( + size_t num_tokens, + char **errstr); +static int ltk_draw_cmd_rect( ltk_window *window, char **tokens, - size_t num_tokens); -static void ltk_draw_cmd_create( + size_t num_tokens, + char **errstr); +static int ltk_draw_cmd_create( ltk_window *window, char **tokens, - size_t num_tokens); + size_t num_tokens, + char **errstr); static void ltk_draw_draw(ltk_draw *draw) { @@ -73,7 +78,7 @@ static ltk_draw * ltk_draw_create(ltk_window *window, const char *id, int w, int h, const char *color) { XWindowAttributes attrs; ltk_draw *draw = malloc(sizeof(ltk_draw)); - if (!draw) ltk_fatal("ERROR: Unable to allocate memory for ltk_draw.\n"); + if (!draw) ltk_fatal_errno("Unable to allocate memory for ltk_draw.\n"); ltk_fill_widget_defaults(&draw->widget, id, window, &ltk_draw_draw, NULL, &ltk_draw_destroy, 1, LTK_DRAW); @@ -85,7 +90,7 @@ ltk_draw_create(ltk_window *window, const char *id, int w, int h, const char *co draw->pix = XCreatePixmap(window->dpy, window->xwindow, w, h, draw->depth); if (!ltk_create_xcolor(window, color, &draw->bg)) { free(draw); - return NULL; + ltk_fatal_errno("Unable to allocate XColor.\n"); } draw->fg = draw->bg; XSetForeground(window->dpy, window->gc, draw->bg.pixel); @@ -120,7 +125,7 @@ ltk_draw_resize(ltk_draw *draw, int orig_w, int orig_h) { static void ltk_draw_destroy(ltk_draw *draw, int shallow) { if (!draw) { - (void)printf("WARNING: Tried to destroy NULL draw.\n"); + ltk_warn("Tried to destroy NULL draw.\n"); return; } ltk_remove_widget(draw->widget.window, draw->widget.id); @@ -139,6 +144,7 @@ ltk_draw_clear(ltk_window *window, ltk_draw *draw) { ltk_draw_draw(draw); } +/* FIXME: Error return */ static void ltk_draw_set_color(ltk_window *window, ltk_draw *draw, const char *color) { XColor tmp; @@ -183,166 +189,186 @@ ltk_draw_rect(ltk_window *window, ltk_draw *draw, int x, int y, int w, int h, in } } -static void +static int ltk_draw_cmd_clear( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_draw *draw; if (num_tokens != 3) { - (void)fprintf(stderr, "draw clear: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - draw = ltk_get_widget(window, tokens[1], LTK_DRAW, "draw clear"); - if (!draw) return; + draw = ltk_get_widget(window, tokens[1], LTK_DRAW, errstr); + if (!draw) return 1; ltk_draw_clear(window, draw); + + return 0; } -static void +static int ltk_draw_cmd_set_color( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_draw *draw; if (num_tokens != 4) { - (void)fprintf(stderr, "draw set-color: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - draw = ltk_get_widget(window, tokens[1], LTK_DRAW, "draw set-color"); - if (!draw) return; + draw = ltk_get_widget(window, tokens[1], LTK_DRAW, errstr); + if (!draw) return 1; ltk_draw_set_color(window, draw, tokens[3]); + + return 0; } -static void +static int ltk_draw_cmd_line( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_draw *draw; int x1, y1, x2, y2; - const char *errstr; + const char *errstr_num; if (num_tokens != 7) { - (void)fprintf(stderr, "draw line: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - draw = ltk_get_widget(window, tokens[1], LTK_DRAW, "draw line"); - if (!draw) return; - x1 = strtonum(tokens[3], 0, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw line: Invalid x1: %s\n", errstr); - return; + draw = ltk_get_widget(window, tokens[1], LTK_DRAW, errstr); + if (!draw) return 1; + x1 = strtonum(tokens[3], 0, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid x1.\n"; + return 1; } - y1 = strtonum(tokens[4], 0, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw line: Invalid y1: %s\n", errstr); - return; + y1 = strtonum(tokens[4], 0, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid y1.\n"; + return 1; } - x2 = strtonum(tokens[5], 0, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw line: Invalid x2: %s\n", errstr); - return; + x2 = strtonum(tokens[5], 0, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid x2.\n"; + return 1; } - y2 = strtonum(tokens[6], 0, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw line: Invalid y2: %s\n", errstr); - return; + y2 = strtonum(tokens[6], 0, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid y2.\n"; + return 1; } ltk_draw_line(window, draw, x1, y1, x2, y2); + + return 0; } -static void +static int ltk_draw_cmd_rect( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_draw *draw; - const char *errstr; + const char *errstr_num; int x, y, w, h, fill; if (num_tokens != 8) { - (void)fprintf(stderr, "draw clear: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - draw = ltk_get_widget(window, tokens[1], LTK_DRAW, "draw clear"); - if (!draw) return; - x = strtonum(tokens[3], 0, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw rect: Invalid x: %s\n", errstr); - return; + draw = ltk_get_widget(window, tokens[1], LTK_DRAW, errstr); + if (!draw) return 1; + x = strtonum(tokens[3], 0, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid x.\n"; + return 1; } - y = strtonum(tokens[4], 0, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw rect: Invalid y: %s\n", errstr); - return; + y = strtonum(tokens[4], 0, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid y.\n"; + return 1; } - w = strtonum(tokens[5], 1, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw rect: Invalid width: %s\n", errstr); - return; + w = strtonum(tokens[5], 1, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid width.\n"; + return 1; } - h = strtonum(tokens[6], 1, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw rect: Invalid height: %s\n", errstr); - return; + h = strtonum(tokens[6], 1, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid height.\n"; + return 1; } - fill = strtonum(tokens[7], 0, 1, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw rect: Invalid fill bool: %s\n", errstr); - return; + fill = strtonum(tokens[7], 0, 1, &errstr_num); + if (errstr_num) { + *errstr = "Invalid fill bool.\n"; + return 1; } ltk_draw_rect(window, draw, x, y, w, h, fill); + + return 0; } /* draw <draw id> create <width> <height> <color> */ -static void +static int ltk_draw_cmd_create( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_draw *draw; int w, h; - const char *errstr; + const char *errstr_num; if (num_tokens != 6) { - (void)fprintf(stderr, "draw create: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - if (!ltk_check_widget_id_free(window, tokens[1], "draw create")) - return; - w = strtonum(tokens[3], 1, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw create: Invalid width: %s\n", errstr); - return; + if (!ltk_widget_id_free(window, tokens[1])) { + *errstr = "Widget ID already taken.\n"; + return 1; } - h = strtonum(tokens[4], 1, 100000, &errstr); - if (errstr) { - (void)fprintf(stderr, "draw create: Invalid height: %s\n", errstr); - return; + w = strtonum(tokens[3], 1, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid width.\n"; + return 1; + } + h = strtonum(tokens[4], 1, 100000, &errstr_num); + if (errstr_num) { + *errstr = "Invalid height.\n"; + return 1; } draw = ltk_draw_create(window, tokens[1], w, h, tokens[5]); - if (draw) - ltk_set_widget(window, draw, tokens[1]); + ltk_set_widget(window, draw, tokens[1]); + + return 0; } /* draw <draw id> <command> ... */ -void +int ltk_draw_cmd( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { if (num_tokens < 3) { - (void)fprintf(stderr, "draw: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } if (strcmp(tokens[2], "create") == 0) { - ltk_draw_cmd_create(window, tokens, num_tokens); + return ltk_draw_cmd_create(window, tokens, num_tokens, errstr); } else if (strcmp(tokens[2], "clear") == 0) { - ltk_draw_cmd_clear(window, tokens, num_tokens); + return ltk_draw_cmd_clear(window, tokens, num_tokens, errstr); } else if (strcmp(tokens[2], "set-color") == 0) { - ltk_draw_cmd_set_color(window, tokens, num_tokens); + return ltk_draw_cmd_set_color(window, tokens, num_tokens, errstr); } else if (strcmp(tokens[2], "line") == 0) { - ltk_draw_cmd_line(window, tokens, num_tokens); + return ltk_draw_cmd_line(window, tokens, num_tokens, errstr); } else if (strcmp(tokens[2], "rect") == 0) { - ltk_draw_cmd_rect(window, tokens, num_tokens); + return ltk_draw_cmd_rect(window, tokens, num_tokens, errstr); } else { - (void)fprintf(stderr, "draw: Invalid command.\n"); + *errstr = "Invalid command.\n"; + return 1; } + + return 0; } diff --git a/draw.h b/draw.h @@ -34,9 +34,10 @@ typedef struct { XColor bg; } ltk_draw; -void ltk_draw_cmd( +int ltk_draw_cmd( ltk_window *window, char **tokens, - size_t num_tokens); + size_t num_tokens, + char **errstr); #endif /* _LTK_DRAW_H_ */ diff --git a/grid.c b/grid.c @@ -41,35 +41,40 @@ static ltk_grid *ltk_grid_create(ltk_window *window, const char *id, int rows, int columns); static void ltk_grid_destroy(ltk_grid *grid, int shallow); static void ltk_recalculate_grid(ltk_grid *grid); -static void 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); -static void ltk_grid_ungrid(ltk_window *window, ltk_widget *widget, ltk_grid *grid); +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_window *window, ltk_widget *widget, ltk_grid *grid, char **errstr); 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 void ltk_grid_mouse_press(ltk_grid *grid, XEvent event); static void ltk_grid_mouse_release(ltk_grid *grid, XEvent event); static void ltk_grid_motion_notify(ltk_grid *grid, XEvent event); -static void ltk_grid_cmd_add( +static int ltk_grid_cmd_add( ltk_window *window, char **tokens, - size_t num_tokens); -static void ltk_grid_cmd_ungrid( + size_t num_tokens, + char **errstr); +static int ltk_grid_cmd_ungrid( ltk_window *window, char **tokens, - size_t num_tokens); -static void ltk_grid_cmd_create( + size_t num_tokens, + char **errstr); +static int ltk_grid_cmd_create( ltk_window *window, char **tokens, - size_t num_tokens); -static void ltk_grid_cmd_set_row_weight( + size_t num_tokens, + char **errstr); +static int ltk_grid_cmd_set_row_weight( ltk_window *window, char **tokens, - size_t num_tokens); -static void ltk_grid_cmd_set_column_weight( + size_t num_tokens, + char **errstr); +static int ltk_grid_cmd_set_column_weight( ltk_window *window, char **tokens, - size_t num_tokens); + size_t num_tokens, + char **errstr); static void ltk_grid_set_row_weight(ltk_grid *grid, int row, int weight) { @@ -251,12 +256,12 @@ ltk_recalculate_grid(ltk_grid *grid) { } } -static void +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) { + int row, int column, int row_span, int column_span, unsigned short sticky, char **errstr) { if (row + row_span > grid->rows || column + column_span > grid->columns) { - (void)fprintf(stderr, "Invalid row or column.\n"); - return; + *errstr = "Invalid row or column.\n"; + return 1; } widget->sticky = sticky; widget->row = row; @@ -277,13 +282,15 @@ ltk_grid_add(ltk_window *window, ltk_widget *widget, ltk_grid *grid, widget->parent = grid; ltk_recalculate_grid(grid); ltk_window_invalidate_rect(window, grid->widget.rect); + + return 0; } -static void -ltk_grid_ungrid(ltk_window *window, ltk_widget *widget, ltk_grid *grid) { +static int +ltk_grid_ungrid(ltk_window *window, ltk_widget *widget, ltk_grid *grid, char **errstr) { if (widget->parent != grid) { - (void)fprintf(stderr, "grid remove: Widget isn't gridded in given grid.\n"); - return; + *errstr = "Widget isn't gridded in given grid.\n"; + return 1; } widget->parent = NULL; for (int i = widget->row; i < widget->row + widget->row_span; i++) { @@ -292,6 +299,8 @@ ltk_grid_ungrid(ltk_window *window, ltk_widget *widget, ltk_grid *grid) { } } ltk_window_invalidate_rect(window, grid->widget.rect); + + return 0; } static int @@ -359,175 +368,192 @@ ltk_grid_motion_notify(ltk_grid *grid, XEvent event) { } /* grid <grid id> add <widget id> <row> <column> <row_span> <column_span> <sticky> */ -static void +static int ltk_grid_cmd_add( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_grid *grid; ltk_widget *widget; - const char *errstr; + const char *errstr_num; int row, column, row_span, column_span, sticky; if (num_tokens != 9) { - (void)fprintf(stderr, "grid: Invalid number of arguments.\n"); - return; - } - grid = ltk_get_widget(window, tokens[1], LTK_GRID, "grid add"); - widget = ltk_get_widget(window, tokens[3], LTK_WIDGET, "grid add"); - if (!grid || !widget) return; - row = strtonum(tokens[4], 0, grid->rows - 1, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid add: Invalid row number: %s\n", errstr); - return; - } - column = strtonum(tokens[5], 0, grid->columns - 1, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid add: Invalid column number: %s\n", errstr); - return; - } - row_span = strtonum(tokens[6], 1, grid->rows, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid add: Invalid row_span: %s\n", errstr); - return; - } - column_span = strtonum(tokens[7], 1, grid->columns, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid add: Invalid column_span: %s\n", errstr); - return; - } - sticky = strtonum(tokens[8], 0, 15, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid add: Invalid sticky setting: %s\n", errstr); - return; - } - ltk_grid_add(window, widget, grid, row, column, row_span, column_span, sticky); + *errstr = "Invalid number of arguments.\n"; + return 1; + } + grid = ltk_get_widget(window, tokens[1], LTK_GRID, errstr); + widget = ltk_get_widget(window, tokens[3], LTK_WIDGET, errstr); + if (!grid || !widget) return 1; + row = strtonum(tokens[4], 0, grid->rows - 1, &errstr_num); + if (errstr_num) { + *errstr = "Invalid row number.\n"; + return 1; + } + column = strtonum(tokens[5], 0, grid->columns - 1, &errstr_num); + if (errstr_num) { + *errstr = "Invalid row number.\n"; + return 1; + } + row_span = strtonum(tokens[6], 1, grid->rows, &errstr_num); + if (errstr_num) { + *errstr = "Invalid row span.\n"; + return 1; + } + column_span = strtonum(tokens[7], 1, grid->columns, &errstr_num); + if (errstr_num) { + *errstr = "Invalid column span.\n"; + return 1; + } + sticky = strtonum(tokens[8], 0, 15, &errstr_num); + if (errstr_num) { + *errstr = "Invalid sticky setting.\n"; + return 1; + } + return ltk_grid_add(window, widget, grid, row, column, row_span, column_span, sticky, errstr); } /* grid <grid id> remove <widget id> */ -static void +static int ltk_grid_cmd_ungrid( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_grid *grid; ltk_widget *widget; if (num_tokens != 4) { - (void)fprintf(stderr, "grid ungrid: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - grid = ltk_get_widget(window, tokens[1], LTK_GRID, "grid remove"); - widget = ltk_get_widget(window, tokens[3], LTK_WIDGET, "grid ungrid"); - if (!grid || !widget) return; - ltk_grid_ungrid(window, widget, grid); + grid = ltk_get_widget(window, tokens[1], LTK_GRID, errstr); + widget = ltk_get_widget(window, tokens[3], LTK_WIDGET, errstr); + if (!grid || !widget) return 1; + return ltk_grid_ungrid(window, widget, grid, errstr); } /* grid <grid id> create <rows> <columns> */ -static void +static int ltk_grid_cmd_create( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { int rows, columns; ltk_grid *grid; - const char *errstr; + const char *errstr_num; if (num_tokens != 5) { - (void)fprintf(stderr, "grid create: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - if (!ltk_check_widget_id_free(window, tokens[1], "grid create")) - return; - rows = strtonum(tokens[3], 1, 64, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid create: Invalid number of rows: %s\n ", errstr); - return; + if (!ltk_widget_id_free(window, tokens[1])) { + *errstr = "Widget ID already taken.\n"; + return 1; } - columns = strtonum(tokens[4], 1, 64, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid create: Invalid number of columns: %s\n ", errstr); - return; + rows = strtonum(tokens[3], 1, 64, &errstr_num); + if (errstr_num) { + *errstr = "Invalid number of rows.\n"; + return 1; + } + columns = strtonum(tokens[4], 1, 64, &errstr_num); + if (errstr_num) { + *errstr = "Invalid number of columns.\n"; + return 1; } grid = ltk_grid_create(window, tokens[1], rows, columns); ltk_set_widget(window, grid, tokens[1]); + + return 0; } /* grid <grid id> set-row-weight <row> <weight> */ -static void +static int ltk_grid_cmd_set_row_weight( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_grid *grid; int row, weight; - const char *errstr; + const char *errstr_num; if (num_tokens != 5) { - (void)fprintf(stderr, "grid set-row-weight: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - grid = ltk_get_widget(window, tokens[1], LTK_GRID, "grid set-row-weight"); - if (!grid) return; - row = strtonum(tokens[3], 0, grid->rows, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid set-row-weight: Invalid row number: %s\n ", errstr); - return; + grid = ltk_get_widget(window, tokens[1], LTK_GRID, errstr); + if (!grid) return 1; + row = strtonum(tokens[3], 0, grid->rows, &errstr_num); + if (errstr_num) { + *errstr = "Invalid row number.\n"; + return 1; } - weight = strtonum(tokens[4], 0, 64, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid set-row-weight: Invalid weight: %s\n ", errstr); - return; + weight = strtonum(tokens[4], 0, 64, &errstr_num); + if (errstr_num) { + *errstr = "Invalid row weight.\n"; + return 1; } ltk_grid_set_row_weight(grid, row, weight); + + return 0; } /* grid <grid id> set-column-weight <column> <weight> */ -static void +static int ltk_grid_cmd_set_column_weight( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { ltk_grid *grid; int column, weight; - const char *errstr; + const char *errstr_num; if (num_tokens != 5) { - (void)fprintf(stderr, "grid set-column-weight: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - grid = ltk_get_widget(window, tokens[1], LTK_GRID, "grid set-column-weight"); - if (!grid) return; - column = strtonum(tokens[3], 0, grid->columns, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid set-column-weight: Invalid column number: %s\n ", errstr); - return; + grid = ltk_get_widget(window, tokens[1], LTK_GRID, errstr); + if (!grid) return 1; + column = strtonum(tokens[3], 0, grid->columns, &errstr_num); + if (errstr_num) { + *errstr = "Invalid column number.\n"; + return 1; } - weight = strtonum(tokens[4], 0, 64, &errstr); - if (errstr) { - (void)fprintf(stderr, "grid set-column-weight: Invalid weight: %s\n ", errstr); - return; + weight = strtonum(tokens[4], 0, 64, &errstr_num); + if (errstr_num) { + *errstr = "Invalid column weight.\n"; + return 1; } ltk_grid_set_column_weight(grid, column, weight); + + return 0; } /* grid <grid id> <command> ... */ -void +int ltk_grid_cmd( ltk_window *window, char **tokens, - size_t num_tokens) { + size_t num_tokens, + char **errstr) { if (num_tokens < 3) { - (void)fprintf(stderr, "grid: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } if (strcmp(tokens[2], "add") == 0) { - ltk_grid_cmd_add(window, tokens, num_tokens); + return ltk_grid_cmd_add(window, tokens, num_tokens, errstr); } else if (strcmp(tokens[2], "ungrid") == 0) { - ltk_grid_cmd_ungrid(window, tokens, num_tokens); + return ltk_grid_cmd_ungrid(window, tokens, num_tokens, errstr); } else if (strcmp(tokens[2], "create") == 0) { - ltk_grid_cmd_create(window, tokens, num_tokens); + return ltk_grid_cmd_create(window, tokens, num_tokens, errstr); } else if (strcmp(tokens[2], "set-row-weight") == 0) { - ltk_grid_cmd_set_row_weight(window, tokens, num_tokens); + return ltk_grid_cmd_set_row_weight(window, tokens, num_tokens, errstr); } else if (strcmp(tokens[2], "set-column-weight") == 0) { - ltk_grid_cmd_set_column_weight(window, tokens, num_tokens); + return ltk_grid_cmd_set_column_weight(window, tokens, num_tokens, errstr); } else { - (void)fprintf(stderr, "button: Invalid command.\n"); + *errstr = "Invalid command.\n"; + return 1; } + + return 0; /* Well, I guess this is impossible anyways... */ } diff --git a/grid.h b/grid.h @@ -42,6 +42,6 @@ typedef struct { unsigned int *column_pos; } ltk_grid; -void ltk_grid_cmd(ltk_window *window, char **tokens, size_t num_tokens); +int ltk_grid_cmd(ltk_window *window, char **tokens, size_t num_tokens, char **errstr); #endif diff --git a/ltk.h b/ltk.h @@ -137,6 +137,8 @@ typedef struct ltk_window { void ltk_window_invalidate_rect(ltk_window *window, ltk_rect rect); void ltk_warn(const char *format, ...); void ltk_fatal(const char *format, ...); +void ltk_warn_errno(const char *format, ...); +void ltk_fatal_errno(const char *format, ...); int ltk_create_xcolor(ltk_window *window, const char *hex, XColor *col); void ltk_queue_event(ltk_window *window, ltk_event_type type, const char *id, const char *data); int ltk_collide_rect(ltk_rect rect, int x, int y); @@ -149,10 +151,9 @@ void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window * w void ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event); void ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event); void ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event); -int ltk_check_widget_id_free(ltk_window *window, const char *id, - const char *caller); +int ltk_check_widget_id_free(ltk_window *window, const char *id); ltk_widget *ltk_get_widget(ltk_window *window, const char *id, - ltk_widget_type type, const char *caller); + ltk_widget_type type, char **errstr); void ltk_set_widget(ltk_window *window, ltk_widget *widget, const char *id); #endif diff --git a/ltkd.c b/ltkd.c @@ -94,7 +94,7 @@ 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 tokenize_command(struct ltk_sock_info *sock); -static void ltk_set_root_widget_cmd(ltk_window *window, char **tokens, int num_tokens); +static int ltk_set_root_widget_cmd(ltk_window *window, char **tokens, int num_tokens, char **errstr); static void process_commands(ltk_window *window, struct ltk_sock_info *sock); static ltk_rect ltk_rect_union(ltk_rect r1, ltk_rect r2); static int add_client(int fd); @@ -126,16 +126,16 @@ int main(int argc, char *argv[]) { } ltk_dir = ltk_setup_directory(); - if (!ltk_dir) ltk_fatal("Unable to setup ltk directory.\n"); + if (!ltk_dir) ltk_fatal_errno("Unable to setup ltk directory.\n"); ltk_logfile = open_log(ltk_dir); - if (!ltk_logfile) ltk_fatal("Unable to open log file.\n"); + if (!ltk_logfile) ltk_fatal_errno("Unable to open log file.\n"); /* FIXME: set window size properly - I only run it in a tiling WM anyways, so it doesn't matter, but still... */ main_window = ltk_create_window(title, 0, 0, 500, 500); sock_path = get_sock_path(ltk_dir, main_window->xwindow); - if (!sock_path) ltk_fatal("Unable to allocate memory for socket path.\n"); + if (!sock_path) ltk_fatal_errno("Unable to allocate memory for socket path.\n"); /* Note: sockets should be initialized to 0 because it is static */ for (int i = 0; i < MAX_SOCK_CONNS; i++) { @@ -164,7 +164,7 @@ ltk_mainloop(ltk_window *window) { FD_ZERO(&wallfds); if ((listenfd = listen_sock(sock_path)) < 0) - ltk_fatal("Error listening on socket.\n"); + ltk_fatal_errno("Error listening on socket.\n"); FD_SET(listenfd, &rallfds); maxfd = listenfd; @@ -191,7 +191,7 @@ ltk_mainloop(ltk_window *window) { if (FD_ISSET(listenfd, &rfds)) { if ((clifd = accept_sock(listenfd)) < 0) { /* FIXME: Just log this! */ - ltk_fatal("Error accepting socket connection.\n"); + ltk_fatal_errno("Error accepting socket connection.\n"); } int i = add_client(clifd); FD_SET(clifd, &rallfds); @@ -207,7 +207,6 @@ ltk_mainloop(ltk_window *window) { continue; if (FD_ISSET(clifd, &rfds)) { if (read_sock(&sockets[i]) == 0) { - fprintf(stderr, "Closed socket fd %d\n", clifd); /* FIXME */ FD_CLR(clifd, &rallfds); FD_CLR(clifd, &wallfds); sockets[i].fd = -1; @@ -236,7 +235,7 @@ ltk_mainloop(ltk_window *window) { for (int i = 0; i <= maxsocket; i++) { if (sockets[i].fd != -1 && sockets[i].event_mask & cur->event_type) { if (queue_sock_write(&sockets[i], cur->data, event_len) < 0) - ltk_fatal("Unable to queue event.\n"); + ltk_fatal_errno("Unable to queue event.\n"); } } free(cur->data); @@ -267,7 +266,7 @@ daemonize(void) { fflush(ltk_logfile); if ((pid = fork()) < 0) - ltk_fatal("Can't fork.\n"); + ltk_fatal_errno("Can't fork.\n"); else if (pid != 0) exit(0); setsid(); @@ -276,14 +275,14 @@ daemonize(void) { sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) - ltk_fatal("Unable to ignore SIGHUP.\n"); + ltk_fatal_errno("Unable to ignore SIGHUP.\n"); if ((pid = fork()) < 0) - ltk_fatal("Can't fork.\n"); + ltk_fatal_errno("Can't fork.\n"); else if (pid != 0) exit(0); if (chdir("/") < 0) - ltk_fatal("Can't change directory to root.\n"); + ltk_fatal_errno("Can't change directory to root.\n"); close(fileno(stdin)); close(fileno(stdout)); @@ -322,6 +321,10 @@ open_log(char *dir) { if (!path) return NULL; f = fopen(path, "a"); + if (!f) { + free(path); + return NULL; + } free(path); return f; @@ -362,26 +365,28 @@ ltk_quit(ltk_window *window) { running = 0; } -static void +static int ltk_set_root_widget_cmd( ltk_window *window, char **tokens, - int num_tokens) { + int num_tokens, + char **errstr) { ltk_widget *widget; if (num_tokens != 2) { - (void)fprintf(stderr, "set-root-widget: Invalid number of arguments.\n"); - return; + *errstr = "Invalid number of arguments.\n"; + return 1; } - widget = ltk_get_widget(window, tokens[1], LTK_WIDGET, "set-root-widget"); - if (!widget) return; + widget = ltk_get_widget(window, tokens[1], LTK_WIDGET, errstr); + if (!widget) return 1; window->root_widget = widget; int w = widget->rect.w; int h = widget->rect.h; widget->rect.w = window->rect.w; widget->rect.h = window->rect.h; - if (widget->resize) { + if (widget->resize) widget->resize(widget, w, h); - } + + return 0; } static ltk_rect @@ -446,12 +451,31 @@ ltk_fatal(const char *format, ...) { exit(1); }; +void +ltk_warn_errno(const char *format, ...) { + va_list args; + char *errstr = strerror(errno); + va_start(args, format); + print_log("Warning", format, args); + va_end(args); + ltk_warn("system error: %s\n", errstr); +} + +void +ltk_fatal_errno(const char *format, ...) { + va_list args; + char *errstr = strerror(errno); + va_start(args, format); + print_log("Fatal", format, args); + va_end(args); + ltk_fatal("system error: %s\n", errstr); +} + +/* FIXME: Proper error checking by calling functions */ int ltk_create_xcolor(ltk_window *window, const char *hex, XColor *col) { - if (!XParseColor(window->dpy, window->cm, hex, col)) { - (void)fprintf(stderr, "Invalid color: %s\n", hex); + if (!XParseColor(window->dpy, window->cm, hex, col)) return 0; - } XAllocColor(window->dpy, window->cm, col); return 1; @@ -461,12 +485,12 @@ void ltk_queue_event(ltk_window *window, ltk_event_type type, const char *id, const char *data) { /* FIXME: make it nicer and safer */ struct ltk_event_queue *new = malloc(sizeof(struct ltk_event_queue)); - if (!new) ltk_fatal("Unable to queue event.\n"); + if (!new) ltk_fatal_errno("Unable to queue event.\n"); new->event_type = type; int id_len = strlen(id); int data_len = strlen(data); new->data = malloc(id_len + data_len + 3); - if (!new->data) ltk_fatal("Unable to queue event.\n"); + if (!new->data) ltk_fatal_errno("Unable to queue event.\n"); strcpy(new->data, id); new->data[id_len] = ' '; strcpy(new->data + id_len + 1, data); @@ -533,14 +557,15 @@ ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int ltk_window *window = malloc(sizeof(ltk_window)); if (!window) - ltk_fatal("Not enough memory left for window!\n"); + ltk_fatal_errno("Not enough memory left for window!\n"); window->dpy = XOpenDisplay(NULL); window->screen = DefaultScreen(window->dpy); window->cm = DefaultColormap(window->dpy, window->screen); theme_path = ltk_strcat_useful(ltk_dir, "/theme.ini"); + window->theme.font = NULL; if (!theme_path) - ltk_fatal("Not enough memory for theme path.\n"); + ltk_fatal_errno("Not enough memory for theme path.\n"); ltk_load_theme(window, theme_path); window->wm_delete_msg = XInternAtom(window->dpy, "WM_DELETE_WINDOW", False); @@ -595,6 +620,8 @@ ltk_destroy_window(ltk_window *window) { kh_destroy(widget, window->widget_hash); ltk_cleanup_text(); XCloseDisplay(window->dpy); + if (window->theme.font) + free(window->theme.font); free(window); } @@ -608,6 +635,8 @@ ltk_window_ini_handler(ltk_window *window, const char *prop, const char *value) ltk_create_xcolor(window, value, &window->theme.fg); } else if (strcmp(prop, "font") == 0) { window->theme.font = strdup(value); + if (!window->theme.font) + ltk_fatal_errno("Unable to allocate copy of font name.\n"); } else if (strcmp(prop, "font_size") == 0) { window->theme.font_size = atoi(value); } @@ -685,6 +714,8 @@ ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window, void (*destroy) (void *, int), unsigned int needs_redraw, ltk_widget_type type) { widget->id = strdup(id); + if (!widget->id) + ltk_fatal_errno("Unable to allocate copy of widget ID.\n"); widget->window = window; widget->active_widget = NULL; widget->parent = NULL; @@ -800,11 +831,10 @@ ltk_handle_event(ltk_window *window, XEvent event) { } int -ltk_check_widget_id_free(ltk_window *window, const char *id, const char *caller) { +ltk_widget_id_free(ltk_window *window, const char *id) { khint_t k; k = kh_get(widget, window->widget_hash, id); if (k != kh_end(window->widget_hash)) { - (void)fprintf(stderr, "%s: Widget \"%s\" already exists.\n", caller, id); return 0; } return 1; @@ -812,17 +842,17 @@ ltk_check_widget_id_free(ltk_window *window, const char *id, const char *caller) ltk_widget * ltk_get_widget(ltk_window *window, const char *id, ltk_widget_type type, - const char *caller) { + char **errstr) { khint_t k; ltk_widget *widget; k = kh_get(widget, window->widget_hash, id); if (k == kh_end(window->widget_hash)) { - (void)fprintf(stderr, "%s: Widget \"%s\" doesn't exist.\n", caller, id); + *errstr = "Widget with given ID doesn't exist.\n"; return NULL; } widget = kh_value(window->widget_hash, k); if (type != LTK_WIDGET && widget->type != type) { - (void)fprintf(stderr, "%s: Widget \"%s\" has wrong type.\n", caller, id); + *errstr = "Widget with given ID has wrong type.\n"; return NULL; } return widget; @@ -833,7 +863,10 @@ ltk_set_widget(ltk_window *window, ltk_widget *widget, const char *id) { int ret; khint_t k; /* apparently, khash requires the string to stay accessible */ + /* FIXME: How is this freed? */ char *tmp = strdup(id); + if (!tmp) + ltk_fatal_errno("Unable to add widget to hash table.\n"); k = kh_put(widget, window->widget_hash, tmp, &ret); kh_value(window->widget_hash, k) = widget; } @@ -1079,26 +1112,33 @@ static void process_commands(ltk_window *window, struct ltk_sock_info *sock) { char **tokens; int num_tokens; + char *errstr; + int err; while (!tokenize_command(sock)) { + err = 0; tokens = sock->tokens.tokens; num_tokens = sock->tokens.num_tokens; if (num_tokens < 1) continue; if (strcmp(tokens[0], "grid") == 0) { - ltk_grid_cmd(window, tokens, num_tokens); + err = ltk_grid_cmd(window, tokens, num_tokens, &errstr); } else if (strcmp(tokens[0], "button") == 0) { - ltk_button_cmd(window, tokens, num_tokens); + err = ltk_button_cmd(window, tokens, num_tokens, &errstr); } else if (strcmp(tokens[0], "set-root-widget") == 0) { - ltk_set_root_widget_cmd(window, tokens, num_tokens); + err = ltk_set_root_widget_cmd(window, tokens, num_tokens, &errstr); } else if (strcmp(tokens[0], "draw") == 0) { - ltk_draw_cmd(window, tokens, num_tokens); + err = ltk_draw_cmd(window, tokens, num_tokens, &errstr); } else if (strcmp(tokens[0], "quit") == 0) { ltk_quit(window); } else { - /* FIXME... */ - (void)fprintf(stderr, "Invalid command.\n"); + errstr = "Invalid command.\n"; + err = 1; } sock->tokens.num_tokens = 0; + if (err) { + if (queue_sock_write(sock, errstr, -1) < 0) + ltk_fatal("Unable to queue socket write.\n"); + } } if (sock->tokens.num_tokens > 0 && sock->tokens.tokens[0] != sock->read) { memmove(sock->read, sock->tokens.tokens[0], sock->read + sock->read_len - sock->tokens.tokens[0]); diff --git a/text_pango.c b/text_pango.c @@ -8,6 +8,7 @@ #include <pango/pangoxft.h> #include "util.h" #include "text.h" +#include "ltk.h" struct LtkTextLine { char *text; @@ -34,7 +35,8 @@ ltk_init_text(const char *default_font, Display *dpy, int screen, Colormap cm) { tm.fontmap = pango_xft_get_font_map(dpy, screen); tm.context = pango_font_map_create_context(tm.fontmap); tm.default_font = strdup(default_font); - if (!tm.default_font) ltk_err("ltk_init_text (pango)"); + if (!tm.default_font) + ltk_fatal_errno("Unable to allocate copy of font path.\n"); tm.dpy = dpy; tm.screen = screen; tm.cm = cm; diff --git a/text_stb.c b/text_stb.c @@ -318,17 +318,17 @@ ltk_create_font(char *path, uint16_t id, int index) { LtkFont *font = malloc(sizeof(LtkFont)); if (!font) ltk_err("ltk_create_font (stb)"); char *contents = ltk_read_file(path, &len); - /* FIXME: error checking */ + if (!contents) + ltk_fatal_errno("Unable to read font file %s\n", path); int offset = stbtt_GetFontOffsetForIndex(contents, index); - if (!stbtt_InitFont(&font->info, contents, offset)) { - (void)fprintf(stderr, "Failed to load font %s\n", path); - exit(1); - } + if (!stbtt_InitFont(&font->info, contents, offset)) + ltk_fatal("Failed to load font %s\n", path); font->id = id; font->refs = 0; font->index = index; font->path = strdup(path); - if (!font->path) ltk_err("ltk_create_font"); + if (!font->path) + ltk_fatal_errno("Unable to allocate copy of font path.\n"); return font; } diff --git a/util.c b/util.c @@ -38,11 +38,12 @@ ltk_read_file(const char *path, unsigned long *len) { FILE *f; char *file_contents; f = fopen(path, "rb"); + if (!f) return NULL; fseek(f, 0, SEEK_END); *len = ftell(f); fseek(f, 0, SEEK_SET); - /* FIXME: error checking */ file_contents = malloc(*len + 1); + if (!file_contents) return NULL; fread(file_contents, 1, *len, f); file_contents[*len] = '\0'; fclose(f);