Update to Window Maker 0.50.2
[wmaker-crm.git] / util / wmsetbg.c
blob095c001b7738f14af7a6411c2a967c220174cfda
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>
35 #include <ctype.h>
37 #include "../src/wconfig.h"
39 #include "../WINGs/WINGs.h"
40 #include "../WINGs/WUtil.h"
41 #include "../wrlib/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, "mpixmap")==0
316 || strcasecmp(type, "tpixmap")==0) {
317 XColor color;
318 Pixmap pixmap;
319 RImage *image;
320 int w, h;
322 GETSTR(val, tmp, 1);
324 image = loadImage(rc, tmp);
325 if (!image) {
326 goto error;
329 GETSTR(val, tmp, 2);
331 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
332 wwarning("could not parse color %s in texture %s\n", tmp, text);
333 RDestroyImage(image);
334 goto error;
337 RColor rcolor;
339 rcolor.red = color.red >> 8;
340 rcolor.green = color.green >> 8;
341 rcolor.blue = color.blue >> 8;
342 RGetClosestXColor(rc, &rcolor, &color);
344 switch (toupper(type[0])) {
345 case 'T':
346 texture->width = image->width;
347 texture->height = image->height;
348 if (!RConvertImage(rc, image, &pixmap)) {
349 wwarning("could not convert texture:%s",
350 RMessageForError(RErrorCode));
351 RDestroyImage(image);
352 goto error;
354 break;
355 case 'S':
356 case 'M':
357 if (toupper(type[0])=='S') {
358 w = scrWidth;
359 h = scrHeight;
360 } else {
361 if (image->width*scrHeight > image->height*scrWidth) {
362 w = scrWidth;
363 h = (scrWidth*image->height)/image->width;
364 } else {
365 h = scrHeight;
366 w = (scrHeight*image->width)/image->height;
370 RImage *simage;
372 simage = RScaleImage(image, w, h);
373 if (!simage) {
374 wwarning("could not scale image:%s",
375 RMessageForError(RErrorCode));
376 RDestroyImage(image);
377 goto error;
379 RDestroyImage(image);
380 image = simage;
382 /* fall through */
383 case 'c':
384 case 'C':
386 Pixmap cpixmap;
388 if (!RConvertImage(rc, image, &pixmap)) {
389 wwarning("could not convert texture:%s",
390 RMessageForError(RErrorCode));
391 RDestroyImage(image);
392 goto error;
395 if (image->width != scrWidth || image->height != scrHeight) {
396 int x, y, sx, sy, w, h;
398 cpixmap = XCreatePixmap(dpy, root, scrWidth, scrHeight,
399 DefaultDepth(dpy, scr));
401 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
402 XFillRectangle(dpy, cpixmap, DefaultGC(dpy, scr),
403 0, 0, scrWidth, scrHeight);
405 if (image->height < scrHeight) {
406 h = image->height;
407 y = (scrHeight - h)/2;
408 sy = 0;
409 } else {
410 sy = (image->height - scrHeight)/2;
411 y = 0;
412 h = scrHeight;
414 if (image->width < scrWidth) {
415 w = image->width;
416 x = (scrWidth - w)/2;
417 sx = 0;
418 } else {
419 sx = (image->width - scrWidth)/2;
420 x = 0;
421 w = scrWidth;
424 XCopyArea(dpy, pixmap, cpixmap, DefaultGC(dpy, scr),
425 sx, sy, w, h, x, y);
426 XFreePixmap(dpy, pixmap);
427 pixmap = cpixmap;
429 RDestroyImage(image);
431 texture->width = scrWidth;
432 texture->height = scrHeight;
434 break;
437 texture->pixmap = pixmap;
438 texture->color = color;
439 } else if (strcasecmp(type, "thgradient")==0
440 || strcasecmp(type, "tvgradient")==0
441 || strcasecmp(type, "tdgradient")==0) {
442 XColor color;
443 RColor color1, color2;
444 RImage *image;
445 RImage *gradient;
446 RImage *tiled;
447 Pixmap pixmap;
448 int opaq;
449 char *file;
450 int gtype;
451 int twidth, theight;
453 GETSTR(val, file, 1);
455 GETSTR(val, tmp, 2);
457 opaq = atoi(tmp);
459 GETSTR(val, tmp, 3);
461 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
462 wwarning("could not parse color %s in texture %s", tmp, text);
463 goto error;
466 color1.red = color.red >> 8;
467 color1.green = color.green >> 8;
468 color1.blue = color.blue >> 8;
470 GETSTR(val, tmp, 4);
472 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
473 wwarning("could not parse color %s in texture %s", tmp, text);
474 goto error;
477 color2.red = color.red >> 8;
478 color2.green = color.green >> 8;
479 color2.blue = color.blue >> 8;
481 image = loadImage(rc, file);
482 if (!image) {
483 RDestroyImage(gradient);
484 goto error;
487 switch (type[1]) {
488 case 'h':
489 case 'H':
490 gtype = RHorizontalGradient;
491 twidth = scrWidth;
492 theight = image->height > scrHeight ? scrHeight : image->height;
493 break;
494 case 'V':
495 case 'v':
496 gtype = RVerticalGradient;
497 twidth = image->width > scrWidth ? scrWidth : image->width;
498 theight = scrHeight;
499 break;
500 default:
501 gtype = RDiagonalGradient;
502 twidth = scrWidth;
503 theight = scrHeight;
504 break;
506 gradient = RRenderGradient(twidth, theight, &color1, &color2, gtype);
508 if (!gradient) {
509 wwarning("could not render texture:%s",
510 RMessageForError(RErrorCode));
511 RDestroyImage(gradient);
512 goto error;
515 tiled = RMakeTiledImage(image, twidth, theight);
516 if (!tiled) {
517 wwarning("could not render texture:%s",
518 RMessageForError(RErrorCode));
519 RDestroyImage(gradient);
520 RDestroyImage(image);
521 goto error;
523 RDestroyImage(image);
525 RCombineImagesWithOpaqueness(tiled, gradient, opaq);
526 RDestroyImage(gradient);
528 if (!RConvertImage(rc, tiled, &pixmap)) {
529 wwarning("could not convert texture:%s",
530 RMessageForError(RErrorCode));
531 RDestroyImage(image);
532 goto error;
534 texture->width = tiled->width;
535 texture->height = tiled->height;
537 RDestroyImage(tiled);
539 texture->pixmap = pixmap;
540 } else {
541 wwarning("invalid texture type %s", text);
542 goto error;
545 texture->spec = wstrdup(text);
547 return texture;
549 error:
550 if (texture)
551 free(texture);
552 if (texarray)
553 PLRelease(texarray);
555 return NULL;
559 void
560 freeTexture(BackgroundTexture *texture)
562 if (texture->solid) {
563 long pixel[1];
565 pixel[0] = texture->color.pixel;
566 /* dont free black/white pixels */
567 if (pixel[0]!=BlackPixelOfScreen(DefaultScreenOfDisplay(dpy))
568 && pixel[0]!=WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
569 XFreeColors(dpy, DefaultColormap(dpy, scr), pixel, 1, 0);
571 free(texture->spec);
572 free(texture);
576 void
577 setupTexture(RContext *rc, BackgroundTexture **textures, int *maxTextures,
578 int workspace, char *texture)
580 BackgroundTexture *newTexture = NULL;
581 int i;
583 /* unset the texture */
584 if (!texture) {
585 if (textures[workspace]!=NULL) {
586 textures[workspace]->refcount--;
588 if (textures[workspace]->refcount == 0)
589 freeTexture(textures[workspace]);
591 textures[workspace] = NULL;
592 return;
595 if (textures[workspace]
596 && strcasecmp(textures[workspace]->spec, texture)==0) {
597 /* texture did not change */
598 return;
601 /* check if the same texture is already created */
602 for (i = 0; i < *maxTextures; i++) {
603 if (textures[i] && strcasecmp(textures[i]->spec, texture)==0) {
604 newTexture = textures[i];
605 break;
609 if (!newTexture) {
610 /* create the texture */
611 newTexture = parseTexture(rc, texture);
613 if (!newTexture)
614 return;
616 if (textures[workspace]!=NULL) {
618 textures[workspace]->refcount--;
620 if (textures[workspace]->refcount == 0)
621 freeTexture(textures[workspace]);
624 newTexture->refcount++;
625 textures[workspace] = newTexture;
627 if (*maxTextures < workspace)
628 *maxTextures = workspace;
633 Pixmap
634 duplicatePixmap(Pixmap pixmap, int width, int height)
636 Display *tmpDpy;
637 Pixmap copyP;
639 /* must open a new display or the RetainPermanent will
640 * leave stuff allocated in RContext unallocated after exit */
641 tmpDpy = XOpenDisplay("");
642 if (!tmpDpy) {
643 wwarning("could not open display to update background image information");
645 return None;
646 } else {
647 XSync(dpy, False);
649 copyP = XCreatePixmap(tmpDpy, root, width, height,
650 DefaultDepth(tmpDpy, scr));
651 XCopyArea(tmpDpy, pixmap, copyP, DefaultGC(tmpDpy, scr),
652 0, 0, width, height, 0, 0);
653 XSync(tmpDpy, False);
655 XSetCloseDownMode(tmpDpy, RetainPermanent);
656 XCloseDisplay(tmpDpy);
659 return copyP;
663 void
664 setPixmapProperty(Pixmap pixmap)
666 static Atom prop = 0;
667 Atom type;
668 int format;
669 unsigned long length, after;
670 unsigned char *data;
671 int mode;
673 if (!prop) {
674 prop = XInternAtom(dpy, "_XROOTPMAP_ID", False);
677 XGrabServer(dpy);
679 /* Clear out the old pixmap */
680 XGetWindowProperty(dpy, root, prop, 0L, 1L, False, AnyPropertyType,
681 &type, &format, &length, &after, &data);
683 if ((type == XA_PIXMAP) && (format == 32) && (length == 1)) {
684 XKillClient(dpy, *((Pixmap *)data));
685 mode = PropModeReplace;
686 } else {
687 mode = PropModeAppend;
689 if (pixmap)
690 XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, mode,
691 (unsigned char *) &pixmap, 1);
692 else
693 XDeleteProperty(dpy, root, prop);
696 XUngrabServer(dpy);
697 XFlush(dpy);
702 void
703 changeTexture(BackgroundTexture *texture)
705 if (!texture)
706 return;
708 if (texture->solid) {
709 XSetWindowBackground(dpy, root, texture->color.pixel);
710 } else {
711 XSetWindowBackgroundPixmap(dpy, root, texture->pixmap);
713 XClearWindow(dpy, root);
715 XSync(dpy, False);
718 Pixmap pixmap;
720 pixmap = duplicatePixmap(texture->pixmap, texture->width,
721 texture->height);
723 setPixmapProperty(pixmap);
729 readmsg(int fd, unsigned char *buffer, int size)
731 int count;
733 count = 0;
734 while (size>0) {
735 count = read(fd, buffer, size);
736 if (count < 0)
737 return -1;
738 size -= count;
739 buffer += count;
740 *buffer = 0;
743 return size;
748 * Message Format:
749 * sizeSntexture_spec - sets the texture for workspace n
750 * sizeCn - change background texture to the one for workspace n
751 * sizePpath - set the pixmap search path
753 * n is 4 bytes
754 * size = 4 bytes for length of the message data
756 void
757 helperLoop(RContext *rc)
759 BackgroundTexture *textures[WORKSPACE_COUNT];
760 int maxTextures = 0;
761 unsigned char buffer[2048], buf[8];
762 int size;
763 int errcount = 4;
765 memset(textures, 0, WORKSPACE_COUNT*sizeof(BackgroundTexture*));
768 while (1) {
769 int workspace;
771 /* get length of message */
772 if (readmsg(0, buffer, 4) < 0) {
773 wsyserror("error reading message from Window Maker");
774 errcount--;
775 if (errcount == 0) {
776 wfatal("quitting");
777 exit(1);
779 continue;
781 memcpy(buf, buffer, 4);
782 buf[4] = 0;
783 size = atoi(buf);
785 /* get message */
786 if (readmsg(0, buffer, size) < 0) {
787 wsyserror("error reading message from Window Maker");
788 errcount--;
789 if (errcount == 0) {
790 wfatal("quitting");
791 exit(1);
793 continue;
795 #ifdef DEBUG
796 printf("RECEIVED %s\n",buffer);
797 #endif
798 if (buffer[0]!='P') {
799 memcpy(buf, &buffer[1], 4);
800 buf[4] = 0;
801 workspace = atoi(buf);
802 if (workspace < 0 || workspace >= WORKSPACE_COUNT) {
803 wwarning("received message with invalid workspace number %i\n",
804 workspace);
805 continue;
809 switch (buffer[0]) {
810 case 'S':
811 #ifdef DEBUG
812 printf("set texture %s\n", &buffer[5]);
813 #endif
814 setupTexture(rc, textures, &maxTextures, workspace, &buffer[5]);
815 break;
817 case 'C':
818 #ifdef DEBUG
819 printf("change texture %i\n", workspace);
820 #endif
821 if (!textures[workspace])
822 changeTexture(textures[0]);
823 else
824 changeTexture(textures[workspace]);
825 break;
827 case 'P':
828 #ifdef DEBUG
829 printf("change pixmappath %s\n", &buffer[1]);
830 #endif
831 if (PixmapPath)
832 free(PixmapPath);
833 PixmapPath = wstrdup(&buffer[1]);
834 break;
836 case 'U':
837 #ifdef DEBUG
838 printf("unset workspace %i\n", workspace);
839 #endif
840 setupTexture(rc, textures, &maxTextures, workspace, NULL);
841 break;
843 case 'K':
844 #ifdef DEBUG
845 printf("exit command\n");
846 #endif
847 exit(0);
849 default:
850 wwarning("unknown message received");
851 break;
857 void
858 updateDomain(char *domain, int workspace, char *texture)
860 char *program = "wdwrite";
862 execlp(program, program, domain, "WorkspaceBack", texture, NULL);
863 wwarning("warning could not run \"%s\"", program);
868 proplist_t
869 getDomain(char *domain)
871 char *path;
872 proplist_t prop;
875 path = wdefaultspathfordomain(domain);
876 if (!path) {
877 wwarning("could not locate file for domain %s", domain);
878 return NULL;
881 prop = PLGetProplistWithPath(path);
883 if (!prop || !PLIsDictionary(prop)) {
884 wwarning("invalid domain file %s", path);
885 free(path);
886 if (prop)
887 PLRelease(prop);
888 return NULL;
890 free(path);
892 return prop;
896 char*
897 getPixmapPath(proplist_t prop)
899 proplist_t key, val;
900 proplist_t d;
901 char *ptr, *data;
902 int len, i, count;
904 key = PLMakeString("PixmapPath");
905 val = PLGetDictionaryEntry(prop, key);
906 PLRelease(key);
907 if (!val || !PLIsArray(val)) {
908 PLRelease(prop);
909 return wstrdup("");
912 count = PLGetNumberOfElements(val);
913 len = 0;
914 for (i=0; i<count; i++) {
915 d = PLGetArrayElement(val, i);
916 if (!d || !PLIsString(d)) {
917 continue;
919 len += strlen(PLGetString(d))+1;
922 ptr = data = wmalloc(len+1);
923 *ptr = 0;
925 for (i=0; i<count; i++) {
926 d = PLGetArrayElement(val, i);
927 if (!d || !PLIsString(d)) {
928 continue;
930 strcpy(ptr, PLGetString(d));
932 ptr += strlen(PLGetString(d));
933 *ptr = ':';
934 ptr++;
936 if (i>0)
937 ptr--; *(ptr--) = 0;
939 return data;
943 void
944 wAbort()
946 wfatal("aborting");
947 exit(1);
952 void
953 print_help(char *ProgName)
955 printf("usage: %s [-options] image\n", ProgName);
956 puts("options:");
957 puts(" -d dither image");
958 puts(" -m match colors");
959 puts(" -b <color> background color");
960 puts(" -t tile image");
961 puts(" -e center image");
962 puts(" -s scale image (default)");
963 puts(" -a scale image and keep aspect ratio");
964 puts(" -u update WindowMaker domain database");
965 puts(" -D <domain> update <domain> database");
966 puts(" -c <cpc> colors per channel to use");
967 puts(" -p <texture> proplist style texture specification");
968 /* puts(" -w <workspace> update the background for the specified workspace");
974 void
975 changeTextureForWorkspace(proplist_t dict, char *texture, int workspace)
977 proplist_t key;
978 proplist_t array;
979 proplist_t val;
980 int j;
982 workspace++;
984 val = PLGetProplistWithDescription(texture);
985 if (!val) {
986 wwarning("could not parse texture %s", texture);
987 return;
990 key = PLMakeString("WorkspaceSpecificBack");
991 array = PLGetDictionaryEntry(dict, key);
992 if (!array) {
993 array = PLMakeArrayFromElements(NULL, NULL);
994 PLInsertDictionaryEntry(dict, key, array);
997 j = PLGetNumberOfElements(array);
998 if (workspace >= j) {
999 proplist_t empty;
1001 empty = PLMakeArrayFromElements(NULL, NULL);
1003 while (j++ < workspace) {
1004 PLAppendArrayElement(array, empty);
1006 PLAppendArrayElement(array, val);
1007 } else {
1008 PLRemoveArrayElement(array, workspace);
1009 PLInsertArrayElement(array, val, workspace);
1012 PLSave(dict, YES);
1017 main(int argc, char **argv)
1019 int i;
1020 int helperMode = 0;
1021 RContext *rc;
1022 RContextAttributes rattr;
1023 char *style = "spixmap";
1024 char *back_color = "gray20";
1025 char *image_name = NULL;
1026 char *domain = "WindowMaker";
1027 int update=0, cpc=4, render_mode=RM_DITHER, obey_user=0;
1028 char *texture = NULL;
1029 int workspace = -1;
1030 proplist_t domain_prop;
1034 signal(SIGINT, SIG_DFL);
1035 signal(SIGTERM, SIG_DFL);
1036 signal(SIGQUIT, SIG_DFL);
1037 signal(SIGSEGV, SIG_DFL);
1038 signal(SIGBUS, SIG_DFL);
1039 signal(SIGFPE, SIG_DFL);
1040 signal(SIGABRT, SIG_DFL);
1041 signal(SIGHUP, SIG_DFL);
1042 signal(SIGPIPE, SIG_DFL);
1043 signal(SIGCHLD, SIG_DFL);
1045 WMInitializeApplication("wmsetbg", &argc, argv);
1047 for (i=0; i<argc; i++) {
1048 if (strcmp(argv[i], "-helper")==0) {
1049 helperMode = 1;
1050 } else if (strcmp(argv[i], "-s")==0) {
1051 style = "spixmap";
1052 } else if (strcmp(argv[i], "-t")==0) {
1053 style = "tpixmap";
1054 } else if (strcmp(argv[i], "-e")==0) {
1055 style = "cpixmap";
1056 } else if (strcmp(argv[i], "-a")==0) {
1057 style = "mpixmap";
1058 } else if (strcmp(argv[i], "-d")==0) {
1059 render_mode = RM_DITHER;
1060 obey_user++;
1061 } else if (strcmp(argv[i], "-m")==0) {
1062 render_mode = RM_MATCH;
1063 obey_user++;
1064 } else if (strcmp(argv[i], "-u")==0) {
1065 update++;
1066 } else if (strcmp(argv[i], "-D")==0) {
1067 update++;
1068 i++;
1069 if (i>=argc) {
1070 wfatal("too few arguments for %s\n", argv[i-1]);
1071 exit(1);
1073 domain = wstrdup(argv[i]);
1074 } else if (strcmp(argv[i], "-c")==0) {
1075 i++;
1076 if (i>=argc) {
1077 wfatal("too few arguments for %s\n", argv[i-1]);
1078 exit(1);
1080 if (sscanf(argv[i], "%i", &cpc)!=1) {
1081 wfatal("bad value for colors per channel: \"%s\"\n", argv[i]);
1082 exit(1);
1084 } else if (strcmp(argv[i], "-b")==0) {
1085 i++;
1086 if (i>=argc) {
1087 wfatal("too few arguments for %s\n", argv[i-1]);
1088 exit(1);
1090 back_color = argv[i];
1091 } else if (strcmp(argv[i], "-p")==0) {
1092 i++;
1093 if (i>=argc) {
1094 wfatal("too few arguments for %s\n", argv[i-1]);
1095 exit(1);
1097 texture = argv[i];
1098 } else if (strcmp(argv[i], "-w")==0) {
1099 i++;
1100 if (i>=argc) {
1101 wfatal("too few arguments for %s\n", argv[i-1]);
1102 exit(1);
1104 if (sscanf(argv[i], "%i", &workspace)!=1) {
1105 wfatal("bad value for workspace number: \"%s\"",
1106 argv[i]);
1107 exit(1);
1109 } else if (argv[i][0] != '-') {
1110 image_name = argv[i];
1111 } else {
1112 print_help(argv[0]);
1113 exit(1);
1117 domain_prop = getDomain(domain);
1119 PixmapPath = getPixmapPath(domain_prop);
1121 dpy = XOpenDisplay("");
1122 if (!dpy) {
1123 wfatal("could not open display");
1124 exit(1);
1126 XSynchronize(dpy, 1);
1128 root = DefaultRootWindow(dpy);
1130 scr = DefaultScreen(dpy);
1132 scrWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
1133 scrHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
1135 if (!obey_user && DefaultDepth(dpy, scr) <= 8)
1136 render_mode = RM_DITHER;
1138 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_DefaultVisual;
1139 rattr.render_mode = render_mode;
1140 rattr.colors_per_channel = cpc;
1142 rc = RCreateContext(dpy, scr, &rattr);
1144 if (helperMode) {
1145 /* lower priority, so that it wont use all the CPU */
1146 nice(1000);
1148 PLRelease(domain_prop);
1150 helperLoop(rc);
1151 } else {
1152 BackgroundTexture *tex;
1153 char buffer[4098];
1155 if (!texture) {
1156 sprintf(buffer, "(%s, %s, %s)", style, image_name, back_color);
1157 texture = (char*)buffer;
1160 if (update && workspace < 0) {
1161 updateDomain(domain, workspace, texture);
1164 tex = parseTexture(rc, texture);
1165 if (!tex)
1166 exit(1);
1168 if (workspace<0)
1169 changeTexture(tex);
1170 else
1171 changeTextureForWorkspace(domain_prop, texture, workspace);
1174 return -1;