URI: 
       tImprove theme handling - ltk - Socket-based GUI for X11 (WIP)
  HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit ee2ba3e29af85489041255d3454c45409f178f34
   DIR parent f983e20c6046e83fb13b2628d523bd8a4828411d
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Tue, 29 Dec 2020 21:38:54 +0100
       
       Improve theme handling
       
       Diffstat:
         M .gitignore                          |       1 -
         A .ltk/.gitignore                     |       2 ++
         R theme.ini -> .ltk/theme.ini         |       0 
         M button.c                            |     112 +++++++++++++++++++++----------
         M button.h                            |      19 +------------------
         M ltk.h                               |       7 +------
         M ltkd.c                              |      74 ++++++++++++++++----------------
         M util.c                              |      20 ++++++++++++++++++++
         M util.h                              |       1 +
       
       9 files changed, 137 insertions(+), 99 deletions(-)
       ---
   DIR diff --git a/.gitignore b/.gitignore
       t@@ -3,4 +3,3 @@ ltkc
        ltk.sock
        *.o
        *.core
       -.ltk
   DIR diff --git a/.ltk/.gitignore b/.ltk/.gitignore
       t@@ -0,0 +1,2 @@
       +*.sock
       +*.log
   DIR diff --git a/theme.ini b/.ltk/theme.ini
   DIR diff --git a/button.c b/button.c
       t@@ -39,73 +39,112 @@ static ltk_button *ltk_button_create(ltk_window *window,
            const char *id, const char *text);
        static void ltk_button_destroy(ltk_button *button, int shallow);
        
       +static struct {
       +        int border_width;
       +        LtkColor text_color;
       +        int pad;
       +
       +        LtkColor border;
       +        LtkColor fill;
       +
       +        LtkColor border_pressed;
       +        LtkColor fill_pressed;
       +
       +        LtkColor border_active;
       +        LtkColor fill_active;
       +
       +        LtkColor border_disabled;
       +        LtkColor fill_disabled;
       +} theme;
       +
       +/* FIXME: do this more efficiently (don't create color twice if
       +   the color is again defined in the theme file) */
       +void
       +ltk_button_setup_theme_defaults(ltk_window *window) {
       +        theme.border_width = 2;
       +        theme.pad = 5;
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#FFFFFF", &theme.text_color);
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#339999", &theme.border);
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#113355", &theme.fill);
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#FFFFFF", &theme.border_pressed);
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#113355", &theme.fill_pressed);
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#FFFFFF", &theme.border_active);
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#738194", &theme.fill_active);
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#FFFFFF", &theme.border_disabled);
       +        ltk_color_create(window->dpy, window->screen, window->cm,
       +            "#292929", &theme.fill_disabled);
       +}
       +
        void
        ltk_button_ini_handler(ltk_window *window, const char *prop, const char *value) {
       -        ltk_theme *theme = window->theme;
       -        if (!theme->button)
       -                theme->button = malloc(sizeof(ltk_button_theme));
       -        if (!theme->button)
       -                ltk_fatal("Unable to allocate ltk_button_theme.\n");
                if (strcmp(prop, "border_width") == 0) {
       -                theme->button->border_width = atoi(value);
       +                theme.border_width = atoi(value);
                } else if (strcmp(prop, "pad") == 0) {
       -                theme->button->pad = atoi(value);
       +                theme.pad = atoi(value);
                } else if (strcmp(prop, "border") == 0) {
                        ltk_color_create(window->dpy, window->screen, window->cm,
       -                    value, &theme->button->border);
       +                    value, &theme.border);
                } else if (strcmp(prop, "fill") == 0) {
                        ltk_color_create(window->dpy, window->screen, window->cm,
       -                    value, &theme->button->fill);
       +                    value, &theme.fill);
                } else if (strcmp(prop, "border_pressed") == 0) {
                        ltk_color_create(window->dpy, window->screen, window->cm,
       -                    value, &theme->button->border_pressed);
       +                    value, &theme.border_pressed);
                } else if (strcmp(prop, "fill_pressed") == 0) {
                        ltk_color_create(window->dpy, window->screen, window->cm,
       -                    value, &theme->button->fill_pressed);
       +                    value, &theme.fill_pressed);
                } else if (strcmp(prop, "border_active") == 0) {
                        ltk_color_create(window->dpy, window->screen, window->cm,
       -                    value, &theme->button->border_active);
       +                    value, &theme.border_active);
                } else if (strcmp(prop, "fill_active") == 0) {
                        ltk_color_create(window->dpy, window->screen, window->cm,
       -                    value, &theme->button->fill_active);
       +                    value, &theme.fill_active);
                } else if (strcmp(prop, "border_disabled") == 0) {
                        ltk_color_create(window->dpy, window->screen, window->cm,
       -                    value, &theme->button->border_disabled);
       +                    value, &theme.border_disabled);
                } else if (strcmp(prop, "fill_disabled") == 0) {
                        ltk_color_create(window->dpy, window->screen, window->cm,
       -                    value, &theme->button->fill_disabled);
       +                    value, &theme.fill_disabled);
                } else if (strcmp(prop, "text_color") == 0) {
                        ltk_color_create(window->dpy, window->screen, window->cm,
       -                    value, &theme->button->text_color);
       +                    value, &theme.text_color);
                } else {
       -                (void)printf("WARNING: Unknown property \"%s\" for button style.\n", prop);
       +                /* FIXME: implement this function...
       +                (void)ltk_log_warn("Unknown property \"%s\" for button style.\n", prop);*/
                }
        }
        
        static void
        ltk_button_draw(ltk_button *button) {
                ltk_window *window = button->widget.window;
       -        ltk_button_theme *theme = window->theme->button;
                ltk_rect rect = button->widget.rect;
       -        int bw = theme->border_width;
       +        int bw = theme.border_width;
                LtkColor *border;
                LtkColor *fill;
                switch (button->widget.state) {
                case LTK_NORMAL:
       -                border = &theme->border;
       -                fill = &theme->fill;
       +                border = &theme.border;
       +                fill = &theme.fill;
                        break;
                case LTK_PRESSED:
       -                border = &theme->border_pressed;
       -                fill = &theme->fill_pressed;
       +                border = &theme.border_pressed;
       +                fill = &theme.fill_pressed;
                        break;
                case LTK_ACTIVE:
       -                border = &theme->border_active;
       -                fill = &theme->fill_active;
       +                border = &theme.border_active;
       +                fill = &theme.fill_active;
                        break;
                case LTK_DISABLED:
       -                border = &theme->border_disabled;
       -                fill = &theme->fill_disabled;
       +                border = &theme.border_disabled;
       +                fill = &theme.fill_disabled;
                        break;
                default:
                        ltk_fatal("No style found for button!\n");
       t@@ -131,25 +170,24 @@ ltk_button_draw(ltk_button *button) {
        static void
        ltk_button_change_state(ltk_button *button) {
                ltk_window *window = button->widget.window;
       -        ltk_button_theme *theme = window->theme->button;
                LtkColor *fill;
                switch (button->widget.state) {
                case LTK_NORMAL:
       -                fill = &theme->fill;
       +                fill = &theme.fill;
                        break;
                case LTK_PRESSED:
       -                fill = &theme->fill_pressed;
       +                fill = &theme.fill_pressed;
                        break;
                case LTK_ACTIVE:
       -                fill = &theme->fill_active;
       +                fill = &theme.fill_active;
                        break;
                case LTK_DISABLED:
       -                fill = &theme->fill_disabled;
       +                fill = &theme.fill_disabled;
                        break;
                default:
                        ltk_fatal("No style found for button!\n");
                }
       -        ltk_text_line_render(button->tl, fill, &theme->text_color);
       +        ltk_text_line_render(button->tl, fill, &theme.text_color);
        }
        
        static void
       t@@ -165,13 +203,13 @@ ltk_button_create(ltk_window *window, const char *id, const char *text) {
                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->window->font_size;
       +        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);
                int text_w, text_h;
                ltk_text_line_get_size(button->tl, &text_w, &text_h);
       -        ltk_button_theme *theme = window->theme->button;
       -        button->widget.rect.w = text_w + theme->border_width * 2 + theme->pad * 2;
       -        button->widget.rect.h = text_h + theme->border_width * 2 + theme->pad * 2;
       +        button->widget.rect.w = text_w + theme.border_width * 2 + theme.pad * 2;
       +        button->widget.rect.h = text_h + theme.border_width * 2 + theme.pad * 2;
                /* render text */
                ltk_button_change_state(button);
        
   DIR diff --git a/button.h b/button.h
       t@@ -32,24 +32,7 @@ typedef struct {
                Pixmap text_pixmap;
        } ltk_button;
        
       -typedef struct ltk_button_theme {
       -        int border_width;
       -        LtkColor text_color;
       -        int pad;
       -
       -        LtkColor border;
       -        LtkColor fill;
       -
       -        LtkColor border_pressed;
       -        LtkColor fill_pressed;
       -
       -        LtkColor border_active;
       -        LtkColor fill_active;
       -
       -        LtkColor border_disabled;
       -        LtkColor fill_disabled;
       -} ltk_button_theme;
       -
       +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(
   DIR diff --git a/ltk.h b/ltk.h
       t@@ -104,11 +104,6 @@ typedef struct {
        
        typedef struct ltk_button_theme ltk_button_theme;
        
       -typedef struct {
       -        ltk_window_theme *window;
       -        ltk_button_theme *button;
       -} ltk_theme;
       -
        struct ltk_event_queue {
                ltk_event_type event_type;
                char *data;
       t@@ -129,7 +124,7 @@ typedef struct ltk_window {
                ltk_widget *active_widget;
                void (*other_event) (ltk_window *, XEvent event);
                ltk_rect rect;
       -        ltk_theme *theme;
       +        ltk_window_theme theme;
                ltk_rect dirty_rect;
                struct ltk_event_queue *first_event;
                struct ltk_event_queue *last_event;
   DIR diff --git a/ltkd.c b/ltkd.c
       t@@ -78,8 +78,8 @@ static int ltk_mainloop(ltk_window *window);
        static char *get_sock_path(char *basedir, Window id);
        static FILE *open_log(char *dir);
        static void daemonize(void);
       -static ltk_window *ltk_create_window(const char *theme_path, const char
       -    *title, int x, int y, unsigned int w, unsigned int h);
       +static ltk_window *ltk_create_window(const char *title, int x, int y,
       +    unsigned int w, unsigned int h);
        static void ltk_destroy_window(ltk_window *window);
        static void ltk_cleanup_gui(ltk_window *window);
        static void ltk_cleanup_nongui(void);
       t@@ -87,7 +87,6 @@ static void ltk_redraw_window(ltk_window *window);
        static void ltk_window_other_event(ltk_window *window, XEvent event);
        static void ltk_handle_event(ltk_window *window, XEvent event);
        static void ltk_load_theme(ltk_window *window, const char *path);
       -static void ltk_destroy_theme(ltk_theme *theme);
        static ltk_rect ltk_rect_union(ltk_rect r1, ltk_rect r2);
        static int read_sock(struct ltk_sock_info *sock);
        static int push_token(struct token_list *tl, char *token);
       t@@ -126,12 +125,13 @@ int main(int argc, char *argv[]) {
                        }
                }
        
       +        ltk_dir = ltk_setup_directory();
       +        if (!ltk_dir) ltk_fatal("Unable to setup ltk directory.\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("theme.ini", title, 0, 0, 500, 500);
       +        main_window = ltk_create_window(title, 0, 0, 500, 500);
        
       -        ltk_dir = ltk_setup_directory();
       -        if (!ltk_dir) ltk_fatal("Unable to setup ltk directory.\n");
                ltk_logfile = open_log(ltk_dir);
                if (!ltk_logfile) ltk_fatal("Unable to open log file.\n");
                sock_path = get_sock_path(ltk_dir, main_window->xwindow);
       t@@ -316,11 +316,9 @@ open_log(char *dir) {
                FILE *f;
                char *path;
        
       -        len = strlen(dir);
       -        path = malloc(len + 10);
       +        path = ltk_strcat_useful(dir, "/ltkd.log");
                if (!path)
                        return NULL;
       -        snprintf(path, len + 10, "%s/ltkd.log", dir);
                f = fopen(path, "a");
                free(path);
        
       t@@ -499,7 +497,9 @@ ltk_window_other_event(ltk_window *window, XEvent event) {
        }
        
        static ltk_window *
       -ltk_create_window(const char *theme_path, const char *title, int x, int y, unsigned int w, unsigned int h) {
       +ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int h) {
       +        char *theme_path;
       +
                ltk_window *window = malloc(sizeof(ltk_window));
                if (!window)
                        ltk_fatal("Not enough memory left for window!\n");
       t@@ -507,24 +507,25 @@ ltk_create_window(const char *theme_path, const char *title, int x, int y, unsig
                window->dpy = XOpenDisplay(NULL);
                window->screen = DefaultScreen(window->dpy);
                window->cm = DefaultColormap(window->dpy, window->screen);
       -        /* FIXME: validate theme properly */
       +        theme_path = ltk_strcat_useful(ltk_dir, "/theme.ini");
       +        if (!theme_path)
       +                ltk_fatal("Not enough memory for theme path.\n");
                ltk_load_theme(window, theme_path);
                window->wm_delete_msg = XInternAtom(window->dpy, "WM_DELETE_WINDOW", False);
        
       -        ltk_window_theme *wtheme = window->theme->window;
                window->xwindow =
                    XCreateSimpleWindow(window->dpy, DefaultRootWindow(window->dpy), x, y,
       -                                w, h, wtheme->border_width,
       -                                wtheme->fg.pixel, wtheme->bg.pixel);
       +                                w, h, window->theme.border_width,
       +                                window->theme.fg.pixel, window->theme.bg.pixel);
                window->gc = XCreateGC(window->dpy, window->xwindow, 0, 0);
       -        XSetForeground(window->dpy, window->gc, wtheme->fg.pixel);
       -        XSetBackground(window->dpy, window->gc, wtheme->bg.pixel);
       +        XSetForeground(window->dpy, window->gc, window->theme.fg.pixel);
       +        XSetBackground(window->dpy, window->gc, window->theme.bg.pixel);
                XSetStandardProperties(window->dpy, window->xwindow, title, NULL, None,
                                       NULL, 0, NULL);
                XSetWMProtocols(window->dpy, window->xwindow, &window->wm_delete_msg, 1);
                window->root_widget = NULL;
        
       -        ltk_init_text(wtheme->font, window->dpy, window->screen, window->cm);
       +        ltk_init_text(window->theme.font, window->dpy, window->screen, window->cm);
        
                window->other_event = &ltk_window_other_event;
        
       t@@ -561,7 +562,6 @@ ltk_destroy_window(ltk_window *window) {
                        }
                }
                kh_destroy(widget, window->widget_hash);
       -        ltk_destroy_theme(window->theme);
                ltk_cleanup_text();
                XCloseDisplay(window->dpy);
                free(window);
       t@@ -569,17 +569,16 @@ ltk_destroy_window(ltk_window *window) {
        
        void
        ltk_window_ini_handler(ltk_window *window, const char *prop, const char *value) {
       -        /* FIXME: A whole lot more error checking! */
                if (strcmp(prop, "border_width") == 0) {
       -                window->theme->window->border_width = atoi(value);
       +                window->theme.border_width = atoi(value);
                } else if (strcmp(prop, "bg") == 0) {
       -                ltk_create_xcolor(window, value, &window->theme->window->bg);
       +                ltk_create_xcolor(window, value, &window->theme.bg);
                } else if (strcmp(prop, "fg") == 0) {
       -                ltk_create_xcolor(window, value, &window->theme->window->fg);
       +                ltk_create_xcolor(window, value, &window->theme.fg);
                } else if (strcmp(prop, "font") == 0) {
       -                window->theme->window->font = strdup(value);
       +                window->theme.font = strdup(value);
                } else if (strcmp(prop, "font_size") == 0) {
       -                window->theme->window->font_size = atoi(value);
       +                window->theme.font_size = atoi(value);
                }
        }
        
       t@@ -596,22 +595,23 @@ ltk_ini_handler(void *window, const char *widget, const char *prop, const char *
        }
        
        static void
       -ltk_load_theme(ltk_window *window, const char *path) {
       -        window->theme = malloc(sizeof(ltk_theme));
       -        if (!window->theme) ltk_fatal("Unable to allocate memory for theme.\n");
       -        window->theme->window = malloc(sizeof(ltk_window_theme));
       -        if (!window->theme->window) ltk_fatal("Unable to allocate memory for window theme.\n");
       -        window->theme->button = NULL;
       -        if (ini_parse(path, ltk_ini_handler, window) < 0) {
       -                ltk_fatal("Can't load theme.\n");
       -        }
       +ltk_window_setup_theme_defaults(ltk_window *window) {
       +        window->theme.border_width = 0;
       +        window->theme.font_size = 15;
       +        window->theme.font = "Liberation Mono";
       +        ltk_create_xcolor(window, "#000000", &window->theme.bg);
       +        ltk_create_xcolor(window, "#FFFFFF", &window->theme.fg);
        }
        
        static void
       -ltk_destroy_theme(ltk_theme *theme) {
       -        free(theme->button);
       -        free(theme->window);
       -        free(theme);
       +ltk_load_theme(ltk_window *window, const char *path) {
       +        /* FIXME: Error checking, especially when creating colors! */
       +        ltk_window_setup_theme_defaults(window);
       +        ltk_button_setup_theme_defaults(window);
       +        if (ini_parse(path, ltk_ini_handler, window) < 0) {
       +                /* FIXME: implement this function...
       +                ltk_log_warn("Can't load theme.\n"); */
       +        }
        }
        
        int
   DIR diff --git a/util.c b/util.c
       t@@ -101,3 +101,23 @@ ltk_setup_directory(void) {
        
                return dir;
        }
       +
       +/* Concatenate the two given strings and return the result.
       +   This allocates new memory for the result string, unlike
       +   the actual strcat.
       +   Returns NULL on error. */
       +char *
       +ltk_strcat_useful(const char *str1, const char *str2) {
       +        int len1, len2;
       +        char *ret;
       +
       +        len1 = strlen(str1);
       +        len2 = strlen(str2);
       +        ret = malloc(len1 + len2 + 1);
       +        if (!ret)
       +                return NULL;
       +        strcpy(ret, str1);
       +        strcpy(ret + len1, str2);
       +
       +        return ret;
       +}
   DIR diff --git a/util.h b/util.h
       t@@ -31,3 +31,4 @@ void ltk_err(const char *msg);
        char *ltk_read_file(const char *path, unsigned long *len);
        int 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);