Some bug fixes to 0.50.0 before release
[wmaker-crm.git] / util / wmsetbg.c
blobe84fb4ad608fbf0728e744b3462519d0484f760c
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.
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <X11/Xatom.h>
31 #include <string.h>
32 #include <pwd.h>
33 #include <signal.h>
34 #include <sys/types.h>
36 #include "../src/wconfig.h"
38 #include "../WINGs/WINGs.h"
39 #include "../WINGs/WUtil.h"
40 #include "../wrlib/wraster.h"
42 #include <proplist.h>
45 #define WORKSPACE_COUNT (MAX_WORKSPACES+1)
49 Display *dpy;
50 Window root;
51 int scr;
52 int scrWidth;
53 int scrHeight;
55 Pixmap CurrentPixmap = None;
56 char *PixmapPath = NULL;
60 typedef struct BackgroundTexture {
61 int refcount;
63 int solid;
65 char *spec;
67 XColor color;
68 Pixmap pixmap; /* for all textures, including solid */
69 int width; /* size of the pixmap */
70 int height;
71 } BackgroundTexture;
76 RImage*
77 loadImage(RContext *rc, char *file)
79 char *path;
80 RImage *image;
82 path = wfindfile(PixmapPath, file);
83 if (!path) {
84 wwarning("%s:could not find image file used in texture", file);
85 return NULL;
88 image = RLoadImage(rc, path, 0);
89 if (!image) {
90 wwarning("%s:could not load image file used in texture:%s", path,
91 RMessageForError(RErrorCode));
93 free(path);
95 return image;
100 BackgroundTexture*
101 parseTexture(RContext *rc, char *text)
103 BackgroundTexture *texture = NULL;
104 proplist_t texarray;
105 proplist_t val;
106 int count;
107 char *tmp;
108 char *type;
110 #define GETSTR(val, str, i) \
111 val = PLGetArrayElement(texarray, i);\
112 if (!PLIsString(val)) {\
113 wwarning("could not parse texture %s", text);\
114 goto error;\
116 str = PLGetString(val)
119 texarray = PLGetProplistWithDescription(text);
120 if (!texarray || !PLIsArray(texarray)
121 || (count = PLGetNumberOfElements(texarray)) < 2) {
123 wwarning("could not parse texture %s", text);
124 if (texarray)
125 PLRelease(texarray);
126 return NULL;
129 texture = wmalloc(sizeof(BackgroundTexture));
130 memset(texture, 0, sizeof(BackgroundTexture));
132 GETSTR(val, type, 0);
134 if (strcasecmp(type, "solid")==0) {
135 XColor color;
136 Pixmap pixmap;
138 texture->solid = 1;
140 GETSTR(val, tmp, 1);
142 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
143 wwarning("could not parse color %s in texture %s", tmp, text);
144 goto error;
146 XAllocColor(dpy, DefaultColormap(dpy, scr), &color);
148 pixmap = XCreatePixmap(dpy, root, 32, 32, DefaultDepth(dpy, scr));
149 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
150 XFillRectangle(dpy, pixmap, DefaultGC(dpy, scr), 0, 0, 32, 32);
152 texture->pixmap = pixmap;
153 texture->color = color;
154 texture->width = 32;
155 texture->height = 32;
156 } else if (strcasecmp(type, "vgradient")==0
157 || strcasecmp(type, "dgradient")==0
158 || strcasecmp(type, "hgradient")==0) {
159 XColor color;
160 RColor color1, color2;
161 RImage *image;
162 Pixmap pixmap;
163 int gtype;
165 GETSTR(val, tmp, 1);
167 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
168 wwarning("could not parse color %s in texture %s", tmp, text);
169 goto error;
172 color1.red = color.red >> 8;
173 color1.green = color.green >> 8;
174 color1.blue = color.blue >> 8;
176 GETSTR(val, tmp, 2);
178 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
179 wwarning("could not parse color %s in texture %s", tmp, text);
180 goto error;
183 color2.red = color.red >> 8;
184 color2.green = color.green >> 8;
185 color2.blue = color.blue >> 8;
187 switch (type[0]) {
188 case 'h':
189 case 'H':
190 gtype = RHorizontalGradient;
191 break;
192 case 'V':
193 case 'v':
194 gtype = RVerticalGradient;
195 break;
196 default:
197 gtype = RDiagonalGradient;
198 break;
201 image = RRenderGradient(scrWidth, scrHeight, &color1, &color2, gtype);
203 if (!image) {
204 wwarning("could not render gradient texture:%s",
205 RMessageForError(RErrorCode));
206 goto error;
209 if (!RConvertImage(rc, image, &pixmap)) {
210 wwarning("could not convert texture:%s",
211 RMessageForError(RErrorCode));
212 RDestroyImage(image);
213 goto error;
216 texture->width = image->width;
217 texture->height = image->height;
218 RDestroyImage(image);
220 texture->pixmap = pixmap;
221 } else if (strcasecmp(type, "mvgradient")==0
222 || strcasecmp(type, "mdgradient")==0
223 || strcasecmp(type, "mhgradient")==0) {
224 XColor color;
225 RColor **colors;
226 RImage *image;
227 Pixmap pixmap;
228 int i;
229 int j;
230 int gtype;
232 colors = malloc(sizeof(RColor*)*(count-1));
233 if (!colors) {
234 wwarning("out of memory while parsing texture");
235 goto error;
237 memset(colors, 0, sizeof(RColor*)*(count-1));
239 for (i = 2; i < count; i++) {
240 val = PLGetArrayElement(texarray, i);
241 if (!PLIsString(val)) {
242 wwarning("could not parse texture %s", text);
244 for (j = 0; colors[j]!=NULL; j++)
245 free(colors[j]);
246 free(colors);
247 goto error;
249 tmp = PLGetString(val);
251 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
252 wwarning("could not parse color %s in texture %s",
253 tmp, text);
255 for (j = 0; colors[j]!=NULL; j++)
256 free(colors[j]);
257 free(colors);
258 goto error;
260 if (!(colors[i-2] = malloc(sizeof(RColor)))) {
261 wwarning("out of memory while parsing texture");
263 for (j = 0; colors[j]!=NULL; j++)
264 free(colors[j]);
265 free(colors);
266 goto error;
269 colors[i-2]->red = color.red >> 8;
270 colors[i-2]->green = color.green >> 8;
271 colors[i-2]->blue = color.blue >> 8;
274 switch (type[1]) {
275 case 'h':
276 case 'H':
277 gtype = RHorizontalGradient;
278 break;
279 case 'V':
280 case 'v':
281 gtype = RVerticalGradient;
282 break;
283 default:
284 gtype = RDiagonalGradient;
285 break;
288 image = RRenderMultiGradient(scrWidth, scrHeight, colors, gtype);
290 for (j = 0; colors[j]!=NULL; j++)
291 free(colors[j]);
292 free(colors);
294 if (!image) {
295 wwarning("could not render gradient texture:%s",
296 RMessageForError(RErrorCode));
297 goto error;
300 if (!RConvertImage(rc, image, &pixmap)) {
301 wwarning("could not convert texture:%s",
302 RMessageForError(RErrorCode));
303 RDestroyImage(image);
304 goto error;
307 texture->width = image->width;
308 texture->height = image->height;
309 RDestroyImage(image);
311 texture->pixmap = pixmap;
312 } else if (strcasecmp(type, "cpixmap")==0
313 || strcasecmp(type, "spixmap")==0
314 || strcasecmp(type, "tpixmap")==0) {
315 XColor color;
316 Pixmap pixmap;
317 RImage *image;
319 GETSTR(val, tmp, 1);
321 image = loadImage(rc, tmp);
322 if (!image) {
323 goto error;
326 GETSTR(val, tmp, 2);
328 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
329 wwarning("could not parse color %s in texture %s\n", tmp, text);
330 RDestroyImage(image);
331 goto error;
334 RColor rcolor;
336 rcolor.red = color.red >> 8;
337 rcolor.green = color.green >> 8;
338 rcolor.blue = color.blue >> 8;
339 RGetClosestXColor(rc, &rcolor, &color);
341 switch (type[0]) {
342 case 't':
343 case 'T':
344 texture->width = image->width;
345 texture->height = image->height;
346 if (!RConvertImage(rc, image, &pixmap)) {
347 wwarning("could not convert texture:%s",
348 RMessageForError(RErrorCode));
349 RDestroyImage(image);
350 goto error;
352 break;
353 case 's':
354 case 'S':
356 RImage *simage;
357 int w, h;
359 if (image->width*scrHeight > image->height*scrWidth) {
360 w = scrWidth;
361 h = (scrWidth*image->height)/image->width;
362 } else {
363 h = scrHeight;
364 w = (scrHeight*image->width)/image->height;
367 simage = RScaleImage(image, w, h);
368 if (!simage) {
369 wwarning("could not scale image:%s",
370 RMessageForError(RErrorCode));
371 RDestroyImage(image);
372 goto error;
374 RDestroyImage(image);
375 image = simage;
377 /* fall through */
378 case 'c':
379 case 'C':
381 Pixmap cpixmap;
383 if (!RConvertImage(rc, image, &pixmap)) {
384 wwarning("could not convert texture:%s",
385 RMessageForError(RErrorCode));
386 RDestroyImage(image);
387 goto error;
390 if (image->width != scrWidth || image->height != scrHeight) {
391 int x, y, sx, sy, w, h;
393 cpixmap = XCreatePixmap(dpy, root, scrWidth, scrHeight,
394 DefaultDepth(dpy, scr));
396 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
397 XFillRectangle(dpy, cpixmap, DefaultGC(dpy, scr),
398 0, 0, scrWidth, scrHeight);
400 if (image->height < scrHeight) {
401 h = image->height;
402 y = (scrHeight - h)/2;
403 sy = 0;
404 } else {
405 sy = (image->height - scrHeight)/2;
406 y = 0;
407 h = scrHeight;
409 if (image->width < scrWidth) {
410 w = image->width;
411 x = (scrWidth - w)/2;
412 sx = 0;
413 } else {
414 sx = (image->width - scrWidth)/2;
415 x = 0;
416 w = scrWidth;
419 XCopyArea(dpy, pixmap, cpixmap, DefaultGC(dpy, scr),
420 sx, sy, w, h, x, y);
421 XFreePixmap(dpy, pixmap);
422 pixmap = cpixmap;
424 RDestroyImage(image);
426 texture->width = scrWidth;
427 texture->height = scrHeight;
429 break;
432 texture->pixmap = pixmap;
433 texture->color = color;
434 } else if (strcasecmp(type, "thgradient")==0
435 || strcasecmp(type, "tvgradient")==0
436 || strcasecmp(type, "tdgradient")==0) {
437 XColor color;
438 RColor color1, color2;
439 RImage *image;
440 RImage *gradient;
441 RImage *tiled;
442 Pixmap pixmap;
443 int opaq;
444 char *file;
445 int gtype;
446 int twidth, theight;
448 GETSTR(val, file, 1);
450 GETSTR(val, tmp, 2);
452 opaq = atoi(tmp);
454 GETSTR(val, tmp, 3);
456 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
457 wwarning("could not parse color %s in texture %s", tmp, text);
458 goto error;
461 color1.red = color.red >> 8;
462 color1.green = color.green >> 8;
463 color1.blue = color.blue >> 8;
465 GETSTR(val, tmp, 4);
467 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
468 wwarning("could not parse color %s in texture %s", tmp, text);
469 goto error;
472 color2.red = color.red >> 8;
473 color2.green = color.green >> 8;
474 color2.blue = color.blue >> 8;
476 image = loadImage(rc, file);
477 if (!image) {
478 RDestroyImage(gradient);
479 goto error;
482 switch (type[1]) {
483 case 'h':
484 case 'H':
485 gtype = RHorizontalGradient;
486 twidth = scrWidth;
487 theight = image->height > scrHeight ? scrHeight : image->height;
488 break;
489 case 'V':
490 case 'v':
491 gtype = RVerticalGradient;
492 twidth = image->width > scrWidth ? scrWidth : image->width;
493 theight = scrHeight;
494 break;
495 default:
496 gtype = RDiagonalGradient;
497 twidth = scrWidth;
498 theight = scrHeight;
499 break;
501 gradient = RRenderGradient(twidth, theight, &color1, &color2, gtype);
503 if (!gradient) {
504 wwarning("could not render texture:%s",
505 RMessageForError(RErrorCode));
506 RDestroyImage(gradient);
507 goto error;
510 tiled = RMakeTiledImage(image, twidth, theight);
511 if (!tiled) {
512 wwarning("could not render texture:%s",
513 RMessageForError(RErrorCode));
514 RDestroyImage(gradient);
515 RDestroyImage(image);
516 goto error;
518 RDestroyImage(image);
520 RCombineImagesWithOpaqueness(tiled, gradient, opaq);
521 RDestroyImage(gradient);
523 if (!RConvertImage(rc, tiled, &pixmap)) {
524 wwarning("could not convert texture:%s",
525 RMessageForError(RErrorCode));
526 RDestroyImage(image);
527 goto error;
529 texture->width = tiled->width;
530 texture->height = tiled->height;
532 RDestroyImage(tiled);
534 texture->pixmap = pixmap;
535 } else {
536 wwarning("invalid texture type %s", text);
537 goto error;
540 texture->spec = wstrdup(text);
542 return texture;
544 error:
545 if (texture)
546 free(texture);
547 if (texarray)
548 PLRelease(texarray);
550 return NULL;
554 void
555 freeTexture(BackgroundTexture *texture)
557 if (texture->solid) {
558 long pixel[1];
560 pixel[0] = texture->color.pixel;
561 /* dont free black/white pixels */
562 if (pixel[0]!=BlackPixelOfScreen(DefaultScreenOfDisplay(dpy))
563 && pixel[0]!=WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
564 XFreeColors(dpy, DefaultColormap(dpy, scr), pixel, 1, 0);
566 free(texture->spec);
567 free(texture);
571 void
572 setupTexture(RContext *rc, BackgroundTexture **textures, int *maxTextures,
573 int workspace, char *texture)
575 BackgroundTexture *newTexture = NULL;
576 int i;
578 /* unset the texture */
579 if (!texture) {
580 if (textures[workspace]!=NULL) {
581 textures[workspace]->refcount--;
583 if (textures[workspace]->refcount == 0)
584 freeTexture(textures[workspace]);
586 textures[workspace] = NULL;
587 return;
590 if (textures[workspace]
591 && strcasecmp(textures[workspace]->spec, texture)==0) {
592 /* texture did not change */
593 return;
596 /* check if the same texture is already created */
597 for (i = 0; i < *maxTextures; i++) {
598 if (textures[i] && strcasecmp(textures[i]->spec, texture)==0) {
599 newTexture = textures[i];
600 break;
604 if (!newTexture) {
605 /* create the texture */
606 newTexture = parseTexture(rc, texture);
608 if (!newTexture)
609 return;
611 if (textures[workspace]!=NULL) {
613 textures[workspace]->refcount--;
615 if (textures[workspace]->refcount == 0)
616 freeTexture(textures[workspace]);
619 newTexture->refcount++;
620 textures[workspace] = newTexture;
622 if (*maxTextures < workspace)
623 *maxTextures = workspace;
628 Pixmap
629 duplicatePixmap(Pixmap pixmap, int width, int height)
631 Display *tmpDpy;
632 Pixmap copyP;
634 /* must open a new display or the RetainPermanent will
635 * leave stuff allocated in RContext unallocated after exit */
636 tmpDpy = XOpenDisplay("");
637 if (!tmpDpy) {
638 wwarning("could not open display to update background image information");
640 return None;
641 } else {
642 XSync(dpy, False);
644 copyP = XCreatePixmap(tmpDpy, root, width, height,
645 DefaultDepth(tmpDpy, scr));
646 XCopyArea(tmpDpy, pixmap, copyP, DefaultGC(tmpDpy, scr),
647 0, 0, width, height, 0, 0);
648 XSync(tmpDpy, False);
650 XSetCloseDownMode(tmpDpy, RetainPermanent);
651 XCloseDisplay(tmpDpy);
654 return copyP;
658 void
659 setPixmapProperty(Pixmap pixmap)
661 static Atom prop = 0;
662 Atom type;
663 int format;
664 unsigned long length, after;
665 unsigned char *data;
666 int mode;
668 if (!prop) {
669 prop = XInternAtom(dpy, "_XROOTPMAP_ID", False);
672 XGrabServer(dpy);
674 /* Clear out the old pixmap */
675 XGetWindowProperty(dpy, root, prop, 0L, 1L, False, AnyPropertyType,
676 &type, &format, &length, &after, &data);
678 if ((type == XA_PIXMAP) && (format == 32) && (length == 1)) {
679 XKillClient(dpy, *((Pixmap *)data));
680 mode = PropModeReplace;
681 } else {
682 mode = PropModeAppend;
684 if (pixmap)
685 XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, mode,
686 (unsigned char *) &pixmap, 1);
687 else
688 XDeleteProperty(dpy, root, prop);
691 XUngrabServer(dpy);
692 XFlush(dpy);
697 void
698 changeTexture(BackgroundTexture *texture)
700 if (!texture)
701 return;
703 if (texture->solid) {
704 XSetWindowBackground(dpy, root, texture->color.pixel);
705 } else {
706 XSetWindowBackgroundPixmap(dpy, root, texture->pixmap);
708 XClearWindow(dpy, root);
710 XSync(dpy, False);
713 Pixmap pixmap;
715 pixmap = duplicatePixmap(texture->pixmap, texture->width,
716 texture->height);
718 setPixmapProperty(pixmap);
724 readmsg(int fd, unsigned char *buffer, int size)
726 int count;
728 count = 0;
729 while (size>0) {
730 count = read(fd, buffer, size);
731 if (count < 0)
732 return -1;
733 size -= count;
734 buffer += count;
735 *buffer = 0;
738 return size;
743 * Message Format:
744 * sizeSntexture_spec - sets the texture for workspace n
745 * sizeCn - change background texture to the one for workspace n
746 * sizePpath - set the pixmap search path
748 * n is 4 bytes
749 * size = 4 bytes for length of the message data
751 void
752 helperLoop(RContext *rc)
754 BackgroundTexture *textures[WORKSPACE_COUNT];
755 int maxTextures = 0;
756 unsigned char buffer[2048], buf[8];
757 int size;
758 int errcount = 4;
760 memset(textures, 0, WORKSPACE_COUNT*sizeof(BackgroundTexture*));
763 while (1) {
764 int workspace;
766 /* get length of message */
767 if (readmsg(0, buffer, 4) < 0) {
768 wsyserror("error reading message from Window Maker");
769 errcount--;
770 if (errcount == 0) {
771 wfatal("quitting");
772 exit(1);
774 continue;
776 memcpy(buf, buffer, 4);
777 buf[4] = 0;
778 size = atoi(buf);
780 /* get message */
781 if (readmsg(0, buffer, size) < 0) {
782 wsyserror("error reading message from Window Maker");
783 errcount--;
784 if (errcount == 0) {
785 wfatal("quitting");
786 exit(1);
788 continue;
790 #ifdef DEBUG
791 printf("RECEIVED %s\n",buffer);
792 #endif
793 if (buffer[0]!='P') {
794 memcpy(buf, &buffer[1], 4);
795 buf[4] = 0;
796 workspace = atoi(buf);
797 if (workspace < 0 || workspace >= WORKSPACE_COUNT) {
798 wwarning("received message with invalid workspace number %i\n",
799 workspace);
800 continue;
804 switch (buffer[0]) {
805 case 'S':
806 #ifdef DEBUG
807 printf("set texture %s\n", &buffer[5]);
808 #endif
809 setupTexture(rc, textures, &maxTextures, workspace, &buffer[5]);
810 break;
812 case 'C':
813 #ifdef DEBUG
814 printf("change texture %i\n", workspace);
815 #endif
816 if (!textures[workspace])
817 changeTexture(textures[0]);
818 else
819 changeTexture(textures[workspace]);
820 break;
822 case 'P':
823 #ifdef DEBUG
824 printf("change pixmappath %s\n", &buffer[1]);
825 #endif
826 if (PixmapPath)
827 free(PixmapPath);
828 PixmapPath = wstrdup(&buffer[1]);
829 break;
831 case 'U':
832 #ifdef DEBUG
833 printf("unset workspace %i\n", workspace);
834 #endif
835 setupTexture(rc, textures, &maxTextures, workspace, NULL);
836 break;
838 default:
839 wwarning("unknown message received");
840 break;
846 void
847 updateDomain(char *domain, int workspace, char *texture)
849 char *program = "wdwrite";
851 execlp(program, program, domain, "WorkspaceBack", texture, NULL);
852 wwarning("warning could not run \"%s\"", program);
857 proplist_t
858 getDomain(char *domain)
860 char *path;
861 proplist_t prop;
864 path = wdefaultspathfordomain(domain);
865 if (!path) {
866 wwarning("could not locate file for domain %s", domain);
867 return NULL;
870 prop = PLGetProplistWithPath(path);
872 if (!prop || !PLIsDictionary(prop)) {
873 wwarning("invalid domain file %s", path);
874 free(path);
875 if (prop)
876 PLRelease(prop);
877 return NULL;
879 free(path);
881 return prop;
885 char*
886 getPixmapPath(proplist_t prop)
888 proplist_t key, val;
889 proplist_t d;
890 char *ptr, *data;
891 int len, i, count;
893 key = PLMakeString("PixmapPath");
894 val = PLGetDictionaryEntry(prop, key);
895 PLRelease(key);
896 if (!val || !PLIsArray(val)) {
897 PLRelease(prop);
898 return wstrdup("");
901 count = PLGetNumberOfElements(val);
902 len = 0;
903 for (i=0; i<count; i++) {
904 d = PLGetArrayElement(val, i);
905 if (!d || !PLIsString(d)) {
906 continue;
908 len += strlen(PLGetString(d))+1;
911 ptr = data = wmalloc(len+1);
912 *ptr = 0;
914 for (i=0; i<count; i++) {
915 d = PLGetArrayElement(val, i);
916 if (!d || !PLIsString(d)) {
917 continue;
919 strcpy(ptr, PLGetString(d));
921 ptr += strlen(PLGetString(d));
922 *ptr = ':';
923 ptr++;
925 if (i>0)
926 ptr--; *(ptr--) = 0;
928 return data;
932 void
933 wAbort()
935 wfatal("aborting");
936 exit(1);
941 void
942 print_help(char *ProgName)
944 printf("usage: %s [-options] image\n", ProgName);
945 puts("options:");
946 puts(" -d dither image");
947 puts(" -m match colors");
948 puts(" -b <color> background color");
949 puts(" -t tile image");
950 puts(" -e center image");
951 puts(" -s scale image (default)");
952 puts(" -u update WindowMaker domain database");
953 puts(" -D <domain> update <domain> database");
954 puts(" -c <cpc> colors per channel to use");
955 puts(" -p <texture> proplist style texture specification");
956 /* puts(" -w <workspace> update the background for the specified workspace");
962 void
963 changeTextureForWorkspace(proplist_t dict, char *texture, int workspace)
965 proplist_t key;
966 proplist_t array;
967 proplist_t val;
968 int j;
970 workspace++;
972 val = PLGetProplistWithDescription(texture);
973 if (!val) {
974 wwarning("could not parse texture %s", texture);
975 return;
978 key = PLMakeString("WorkspaceSpecificBack");
979 array = PLGetDictionaryEntry(dict, key);
980 if (!array) {
981 array = PLMakeArrayFromElements(NULL, NULL);
982 PLInsertDictionaryEntry(dict, key, array);
985 j = PLGetNumberOfElements(array);
986 if (workspace >= j) {
987 proplist_t empty;
989 empty = PLMakeArrayFromElements(NULL, NULL);
991 while (j++ < workspace) {
992 PLAppendArrayElement(array, empty);
994 PLAppendArrayElement(array, val);
995 } else {
996 PLRemoveArrayElement(array, workspace);
997 PLInsertArrayElement(array, val, workspace);
1000 PLSave(dict, YES);
1005 main(int argc, char **argv)
1007 int i;
1008 int helperMode = 0;
1009 RContext *rc;
1010 RContextAttributes rattr;
1011 char *style = "spixmap";
1012 char *back_color = "gray20";
1013 char *image_name = NULL;
1014 char *domain = "WindowMaker";
1015 int update=0, cpc=4, render_mode=RM_DITHER, obey_user=0;
1016 char *texture = NULL;
1017 int workspace = -1;
1018 proplist_t domain_prop;
1022 signal(SIGINT, SIG_DFL);
1023 signal(SIGTERM, SIG_DFL);
1024 signal(SIGQUIT, SIG_DFL);
1025 signal(SIGSEGV, SIG_DFL);
1026 signal(SIGBUS, SIG_DFL);
1027 signal(SIGFPE, SIG_DFL);
1028 signal(SIGABRT, SIG_DFL);
1029 signal(SIGHUP, SIG_DFL);
1030 signal(SIGPIPE, SIG_DFL);
1031 signal(SIGCHLD, SIG_DFL);
1033 WMInitializeApplication("wmsetbg", &argc, argv);
1035 for (i=0; i<argc; i++) {
1036 if (strcmp(argv[i], "-helper")==0) {
1037 helperMode = 1;
1038 } else if (strcmp(argv[i], "-s")==0) {
1039 style = "spixmap";
1040 } else if (strcmp(argv[i], "-t")==0) {
1041 style = "tpixmap";
1042 } else if (strcmp(argv[i], "-e")==0) {
1043 style = "cpixmap";
1044 } else if (strcmp(argv[i], "-d")==0) {
1045 render_mode = RM_DITHER;
1046 obey_user++;
1047 } else if (strcmp(argv[i], "-m")==0) {
1048 render_mode = RM_MATCH;
1049 obey_user++;
1050 } else if (strcmp(argv[i], "-u")==0) {
1051 update++;
1052 } else if (strcmp(argv[i], "-D")==0) {
1053 update++;
1054 i++;
1055 if (i>=argc) {
1056 wfatal("too few arguments for %s\n", argv[i-1]);
1057 exit(1);
1059 domain = wstrdup(argv[i]);
1060 } else if (strcmp(argv[i], "-c")==0) {
1061 i++;
1062 if (i>=argc) {
1063 wfatal("too few arguments for %s\n", argv[i-1]);
1064 exit(1);
1066 if (sscanf(argv[i], "%i", &cpc)!=1) {
1067 wfatal("bad value for colors per channel: \"%s\"\n", argv[i]);
1068 exit(1);
1070 } else if (strcmp(argv[i], "-b")==0) {
1071 i++;
1072 if (i>=argc) {
1073 wfatal("too few arguments for %s\n", argv[i-1]);
1074 exit(1);
1076 back_color = argv[i];
1077 } else if (strcmp(argv[i], "-p")==0) {
1078 i++;
1079 if (i>=argc) {
1080 wfatal("too few arguments for %s\n", argv[i-1]);
1081 exit(1);
1083 texture = argv[i];
1084 } else if (strcmp(argv[i], "-w")==0) {
1085 i++;
1086 if (i>=argc) {
1087 wfatal("too few arguments for %s\n", argv[i-1]);
1088 exit(1);
1090 if (sscanf(argv[i], "%i", &workspace)!=1) {
1091 wfatal("bad value for workspace number: \"%s\"",
1092 argv[i]);
1093 exit(1);
1095 } else if (argv[i][0] != '-') {
1096 image_name = argv[i];
1097 } else {
1098 print_help(argv[0]);
1099 exit(1);
1103 domain_prop = getDomain(domain);
1105 PixmapPath = getPixmapPath(domain_prop);
1107 dpy = XOpenDisplay("");
1108 if (!dpy) {
1109 wfatal("could not open display");
1110 exit(1);
1112 XSynchronize(dpy, 1);
1114 root = DefaultRootWindow(dpy);
1116 scr = DefaultScreen(dpy);
1118 scrWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
1119 scrHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
1121 if (!obey_user && DefaultDepth(dpy, scr) <= 8)
1122 render_mode = RM_DITHER;
1124 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_DefaultVisual;
1125 rattr.render_mode = render_mode;
1126 rattr.colors_per_channel = cpc;
1128 rc = RCreateContext(dpy, scr, &rattr);
1130 if (helperMode) {
1131 /* lower priority, so that it wont use all the CPU */
1132 nice(1000);
1134 PLRelease(domain_prop);
1136 helperLoop(rc);
1137 } else {
1138 BackgroundTexture *tex;
1139 char buffer[4098];
1141 if (!texture) {
1142 sprintf(buffer, "(%s, %s, %s)", style, image_name, back_color);
1143 texture = (char*)buffer;
1146 if (update && workspace < 0) {
1147 updateDomain(domain, workspace, texture);
1150 tex = parseTexture(rc, texture);
1151 if (!tex)
1152 exit(1);
1154 if (workspace<0)
1155 changeTexture(tex);
1156 else
1157 changeTextureForWorkspace(domain_prop, texture, workspace);
1160 return -1;