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 ee2ba3e29af85489041255d3454c45409f178f34
parent f983e20c6046e83fb13b2628d523bd8a4828411d
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++
Rtheme.ini -> .ltk/theme.ini | 0
Mbutton.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mbutton.h | 19+------------------
Mltk.h | 7+------
Mltkd.c | 74+++++++++++++++++++++++++++++++++++++-------------------------------------
Mutil.c | 20++++++++++++++++++++
Mutil.h | 1+
9 files changed, 137 insertions(+), 99 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -3,4 +3,3 @@ ltkc ltk.sock *.o *.core -.ltk diff --git a/.ltk/.gitignore b/.ltk/.gitignore @@ -0,0 +1,2 @@ +*.sock +*.log diff --git a/theme.ini b/.ltk/theme.ini diff --git a/button.c b/button.c @@ -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"); @@ -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 @@ -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); diff --git a/button.h b/button.h @@ -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( diff --git a/ltk.h b/ltk.h @@ -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; @@ -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; diff --git a/ltkd.c b/ltkd.c @@ -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); @@ -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); @@ -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); @@ -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); @@ -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"); @@ -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; @@ -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); @@ -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); } } @@ -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 diff --git a/util.c b/util.c @@ -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; +} diff --git a/util.h b/util.h @@ -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);