Menu parser: added boundary checks in the path-gen for #include file search
[wmaker-crm.git] / util / setstyle.c
bloba0d764d9bd501d268fd1f99df3c3315a418a7535
1 /* setstyle.c - loads style related options to wmaker
3 * WindowMaker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #ifdef __GLIBC__
23 #define _GNU_SOURCE /* getopt_long */
24 #endif
26 #include <sys/stat.h>
28 #include <getopt.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <unistd.h>
35 #include <X11/Xlib.h>
37 #include <WINGs/WUtil.h>
39 #include "../src/wconfig.h"
41 #define MAX_OPTIONS 128
43 char *FontOptions[] = {
44 "IconTitleFont",
45 "ClipTitleFont",
46 "DisplayFont",
47 "LargeDisplayFont",
48 "MenuTextFont",
49 "MenuTitleFont",
50 "WindowTitleFont",
51 NULL
54 char *CursorOptions[] = {
55 "NormalCursor",
56 "ArrowCursor",
57 "MoveCursor",
58 "ResizeCursor",
59 "TopLeftResizeCursor",
60 "TopRightResizeCursor",
61 "BottomLeftResizeCursor",
62 "BottomRightResizeCursor",
63 "VerticalResizeCursor",
64 "HorizontalResizeCursor",
65 "WaitCursor",
66 "QuestionCursor",
67 "TextCursor",
68 "SelectCursor",
69 NULL
72 extern char *__progname;
73 int ignoreFonts = 0;
74 int ignoreCursors = 0;
76 Display *dpy;
78 extern char *convertFont(char *font, Bool keepXLFD);
80 static Bool isCursorOption(char *option)
82 int i;
84 for (i = 0; CursorOptions[i] != NULL; i++) {
85 if (strcasecmp(option, CursorOptions[i]) == 0) {
86 return True;
90 return False;
93 static Bool isFontOption(char *option)
95 int i;
97 for (i = 0; FontOptions[i] != NULL; i++) {
98 if (strcasecmp(option, FontOptions[i]) == 0) {
99 return True;
103 return False;
107 * finds elements in `texture' that reference external files,
108 * prepends `prefix' to these files. `prefix' is a path component
109 * that qualifies the external references to be absolute, possibly
110 * pending further expansion
112 void hackPathInTexture(WMPropList * texture, char *prefix)
114 WMPropList *type;
115 char *t;
117 /* get texture type */
118 type = WMGetFromPLArray(texture, 0);
119 t = WMGetFromPLString(type);
120 if (t == NULL)
121 return;
123 if (strcasecmp(t, "tpixmap") == 0 ||
124 strcasecmp(t, "spixmap") == 0 ||
125 strcasecmp(t, "mpixmap") == 0 ||
126 strcasecmp(t, "cpixmap") == 0 ||
127 strcasecmp(t, "tvgradient") == 0 ||
128 strcasecmp(t, "thgradient") == 0 ||
129 strcasecmp(t, "tdgradient") == 0) {
130 WMPropList *file;
131 char buffer[4018];
133 /* get pixmap file path */
134 file = WMGetFromPLArray(texture, 1);
135 sprintf(buffer, "%s/%s", prefix, WMGetFromPLString(file));
136 /* replace path with full path */
137 WMDeleteFromPLArray(texture, 1);
138 WMInsertInPLArray(texture, 1, WMCreatePLString(buffer));
140 } else if (strcasecmp(t, "bitmap") == 0) {
141 WMPropList *file;
142 char buffer[4018];
144 /* get bitmap file path */
145 file = WMGetFromPLArray(texture, 1);
146 sprintf(buffer, "%s/%s", prefix, WMGetFromPLString(file));
147 /* replace path with full path */
148 WMDeleteFromPLArray(texture, 1);
149 WMInsertInPLArray(texture, 1, WMCreatePLString(buffer));
151 /* get mask file path */
152 file = WMGetFromPLArray(texture, 2);
153 sprintf(buffer, "%s/%s", prefix, WMGetFromPLString(file));
154 /* replace path with full path */
155 WMDeleteFromPLArray(texture, 2);
156 WMInsertInPLArray(texture, 2, WMCreatePLString(buffer));
160 void hackPaths(WMPropList * style, char *prefix)
162 WMPropList *keys;
163 WMPropList *key;
164 WMPropList *value;
165 int i;
167 keys = WMGetPLDictionaryKeys(style);
169 for (i = 0; i < WMGetPropListItemCount(keys); i++) {
170 key = WMGetFromPLArray(keys, i);
172 value = WMGetFromPLDictionary(style, key);
173 if (!value)
174 continue;
176 if (strcasecmp(WMGetFromPLString(key), "WorkspaceSpecificBack") == 0) {
177 if (WMIsPLArray(value)) {
178 int j;
179 WMPropList *texture;
181 for (j = 0; j < WMGetPropListItemCount(value); j++) {
182 texture = WMGetFromPLArray(value, j);
184 if (texture && WMIsPLArray(texture)
185 && WMGetPropListItemCount(texture) > 2) {
187 hackPathInTexture(texture, prefix);
191 } else {
193 if (WMIsPLArray(value) && WMGetPropListItemCount(value) > 2) {
195 hackPathInTexture(value, prefix);
202 static WMPropList *getColor(WMPropList * texture)
204 WMPropList *value, *type;
205 char *str;
207 type = WMGetFromPLArray(texture, 0);
208 if (!type)
209 return NULL;
211 value = NULL;
213 str = WMGetFromPLString(type);
214 if (strcasecmp(str, "solid") == 0) {
215 value = WMGetFromPLArray(texture, 1);
216 } else if (strcasecmp(str, "dgradient") == 0
217 || strcasecmp(str, "hgradient") == 0 || strcasecmp(str, "vgradient") == 0) {
218 WMPropList *c1, *c2;
219 int r1, g1, b1, r2, g2, b2;
220 char buffer[32];
222 c1 = WMGetFromPLArray(texture, 1);
223 c2 = WMGetFromPLArray(texture, 2);
224 if (!dpy) {
225 if (sscanf(WMGetFromPLString(c1), "#%2x%2x%2x", &r1, &g1, &b1) == 3
226 && sscanf(WMGetFromPLString(c2), "#%2x%2x%2x", &r2, &g2, &b2) == 3) {
227 sprintf(buffer, "#%02x%02x%02x", (r1 + r2) / 2, (g1 + g2) / 2, (b1 + b2) / 2);
228 value = WMCreatePLString(buffer);
229 } else {
230 value = c1;
232 } else {
233 XColor color1;
234 XColor color2;
236 XParseColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), WMGetFromPLString(c1), &color1);
237 XParseColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), WMGetFromPLString(c2), &color2);
239 sprintf(buffer, "#%02x%02x%02x",
240 (color1.red + color2.red) >> 9,
241 (color1.green + color2.green) >> 9, (color1.blue + color2.blue) >> 9);
242 value = WMCreatePLString(buffer);
244 } else if (strcasecmp(str, "mdgradient") == 0
245 || strcasecmp(str, "mhgradient") == 0 || strcasecmp(str, "mvgradient") == 0) {
247 value = WMGetFromPLArray(texture, 1);
249 } else if (strcasecmp(str, "tpixmap") == 0
250 || strcasecmp(str, "cpixmap") == 0 || strcasecmp(str, "spixmap") == 0) {
252 value = WMGetFromPLArray(texture, 2);
255 return value;
259 * since some of the options introduce incompatibilities, we will need
260 * to do a kluge here or the themes ppl will get real annoying.
261 * So, treat for the absence of the following options:
262 * IconTitleColor
263 * IconTitleBack
265 void hackStyle(WMPropList * style)
267 WMPropList *keys, *tmp;
268 int foundIconTitle = 0, foundResizebarBack = 0;
269 int i;
271 keys = WMGetPLDictionaryKeys(style);
273 for (i = 0; i < WMGetPropListItemCount(keys); i++) {
274 char *str;
276 tmp = WMGetFromPLArray(keys, i);
277 str = WMGetFromPLString(tmp);
278 if (str) {
279 if (ignoreFonts && isFontOption(str)) {
280 WMRemoveFromPLDictionary(style, tmp);
281 continue;
283 if (ignoreCursors && isCursorOption(str)) {
284 WMRemoveFromPLDictionary(style, tmp);
285 continue;
287 if (isFontOption(str)) {
288 WMPropList *value;
289 char *newfont, *oldfont;
291 value = WMGetFromPLDictionary(style, tmp);
292 if (value) {
293 oldfont = WMGetFromPLString(value);
294 newfont = convertFont(oldfont, False);
295 if (newfont != oldfont) {
296 value = WMCreatePLString(newfont);
297 WMPutInPLDictionary(style, tmp, value);
298 WMReleasePropList(value);
299 wfree(newfont);
303 if (strcasecmp(str, "IconTitleColor") == 0 || strcasecmp(str, "IconTitleBack") == 0) {
304 foundIconTitle = 1;
305 } else if (strcasecmp(str, "ResizebarBack") == 0) {
306 foundResizebarBack = 1;
311 if (!foundIconTitle) {
312 /* set the default values */
313 tmp = WMGetFromPLDictionary(style, WMCreatePLString("FTitleColor"));
314 if (tmp) {
315 WMPutInPLDictionary(style, WMCreatePLString("IconTitleColor"), tmp);
318 tmp = WMGetFromPLDictionary(style, WMCreatePLString("FTitleBack"));
319 if (tmp) {
320 WMPropList *value;
322 value = getColor(tmp);
324 if (value) {
325 WMPutInPLDictionary(style, WMCreatePLString("IconTitleBack"), value);
330 if (!foundResizebarBack) {
331 /* set the default values */
332 tmp = WMGetFromPLDictionary(style, WMCreatePLString("UTitleBack"));
333 if (tmp) {
334 WMPropList *value;
336 value = getColor(tmp);
338 if (value) {
339 WMPropList *t;
341 t = WMCreatePLArray(WMCreatePLString("solid"), value, NULL);
342 WMPutInPLDictionary(style, WMCreatePLString("ResizebarBack"), t);
347 if (!WMGetFromPLDictionary(style, WMCreatePLString("MenuStyle"))) {
348 WMPutInPLDictionary(style, WMCreatePLString("MenuStyle"), WMCreatePLString("normal"));
352 void print_help(int print_usage, int exitval)
354 printf("Usage: %s [OPTIONS] FILE\n", __progname);
355 if (print_usage) {
356 puts("Reads style/theme configuration from FILE and updates Window Maker.");
357 puts("");
358 puts(" --no-fonts ignore font related options");
359 puts(" --no-cursors ignore cursor related options");
360 puts(" --ignore <option> ignore changes in the specified option");
361 puts(" -h, --help display this help and exit");
362 puts(" -v, --version output version information and exit");
364 exit(exitval);
367 int main(int argc, char **argv)
369 WMPropList *prop, *style;
370 char *path;
371 char *file = NULL;
372 struct stat st;
373 int i, ch, ignflag = 0;
374 int ignoreCount = 0;
375 char *ignoreList[MAX_OPTIONS];
376 XEvent ev;
378 struct option longopts[] = {
379 { "version", no_argument, NULL, 'v' },
380 { "help", no_argument, NULL, 'h' },
381 { "no-fonts", no_argument, &ignoreFonts, 1 },
382 { "no-cursors", no_argument, &ignoreCursors, 1 },
383 { "ignore", required_argument, &ignflag, 1 },
384 { NULL, 0, NULL, 0 }
387 while ((ch = getopt_long(argc, argv, "hv", longopts, NULL)) != -1)
388 switch(ch) {
389 case 'v':
390 printf("%s (Window Maker %s)\n", __progname, VERSION);
391 return 0;
392 /* NOTREACHED */
393 case 'h':
394 print_help(1, 0);
395 /* NOTREACHED */
396 case 0:
397 if (ignflag) {
398 if (ignoreCount >= MAX_OPTIONS) {
399 printf("Maximum %d `ignore' arguments\n", MAX_OPTIONS);
400 return 1;
402 ignoreList[ignoreCount++] = optarg;
403 ignflag = 0;
405 break;
406 default:
407 print_help(0, 1);
408 /* NOTREACHED */
411 argc -= optind;
412 argv += optind;
414 if (argc != 1)
415 print_help(0, 1);
417 file = argv[0];
419 WMPLSetCaseSensitive(False);
421 path = wdefaultspathfordomain("WindowMaker");
423 prop = WMReadPropListFromFile(path);
424 if (!prop) {
425 perror(path);
426 printf("%s: could not load WindowMaker configuration file.\n", __progname);
427 return 1;
430 if (stat(file, &st) < 0) {
431 perror(file);
432 return 1;
434 if (S_ISDIR(st.st_mode)) { /* theme pack */
435 char buf[PATH_MAX];
436 char *homedir;
438 if (realpath(file, buf) == NULL) {
439 perror(file);
440 return 1;
442 strncat(buf, "/style", sizeof(buf) - strlen(buf));
444 if (stat(buf, &st) != 0 || !S_ISREG(st.st_mode)) { /* maybe symlink too? */
445 printf("%s: %s: style file not found or not a file\n", __progname, buf);
446 return 1;
449 style = WMReadPropListFromFile(buf);
450 if (!style) {
451 perror(buf);
452 printf("%s: could not load style file.\n", __progname);
453 return 1;
456 buf[strlen(buf) - 6 /* strlen("/style") */] = '\0';
457 homedir = wstrdup(wgethomedir());
458 if (strlen(homedir) > 1 && /* this is insane, wgethomedir() returns `/' on error */
459 strncmp(homedir, buf, strlen(homedir)) == 0) {
460 /* theme pack is under ${HOME}; exchange ${HOME} part
461 * for `~' so it gets portable references to the user home dir */
462 *buf = '~';
463 memmove(buf + 1, buf + strlen(homedir), strlen(buf) - strlen(homedir) + 1);
465 wfree(homedir);
467 hackPaths(style, buf); /* this will prefix pixmaps in the style
468 * with absolute(ish) references */
470 } else { /* normal style file */
472 style = WMReadPropListFromFile(file);
473 if (!style) {
474 perror(file);
475 printf("%s:could not load style file.\n", __progname);
476 return 1;
480 if (!WMIsPLDictionary(style)) {
481 printf("%s: '%s' is not a style file/theme\n", __progname, file);
482 return 1;
485 hackStyle(style);
487 if (ignoreCount > 0) {
488 for (i = 0; i < ignoreCount; i++) {
489 WMRemoveFromPLDictionary(style, WMCreatePLString(ignoreList[i]));
493 WMMergePLDictionaries(prop, style, True);
495 WMWritePropListToFile(prop, path);
497 dpy = XOpenDisplay("");
498 if (dpy) {
499 memset(&ev, 0, sizeof(XEvent));
501 ev.xclient.type = ClientMessage;
502 ev.xclient.message_type = XInternAtom(dpy, "_WINDOWMAKER_COMMAND", False);
503 ev.xclient.window = DefaultRootWindow(dpy);
504 ev.xclient.format = 8;
505 strncpy(ev.xclient.data.b, "Reconfigure", sizeof(ev.xclient.data.b));
507 XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureRedirectMask, &ev);
508 XFlush(dpy);
511 return 0;