Code update for Window Maker version 0.50.0
[wmaker-crm.git] / util / wmsetbg.c
blob4c1f00c82085e0a86f414c312ba6114330248d0d
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 <wraster.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #include <sys/types.h>
37 #include "../src/wconfig.h"
39 #include "WINGs.h"
40 #include "WUtil.h"
41 #include "wraster.h"
43 #include <proplist.h>
46 #define WORKSPACE_COUNT (MAX_WORKSPACES+1)
50 Display *dpy;
51 Window root;
52 int scr;
53 int scrWidth;
54 int scrHeight;
56 Pixmap CurrentPixmap = None;
57 char *PixmapPath = NULL;
61 typedef struct BackgroundTexture {
62 int refcount;
64 int solid;
66 char *spec;
68 XColor color;
69 Pixmap pixmap; /* for all textures, including solid */
70 int width; /* size of the pixmap */
71 int height;
72 } BackgroundTexture;
77 RImage*
78 loadImage(RContext *rc, char *file)
80 char *path;
81 RImage *image;
83 path = wfindfile(PixmapPath, file);
84 if (!path) {
85 wwarning("%s:could not find image file used in texture", file);
86 return NULL;
89 image = RLoadImage(rc, path, 0);
90 if (!image) {
91 wwarning("%s:could not load image file used in texture:%s", path,
92 RMessageForError(RErrorCode));
94 free(path);
96 return image;
101 BackgroundTexture*
102 parseTexture(RContext *rc, char *text)
104 BackgroundTexture *texture = NULL;
105 proplist_t texarray;
106 proplist_t val;
107 int count;
108 char *tmp;
109 char *type;
111 #define GETSTR(val, str, i) \
112 val = PLGetArrayElement(texarray, i);\
113 if (!PLIsString(val)) {\
114 wwarning("could not parse texture %s", text);\
115 goto error;\
117 str = PLGetString(val)
120 texarray = PLGetProplistWithDescription(text);
121 if (!texarray || !PLIsArray(texarray)
122 || (count = PLGetNumberOfElements(texarray)) < 2) {
124 wwarning("could not parse texture %s", text);
125 if (texarray)
126 PLRelease(texarray);
127 return NULL;
130 texture = wmalloc(sizeof(BackgroundTexture));
131 memset(texture, 0, sizeof(BackgroundTexture));
133 GETSTR(val, type, 0);
135 if (strcasecmp(type, "solid")==0) {
136 XColor color;
137 Pixmap pixmap;
139 texture->solid = 1;
141 GETSTR(val, tmp, 1);
143 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
144 wwarning("could not parse color %s in texture %s", tmp, text);
145 goto error;
147 XAllocColor(dpy, DefaultColormap(dpy, scr), &color);
149 pixmap = XCreatePixmap(dpy, root, 32, 32, DefaultDepth(dpy, scr));
150 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
151 XFillRectangle(dpy, pixmap, DefaultGC(dpy, scr), 0, 0, 32, 32);
153 texture->pixmap = pixmap;
154 texture->color = color;
155 texture->width = 32;
156 texture->height = 32;
157 } else if (strcasecmp(type, "vgradient")==0
158 || strcasecmp(type, "dgradient")==0
159 || strcasecmp(type, "hgradient")==0) {
160 XColor color;
161 RColor color1, color2;
162 RImage *image;
163 Pixmap pixmap;
164 int gtype;
166 GETSTR(val, tmp, 1);
168 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
169 wwarning("could not parse color %s in texture %s", tmp, text);
170 goto error;
173 color1.red = color.red >> 8;
174 color1.green = color.green >> 8;
175 color1.blue = color.blue >> 8;
177 GETSTR(val, tmp, 2);
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 color2.red = color.red >> 8;
185 color2.green = color.green >> 8;
186 color2.blue = color.blue >> 8;
188 switch (type[0]) {
189 case 'h':
190 case 'H':
191 gtype = RHorizontalGradient;
192 break;
193 case 'V':
194 case 'v':
195 gtype = RVerticalGradient;
196 break;
197 default:
198 gtype = RDiagonalGradient;
199 break;
202 image = RRenderGradient(scrWidth, scrHeight, &color1, &color2, gtype);
204 if (!image) {
205 wwarning("could not render gradient texture:%s",
206 RMessageForError(RErrorCode));
207 goto error;
210 if (!RConvertImage(rc, image, &pixmap)) {
211 wwarning("could not convert texture:%s",
212 RMessageForError(RErrorCode));
213 RDestroyImage(image);
214 goto error;
217 texture->width = image->width;
218 texture->height = image->height;
219 RDestroyImage(image);
221 texture->pixmap = pixmap;
222 } else if (strcasecmp(type, "mvgradient")==0
223 || strcasecmp(type, "mdgradient")==0
224 || strcasecmp(type, "mhgradient")==0) {
225 XColor color;
226 RColor **colors;
227 RImage *image;
228 Pixmap pixmap;
229 int i;
230 int j;
231 int gtype;
233 colors = malloc(sizeof(RColor*)*(count-1));
234 if (!colors) {
235 wwarning("out of memory while parsing texture");
236 goto error;
238 memset(colors, 0, sizeof(RColor*)*(count-1));
240 for (i = 2; i < count; i++) {
241 val = PLGetArrayElement(texarray, i);
242 if (!PLIsString(val)) {
243 wwarning("could not parse texture %s", text);
245 for (j = 0; colors[j]!=NULL; j++)
246 free(colors[j]);
247 free(colors);
248 goto error;
250 tmp = PLGetString(val);
252 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
253 wwarning("could not parse color %s in texture %s",
254 tmp, text);
256 for (j = 0; colors[j]!=NULL; j++)
257 free(colors[j]);
258 free(colors);
259 goto error;
261 if (!(colors[i-2] = malloc(sizeof(RColor)))) {
262 wwarning("out of memory while parsing texture");
264 for (j = 0; colors[j]!=NULL; j++)
265 free(colors[j]);
266 free(colors);
267 goto error;
270 colors[i-2]->red = color.red >> 8;
271 colors[i-2]->green = color.green >> 8;
272 colors[i-2]->blue = color.blue >> 8;
275 switch (type[1]) {
276 case 'h':
277 case 'H':
278 gtype = RHorizontalGradient;
279 break;
280 case 'V':
281 case 'v':
282 gtype = RVerticalGradient;
283 break;
284 default:
285 gtype = RDiagonalGradient;
286 break;
289 image = RRenderMultiGradient(scrWidth, scrHeight, colors, gtype);
291 for (j = 0; colors[j]!=NULL; j++)
292 free(colors[j]);
293 free(colors);
295 if (!image) {
296 wwarning("could not render gradient texture:%s",
297 RMessageForError(RErrorCode));
298 goto error;
301 if (!RConvertImage(rc, image, &pixmap)) {
302 wwarning("could not convert texture:%s",
303 RMessageForError(RErrorCode));
304 RDestroyImage(image);
305 goto error;
308 texture->width = image->width;
309 texture->height = image->height;
310 RDestroyImage(image);
312 texture->pixmap = pixmap;
313 } else if (strcasecmp(type, "cpixmap")==0
314 || strcasecmp(type, "spixmap")==0
315 || strcasecmp(type, "tpixmap")==0) {
316 XColor color;
317 Pixmap pixmap;
318 RImage *image;
320 GETSTR(val, tmp, 1);
322 image = loadImage(rc, tmp);
323 if (!image) {
324 goto error;
327 GETSTR(val, tmp, 2);
329 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
330 wwarning("could not parse color %s in texture %s\n", tmp, text);
331 RDestroyImage(image);
332 goto error;
335 RColor rcolor;
337 rcolor.red = color.red >> 8;
338 rcolor.green = color.green >> 8;
339 rcolor.blue = color.blue >> 8;
340 RGetClosestXColor(rc, &rcolor, &color);
342 switch (type[0]) {
343 case 't':
344 case 'T':
345 texture->width = image->width;
346 texture->height = image->height;
347 if (!RConvertImage(rc, image, &pixmap)) {
348 wwarning("could not convert texture:%s",
349 RMessageForError(RErrorCode));
350 RDestroyImage(image);
351 goto error;
353 break;
354 case 's':
355 case 'S':
357 RImage *simage;
358 int w, h;
360 if (image->width*scrHeight > image->height*scrWidth) {
361 w = scrWidth;
362 h = (scrWidth*image->height)/image->width;
363 } else {
364 h = scrHeight;
365 w = (scrHeight*image->width)/image->height;
368 simage = RScaleImage(image, w, h);
369 if (!simage) {
370 wwarning("could not scale image:%s",
371 RMessageForError(RErrorCode));
372 RDestroyImage(image);
373 goto error;
375 RDestroyImage(image);
376 image = simage;
378 /* fall through */
379 case 'c':
380 case 'C':
382 Pixmap cpixmap;
384 if (!RConvertImage(rc, image, &pixmap)) {
385 wwarning("could not convert texture:%s",
386 RMessageForError(RErrorCode));
387 RDestroyImage(image);
388 goto error;
391 if (image->width != scrWidth || image->height != scrHeight) {
392 int x, y, sx, sy, w, h;
394 cpixmap = XCreatePixmap(dpy, root, scrWidth, scrHeight,
395 DefaultDepth(dpy, scr));
397 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
398 XFillRectangle(dpy, cpixmap, DefaultGC(dpy, scr),
399 0, 0, scrWidth, scrHeight);
401 if (image->height < scrHeight) {
402 h = image->height;
403 y = (scrHeight - h)/2;
404 sy = 0;
405 } else {
406 sy = (image->height - scrHeight)/2;
407 y = 0;
408 h = scrHeight;
410 if (image->width < scrWidth) {
411 w = image->width;
412 x = (scrWidth - w)/2;
413 sx = 0;
414 } else {
415 sx = (image->width - scrWidth)/2;
416 x = 0;
417 w = scrWidth;
420 XCopyArea(dpy, pixmap, cpixmap, DefaultGC(dpy, scr),
421 sx, sy, w, h, x, y);
422 XFreePixmap(dpy, pixmap);
423 pixmap = cpixmap;
425 RDestroyImage(image);
427 texture->width = scrWidth;
428 texture->height = scrHeight;
430 break;
433 texture->pixmap = pixmap;
434 texture->color = color;
435 } else if (strcasecmp(type, "thgradient")==0
436 || strcasecmp(type, "tvgradient")==0
437 || strcasecmp(type, "tdgradient")==0) {
438 XColor color;
439 RColor color1, color2;
440 RImage *image;
441 RImage *gradient;
442 RImage *tiled;
443 Pixmap pixmap;
444 int opaq;
445 char *file;
446 int gtype;
447 int twidth, theight;
449 GETSTR(val, file, 1);
451 GETSTR(val, tmp, 2);
453 opaq = atoi(tmp);
455 GETSTR(val, tmp, 3);
457 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
458 wwarning("could not parse color %s in texture %s", tmp, text);
459 goto error;
462 color1.red = color.red >> 8;
463 color1.green = color.green >> 8;
464 color1.blue = color.blue >> 8;
466 GETSTR(val, tmp, 4);
468 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
469 wwarning("could not parse color %s in texture %s", tmp, text);
470 goto error;
473 color2.red = color.red >> 8;
474 color2.green = color.green >> 8;
475 color2.blue = color.blue >> 8;
477 image = loadImage(rc, file);
478 if (!image) {
479 RDestroyImage(gradient);
480 goto error;
483 switch (type[1]) {
484 case 'h':
485 case 'H':
486 gtype = RHorizontalGradient;
487 twidth = scrWidth;
488 theight = image->height > scrHeight ? scrHeight : image->height;
489 break;
490 case 'V':
491 case 'v':
492 gtype = RVerticalGradient;
493 twidth = image->width > scrWidth ? scrWidth : image->width;
494 theight = scrHeight;
495 break;
496 default:
497 gtype = RDiagonalGradient;
498 twidth = scrWidth;
499 theight = scrHeight;
500 break;
502 gradient = RRenderGradient(twidth, theight, &color1, &color2, gtype);
504 if (!gradient) {
505 wwarning("could not render texture:%s",
506 RMessageForError(RErrorCode));
507 RDestroyImage(gradient);
508 goto error;
511 tiled = RMakeTiledImage(image, twidth, theight);
512 if (!tiled) {
513 wwarning("could not render texture:%s",
514 RMessageForError(RErrorCode));
515 RDestroyImage(gradient);
516 RDestroyImage(image);
517 goto error;
519 RDestroyImage(image);
521 RCombineImagesWithOpaqueness(tiled, gradient, opaq);
522 RDestroyImage(gradient);
524 if (!RConvertImage(rc, tiled, &pixmap)) {
525 wwarning("could not convert texture:%s",
526 RMessageForError(RErrorCode));
527 RDestroyImage(image);
528 goto error;
530 texture->width = tiled->width;
531 texture->height = tiled->height;
533 RDestroyImage(tiled);
535 texture->pixmap = pixmap;
536 } else {
537 wwarning("invalid texture type %s", text);
538 goto error;
541 texture->spec = wstrdup(text);
543 return texture;
545 error:
546 if (texture)
547 free(texture);
548 if (texarray)
549 PLRelease(texarray);
551 return NULL;
555 void
556 freeTexture(BackgroundTexture *texture)
558 if (texture->solid) {
559 long pixel[1];
561 pixel[0] = texture->color.pixel;
562 /* dont free black/white pixels */
563 if (pixel[0]!=BlackPixelOfScreen(DefaultScreenOfDisplay(dpy))
564 && pixel[0]!=WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
565 XFreeColors(dpy, DefaultColormap(dpy, scr), pixel, 1, 0);
567 free(texture->spec);
568 free(texture);
572 void
573 setupTexture(RContext *rc, BackgroundTexture **textures, int *maxTextures,
574 int workspace, char *texture)
576 BackgroundTexture *newTexture = NULL;
577 int i;
579 /* unset the texture */
580 if (!texture) {
581 if (textures[workspace]!=NULL) {
582 textures[workspace]->refcount--;
584 if (textures[workspace]->refcount == 0)
585 freeTexture(textures[workspace]);
587 textures[workspace] = NULL;
588 return;
591 if (textures[workspace]
592 && strcasecmp(textures[workspace]->spec, texture)==0) {
593 /* texture did not change */
594 return;
597 /* check if the same texture is already created */
598 for (i = 0; i < *maxTextures; i++) {
599 if (textures[i] && strcasecmp(textures[i]->spec, texture)==0) {
600 newTexture = textures[i];
601 break;
605 if (!newTexture) {
606 /* create the texture */
607 newTexture = parseTexture(rc, texture);
609 if (!newTexture)
610 return;
612 if (textures[workspace]!=NULL) {
614 textures[workspace]->refcount--;
616 if (textures[workspace]->refcount == 0)
617 freeTexture(textures[workspace]);
620 newTexture->refcount++;
621 textures[workspace] = newTexture;
623 if (*maxTextures < workspace)
624 *maxTextures = workspace;
629 Pixmap
630 duplicatePixmap(Pixmap pixmap, int width, int height)
632 Display *tmpDpy;
633 Pixmap copyP;
635 /* must open a new display or the RetainPermanent will
636 * leave stuff allocated in RContext unallocated after exit */
637 tmpDpy = XOpenDisplay("");
638 if (!tmpDpy) {
639 wwarning("could not open display to update background image information");
641 return None;
642 } else {
643 XSync(dpy, False);
645 copyP = XCreatePixmap(tmpDpy, root, width, height,
646 DefaultDepth(tmpDpy, scr));
647 XCopyArea(tmpDpy, pixmap, copyP, DefaultGC(tmpDpy, scr),
648 0, 0, width, height, 0, 0);
649 XSync(tmpDpy, False);
651 XSetCloseDownMode(tmpDpy, RetainPermanent);
652 XCloseDisplay(tmpDpy);
655 return copyP;
659 void
660 setPixmapProperty(Pixmap pixmap)
662 static Atom prop = 0;
663 Atom type;
664 int format;
665 unsigned long length, after;
666 unsigned char *data;
667 int mode;
669 if (!prop) {
670 prop = XInternAtom(dpy, "_XROOTPMAP_ID", False);
673 XGrabServer(dpy);
675 /* Clear out the old pixmap */
676 XGetWindowProperty(dpy, root, prop, 0L, 1L, False, AnyPropertyType,
677 &type, &format, &length, &after, &data);
679 if ((type == XA_PIXMAP) && (format == 32) && (length == 1)) {
680 XKillClient(dpy, *((Pixmap *)data));
681 mode = PropModeReplace;
682 } else {
683 mode = PropModeAppend;
685 if (pixmap)
686 XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, mode,
687 (unsigned char *) &pixmap, 1);
688 else
689 XDeleteProperty(dpy, root, prop);
692 XUngrabServer(dpy);
693 XFlush(dpy);
698 void
699 changeTexture(BackgroundTexture *texture)
701 if (!texture)
702 return;
704 if (texture->solid) {
705 XSetWindowBackground(dpy, root, texture->color.pixel);
706 } else {
707 XSetWindowBackgroundPixmap(dpy, root, texture->pixmap);
709 XClearWindow(dpy, root);
711 XSync(dpy, False);
714 Pixmap pixmap;
716 pixmap = duplicatePixmap(texture->pixmap, texture->width,
717 texture->height);
719 setPixmapProperty(pixmap);
725 readmsg(int fd, unsigned char *buffer, int size)
727 int count;
729 count = 0;
730 while (size>0) {
731 count = read(fd, buffer, size);
732 if (count < 0)
733 return -1;
734 size -= count;
735 buffer += count;
736 *buffer = 0;
739 return size;
744 * Message Format:
745 * sizeSntexture_spec - sets the texture for workspace n
746 * sizeCn - change background texture to the one for workspace n
747 * sizePpath - set the pixmap search path
749 * n is 4 bytes
750 * size = 4 bytes for length of the message data
752 void
753 helperLoop(RContext *rc)
755 BackgroundTexture *textures[WORKSPACE_COUNT];
756 int maxTextures = 0;
757 unsigned char buffer[2048], buf[8];
758 int size;
759 int errcount = 4;
761 memset(textures, 0, WORKSPACE_COUNT*sizeof(BackgroundTexture*));
764 while (1) {
765 int workspace;
767 /* get length of message */
768 if (readmsg(0, buffer, 4) < 0) {
769 wsyserror("error reading message from Window Maker");
770 errcount--;
771 if (errcount == 0) {
772 wfatal("quitting");
773 exit(1);
775 continue;
777 memcpy(buf, buffer, 4);
778 buf[4] = 0;
779 size = atoi(buf);
781 /* get message */
782 if (readmsg(0, buffer, size) < 0) {
783 wsyserror("error reading message from Window Maker");
784 errcount--;
785 if (errcount == 0) {
786 wfatal("quitting");
787 exit(1);
789 continue;
791 #ifdef DEBUG
792 printf("RECEIVED %s\n",buffer);
793 #endif
794 if (buffer[0]!='P') {
795 memcpy(buf, &buffer[1], 4);
796 buf[4] = 0;
797 workspace = atoi(buf);
798 if (workspace < 0 || workspace >= WORKSPACE_COUNT) {
799 wwarning("received message with invalid workspace number %i\n",
800 workspace);
801 continue;
805 switch (buffer[0]) {
806 case 'S':
807 #ifdef DEBUG
808 printf("set texture %s\n", &buffer[5]);
809 #endif
810 setupTexture(rc, textures, &maxTextures, workspace, &buffer[5]);
811 break;
813 case 'C':
814 #ifdef DEBUG
815 printf("change texture %i\n", workspace);
816 #endif
817 if (!textures[workspace])
818 changeTexture(textures[0]);
819 else
820 changeTexture(textures[workspace]);
821 break;
823 case 'P':
824 #ifdef DEBUG
825 printf("change pixmappath %s\n", &buffer[1]);
826 #endif
827 if (PixmapPath)
828 free(PixmapPath);
829 PixmapPath = wstrdup(&buffer[1]);
830 break;
832 case 'U':
833 #ifdef DEBUG
834 printf("unset workspace %i\n", workspace);
835 #endif
836 setupTexture(rc, textures, &maxTextures, workspace, NULL);
837 break;
839 default:
840 wwarning("unknown message received");
841 break;
847 void
848 updateDomain(char *domain, int workspace, char *texture)
850 char *program = "wdwrite";
852 execlp(program, program, domain, "WorkspaceBack", texture, NULL);
853 wwarning("warning could not run \"%s\"", program);
858 proplist_t
859 getDomain(char *domain)
861 char *path;
862 proplist_t prop;
865 path = wdefaultspathfordomain(domain);
866 if (!path) {
867 wwarning("could not locate file for domain %s", domain);
868 return NULL;
871 prop = PLGetProplistWithPath(path);
873 if (!prop || !PLIsDictionary(prop)) {
874 wwarning("invalid domain file %s", path);
875 free(path);
876 if (prop)
877 PLRelease(prop);
878 return NULL;
880 free(path);
882 return prop;
886 char*
887 getPixmapPath(proplist_t prop)
889 proplist_t key, val;
890 proplist_t d;
891 char *ptr, *data;
892 int len, i, count;
894 key = PLMakeString("PixmapPath");
895 val = PLGetDictionaryEntry(prop, key);
896 PLRelease(key);
897 if (!val || !PLIsArray(val)) {
898 PLRelease(prop);
899 return wstrdup("");
902 count = PLGetNumberOfElements(val);
903 len = 0;
904 for (i=0; i<count; i++) {
905 d = PLGetArrayElement(val, i);
906 if (!d || !PLIsString(d)) {
907 continue;
909 len += strlen(PLGetString(d))+1;
912 ptr = data = wmalloc(len+1);
913 *ptr = 0;
915 for (i=0; i<count; i++) {
916 d = PLGetArrayElement(val, i);
917 if (!d || !PLIsString(d)) {
918 continue;
920 strcpy(ptr, PLGetString(d));
922 ptr += strlen(PLGetString(d));
923 *ptr = ':';
924 ptr++;
926 if (i>0)
927 ptr--; *(ptr--) = 0;
929 return data;
933 void
934 wAbort()
936 wfatal("aborting");
937 exit(1);
942 void
943 print_help(char *ProgName)
945 printf("usage: %s [-options] image\n", ProgName);
946 puts("options:");
947 puts(" -d dither image");
948 puts(" -m match colors");
949 puts(" -b <color> background color");
950 puts(" -t tile image");
951 puts(" -e center image");
952 puts(" -s scale image (default)");
953 puts(" -u update WindowMaker domain database");
954 puts(" -D <domain> update <domain> database");
955 puts(" -c <cpc> colors per channel to use");
956 puts(" -p <texture> proplist style texture specification");
957 /* puts(" -w <workspace> update the background for the specified workspace");
963 void
964 changeTextureForWorkspace(proplist_t dict, char *texture, int workspace)
966 proplist_t key;
967 proplist_t array;
968 proplist_t val;
969 int j;
971 workspace++;
973 val = PLGetProplistWithDescription(texture);
974 if (!val) {
975 wwarning("could not parse texture %s", texture);
976 return;
979 key = PLMakeString("WorkspaceSpecificBack");
980 array = PLGetDictionaryEntry(dict, key);
981 if (!array) {
982 array = PLMakeArrayFromElements(NULL, NULL);
983 PLInsertDictionaryEntry(dict, key, array);
986 j = PLGetNumberOfElements(array);
987 if (workspace >= j) {
988 proplist_t empty;
990 empty = PLMakeArrayFromElements(NULL, NULL);
992 while (j++ < workspace) {
993 PLAppendArrayElement(array, empty);
995 PLAppendArrayElement(array, val);
996 } else {
997 PLRemoveArrayElement(array, workspace);
998 PLInsertArrayElement(array, val, workspace);
1001 PLSave(dict, YES);
1006 main(int argc, char **argv)
1008 int i;
1009 int helperMode = 0;
1010 RContext *rc;
1011 RContextAttributes rattr;
1012 char *style = "spixmap";
1013 char *back_color = "gray20";
1014 char *image_name = NULL;
1015 char *domain = "WindowMaker";
1016 int update=0, cpc=4, render_mode=RM_DITHER, obey_user=0;
1017 char *texture = NULL;
1018 int workspace = -1;
1019 proplist_t domain_prop;
1023 signal(SIGINT, SIG_DFL);
1024 signal(SIGTERM, SIG_DFL);
1025 signal(SIGQUIT, SIG_DFL);
1026 signal(SIGSEGV, SIG_DFL);
1027 signal(SIGBUS, SIG_DFL);
1028 signal(SIGFPE, SIG_DFL);
1029 signal(SIGABRT, SIG_DFL);
1030 signal(SIGHUP, SIG_DFL);
1031 signal(SIGPIPE, SIG_DFL);
1032 signal(SIGCHLD, SIG_DFL);
1034 WMInitializeApplication("wmsetbg", &argc, argv);
1036 for (i=0; i<argc; i++) {
1037 if (strcmp(argv[i], "-helper")==0) {
1038 helperMode = 1;
1039 } else if (strcmp(argv[i], "-s")==0) {
1040 style = "spixmap";
1041 } else if (strcmp(argv[i], "-t")==0) {
1042 style = "tpixmap";
1043 } else if (strcmp(argv[i], "-e")==0) {
1044 style = "cpixmap";
1045 } else if (strcmp(argv[i], "-d")==0) {
1046 render_mode = RM_DITHER;
1047 obey_user++;
1048 } else if (strcmp(argv[i], "-m")==0) {
1049 render_mode = RM_MATCH;
1050 obey_user++;
1051 } else if (strcmp(argv[i], "-u")==0) {
1052 update++;
1053 } else if (strcmp(argv[i], "-D")==0) {
1054 update++;
1055 i++;
1056 if (i>=argc) {
1057 wfatal("too few arguments for %s\n", argv[i-1]);
1058 exit(1);
1060 domain = wstrdup(argv[i]);
1061 } else if (strcmp(argv[i], "-c")==0) {
1062 i++;
1063 if (i>=argc) {
1064 wfatal("too few arguments for %s\n", argv[i-1]);
1065 exit(1);
1067 if (sscanf(argv[i], "%i", &cpc)!=1) {
1068 wfatal("bad value for colors per channel: \"%s\"\n", argv[i]);
1069 exit(1);
1071 } else if (strcmp(argv[i], "-b")==0) {
1072 i++;
1073 if (i>=argc) {
1074 wfatal("too few arguments for %s\n", argv[i-1]);
1075 exit(1);
1077 back_color = argv[i];
1078 } else if (strcmp(argv[i], "-p")==0) {
1079 i++;
1080 if (i>=argc) {
1081 wfatal("too few arguments for %s\n", argv[i-1]);
1082 exit(1);
1084 texture = argv[i];
1085 } else if (strcmp(argv[i], "-w")==0) {
1086 i++;
1087 if (i>=argc) {
1088 wfatal("too few arguments for %s\n", argv[i-1]);
1089 exit(1);
1091 if (sscanf(argv[i], "%i", &workspace)!=1) {
1092 wfatal("bad value for workspace number: \"%s\"",
1093 argv[i]);
1094 exit(1);
1096 } else if (argv[i][0] != '-') {
1097 image_name = argv[i];
1098 } else {
1099 print_help(argv[0]);
1100 exit(1);
1104 domain_prop = getDomain(domain);
1106 PixmapPath = getPixmapPath(domain_prop);
1108 dpy = XOpenDisplay("");
1109 if (!dpy) {
1110 wfatal("could not open display");
1111 exit(1);
1113 XSynchronize(dpy, 1);
1115 root = DefaultRootWindow(dpy);
1117 scr = DefaultScreen(dpy);
1119 scrWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
1120 scrHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
1122 if (!obey_user && DefaultDepth(dpy, scr) <= 8)
1123 render_mode = RM_DITHER;
1125 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_DefaultVisual;
1126 rattr.render_mode = render_mode;
1127 rattr.colors_per_channel = cpc;
1129 rc = RCreateContext(dpy, scr, &rattr);
1131 if (helperMode) {
1132 /* lower priority, so that it wont use all the CPU */
1133 nice(1000);
1135 PLRelease(domain_prop);
1137 helperLoop(rc);
1138 } else {
1139 BackgroundTexture *tex;
1140 char buffer[4098];
1142 if (!texture) {
1143 sprintf(buffer, "(%s, %s, %s)", style, image_name, back_color);
1144 texture = (char*)buffer;
1147 if (update && workspace < 0) {
1148 updateDomain(domain, workspace, texture);
1151 tex = parseTexture(rc, texture);
1152 if (!tex)
1153 exit(1);
1155 if (workspace<0)
1156 changeTexture(tex);
1157 else
1158 changeTextureForWorkspace(domain_prop, texture, workspace);
1161 return -1;