theme.c - ltk - GUI toolkit for X11 (WIP)
HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
HTML git clone https://lumidify.org/ltk.git (encrypted, but very slow)
HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
DIR Log
DIR Files
DIR Refs
DIR README
DIR 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 }