Initial update from my source tree. For 0.52.0
[wmaker-crm.git] / util / wmsetbg.c
blob35d43577d7b6298de0c9962db04cf87604d32efb
1 /* wmsetbg.c- sets root window background image and also works as
2 * workspace background setting helper for wmaker
4 * WindowMaker window manager
5 *
6 * Copyright (c) 1998, 1999 Alfredo K. Kojima
7 * Copyright (c) 1998 Dan Pascu
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22 * USA.
26 * TODO: rewrite, too dirty
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34 #include <X11/Xatom.h>
35 #include <string.h>
36 #include <pwd.h>
37 #include <signal.h>
38 #include <sys/types.h>
39 #include <ctype.h>
41 #include "../src/wconfig.h"
43 #include "../WINGs/WINGs.h"
44 #include "../WINGs/WUtil.h"
45 #include "../wrlib/wraster.h"
47 #include <proplist.h>
49 #define PROG_VERSION "wmsetbg (Window Maker) 2.1"
52 #define WORKSPACE_COUNT (MAX_WORKSPACES+1)
55 Display *dpy;
56 char *display = "";
57 Window root;
58 int scr;
59 int scrWidth;
60 int scrHeight;
62 Pixmap CurrentPixmap = None;
63 char *PixmapPath = NULL;
66 extern Pixmap LoadJPEG(RContext *rc, char *file_name, int *width, int *height);
69 typedef struct BackgroundTexture {
70 int refcount;
72 int solid;
74 char *spec;
76 XColor color;
77 Pixmap pixmap; /* for all textures, including solid */
78 int width; /* size of the pixmap */
79 int height;
80 } BackgroundTexture;
84 RImage*
85 loadImage(RContext *rc, char *file)
87 char *path;
88 RImage *image;
90 if (access(file, F_OK)!=0) {
91 path = wfindfile(PixmapPath, file);
92 if (!path) {
93 wwarning("%s:could not find image file used in texture", file);
94 return NULL;
96 } else {
97 path = wstrdup(file);
100 image = RLoadImage(rc, path, 0);
101 if (!image) {
102 wwarning("%s:could not load image file used in texture:%s", path,
103 RMessageForError(RErrorCode));
105 free(path);
107 return image;
111 BackgroundTexture*
112 parseTexture(RContext *rc, char *text)
114 BackgroundTexture *texture = NULL;
115 proplist_t texarray;
116 proplist_t val;
117 int count;
118 char *tmp;
119 char *type;
121 #define GETSTR(val, str, i) \
122 val = PLGetArrayElement(texarray, i);\
123 if (!PLIsString(val)) {\
124 wwarning("could not parse texture %s", text);\
125 goto error;\
127 str = PLGetString(val)
130 texarray = PLGetProplistWithDescription(text);
131 if (!texarray || !PLIsArray(texarray)
132 || (count = PLGetNumberOfElements(texarray)) < 2) {
134 wwarning("could not parse texture %s", text);
135 if (texarray)
136 PLRelease(texarray);
137 return NULL;
140 texture = wmalloc(sizeof(BackgroundTexture));
141 memset(texture, 0, sizeof(BackgroundTexture));
143 GETSTR(val, type, 0);
145 if (strcasecmp(type, "solid")==0) {
146 XColor color;
147 Pixmap pixmap;
149 texture->solid = 1;
151 GETSTR(val, tmp, 1);
153 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
154 wwarning("could not parse color %s in texture %s", tmp, text);
155 goto error;
157 XAllocColor(dpy, DefaultColormap(dpy, scr), &color);
159 pixmap = XCreatePixmap(dpy, root, 8, 8, DefaultDepth(dpy, scr));
160 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
161 XFillRectangle(dpy, pixmap, DefaultGC(dpy, scr), 0, 0, 8, 8);
163 texture->pixmap = pixmap;
164 texture->color = color;
165 texture->width = 8;
166 texture->height = 8;
167 } else if (strcasecmp(type, "vgradient")==0
168 || strcasecmp(type, "dgradient")==0
169 || strcasecmp(type, "hgradient")==0) {
170 XColor color;
171 RColor color1, color2;
172 RImage *image;
173 Pixmap pixmap;
174 int gtype;
175 int iwidth, iheight;
177 GETSTR(val, tmp, 1);
179 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
180 wwarning("could not parse color %s in texture %s", tmp, text);
181 goto error;
184 color1.red = color.red >> 8;
185 color1.green = color.green >> 8;
186 color1.blue = color.blue >> 8;
188 GETSTR(val, tmp, 2);
190 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
191 wwarning("could not parse color %s in texture %s", tmp, text);
192 goto error;
195 color2.red = color.red >> 8;
196 color2.green = color.green >> 8;
197 color2.blue = color.blue >> 8;
199 switch (type[0]) {
200 case 'h':
201 case 'H':
202 gtype = RHorizontalGradient;
203 iwidth = scrWidth;
204 iheight = 1;
205 break;
206 case 'V':
207 case 'v':
208 gtype = RVerticalGradient;
209 iwidth = 1;
210 iheight = scrHeight;
211 break;
212 default:
213 gtype = RDiagonalGradient;
214 iwidth = scrWidth;
215 iheight = scrHeight;
216 break;
219 image = RRenderGradient(iwidth, iheight, &color1, &color2, gtype);
221 if (!image) {
222 wwarning("could not render gradient texture:%s",
223 RMessageForError(RErrorCode));
224 goto error;
227 if (!RConvertImage(rc, image, &pixmap)) {
228 wwarning("could not convert texture:%s",
229 RMessageForError(RErrorCode));
230 RDestroyImage(image);
231 goto error;
234 texture->width = image->width;
235 texture->height = image->height;
236 RDestroyImage(image);
238 texture->pixmap = pixmap;
239 } else if (strcasecmp(type, "mvgradient")==0
240 || strcasecmp(type, "mdgradient")==0
241 || strcasecmp(type, "mhgradient")==0) {
242 XColor color;
243 RColor **colors;
244 RImage *image;
245 Pixmap pixmap;
246 int i, j;
247 int gtype;
248 int iwidth, iheight;
250 colors = malloc(sizeof(RColor*)*(count-1));
251 if (!colors) {
252 wwarning("out of memory while parsing texture");
253 goto error;
255 memset(colors, 0, sizeof(RColor*)*(count-1));
257 for (i = 2; i < count; i++) {
258 val = PLGetArrayElement(texarray, i);
259 if (!PLIsString(val)) {
260 wwarning("could not parse texture %s", text);
262 for (j = 0; colors[j]!=NULL; j++)
263 free(colors[j]);
264 free(colors);
265 goto error;
267 tmp = PLGetString(val);
269 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
270 wwarning("could not parse color %s in texture %s",
271 tmp, text);
273 for (j = 0; colors[j]!=NULL; j++)
274 free(colors[j]);
275 free(colors);
276 goto error;
278 if (!(colors[i-2] = malloc(sizeof(RColor)))) {
279 wwarning("out of memory while parsing texture");
281 for (j = 0; colors[j]!=NULL; j++)
282 free(colors[j]);
283 free(colors);
284 goto error;
287 colors[i-2]->red = color.red >> 8;
288 colors[i-2]->green = color.green >> 8;
289 colors[i-2]->blue = color.blue >> 8;
292 switch (type[1]) {
293 case 'h':
294 case 'H':
295 gtype = RHorizontalGradient;
296 iwidth = scrWidth;
297 iheight = 1;
298 break;
299 case 'V':
300 case 'v':
301 gtype = RVerticalGradient;
302 iwidth = 1;
303 iheight = scrHeight;
304 break;
305 default:
306 gtype = RDiagonalGradient;
307 iwidth = scrWidth;
308 iheight = scrHeight;
309 break;
312 image = RRenderMultiGradient(iwidth, iheight, colors, gtype);
314 for (j = 0; colors[j]!=NULL; j++)
315 free(colors[j]);
316 free(colors);
318 if (!image) {
319 wwarning("could not render gradient texture:%s",
320 RMessageForError(RErrorCode));
321 goto error;
324 if (!RConvertImage(rc, image, &pixmap)) {
325 wwarning("could not convert texture:%s",
326 RMessageForError(RErrorCode));
327 RDestroyImage(image);
328 goto error;
331 texture->width = image->width;
332 texture->height = image->height;
333 RDestroyImage(image);
335 texture->pixmap = pixmap;
336 } else if (strcasecmp(type, "cpixmap")==0
337 || strcasecmp(type, "spixmap")==0
338 || strcasecmp(type, "mpixmap")==0
339 || strcasecmp(type, "tpixmap")==0) {
340 XColor color;
341 Pixmap pixmap = None;
342 RImage *image = NULL;
343 int w, h;
344 int iwidth, iheight;
346 GETSTR(val, tmp, 1);
348 if (toupper(type[0]) == 'T' || toupper(type[0]) == 'C')
349 pixmap = LoadJPEG(rc, tmp, &iwidth, &iheight);
352 if (!pixmap) {
353 image = loadImage(rc, tmp);
354 if (!image) {
355 goto error;
357 iwidth = image->width;
358 iheight = image->height;
361 GETSTR(val, tmp, 2);
363 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
364 wwarning("could not parse color %s in texture %s\n", tmp, text);
365 RDestroyImage(image);
366 goto error;
368 if (!XAllocColor(dpy, DefaultColormap(dpy, scr), &color)) {
369 RColor rcolor;
371 rcolor.red = color.red >> 8;
372 rcolor.green = color.green >> 8;
373 rcolor.blue = color.blue >> 8;
374 RGetClosestXColor(rc, &rcolor, &color);
376 switch (toupper(type[0])) {
377 case 'T':
378 texture->width = iwidth;
379 texture->height = iheight;
380 if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
381 wwarning("could not convert texture:%s",
382 RMessageForError(RErrorCode));
383 RDestroyImage(image);
384 goto error;
386 if (image)
387 RDestroyImage(image);
388 break;
389 case 'S':
390 case 'M':
391 if (toupper(type[0])=='S') {
392 w = scrWidth;
393 h = scrHeight;
394 } else {
395 if (iwidth*scrHeight > iheight*scrWidth) {
396 w = scrWidth;
397 h = (scrWidth*iheight)/iwidth;
398 } else {
399 h = scrHeight;
400 w = (scrHeight*iwidth)/iheight;
404 RImage *simage;
406 simage = RScaleImage(image, w, h);
407 if (!simage) {
408 wwarning("could not scale image:%s",
409 RMessageForError(RErrorCode));
410 RDestroyImage(image);
411 goto error;
413 RDestroyImage(image);
414 image = simage;
415 iwidth = image->width;
416 iheight = image->height;
418 /* fall through */
419 case 'C':
421 Pixmap cpixmap;
423 if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
424 wwarning("could not convert texture:%s",
425 RMessageForError(RErrorCode));
426 RDestroyImage(image);
427 goto error;
430 if (iwidth != scrWidth || iheight != scrHeight) {
431 int x, y, sx, sy, w, h;
433 cpixmap = XCreatePixmap(dpy, root, scrWidth, scrHeight,
434 DefaultDepth(dpy, scr));
436 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
437 XFillRectangle(dpy, cpixmap, DefaultGC(dpy, scr),
438 0, 0, scrWidth, scrHeight);
440 if (iheight < scrHeight) {
441 h = iheight;
442 y = (scrHeight - h)/2;
443 sy = 0;
444 } else {
445 sy = (iheight - scrHeight)/2;
446 y = 0;
447 h = scrHeight;
449 if (iwidth < scrWidth) {
450 w = iwidth;
451 x = (scrWidth - w)/2;
452 sx = 0;
453 } else {
454 sx = (iwidth - scrWidth)/2;
455 x = 0;
456 w = scrWidth;
459 XCopyArea(dpy, pixmap, cpixmap, DefaultGC(dpy, scr),
460 sx, sy, w, h, x, y);
461 XFreePixmap(dpy, pixmap);
462 pixmap = cpixmap;
464 if (image)
465 RDestroyImage(image);
467 texture->width = scrWidth;
468 texture->height = scrHeight;
470 break;
473 texture->pixmap = pixmap;
474 texture->color = color;
475 } else if (strcasecmp(type, "thgradient")==0
476 || strcasecmp(type, "tvgradient")==0
477 || strcasecmp(type, "tdgradient")==0) {
478 XColor color;
479 RColor color1, color2;
480 RImage *image;
481 RImage *gradient;
482 RImage *tiled;
483 Pixmap pixmap;
484 int opaq;
485 char *file;
486 int gtype;
487 int twidth, theight;
489 GETSTR(val, file, 1);
491 GETSTR(val, tmp, 2);
493 opaq = atoi(tmp);
495 GETSTR(val, tmp, 3);
497 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
498 wwarning("could not parse color %s in texture %s", tmp, text);
499 goto error;
502 color1.red = color.red >> 8;
503 color1.green = color.green >> 8;
504 color1.blue = color.blue >> 8;
506 GETSTR(val, tmp, 4);
508 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
509 wwarning("could not parse color %s in texture %s", tmp, text);
510 goto error;
513 color2.red = color.red >> 8;
514 color2.green = color.green >> 8;
515 color2.blue = color.blue >> 8;
517 image = loadImage(rc, file);
518 if (!image) {
519 RDestroyImage(gradient);
520 goto error;
523 switch (type[1]) {
524 case 'h':
525 case 'H':
526 gtype = RHorizontalGradient;
527 twidth = scrWidth;
528 theight = image->height > scrHeight ? scrHeight : image->height;
529 break;
530 case 'V':
531 case 'v':
532 gtype = RVerticalGradient;
533 twidth = image->width > scrWidth ? scrWidth : image->width;
534 theight = scrHeight;
535 break;
536 default:
537 gtype = RDiagonalGradient;
538 twidth = scrWidth;
539 theight = scrHeight;
540 break;
542 gradient = RRenderGradient(twidth, theight, &color1, &color2, gtype);
544 if (!gradient) {
545 wwarning("could not render texture:%s",
546 RMessageForError(RErrorCode));
547 RDestroyImage(gradient);
548 goto error;
551 tiled = RMakeTiledImage(image, twidth, theight);
552 if (!tiled) {
553 wwarning("could not render texture:%s",
554 RMessageForError(RErrorCode));
555 RDestroyImage(gradient);
556 RDestroyImage(image);
557 goto error;
559 RDestroyImage(image);
561 RCombineImagesWithOpaqueness(tiled, gradient, opaq);
562 RDestroyImage(gradient);
564 if (!RConvertImage(rc, tiled, &pixmap)) {
565 wwarning("could not convert texture:%s",
566 RMessageForError(RErrorCode));
567 RDestroyImage(image);
568 goto error;
570 texture->width = tiled->width;
571 texture->height = tiled->height;
573 RDestroyImage(tiled);
575 texture->pixmap = pixmap;
576 } else {
577 wwarning("invalid texture type %s", text);
578 goto error;
581 texture->spec = wstrdup(text);
583 return texture;
585 error:
586 if (texture)
587 free(texture);
588 if (texarray)
589 PLRelease(texarray);
591 return NULL;
595 void
596 freeTexture(BackgroundTexture *texture)
598 if (texture->solid) {
599 long pixel[1];
601 pixel[0] = texture->color.pixel;
602 /* dont free black/white pixels */
603 if (pixel[0]!=BlackPixelOfScreen(DefaultScreenOfDisplay(dpy))
604 && pixel[0]!=WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
605 XFreeColors(dpy, DefaultColormap(dpy, scr), pixel, 1, 0);
607 free(texture->spec);
608 free(texture);
612 void
613 setupTexture(RContext *rc, BackgroundTexture **textures, int *maxTextures,
614 int workspace, char *texture)
616 BackgroundTexture *newTexture = NULL;
617 int i;
619 /* unset the texture */
620 if (!texture) {
621 if (textures[workspace]!=NULL) {
622 textures[workspace]->refcount--;
624 if (textures[workspace]->refcount == 0)
625 freeTexture(textures[workspace]);
627 textures[workspace] = NULL;
628 return;
631 if (textures[workspace]
632 && strcasecmp(textures[workspace]->spec, texture)==0) {
633 /* texture did not change */
634 return;
637 /* check if the same texture is already created */
638 for (i = 0; i < *maxTextures; i++) {
639 if (textures[i] && strcasecmp(textures[i]->spec, texture)==0) {
640 newTexture = textures[i];
641 break;
645 if (!newTexture) {
646 /* create the texture */
647 newTexture = parseTexture(rc, texture);
649 if (!newTexture)
650 return;
652 if (textures[workspace]!=NULL) {
654 textures[workspace]->refcount--;
656 if (textures[workspace]->refcount == 0)
657 freeTexture(textures[workspace]);
660 newTexture->refcount++;
661 textures[workspace] = newTexture;
663 if (*maxTextures < workspace)
664 *maxTextures = workspace;
669 Pixmap
670 duplicatePixmap(Pixmap pixmap, int width, int height)
672 Display *tmpDpy;
673 Pixmap copyP;
675 /* must open a new display or the RetainPermanent will
676 * leave stuff allocated in RContext unallocated after exit */
677 tmpDpy = XOpenDisplay(display);
678 if (!tmpDpy) {
679 wwarning("could not open display to update background image information");
681 return None;
682 } else {
683 XSync(dpy, False);
685 copyP = XCreatePixmap(tmpDpy, root, width, height,
686 DefaultDepth(tmpDpy, scr));
687 XCopyArea(tmpDpy, pixmap, copyP, DefaultGC(tmpDpy, scr),
688 0, 0, width, height, 0, 0);
689 XSync(tmpDpy, False);
691 XSetCloseDownMode(tmpDpy, RetainPermanent);
692 XCloseDisplay(tmpDpy);
695 return copyP;
699 static int
700 dummyErrorHandler(Display *dpy, XErrorEvent *err)
702 return 0;
705 void
706 setPixmapProperty(Pixmap pixmap)
708 static Atom prop = 0;
709 Atom type;
710 int format;
711 unsigned long length, after;
712 unsigned char *data;
713 int mode;
715 if (!prop) {
716 prop = XInternAtom(dpy, "_XROOTPMAP_ID", False);
719 XGrabServer(dpy);
721 /* Clear out the old pixmap */
722 XGetWindowProperty(dpy, root, prop, 0L, 1L, False, AnyPropertyType,
723 &type, &format, &length, &after, &data);
725 if ((type == XA_PIXMAP) && (format == 32) && (length == 1)) {
726 XSetErrorHandler(dummyErrorHandler);
727 XKillClient(dpy, *((Pixmap *)data));
728 XSync(dpy, False);
729 XSetErrorHandler(NULL);
730 mode = PropModeReplace;
731 } else {
732 mode = PropModeAppend;
734 if (pixmap)
735 XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, mode,
736 (unsigned char *) &pixmap, 1);
737 else
738 XDeleteProperty(dpy, root, prop);
741 XUngrabServer(dpy);
742 XFlush(dpy);
747 void
748 changeTexture(BackgroundTexture *texture)
750 if (!texture)
751 return;
753 if (texture->solid) {
754 XSetWindowBackground(dpy, root, texture->color.pixel);
755 } else {
756 XSetWindowBackgroundPixmap(dpy, root, texture->pixmap);
758 XClearWindow(dpy, root);
760 XSync(dpy, False);
763 Pixmap pixmap;
765 pixmap = duplicatePixmap(texture->pixmap, texture->width,
766 texture->height);
768 setPixmapProperty(pixmap);
774 readmsg(int fd, unsigned char *buffer, int size)
776 int count;
778 count = 0;
779 while (size>0) {
780 count = read(fd, buffer, size);
781 if (count < 0)
782 return -1;
783 size -= count;
784 buffer += count;
785 *buffer = 0;
788 return size;
793 * Message Format:
794 * sizeSntexture_spec - sets the texture for workspace n
795 * sizeCn - change background texture to the one for workspace n
796 * sizePpath - set the pixmap search path
798 * n is 4 bytes
799 * size = 4 bytes for length of the message data
801 void
802 helperLoop(RContext *rc)
804 BackgroundTexture *textures[WORKSPACE_COUNT];
805 int maxTextures = 0;
806 unsigned char buffer[2048], buf[8];
807 int size;
808 int errcount = 4;
810 memset(textures, 0, WORKSPACE_COUNT*sizeof(BackgroundTexture*));
813 while (1) {
814 int workspace;
816 /* get length of message */
817 if (readmsg(0, buffer, 4) < 0) {
818 wsyserror("error reading message from Window Maker");
819 errcount--;
820 if (errcount == 0) {
821 wfatal("quitting");
822 exit(1);
824 continue;
826 memcpy(buf, buffer, 4);
827 buf[4] = 0;
828 size = atoi(buf);
830 /* get message */
831 if (readmsg(0, buffer, size) < 0) {
832 wsyserror("error reading message from Window Maker");
833 errcount--;
834 if (errcount == 0) {
835 wfatal("quitting");
836 exit(1);
838 continue;
840 #ifdef DEBUG
841 printf("RECEIVED %s\n",buffer);
842 #endif
843 if (buffer[0]!='P' && buffer[0]!='K') {
844 memcpy(buf, &buffer[1], 4);
845 buf[4] = 0;
846 workspace = atoi(buf);
847 if (workspace < 0 || workspace >= WORKSPACE_COUNT) {
848 wwarning("received message with invalid workspace number %i\n",
849 workspace);
850 continue;
854 switch (buffer[0]) {
855 case 'S':
856 #ifdef DEBUG
857 printf("set texture %s\n", &buffer[5]);
858 #endif
859 setupTexture(rc, textures, &maxTextures, workspace, &buffer[5]);
860 break;
862 case 'C':
863 #ifdef DEBUG
864 printf("change texture %i\n", workspace);
865 #endif
866 if (!textures[workspace])
867 changeTexture(textures[0]);
868 else
869 changeTexture(textures[workspace]);
870 break;
872 case 'P':
873 #ifdef DEBUG
874 printf("change pixmappath %s\n", &buffer[1]);
875 #endif
876 if (PixmapPath)
877 free(PixmapPath);
878 PixmapPath = wstrdup(&buffer[1]);
879 break;
881 case 'U':
882 #ifdef DEBUG
883 printf("unset workspace %i\n", workspace);
884 #endif
885 setupTexture(rc, textures, &maxTextures, workspace, NULL);
886 break;
888 case 'K':
889 #ifdef DEBUG
890 printf("exit command\n");
891 #endif
892 exit(0);
894 default:
895 wwarning("unknown message received");
896 break;
902 void
903 updateDomain(char *domain, char *key, char *texture)
905 char *program = "wdwrite";
907 execlp(program, program, domain, key, texture, NULL);
908 wwarning("warning could not run \"%s\"", program);
913 char*
914 globalDefaultsPathForDomain(char *domain)
916 char path[1024];
918 sprintf(path, "%s/%s", SYSCONFDIR, domain);
920 return wstrdup(path);
924 proplist_t
925 getValueForKey(char *domain, char *keyName)
927 char *path;
928 proplist_t key;
929 proplist_t d;
930 proplist_t val;
932 key = PLMakeString(keyName);
934 /* try to find PixmapPath in user defaults */
935 path = wdefaultspathfordomain(domain);
936 d = PLGetProplistWithPath(path);
937 if (!d) {
938 wwarning("could not open domain file %s", path);
940 free(path);
942 if (d && !PLIsDictionary(d)) {
943 PLRelease(d);
944 d = NULL;
946 if (d) {
947 val = PLGetDictionaryEntry(d, key);
948 } else {
949 val = NULL;
951 /* try to find PixmapPath in global defaults */
952 if (!val) {
953 path = globalDefaultsPathForDomain(domain);
954 if (!path) {
955 wwarning("could not locate file for domain %s", domain);
956 d = NULL;
957 } else {
958 d = PLGetProplistWithPath(path);
959 free(path);
962 if (d && !PLIsDictionary(d)) {
963 PLRelease(d);
964 d = NULL;
966 if (d) {
967 val = PLGetDictionaryEntry(d, key);
969 } else {
970 val = NULL;
974 if (val)
975 PLRetain(val);
977 PLRelease(key);
978 if (d)
979 PLRelease(d);
981 return val;
984 char*
985 getPixmapPath(char *domain)
987 proplist_t val;
988 char *ptr, *data;
989 int len, i, count;
991 val = getValueForKey(domain, "PixmapPath");
993 if (!val || !PLIsArray(val)) {
994 if (val)
995 PLRelease(val);
996 return wstrdup("");
999 count = PLGetNumberOfElements(val);
1000 len = 0;
1001 for (i=0; i<count; i++) {
1002 proplist_t v;
1004 v = PLGetArrayElement(val, i);
1005 if (!v || !PLIsString(v)) {
1006 continue;
1008 len += strlen(PLGetString(v))+1;
1011 ptr = data = wmalloc(len+1);
1012 *ptr = 0;
1014 for (i=0; i<count; i++) {
1015 proplist_t v;
1017 v = PLGetArrayElement(val, i);
1018 if (!v || !PLIsString(v)) {
1019 continue;
1021 strcpy(ptr, PLGetString(v));
1023 ptr += strlen(PLGetString(v));
1024 *ptr = ':';
1025 ptr++;
1027 if (i>0)
1028 ptr--; *(ptr--) = 0;
1030 PLRelease(val);
1032 return data;
1036 void
1037 wAbort()
1039 wfatal("aborting");
1040 exit(1);
1045 void
1046 print_help(char *ProgName)
1048 printf("Usage: %s [options] [image]\n", ProgName);
1049 puts("Sets the workspace background to the specified image or a texture and optionally update Window Maker configuration");
1050 puts("");
1051 #define P(m) puts(m)
1052 P(" -display display to use");
1053 P(" -d, --dither dither image");
1054 P(" -m, --match match colors");
1055 P(" -b, --back-color <color> background color");
1056 P(" -t, --tile tile image");
1057 P(" -e, --center center image");
1058 P(" -s, --scale scale image (default)");
1059 P(" -a, --maxscale scale image and keep aspect ratio");
1060 P(" -u, --update-wmaker update WindowMaker domain database");
1061 P(" -D, --update-domain <domain> update <domain> database");
1062 P(" -c, --colors <cpc> colors per channel to use");
1063 P(" -p, --parse <texture> proplist style texture specification");
1064 P(" -w, --workspace <workspace> update background for the specified workspace");
1065 P(" --version show version of wmsetbg and exit");
1066 P(" --help show this help and exit");
1067 #undef P
1072 void
1073 changeTextureForWorkspace(char *domain, char *texture, int workspace)
1075 proplist_t array;
1076 proplist_t val;
1077 char *value;
1078 int j;
1080 val = PLGetProplistWithDescription(texture);
1081 if (!val) {
1082 wwarning("could not parse texture %s", texture);
1083 return;
1086 array = getValueForKey("WindowMaker", "WorkspaceSpecificBack");
1088 if (!array) {
1089 array = PLMakeArrayFromElements(NULL, NULL);
1092 j = PLGetNumberOfElements(array);
1093 if (workspace >= j) {
1094 proplist_t empty;
1096 empty = PLMakeArrayFromElements(NULL, NULL);
1098 while (j++ < workspace-1) {
1099 PLAppendArrayElement(array, empty);
1101 PLAppendArrayElement(array, val);
1102 } else {
1103 PLRemoveArrayElement(array, workspace);
1104 PLInsertArrayElement(array, val, workspace);
1107 value = PLGetDescription(array);
1108 updateDomain(domain, "WorkspaceSpecificBack", value);
1113 main(int argc, char **argv)
1115 int i;
1116 int helperMode = 0;
1117 RContext *rc;
1118 RContextAttributes rattr;
1119 char *style = "spixmap";
1120 char *back_color = "gray20";
1121 char *image_name = NULL;
1122 char *domain = "WindowMaker";
1123 int update=0, cpc=4, render_mode=RM_DITHER, obey_user=0;
1124 char *texture = NULL;
1125 int workspace = -1;
1127 signal(SIGINT, SIG_DFL);
1128 signal(SIGTERM, SIG_DFL);
1129 signal(SIGQUIT, SIG_DFL);
1130 signal(SIGSEGV, SIG_DFL);
1131 signal(SIGBUS, SIG_DFL);
1132 signal(SIGFPE, SIG_DFL);
1133 signal(SIGABRT, SIG_DFL);
1134 signal(SIGHUP, SIG_DFL);
1135 signal(SIGPIPE, SIG_DFL);
1136 signal(SIGCHLD, SIG_DFL);
1138 WMInitializeApplication("wmsetbg", &argc, argv);
1140 for (i=1; i<argc; i++) {
1141 if (strcmp(argv[i], "-helper")==0) {
1142 helperMode = 1;
1143 } else if (strcmp(argv[i], "-display")==0) {
1144 i++;
1145 if (i>=argc) {
1146 wfatal("too few arguments for %s\n", argv[i-1]);
1147 exit(1);
1149 display = argv[i];
1150 } else if (strcmp(argv[i], "-s")==0
1151 || strcmp(argv[i], "--scale")==0) {
1152 style = "spixmap";
1153 } else if (strcmp(argv[i], "-t")==0
1154 || strcmp(argv[i], "--tile")==0) {
1155 style = "tpixmap";
1156 } else if (strcmp(argv[i], "-e")==0
1157 || strcmp(argv[i], "--center")==0) {
1158 style = "cpixmap";
1159 } else if (strcmp(argv[i], "-a")==0
1160 || strcmp(argv[i], "--maxscale")==0) {
1161 style = "mpixmap";
1162 } else if (strcmp(argv[i], "-d")==0
1163 || strcmp(argv[i], "--dither")==0) {
1164 render_mode = RM_DITHER;
1165 obey_user++;
1166 } else if (strcmp(argv[i], "-m")==0
1167 || strcmp(argv[i], "--match")==0) {
1168 render_mode = RM_MATCH;
1169 obey_user++;
1170 } else if (strcmp(argv[i], "-u")==0
1171 || strcmp(argv[i], "--update-wmaker")==0) {
1172 update++;
1173 } else if (strcmp(argv[i], "-D")==0
1174 || strcmp(argv[i], "--update-domain")==0) {
1175 update++;
1176 i++;
1177 if (i>=argc) {
1178 wfatal("too few arguments for %s\n", argv[i-1]);
1179 exit(1);
1181 domain = wstrdup(argv[i]);
1182 } else if (strcmp(argv[i], "-c")==0
1183 || strcmp(argv[i], "--colors")==0) {
1184 i++;
1185 if (i>=argc) {
1186 wfatal("too few arguments for %s\n", argv[i-1]);
1187 exit(1);
1189 if (sscanf(argv[i], "%i", &cpc)!=1) {
1190 wfatal("bad value for colors per channel: \"%s\"\n", argv[i]);
1191 exit(1);
1193 } else if (strcmp(argv[i], "-b")==0
1194 || strcmp(argv[i], "--back-color")==0) {
1195 i++;
1196 if (i>=argc) {
1197 wfatal("too few arguments for %s\n", argv[i-1]);
1198 exit(1);
1200 back_color = argv[i];
1201 } else if (strcmp(argv[i], "-p")==0
1202 || strcmp(argv[i], "--parse")==0) {
1203 i++;
1204 if (i>=argc) {
1205 wfatal("too few arguments for %s\n", argv[i-1]);
1206 exit(1);
1208 texture = argv[i];
1209 } else if (strcmp(argv[i], "-w")==0
1210 || strcmp(argv[i], "--workspace")==0) {
1211 i++;
1212 if (i>=argc) {
1213 wfatal("too few arguments for %s\n", argv[i-1]);
1214 exit(1);
1216 if (sscanf(argv[i], "%i", &workspace)!=1) {
1217 wfatal("bad value for workspace number: \"%s\"",
1218 argv[i]);
1219 exit(1);
1221 } else if (strcmp(argv[i], "--version")==0) {
1223 printf(PROG_VERSION);
1224 exit(0);
1226 } else if (strcmp(argv[i], "--help")==0) {
1227 print_help(argv[0]);
1228 exit(0);
1229 } else if (argv[i][0] != '-') {
1230 image_name = argv[i];
1231 } else {
1232 printf("%s: invalid argument '%s'\n", argv[0], argv[i]);
1233 printf("Try '%s --help' for more information\n", argv[0]);
1234 exit(1);
1237 if (!image_name && !texture && !helperMode) {
1238 printf("%s: you must specify a image file name or a texture\n",
1239 argv[0]);
1240 printf("Try '%s --help' for more information\n", argv[0]);
1241 exit(1);
1245 PixmapPath = getPixmapPath(domain);
1247 dpy = XOpenDisplay(display);
1248 if (!dpy) {
1249 wfatal("could not open display");
1250 exit(1);
1252 XSynchronize(dpy, 1);
1254 root = DefaultRootWindow(dpy);
1256 scr = DefaultScreen(dpy);
1258 scrWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
1259 scrHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
1261 if (!obey_user && DefaultDepth(dpy, scr) <= 8)
1262 render_mode = RM_DITHER;
1264 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_DefaultVisual;
1265 rattr.render_mode = render_mode;
1266 rattr.colors_per_channel = cpc;
1268 rc = RCreateContext(dpy, scr, &rattr);
1270 if (helperMode) {
1271 /* lower priority, so that it wont use all the CPU */
1272 nice(1000);
1274 helperLoop(rc);
1275 } else {
1276 BackgroundTexture *tex;
1277 char buffer[4098];
1279 if (!texture) {
1280 sprintf(buffer, "(%s, \"%s\", %s)", style, image_name, back_color);
1281 texture = (char*)buffer;
1284 if (update && workspace < 0) {
1285 updateDomain(domain, "WorkspaceBack", texture);
1288 tex = parseTexture(rc, texture);
1289 if (!tex)
1290 exit(1);
1292 if (workspace<0)
1293 changeTexture(tex);
1294 else {
1295 /* always update domain */
1296 changeTextureForWorkspace(domain, texture, workspace-1);
1300 return 0;