ltk

GUI toolkit for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/ltk.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
Log | Files | Refs | README | LICENSE

theme.c (6292B)


      1 /*
      2  * Copyright (c) 2022-2024 lumidify <nobody@lumidify.org>
      3  *
      4  * Permission to use, copy, modify, and/or distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <stdlib.h>
     18 #include <string.h>
     19 
     20 #include "graphics.h"
     21 #include "util.h"
     22 #include "theme.h"
     23 #include "memory.h"
     24 
     25 /* FIXME: handle '#' or no '#' in color specification */
     26 static int
     27 search_helper(const void *keyv, const void *entryv) {
     28 	char *key = (char *)keyv;
     29 	ltk_theme_parseinfo *entry = (ltk_theme_parseinfo *)entryv;
     30 	return strcmp(key, entry->key);
     31 }
     32 
     33 static int
     34 sort_helper(const void *entry1v, const void *entry2v) {
     35 	ltk_theme_parseinfo *entry1 = (ltk_theme_parseinfo *)entry1v;
     36 	ltk_theme_parseinfo *entry2 = (ltk_theme_parseinfo *)entry2v;
     37 	return strcmp(entry1->key, entry2->key);
     38 }
     39 
     40 /* FIXME: more information for errors */
     41 int
     42 ltk_theme_handle_value(ltk_renderdata *renderdata, char *debug_name, const char *prop, const char *value, ltk_theme_parseinfo *parseinfo, size_t len, int *sorted) {
     43 	if (!*sorted) {
     44 		qsort(parseinfo, len, sizeof(ltk_theme_parseinfo), &sort_helper);
     45 		*sorted = 1;
     46 	}
     47 	ltk_theme_parseinfo *entry = bsearch(prop, parseinfo, len, sizeof(ltk_theme_parseinfo), &search_helper);
     48 	if (!entry) {
     49 		ltk_warn("Invalid property '%s:%s'.\n", debug_name, prop);
     50 		return 1;
     51 	} else if (entry->initialized) {
     52 		ltk_warn("Duplicate setting for property '%s:%s'.\n", debug_name, prop);
     53 		return 1;
     54 	}
     55 	const char *errstr = NULL;
     56 	switch (entry->type) {
     57 	case THEME_INT:
     58 		*(entry->ptr.i) = ltk_strtonum(value, entry->min, entry->max, &errstr);
     59 		if (errstr) {
     60 			ltk_warn("Invalid value '%s' for property '%s:%s'.\n", value, debug_name, prop);
     61 			return 1;
     62 		} else {
     63 			entry->initialized = 1;
     64 		}
     65 		break;
     66 	case THEME_SIZE:
     67 		entry->ptr.size->unit = LTK_UNIT_PX;
     68 		char *endptr = NULL;
     69 		/* this already takes care of overflow prevention because entry->min and entry->max are int */
     70 		entry->ptr.size->val = ltk_strtoscalednum(value, entry->min, entry->max, &endptr, &errstr);
     71 		if (errstr) {
     72 			ltk_warn("Invalid value '%s' for property '%s:%s': %s\n", value, debug_name, prop, errstr);
     73 			return 1;
     74 		}
     75 		if (*endptr == '\0') {
     76 			/* NOP */
     77 		} else if (!strcmp(endptr, "px")) {
     78 			entry->ptr.size->unit = LTK_UNIT_PX;
     79 		} else if (!strcmp(endptr, "pt")) {
     80 			entry->ptr.size->unit = LTK_UNIT_PT;
     81 		} else if (!strcmp(endptr, "mm")) {
     82 			entry->ptr.size->unit = LTK_UNIT_MM;
     83 		} else {
     84 			ltk_warn("Invalid value '%s' for property '%s:%s'\n", value, debug_name, prop);
     85 			return 1;
     86 		}
     87 		entry->initialized = 1;
     88 		break;
     89 	case THEME_STRING:
     90 		/* FIXME: check if already set? */
     91 		*(entry->ptr.str) = ltk_strdup(value);
     92 		entry->initialized = 1;
     93 		break;
     94 	case THEME_COLOR:
     95 		if (!(*(entry->ptr.color) = ltk_color_create(renderdata, value))) {
     96 			ltk_warn("Unable to create color '%s' for property '%s:%s'.\n", value, debug_name, prop);
     97 			return 1;
     98 		} else {
     99 			entry->initialized = 1;
    100 		}
    101 		break;
    102 	case THEME_BOOL:
    103 		if (strcmp(value, "true") == 0) {
    104 			*(entry->ptr.b) = 1;
    105 		} else if (strcmp(value, "false") == 0) {
    106 			*(entry->ptr.b) = 0;
    107 		} else {
    108 			ltk_warn("Invalid value '%s' for property '%s:%s'.\n", value, debug_name, prop);
    109 			return 1;
    110 		}
    111 		entry->initialized = 1;
    112 		break;
    113 	case THEME_BORDERSIDES:
    114 		*(entry->ptr.border) = LTK_BORDER_NONE;
    115 		for (const char *c = value; *c != '\0'; c++) {
    116 			switch (*c) {
    117 			case 't':
    118 				*(entry->ptr.border) |= LTK_BORDER_TOP;
    119 				break;
    120 			case 'b':
    121 				*(entry->ptr.border) |= LTK_BORDER_BOTTOM;
    122 				break;
    123 			case 'l':
    124 				*(entry->ptr.border) |= LTK_BORDER_LEFT;
    125 				break;
    126 			case 'r':
    127 				*(entry->ptr.border) |= LTK_BORDER_RIGHT;
    128 				break;
    129 			default:
    130 				ltk_warn("Invalid value '%s' for property '%s:%s'.\n", value, debug_name, prop);
    131 				return 1;
    132 			}
    133 		}
    134 		entry->initialized = 1;
    135 		break;
    136 	default:
    137 		ltk_fatal("Invalid theme setting type. This should not happen.\n");
    138 		/* TODO: ltk_assert(0); */
    139 	}
    140 	return 0;
    141 }
    142 
    143 int
    144 ltk_theme_fill_defaults(ltk_renderdata *renderdata, char *debug_name, ltk_theme_parseinfo *parseinfo, size_t len) {
    145 	for (size_t i = 0; i < len; i++) {
    146 		ltk_theme_parseinfo *e = &parseinfo[i];
    147 		if (e->initialized)
    148 			continue;
    149 		switch (e->type) {
    150 		case THEME_INT:
    151 			*(e->ptr.i) = e->defaultval.i;
    152 			e->initialized = 1;
    153 			break;
    154 		case THEME_SIZE:
    155 			*(e->ptr.size) = e->defaultval.size;
    156 			e->initialized = 1;
    157 			break;
    158 		case THEME_STRING:
    159 			*(e->ptr.str) = ltk_strdup(e->defaultval.str);
    160 			e->initialized = 1;
    161 			break;
    162 		case THEME_COLOR:
    163 			if (!(*(e->ptr.color) = ltk_color_create(renderdata, e->defaultval.color))) {
    164 				ltk_warn("Unable to create default color '%s' for property '%s:%s'.\n", e->defaultval.color, debug_name, e->key);
    165 				return 1;
    166 			} else {
    167 				e->initialized = 1;
    168 			}
    169 			break;
    170 		case THEME_BOOL:
    171 			*(e->ptr.b) = e->defaultval.b;
    172 			e->initialized = 1;
    173 			break;
    174 		case THEME_BORDERSIDES:
    175 			*(e->ptr.border) = e->defaultval.border;
    176 			e->initialized = 1;
    177 			break;
    178 		default:
    179 			ltk_fatal("Invalid theme setting type. This should not happen.\n");
    180 			/* TODO: ltk_assert(0); */
    181 		}
    182 	}
    183 	return 0;
    184 }
    185 
    186 void
    187 ltk_theme_uninitialize(ltk_renderdata *renderdata, ltk_theme_parseinfo *parseinfo, size_t len) {
    188 	for (size_t i = 0; i < len; i++) {
    189 		ltk_theme_parseinfo *e = &parseinfo[i];
    190 		if (!e->initialized)
    191 			continue;
    192 		switch (e->type) {
    193 		case THEME_STRING:
    194 			ltk_free(*(e->ptr.str));
    195 			e->initialized = 0;
    196 			break;
    197 		case THEME_COLOR:
    198 			ltk_color_destroy(renderdata, *(e->ptr.color));
    199 			e->initialized = 0;
    200 			break;
    201 		case THEME_SIZE:
    202 		case THEME_INT:
    203 		case THEME_BOOL:
    204 		case THEME_BORDERSIDES:
    205 			e->initialized = 0;
    206 			break;
    207 		default:
    208 			ltk_fatal("Invalid theme setting type. This should not happen.\n");
    209 		}
    210 	}
    211 }