WMList compiles now, single selection seems to be ok (as it used to be) but
[wmaker-crm.git] / util / setstyle.c
blob6246d65765e7c9ef9c777108f7f2f4e0bb7e4407
1 /* setstyle.c - loads style related options to wmaker
3 * WindowMaker window manager
4 *
5 * Copyright (c) 1997~2000 Alfredo K. Kojima
6 *
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
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
24 #define PROG_VERSION "setstyle (Window Maker) 0.6"
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <proplist.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
32 #include <X11/Xlib.h>
34 #include <string.h>
36 #include "../src/wconfig.h"
38 #define MAX_OPTIONS 128
40 char *FontOptions[] = {
41 "IconTitleFont",
42 "ClipTitleFont",
43 "DisplayFont",
44 "LargeDisplayFont",
45 "MenuTextFont",
46 "MenuTitleFont",
47 "WindowTitleFont",
48 NULL
53 char *ProgName;
54 int ignoreFonts = 0;
56 Display *dpy;
60 proplist_t readBlackBoxStyle(char *path);
64 char*
65 defaultsPathForDomain(char *domain)
67 char path[1024];
68 char *gspath, *tmp;
70 gspath = getenv("GNUSTEP_USER_ROOT");
71 if (gspath) {
72 strcpy(path, gspath);
73 strcat(path, "/");
74 } else {
75 char *home;
77 home = getenv("HOME");
78 if (!home) {
79 printf("%s:could not get HOME environment variable!\n", ProgName);
80 exit(0);
83 strcpy(path, home);
84 strcat(path, "/GNUstep/");
86 strcat(path, DEFAULTS_DIR);
87 strcat(path, "/");
88 strcat(path, domain);
90 tmp = malloc(strlen(path)+2);
91 strcpy(tmp, path);
93 return tmp;
98 void
99 hackPathInTexture(proplist_t texture, char *prefix)
101 proplist_t type;
102 char *t;
104 /* get texture type */
105 type = PLGetArrayElement(texture, 0);
106 t = PLGetString(type);
107 if (t == NULL)
108 return;
109 if (strcasecmp(t, "tpixmap")==0
110 || strcasecmp(t, "spixmap")==0
111 || strcasecmp(t, "mpixmap")==0
112 || strcasecmp(t, "cpixmap")==0
113 || strcasecmp(t, "tvgradient")==0
114 || strcasecmp(t, "thgradient")==0
115 || strcasecmp(t, "tdgradient")==0) {
116 proplist_t file;
117 char buffer[4018];
119 /* get pixmap file path */
120 file = PLGetArrayElement(texture, 1);
121 sprintf(buffer, "%s/%s", prefix, PLGetString(file));
122 /* replace path with full path */
123 PLRemoveArrayElement(texture, 1);
124 PLInsertArrayElement(texture, PLMakeString(buffer), 1);
125 } else if (strcasecmp(t, "bitmap") == 0) {
126 proplist_t file;
127 char buffer[4018];
129 /* get bitmap file path */
130 file = PLGetArrayElement(texture, 1);
131 sprintf(buffer, "%s/%s", prefix, PLGetString(file));
132 /* replace path with full path */
133 PLRemoveArrayElement(texture, 1);
134 PLInsertArrayElement(texture, PLMakeString(buffer), 1);
136 /* get mask file path */
137 file = PLGetArrayElement(texture, 2);
138 sprintf(buffer, "%s/%s", prefix, PLGetString(file));
139 /* replace path with full path */
140 PLRemoveArrayElement(texture, 2);
141 PLInsertArrayElement(texture, PLMakeString(buffer), 2);
146 void
147 hackPaths(proplist_t style, char *prefix)
149 proplist_t keys;
150 proplist_t key;
151 proplist_t value;
152 int i;
155 keys = PLGetAllDictionaryKeys(style);
157 for (i = 0; i < PLGetNumberOfElements(keys); i++) {
158 key = PLGetArrayElement(keys, i);
160 value = PLGetDictionaryEntry(style, key);
161 if (!value)
162 continue;
164 if (strcasecmp(PLGetString(key), "WorkspaceSpecificBack")==0) {
165 if (PLIsArray(value)) {
166 int j;
167 proplist_t texture;
169 for (j = 0; j < PLGetNumberOfElements(value); j++) {
170 texture = PLGetArrayElement(value, j);
172 if (texture && PLIsArray(texture)
173 && PLGetNumberOfElements(texture) > 2) {
175 hackPathInTexture(texture, prefix);
179 } else {
181 if (PLIsArray(value) && PLGetNumberOfElements(value) > 2) {
183 hackPathInTexture(value, prefix);
191 static proplist_t
192 getColor(proplist_t texture)
194 proplist_t value, type;
195 char *str;
197 type = PLGetArrayElement(texture, 0);
198 if (!type)
199 return NULL;
201 value = NULL;
203 str = PLGetString(type);
204 if (strcasecmp(str, "solid")==0) {
205 value = PLGetArrayElement(texture, 1);
206 } else if (strcasecmp(str, "dgradient")==0
207 || strcasecmp(str, "hgradient")==0
208 || strcasecmp(str, "vgradient")==0) {
209 proplist_t c1, c2;
210 int r1, g1, b1, r2, g2, b2;
211 char buffer[32];
213 c1 = PLGetArrayElement(texture, 1);
214 c2 = PLGetArrayElement(texture, 2);
215 if (!dpy) {
216 if (sscanf(PLGetString(c1), "#%2x%2x%2x", &r1, &g1, &b1)==3
217 && sscanf(PLGetString(c2), "#%2x%2x%2x", &r2, &g2, &b2)==3) {
218 sprintf(buffer, "#%02x%02x%02x", (r1+r2)/2, (g1+g2)/2,
219 (b1+b2)/2);
220 value = PLMakeString(buffer);
221 } else {
222 value = c1;
224 } else {
225 XColor color1;
226 XColor color2;
228 XParseColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),
229 PLGetString(c1), &color1);
230 XParseColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),
231 PLGetString(c2), &color2);
233 sprintf(buffer, "#%02x%02x%02x",
234 (color1.red+color2.red)>>9,
235 (color1.green+color2.green)>>9,
236 (color1.blue+color2.blue)>>9);
237 value = PLMakeString(buffer);
239 } else if (strcasecmp(str, "mdgradient")==0
240 || strcasecmp(str, "mhgradient")==0
241 || strcasecmp(str, "mvgradient")==0) {
243 value = PLGetArrayElement(texture, 1);
245 } else if (strcasecmp(str, "tpixmap")==0
246 || strcasecmp(str, "cpixmap")==0
247 || strcasecmp(str, "spixmap")==0) {
249 value = PLGetArrayElement(texture, 2);
252 return value;
257 * since some of the options introduce incompatibilities, we will need
258 * to do a kluge here or the themes ppl will get real annoying.
259 * So, treat for the absence of the following options:
260 * IconTitleColor
261 * IconTitleBack
263 void
264 hackStyle(proplist_t style)
266 proplist_t keys;
267 proplist_t tmp;
268 int i;
269 int foundIconTitle = 0;
270 int foundResizebarBack = 0;
272 keys = PLGetAllDictionaryKeys(style);
274 for (i = 0; i < PLGetNumberOfElements(keys); i++) {
275 char *str;
277 tmp = PLGetArrayElement(keys, i);
278 str = PLGetString(tmp);
279 if (str) {
280 int j, found;
282 if (ignoreFonts) {
283 for (j = 0, found = 0; FontOptions[j]!=NULL; j++) {
284 if (strcasecmp(str, FontOptions[j])==0) {
285 PLRemoveDictionaryEntry(style, tmp);
286 found = 1;
287 break;
290 if (found)
291 continue;
294 if (strcasecmp(str, "IconTitleColor")==0
295 || strcasecmp(str, "IconTitleBack")==0) {
296 foundIconTitle = 1;
297 } else if (strcasecmp(str, "ResizebarBack")==0) {
298 foundResizebarBack = 1;
303 if (!foundIconTitle) {
304 /* set the default values */
305 tmp = PLGetDictionaryEntry(style, PLMakeString("FTitleColor"));
306 if (tmp) {
307 PLInsertDictionaryEntry(style, PLMakeString("IconTitleColor"),
308 tmp);
311 tmp = PLGetDictionaryEntry(style, PLMakeString("FTitleBack"));
312 if (tmp) {
313 proplist_t value;
315 value = getColor(tmp);
317 if (value) {
318 PLInsertDictionaryEntry(style, PLMakeString("IconTitleBack"),
319 value);
324 if (!foundResizebarBack) {
325 /* set the default values */
326 tmp = PLGetDictionaryEntry(style, PLMakeString("UTitleBack"));
327 if (tmp) {
328 proplist_t value;
330 value = getColor(tmp);
332 if (value) {
333 proplist_t t;
335 t = PLMakeArrayFromElements(PLMakeString("solid"), value,
336 NULL);
337 PLInsertDictionaryEntry(style, PLMakeString("ResizebarBack"),
344 if (!PLGetDictionaryEntry(style, PLMakeString("MenuStyle"))) {
345 PLInsertDictionaryEntry(style, PLMakeString("MenuStyle"),
346 PLMakeString("normal"));
351 BOOL
352 StringCompareHook(proplist_t pl1, proplist_t pl2)
354 char *str1, *str2;
356 str1 = PLGetString(pl1);
357 str2 = PLGetString(pl2);
359 if (strcasecmp(str1, str2)==0)
360 return YES;
361 else
362 return NO;
366 void
367 print_help()
369 printf("Usage: %s [OPTIONS] FILE\n", ProgName);
370 puts("Reads style/theme configuration from FILE and updates Window Maker.");
371 puts("");
372 puts(" --no-fonts ignore font related options");
373 puts(" --ignore <option> ignore changes in the specified option");
374 puts(" --help display this help and exit");
376 puts(" --format <format> specifies the format of the theme to be converted");
378 puts(" --version output version information and exit");
379 puts("");
380 puts("Supported formats: blackbox");
384 #define F_BLACKBOX 1
386 int
387 main(int argc, char **argv)
389 proplist_t prop, style;
390 char *path;
391 char *file = NULL;
392 struct stat statbuf;
393 int i;
394 int ignoreCount = 0;
395 char *ignoreList[MAX_OPTIONS];
397 dpy = XOpenDisplay("");
399 ProgName = argv[0];
401 if (argc<2) {
402 printf("%s: missing argument\n", ProgName);
403 printf("Try '%s --help' for more information\n", ProgName);
404 exit(1);
407 for (i = 1; i < argc; i++) {
408 if (strcmp("--ignore", argv[i])==0) {
409 i++;
410 if (i == argc) {
411 printf("%s: missing argument for option --ignore\n", ProgName);
412 exit(1);
414 ignoreList[ignoreCount++] = argv[i];
416 } else if (strcmp("--no-fonts", argv[i])==0) {
417 ignoreFonts = 1;
418 } else if (strcmp("--version", argv[i])==0) {
419 puts(PROG_VERSION);
420 exit(0);
421 } else if (strcmp("--help", argv[i])==0) {
422 print_help();
423 exit(0);
424 #if 0
425 } else if (strcmp("--format", argv[i])==0) {
426 i++;
427 if (i == argc) {
428 printf("%s: missing argument for option --format\n", ProgName);
429 exit(1);
431 if (strcasecmp(argv[i], "blackbox")==0) {
432 format = F_BLACKBOX;
433 } else {
434 printf("%s: unknown theme format '%s'\n", ProgName, argv[i]);
435 exit(1);
437 #endif
438 } else {
439 if (file) {
440 printf("%s: invalid argument '%s'\n", ProgName, argv[i]);
441 printf("Try '%s --help' for more information\n", ProgName);
442 exit(1);
444 file = argv[i];
448 PLSetStringCmpHook(StringCompareHook);
450 path = defaultsPathForDomain("WindowMaker");
452 prop = PLGetProplistWithPath(path);
453 if (!prop) {
454 perror(path);
455 printf("%s:could not load WindowMaker configuration file.\n",
456 ProgName);
457 exit(1);
460 if (stat(file, &statbuf) < 0) {
461 perror(file);
462 exit(1);
464 #if 0
465 if (format == F_BLACKBOX) {
466 style = readBlackBoxStyle(file);
467 if (!style) {
468 printf("%s: could not open style file\n", ProgName);
469 exit(1);
471 } else
472 #endif
474 if (S_ISDIR(statbuf.st_mode)) {
475 char buffer[4018];
476 char *prefix;
477 /* theme pack */
479 if (*argv[argc-1] != '/') {
480 if (!getcwd(buffer, 4000)) {
481 printf("%s: complete path for %s is too long\n", ProgName,
482 file);
483 exit(1);
485 if (strlen(buffer) + strlen(file) > 4000) {
486 printf("%s: complete path for %s is too long\n", ProgName,
487 file);
488 exit(1);
490 strcat(buffer, "/");
491 } else {
492 buffer[0] = 0;
494 strcat(buffer, file);
496 prefix = malloc(strlen(buffer)+10);
497 if (!prefix) {
498 printf("%s: out of memory\n", ProgName);
499 exit(1);
501 strcpy(prefix, buffer);
503 strcat(buffer, "/style");
505 style = PLGetProplistWithPath(buffer);
506 if (!style) {
507 perror(buffer);
508 printf("%s:could not load style file.\n", ProgName);
509 exit(1);
512 hackPaths(style, prefix);
513 free(prefix);
514 } else {
515 /* normal style file */
517 style = PLGetProplistWithPath(file);
518 if (!style) {
519 perror(file);
520 printf("%s:could not load style file.\n", ProgName);
521 exit(1);
526 if (!PLIsDictionary(style)) {
527 printf("%s: '%s' is not a style file/theme\n", ProgName, file);
528 exit(1);
531 hackStyle(style);
533 if (ignoreCount > 0) {
534 for (i = 0; i < ignoreCount; i++) {
535 PLRemoveDictionaryEntry(style, PLMakeString(ignoreList[i]));
539 PLMergeDictionaries(prop, style);
541 PLSave(prop, YES);
543 XEvent ev;
545 if (dpy) {
546 int i;
547 char *msg = "Reconfigure";
549 memset(&ev, 0, sizeof(XEvent));
551 ev.xclient.type = ClientMessage;
552 ev.xclient.message_type = XInternAtom(dpy, "_WINDOWMAKER_COMMAND",
553 False);
554 ev.xclient.window = DefaultRootWindow(dpy);
555 ev.xclient.format = 8;
557 for (i = 0; i <= strlen(msg); i++) {
558 ev.xclient.data.b[i] = msg[i];
560 XSendEvent(dpy, DefaultRootWindow(dpy), False,
561 SubstructureRedirectMask, &ev);
562 XFlush(dpy);
566 exit(0);
570 #if 0
571 char*
572 getToken(char *str, int i, char *buf)
578 proplist_t
579 readBlackBoxStyle(char *path)
581 FILE *f;
582 char buffer[128], char token[128];
583 proplist_t style;
584 proplist_t p;
586 f = fopen(path, "r");
587 if (!f) {
588 perror(path);
589 return NULL;
592 while (1) {
593 if (!fgets(buffer, 127, f))
594 break;
596 if (strncasecmp(buffer, "menu.title:", 11)==0) {
601 #endif