Small bug fix, and updated for some #defines that were removed.
[wmaker-crm.git] / util / wmsetbg.c
blobf567aee385a1a1594552a2ff49bdb0c62c05c427
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/config.h"
43 #ifdef HAVE_DLFCN_H
44 #include <dlfcn.h>
45 #endif
47 #include "../src/wconfig.h"
49 #include "../WINGs/WINGs.h"
50 #include "../WINGs/WUtil.h"
51 #include "../wrlib/wraster.h"
53 #include <proplist.h>
55 #define PROG_VERSION "wmsetbg (Window Maker) 2.2"
58 #define WORKSPACE_COUNT (MAX_WORKSPACES+1)
61 Display *dpy;
62 char *display = "";
63 Window root;
64 int scr;
65 int scrWidth;
66 int scrHeight;
69 Bool smooth = False;
72 Pixmap CurrentPixmap = None;
73 char *PixmapPath = NULL;
76 extern Pixmap LoadJPEG(RContext *rc, char *file_name, int *width, int *height);
79 typedef struct BackgroundTexture {
80 int refcount;
82 int solid;
84 char *spec;
86 XColor color;
87 Pixmap pixmap; /* for all textures, including solid */
88 int width; /* size of the pixmap */
89 int height;
90 } BackgroundTexture;
94 RImage*
95 loadImage(RContext *rc, char *file)
97 char *path;
98 RImage *image;
100 if (access(file, F_OK)!=0) {
101 path = wfindfile(PixmapPath, file);
102 if (!path) {
103 wwarning("%s:could not find image file used in texture", file);
104 return NULL;
106 } else {
107 path = wstrdup(file);
110 image = RLoadImage(rc, path, 0);
111 if (!image) {
112 wwarning("%s:could not load image file used in texture:%s", path,
113 RMessageForError(RErrorCode));
115 free(path);
117 return image;
121 BackgroundTexture*
122 parseTexture(RContext *rc, char *text)
124 BackgroundTexture *texture = NULL;
125 proplist_t texarray;
126 proplist_t val;
127 int count;
128 char *tmp;
129 char *type;
131 #define GETSTRORGOTO(val, str, i, label) \
132 val = PLGetArrayElement(texarray, i);\
133 if (!PLIsString(val)) {\
134 wwarning("could not parse texture %s", text);\
135 goto label;\
137 str = PLGetString(val)
139 texarray = PLGetProplistWithDescription(text);
140 if (!texarray || !PLIsArray(texarray)
141 || (count = PLGetNumberOfElements(texarray)) < 2) {
143 wwarning("could not parse texture %s", text);
144 if (texarray)
145 PLRelease(texarray);
146 return NULL;
149 texture = wmalloc(sizeof(BackgroundTexture));
150 memset(texture, 0, sizeof(BackgroundTexture));
152 GETSTRORGOTO(val, type, 0, error);
154 if (strcasecmp(type, "solid")==0) {
155 XColor color;
156 Pixmap pixmap;
158 texture->solid = 1;
160 GETSTRORGOTO(val, tmp, 1, error);
162 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
163 wwarning("could not parse color %s in texture %s", tmp, text);
164 goto error;
166 XAllocColor(dpy, DefaultColormap(dpy, scr), &color);
168 pixmap = XCreatePixmap(dpy, root, 8, 8, DefaultDepth(dpy, scr));
169 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
170 XFillRectangle(dpy, pixmap, DefaultGC(dpy, scr), 0, 0, 8, 8);
172 texture->pixmap = pixmap;
173 texture->color = color;
174 texture->width = 8;
175 texture->height = 8;
176 } else if (strcasecmp(type, "vgradient")==0
177 || strcasecmp(type, "dgradient")==0
178 || strcasecmp(type, "hgradient")==0) {
179 XColor color;
180 RColor color1, color2;
181 RImage *image;
182 Pixmap pixmap;
183 int gtype;
184 int iwidth, iheight;
186 GETSTRORGOTO(val, tmp, 1, error);
188 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
189 wwarning("could not parse color %s in texture %s", tmp, text);
190 goto error;
193 color1.red = color.red >> 8;
194 color1.green = color.green >> 8;
195 color1.blue = color.blue >> 8;
197 GETSTRORGOTO(val, tmp, 2, error);
199 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
200 wwarning("could not parse color %s in texture %s", tmp, text);
201 goto error;
204 color2.red = color.red >> 8;
205 color2.green = color.green >> 8;
206 color2.blue = color.blue >> 8;
208 switch (type[0]) {
209 case 'h':
210 case 'H':
211 gtype = RHorizontalGradient;
212 iwidth = scrWidth;
213 iheight = 8;
214 break;
215 case 'V':
216 case 'v':
217 gtype = RVerticalGradient;
218 iwidth = 8;
219 iheight = scrHeight;
220 break;
221 default:
222 gtype = RDiagonalGradient;
223 iwidth = scrWidth;
224 iheight = scrHeight;
225 break;
228 image = RRenderGradient(iwidth, iheight, &color1, &color2, gtype);
230 if (!image) {
231 wwarning("could not render gradient texture:%s",
232 RMessageForError(RErrorCode));
233 goto error;
236 if (!RConvertImage(rc, image, &pixmap)) {
237 wwarning("could not convert texture:%s",
238 RMessageForError(RErrorCode));
239 RDestroyImage(image);
240 goto error;
243 texture->width = image->width;
244 texture->height = image->height;
245 RDestroyImage(image);
247 texture->pixmap = pixmap;
248 } else if (strcasecmp(type, "mvgradient")==0
249 || strcasecmp(type, "mdgradient")==0
250 || strcasecmp(type, "mhgradient")==0) {
251 XColor color;
252 RColor **colors;
253 RImage *image;
254 Pixmap pixmap;
255 int i, j;
256 int gtype;
257 int iwidth, iheight;
259 colors = malloc(sizeof(RColor*)*(count-1));
260 if (!colors) {
261 wwarning("out of memory while parsing texture");
262 goto error;
264 memset(colors, 0, sizeof(RColor*)*(count-1));
266 for (i = 2; i < count; i++) {
267 val = PLGetArrayElement(texarray, i);
268 if (!PLIsString(val)) {
269 wwarning("could not parse texture %s", text);
271 for (j = 0; colors[j]!=NULL; j++)
272 free(colors[j]);
273 free(colors);
274 goto error;
276 tmp = PLGetString(val);
278 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
279 wwarning("could not parse color %s in texture %s",
280 tmp, text);
282 for (j = 0; colors[j]!=NULL; j++)
283 free(colors[j]);
284 free(colors);
285 goto error;
287 if (!(colors[i-2] = malloc(sizeof(RColor)))) {
288 wwarning("out of memory while parsing texture");
290 for (j = 0; colors[j]!=NULL; j++)
291 free(colors[j]);
292 free(colors);
293 goto error;
296 colors[i-2]->red = color.red >> 8;
297 colors[i-2]->green = color.green >> 8;
298 colors[i-2]->blue = color.blue >> 8;
301 switch (type[1]) {
302 case 'h':
303 case 'H':
304 gtype = RHorizontalGradient;
305 iwidth = scrWidth;
306 iheight = 8;
307 break;
308 case 'V':
309 case 'v':
310 gtype = RVerticalGradient;
311 iwidth = 8;
312 iheight = scrHeight;
313 break;
314 default:
315 gtype = RDiagonalGradient;
316 iwidth = scrWidth;
317 iheight = scrHeight;
318 break;
321 image = RRenderMultiGradient(iwidth, iheight, colors, gtype);
323 for (j = 0; colors[j]!=NULL; j++)
324 free(colors[j]);
325 free(colors);
327 if (!image) {
328 wwarning("could not render gradient texture:%s",
329 RMessageForError(RErrorCode));
330 goto error;
333 if (!RConvertImage(rc, image, &pixmap)) {
334 wwarning("could not convert texture:%s",
335 RMessageForError(RErrorCode));
336 RDestroyImage(image);
337 goto error;
340 texture->width = image->width;
341 texture->height = image->height;
342 RDestroyImage(image);
344 texture->pixmap = pixmap;
345 } else if (strcasecmp(type, "cpixmap")==0
346 || strcasecmp(type, "spixmap")==0
347 || strcasecmp(type, "mpixmap")==0
348 || strcasecmp(type, "tpixmap")==0) {
349 XColor color;
350 Pixmap pixmap = None;
351 RImage *image = NULL;
352 int w, h;
353 int iwidth, iheight;
355 GETSTRORGOTO(val, tmp, 1, error);
357 if (toupper(type[0]) == 'T' || toupper(type[0]) == 'C')
358 pixmap = LoadJPEG(rc, tmp, &iwidth, &iheight);
361 if (!pixmap) {
362 image = loadImage(rc, tmp);
363 if (!image) {
364 goto error;
366 iwidth = image->width;
367 iheight = image->height;
370 GETSTRORGOTO(val, tmp, 2, error);
372 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
373 wwarning("could not parse color %s in texture %s\n", tmp, text);
374 RDestroyImage(image);
375 goto error;
377 if (!XAllocColor(dpy, DefaultColormap(dpy, scr), &color)) {
378 RColor rcolor;
380 rcolor.red = color.red >> 8;
381 rcolor.green = color.green >> 8;
382 rcolor.blue = color.blue >> 8;
383 RGetClosestXColor(rc, &rcolor, &color);
385 switch (toupper(type[0])) {
386 case 'T':
387 texture->width = iwidth;
388 texture->height = iheight;
389 if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
390 wwarning("could not convert texture:%s",
391 RMessageForError(RErrorCode));
392 RDestroyImage(image);
393 goto error;
395 if (image)
396 RDestroyImage(image);
397 break;
398 case 'S':
399 case 'M':
400 if (toupper(type[0])=='S') {
401 w = scrWidth;
402 h = scrHeight;
403 } else {
404 if (iwidth*scrHeight > iheight*scrWidth) {
405 w = scrWidth;
406 h = (scrWidth*iheight)/iwidth;
407 } else {
408 h = scrHeight;
409 w = (scrHeight*iwidth)/iheight;
413 RImage *simage;
415 if (smooth)
416 simage = RSmoothScaleImage(image, w, h);
417 else
418 simage = RScaleImage(image, w, h);
419 if (!simage) {
420 wwarning("could not scale image:%s",
421 RMessageForError(RErrorCode));
422 RDestroyImage(image);
423 goto error;
425 RDestroyImage(image);
426 image = simage;
427 iwidth = image->width;
428 iheight = image->height;
430 /* fall through */
431 case 'C':
433 Pixmap cpixmap;
435 if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
436 wwarning("could not convert texture:%s",
437 RMessageForError(RErrorCode));
438 RDestroyImage(image);
439 goto error;
442 if (iwidth != scrWidth || iheight != scrHeight) {
443 int x, y, sx, sy, w, h;
445 cpixmap = XCreatePixmap(dpy, root, scrWidth, scrHeight,
446 DefaultDepth(dpy, scr));
448 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
449 XFillRectangle(dpy, cpixmap, DefaultGC(dpy, scr),
450 0, 0, scrWidth, scrHeight);
452 if (iheight < scrHeight) {
453 h = iheight;
454 y = (scrHeight - h)/2;
455 sy = 0;
456 } else {
457 sy = (iheight - scrHeight)/2;
458 y = 0;
459 h = scrHeight;
461 if (iwidth < scrWidth) {
462 w = iwidth;
463 x = (scrWidth - w)/2;
464 sx = 0;
465 } else {
466 sx = (iwidth - scrWidth)/2;
467 x = 0;
468 w = scrWidth;
471 XCopyArea(dpy, pixmap, cpixmap, DefaultGC(dpy, scr),
472 sx, sy, w, h, x, y);
473 XFreePixmap(dpy, pixmap);
474 pixmap = cpixmap;
476 if (image)
477 RDestroyImage(image);
479 texture->width = scrWidth;
480 texture->height = scrHeight;
482 break;
485 texture->pixmap = pixmap;
486 texture->color = color;
487 } else if (strcasecmp(type, "thgradient")==0
488 || strcasecmp(type, "tvgradient")==0
489 || strcasecmp(type, "tdgradient")==0) {
490 XColor color;
491 RColor color1, color2;
492 RImage *image;
493 RImage *gradient;
494 RImage *tiled;
495 Pixmap pixmap;
496 int opaq;
497 char *file;
498 int gtype;
499 int twidth, theight;
501 GETSTRORGOTO(val, file, 1, error);
503 GETSTRORGOTO(val, tmp, 2, error);
505 opaq = atoi(tmp);
507 GETSTRORGOTO(val, tmp, 3, error);
509 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
510 wwarning("could not parse color %s in texture %s", tmp, text);
511 goto error;
514 color1.red = color.red >> 8;
515 color1.green = color.green >> 8;
516 color1.blue = color.blue >> 8;
518 GETSTRORGOTO(val, tmp, 4, error);
520 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
521 wwarning("could not parse color %s in texture %s", tmp, text);
522 goto error;
525 color2.red = color.red >> 8;
526 color2.green = color.green >> 8;
527 color2.blue = color.blue >> 8;
529 image = loadImage(rc, file);
530 if (!image) {
531 RDestroyImage(gradient);
532 goto error;
535 switch (type[1]) {
536 case 'h':
537 case 'H':
538 gtype = RHorizontalGradient;
539 twidth = scrWidth;
540 theight = image->height > scrHeight ? scrHeight : image->height;
541 break;
542 case 'V':
543 case 'v':
544 gtype = RVerticalGradient;
545 twidth = image->width > scrWidth ? scrWidth : image->width;
546 theight = scrHeight;
547 break;
548 default:
549 gtype = RDiagonalGradient;
550 twidth = scrWidth;
551 theight = scrHeight;
552 break;
554 gradient = RRenderGradient(twidth, theight, &color1, &color2, gtype);
556 if (!gradient) {
557 wwarning("could not render texture:%s",
558 RMessageForError(RErrorCode));
559 RDestroyImage(gradient);
560 goto error;
563 tiled = RMakeTiledImage(image, twidth, theight);
564 if (!tiled) {
565 wwarning("could not render texture:%s",
566 RMessageForError(RErrorCode));
567 RDestroyImage(gradient);
568 RDestroyImage(image);
569 goto error;
571 RDestroyImage(image);
573 RCombineImagesWithOpaqueness(tiled, gradient, opaq);
574 RDestroyImage(gradient);
576 if (!RConvertImage(rc, tiled, &pixmap)) {
577 wwarning("could not convert texture:%s",
578 RMessageForError(RErrorCode));
579 RDestroyImage(image);
580 goto error;
582 texture->width = tiled->width;
583 texture->height = tiled->height;
585 RDestroyImage(tiled);
587 texture->pixmap = pixmap;
588 } else if (strcasecmp(type, "function")==0) {
589 #ifdef HAVE_DLFCN_H
590 void (*initFunc) (Display*, Colormap);
591 RImage* (*mainFunc) (int, char**, int, int, int);
592 Pixmap pixmap;
593 RImage *image = 0;
594 int success = 0;
595 char *lib, *func, **argv = 0;
596 void *handle = 0;
597 int i, argc;
599 if (count < 3)
600 goto function_cleanup;
602 /* get the library name */
603 GETSTRORGOTO(val, lib, 1, function_cleanup);
605 /* get the function name */
606 GETSTRORGOTO(val, func, 2, function_cleanup);
608 argc = count - 2;
609 argv = (char**)wmalloc(argc * sizeof(char*));
611 /* get the parameters */
612 argv[0] = func;
613 for (i=0; i<argc-1; i++) {
614 GETSTRORGOTO(val, tmp, 3+i, function_cleanup);
615 argv[i+1] = wstrdup(tmp);
618 handle = dlopen(lib, RTLD_LAZY);
619 if (!handle) {
620 wwarning("could not find library %s", lib);
621 goto function_cleanup;
624 initFunc = dlsym(handle, "initWindowMaker");
625 if (!initFunc) {
626 wwarning("could not initialize library %s", lib);
627 goto function_cleanup;
629 initFunc(dpy, DefaultColormap(dpy, scr));
631 mainFunc = dlsym(handle, func);
632 if (!mainFunc) {
633 wwarning("could not find function %s::%s", lib, func);
634 goto function_cleanup;
636 image = mainFunc(argc, argv, scrWidth, scrHeight, 0);
638 if (!RConvertImage(rc, image, &pixmap)) {
639 wwarning("could not convert texture:%s",
640 RMessageForError(RErrorCode));
641 goto function_cleanup;
643 texture->width = scrWidth;
644 texture->height = scrHeight;
645 texture->pixmap = pixmap;
646 success = 1;
648 function_cleanup:
649 if (argv) {
650 int i;
651 for (i=0; i<argc; i++) {
652 free(argv[i]);
655 if (handle) {
656 dlclose(handle);
658 if (image) {
659 RDestroyImage(image);
661 if (!success) {
662 goto error;
664 #else
665 wwarning("function textures not supported");
666 goto error;
667 #endif
668 } else {
669 wwarning("invalid texture type %s", text);
670 goto error;
673 texture->spec = wstrdup(text);
675 return texture;
677 error:
678 if (texture)
679 free(texture);
680 if (texarray)
681 PLRelease(texarray);
683 return NULL;
687 void
688 freeTexture(BackgroundTexture *texture)
690 if (texture->solid) {
691 long pixel[1];
693 pixel[0] = texture->color.pixel;
694 /* dont free black/white pixels */
695 if (pixel[0]!=BlackPixelOfScreen(DefaultScreenOfDisplay(dpy))
696 && pixel[0]!=WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
697 XFreeColors(dpy, DefaultColormap(dpy, scr), pixel, 1, 0);
699 if (texture->pixmap) {
700 XFreePixmap(dpy, texture->pixmap);
702 free(texture->spec);
703 free(texture);
707 void
708 setupTexture(RContext *rc, BackgroundTexture **textures, int *maxTextures,
709 int workspace, char *texture)
711 BackgroundTexture *newTexture = NULL;
712 int i;
714 /* unset the texture */
715 if (!texture) {
716 if (textures[workspace]!=NULL) {
717 textures[workspace]->refcount--;
719 if (textures[workspace]->refcount == 0)
720 freeTexture(textures[workspace]);
722 textures[workspace] = NULL;
723 return;
726 if (textures[workspace]
727 && strcasecmp(textures[workspace]->spec, texture)==0) {
728 /* texture did not change */
729 return;
732 /* check if the same texture is already created */
733 for (i = 0; i < *maxTextures; i++) {
734 if (textures[i] && strcasecmp(textures[i]->spec, texture)==0) {
735 newTexture = textures[i];
736 break;
740 if (!newTexture) {
741 /* create the texture */
742 newTexture = parseTexture(rc, texture);
744 if (!newTexture)
745 return;
747 if (textures[workspace]!=NULL) {
749 textures[workspace]->refcount--;
751 if (textures[workspace]->refcount == 0)
752 freeTexture(textures[workspace]);
755 newTexture->refcount++;
756 textures[workspace] = newTexture;
758 if (*maxTextures < workspace)
759 *maxTextures = workspace;
764 Pixmap
765 duplicatePixmap(Pixmap pixmap, int width, int height)
767 Display *tmpDpy;
768 Pixmap copyP;
770 /* must open a new display or the RetainPermanent will
771 * leave stuff allocated in RContext unallocated after exit */
772 tmpDpy = XOpenDisplay(display);
773 if (!tmpDpy) {
774 wwarning("could not open display to update background image information");
776 return None;
777 } else {
778 XSync(dpy, False);
780 copyP = XCreatePixmap(tmpDpy, root, width, height,
781 DefaultDepth(tmpDpy, scr));
782 XCopyArea(tmpDpy, pixmap, copyP, DefaultGC(tmpDpy, scr),
783 0, 0, width, height, 0, 0);
784 XSync(tmpDpy, False);
786 XSetCloseDownMode(tmpDpy, RetainPermanent);
787 XCloseDisplay(tmpDpy);
790 return copyP;
794 static int
795 dummyErrorHandler(Display *dpy, XErrorEvent *err)
797 return 0;
800 void
801 setPixmapProperty(Pixmap pixmap)
803 static Atom prop = 0;
804 Atom type;
805 int format;
806 unsigned long length, after;
807 unsigned char *data;
808 int mode;
810 if (!prop) {
811 prop = XInternAtom(dpy, "_XROOTPMAP_ID", False);
814 XGrabServer(dpy);
816 /* Clear out the old pixmap */
817 XGetWindowProperty(dpy, root, prop, 0L, 1L, False, AnyPropertyType,
818 &type, &format, &length, &after, &data);
820 if ((type == XA_PIXMAP) && (format == 32) && (length == 1)) {
821 XSetErrorHandler(dummyErrorHandler);
822 XKillClient(dpy, *((Pixmap *)data));
823 XSync(dpy, False);
824 XSetErrorHandler(NULL);
825 mode = PropModeReplace;
826 } else {
827 mode = PropModeAppend;
829 if (pixmap)
830 XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, mode,
831 (unsigned char *) &pixmap, 1);
832 else
833 XDeleteProperty(dpy, root, prop);
836 XUngrabServer(dpy);
837 XFlush(dpy);
842 void
843 changeTexture(BackgroundTexture *texture)
845 if (!texture)
846 return;
848 if (texture->solid) {
849 XSetWindowBackground(dpy, root, texture->color.pixel);
850 } else {
851 XSetWindowBackgroundPixmap(dpy, root, texture->pixmap);
853 XClearWindow(dpy, root);
855 XSync(dpy, False);
858 Pixmap pixmap;
860 pixmap = duplicatePixmap(texture->pixmap, texture->width,
861 texture->height);
863 setPixmapProperty(pixmap);
869 readmsg(int fd, unsigned char *buffer, int size)
871 int count;
873 count = 0;
874 while (size>0) {
875 count = read(fd, buffer, size);
876 if (count < 0)
877 return -1;
878 size -= count;
879 buffer += count;
880 *buffer = 0;
883 return size;
888 * Message Format:
889 * sizeSntexture_spec - sets the texture for workspace n
890 * sizeCn - change background texture to the one for workspace n
891 * sizePpath - set the pixmap search path
893 * n is 4 bytes
894 * size = 4 bytes for length of the message data
896 void
897 helperLoop(RContext *rc)
899 BackgroundTexture *textures[WORKSPACE_COUNT];
900 int maxTextures = 0;
901 unsigned char buffer[2048], buf[8];
902 int size;
903 int errcount = 4;
905 memset(textures, 0, WORKSPACE_COUNT*sizeof(BackgroundTexture*));
908 while (1) {
909 int workspace;
911 /* get length of message */
912 if (readmsg(0, buffer, 4) < 0) {
913 wsyserror("error reading message from Window Maker");
914 errcount--;
915 if (errcount == 0) {
916 wfatal("quitting");
917 exit(1);
919 continue;
921 memcpy(buf, buffer, 4);
922 buf[4] = 0;
923 size = atoi(buf);
925 /* get message */
926 if (readmsg(0, buffer, size) < 0) {
927 wsyserror("error reading message from Window Maker");
928 errcount--;
929 if (errcount == 0) {
930 wfatal("quitting");
931 exit(1);
933 continue;
935 #ifdef DEBUG
936 printf("RECEIVED %s\n",buffer);
937 #endif
938 if (buffer[0]!='P' && buffer[0]!='K') {
939 memcpy(buf, &buffer[1], 4);
940 buf[4] = 0;
941 workspace = atoi(buf);
942 if (workspace < 0 || workspace >= WORKSPACE_COUNT) {
943 wwarning("received message with invalid workspace number %i\n",
944 workspace);
945 continue;
949 switch (buffer[0]) {
950 case 'S':
951 #ifdef DEBUG
952 printf("set texture %s\n", &buffer[5]);
953 #endif
954 setupTexture(rc, textures, &maxTextures, workspace, &buffer[5]);
955 break;
957 case 'C':
958 #ifdef DEBUG
959 printf("change texture %i\n", workspace);
960 #endif
961 if (!textures[workspace])
962 changeTexture(textures[0]);
963 else
964 changeTexture(textures[workspace]);
965 break;
967 case 'P':
968 #ifdef DEBUG
969 printf("change pixmappath %s\n", &buffer[1]);
970 #endif
971 if (PixmapPath)
972 free(PixmapPath);
973 PixmapPath = wstrdup(&buffer[1]);
974 break;
976 case 'U':
977 #ifdef DEBUG
978 printf("unset workspace %i\n", workspace);
979 #endif
980 setupTexture(rc, textures, &maxTextures, workspace, NULL);
981 break;
983 case 'K':
984 #ifdef DEBUG
985 printf("exit command\n");
986 #endif
987 exit(0);
989 default:
990 wwarning("unknown message received");
991 break;
997 void
998 updateDomain(char *domain, char *key, char *texture)
1000 char *program = "wdwrite";
1002 execlp(program, program, domain, key, texture, NULL);
1003 wwarning("warning could not run \"%s\"", program);
1008 char*
1009 globalDefaultsPathForDomain(char *domain)
1011 char path[1024];
1013 sprintf(path, "%s/%s", SYSCONFDIR, domain);
1015 return wstrdup(path);
1019 proplist_t
1020 getValueForKey(char *domain, char *keyName)
1022 char *path;
1023 proplist_t key;
1024 proplist_t d;
1025 proplist_t val;
1027 key = PLMakeString(keyName);
1029 /* try to find PixmapPath in user defaults */
1030 path = wdefaultspathfordomain(domain);
1031 d = PLGetProplistWithPath(path);
1032 if (!d) {
1033 wwarning("could not open domain file %s", path);
1035 free(path);
1037 if (d && !PLIsDictionary(d)) {
1038 PLRelease(d);
1039 d = NULL;
1041 if (d) {
1042 val = PLGetDictionaryEntry(d, key);
1043 } else {
1044 val = NULL;
1046 /* try to find PixmapPath in global defaults */
1047 if (!val) {
1048 path = globalDefaultsPathForDomain(domain);
1049 if (!path) {
1050 wwarning("could not locate file for domain %s", domain);
1051 d = NULL;
1052 } else {
1053 d = PLGetProplistWithPath(path);
1054 free(path);
1057 if (d && !PLIsDictionary(d)) {
1058 PLRelease(d);
1059 d = NULL;
1061 if (d) {
1062 val = PLGetDictionaryEntry(d, key);
1064 } else {
1065 val = NULL;
1069 if (val)
1070 PLRetain(val);
1072 PLRelease(key);
1073 if (d)
1074 PLRelease(d);
1076 return val;
1081 char*
1082 getPixmapPath(char *domain)
1084 proplist_t val;
1085 char *ptr, *data;
1086 int len, i, count;
1088 val = getValueForKey(domain, "PixmapPath");
1090 if (!val || !PLIsArray(val)) {
1091 if (val)
1092 PLRelease(val);
1093 return wstrdup("");
1096 count = PLGetNumberOfElements(val);
1097 len = 0;
1098 for (i=0; i<count; i++) {
1099 proplist_t v;
1101 v = PLGetArrayElement(val, i);
1102 if (!v || !PLIsString(v)) {
1103 continue;
1105 len += strlen(PLGetString(v))+1;
1108 ptr = data = wmalloc(len+1);
1109 *ptr = 0;
1111 for (i=0; i<count; i++) {
1112 proplist_t v;
1114 v = PLGetArrayElement(val, i);
1115 if (!v || !PLIsString(v)) {
1116 continue;
1118 strcpy(ptr, PLGetString(v));
1120 ptr += strlen(PLGetString(v));
1121 *ptr = ':';
1122 ptr++;
1124 if (i>0)
1125 ptr--; *(ptr--) = 0;
1127 PLRelease(val);
1129 return data;
1133 void
1134 wAbort()
1136 wfatal("aborting");
1137 exit(1);
1142 void
1143 print_help(char *ProgName)
1145 printf("Usage: %s [options] [image]\n", ProgName);
1146 puts("Sets the workspace background to the specified image or a texture and optionally update Window Maker configuration");
1147 puts("");
1148 #define P(m) puts(m)
1149 P(" -display display to use");
1150 P(" -d, --dither dither image");
1151 P(" -m, --match match colors");
1152 P(" -S, --smooth smooth scaled image");
1153 P(" -b, --back-color <color> background color");
1154 P(" -t, --tile tile image");
1155 P(" -e, --center center image");
1156 P(" -s, --scale scale image (default)");
1157 P(" -a, --maxscale scale image and keep aspect ratio");
1158 P(" -u, --update-wmaker update WindowMaker domain database");
1159 P(" -D, --update-domain <domain> update <domain> database");
1160 P(" -c, --colors <cpc> colors per channel to use");
1161 P(" -p, --parse <texture> proplist style texture specification");
1162 P(" -w, --workspace <workspace> update background for the specified workspace");
1163 P(" --version show version of wmsetbg and exit");
1164 P(" --help show this help and exit");
1165 #undef P
1170 void
1171 changeTextureForWorkspace(char *domain, char *texture, int workspace)
1173 proplist_t array;
1174 proplist_t val;
1175 char *value;
1176 int j;
1178 val = PLGetProplistWithDescription(texture);
1179 if (!val) {
1180 wwarning("could not parse texture %s", texture);
1181 return;
1184 array = getValueForKey("WindowMaker", "WorkspaceSpecificBack");
1186 if (!array) {
1187 array = PLMakeArrayFromElements(NULL, NULL);
1190 j = PLGetNumberOfElements(array);
1191 if (workspace >= j) {
1192 proplist_t empty;
1194 empty = PLMakeArrayFromElements(NULL, NULL);
1196 while (j++ < workspace-1) {
1197 PLAppendArrayElement(array, empty);
1199 PLAppendArrayElement(array, val);
1200 } else {
1201 PLRemoveArrayElement(array, workspace);
1202 PLInsertArrayElement(array, val, workspace);
1205 value = PLGetDescription(array);
1206 updateDomain(domain, "WorkspaceSpecificBack", value);
1211 main(int argc, char **argv)
1213 int i;
1214 int helperMode = 0;
1215 RContext *rc;
1216 RContextAttributes rattr;
1217 char *style = "spixmap";
1218 char *back_color = "gray20";
1219 char *image_name = NULL;
1220 char *domain = "WindowMaker";
1221 int update=0, cpc=4, render_mode=RDitheredRendering, obey_user=0;
1222 char *texture = NULL;
1223 int workspace = -1;
1225 signal(SIGINT, SIG_DFL);
1226 signal(SIGTERM, SIG_DFL);
1227 signal(SIGQUIT, SIG_DFL);
1228 signal(SIGSEGV, SIG_DFL);
1229 signal(SIGBUS, SIG_DFL);
1230 signal(SIGFPE, SIG_DFL);
1231 signal(SIGABRT, SIG_DFL);
1232 signal(SIGHUP, SIG_DFL);
1233 signal(SIGPIPE, SIG_DFL);
1234 signal(SIGCHLD, SIG_DFL);
1236 WMInitializeApplication("wmsetbg", &argc, argv);
1238 for (i=1; i<argc; i++) {
1239 if (strcmp(argv[i], "-helper")==0) {
1240 helperMode = 1;
1241 } else if (strcmp(argv[i], "-display")==0) {
1242 i++;
1243 if (i>=argc) {
1244 wfatal("too few arguments for %s\n", argv[i-1]);
1245 exit(1);
1247 display = argv[i];
1248 } else if (strcmp(argv[i], "-s")==0
1249 || strcmp(argv[i], "--scale")==0) {
1250 style = "spixmap";
1251 } else if (strcmp(argv[i], "-t")==0
1252 || strcmp(argv[i], "--tile")==0) {
1253 style = "tpixmap";
1254 } else if (strcmp(argv[i], "-e")==0
1255 || strcmp(argv[i], "--center")==0) {
1256 style = "cpixmap";
1257 } else if (strcmp(argv[i], "-a")==0
1258 || strcmp(argv[i], "--maxscale")==0) {
1259 style = "mpixmap";
1260 } else if (strcmp(argv[i], "-d")==0
1261 || strcmp(argv[i], "--dither")==0) {
1262 render_mode = RDitheredRendering;
1263 obey_user++;
1264 } else if (strcmp(argv[i], "-m")==0
1265 || strcmp(argv[i], "--match")==0) {
1266 render_mode = RBestMatchRendering;
1267 obey_user++;
1268 } else if (strcmp(argv[i], "-S")==0
1269 || strcmp(argv[i], "--smooth")==0) {
1270 smooth = True;
1271 } else if (strcmp(argv[i], "-u")==0
1272 || strcmp(argv[i], "--update-wmaker")==0) {
1273 update++;
1274 } else if (strcmp(argv[i], "-D")==0
1275 || strcmp(argv[i], "--update-domain")==0) {
1276 update++;
1277 i++;
1278 if (i>=argc) {
1279 wfatal("too few arguments for %s\n", argv[i-1]);
1280 exit(1);
1282 domain = wstrdup(argv[i]);
1283 } else if (strcmp(argv[i], "-c")==0
1284 || strcmp(argv[i], "--colors")==0) {
1285 i++;
1286 if (i>=argc) {
1287 wfatal("too few arguments for %s\n", argv[i-1]);
1288 exit(1);
1290 if (sscanf(argv[i], "%i", &cpc)!=1) {
1291 wfatal("bad value for colors per channel: \"%s\"\n", argv[i]);
1292 exit(1);
1294 } else if (strcmp(argv[i], "-b")==0
1295 || strcmp(argv[i], "--back-color")==0) {
1296 i++;
1297 if (i>=argc) {
1298 wfatal("too few arguments for %s\n", argv[i-1]);
1299 exit(1);
1301 back_color = argv[i];
1302 } else if (strcmp(argv[i], "-p")==0
1303 || strcmp(argv[i], "--parse")==0) {
1304 i++;
1305 if (i>=argc) {
1306 wfatal("too few arguments for %s\n", argv[i-1]);
1307 exit(1);
1309 texture = argv[i];
1310 } else if (strcmp(argv[i], "-w")==0
1311 || strcmp(argv[i], "--workspace")==0) {
1312 i++;
1313 if (i>=argc) {
1314 wfatal("too few arguments for %s\n", argv[i-1]);
1315 exit(1);
1317 if (sscanf(argv[i], "%i", &workspace)!=1) {
1318 wfatal("bad value for workspace number: \"%s\"",
1319 argv[i]);
1320 exit(1);
1322 } else if (strcmp(argv[i], "--version")==0) {
1324 printf(PROG_VERSION);
1325 exit(0);
1327 } else if (strcmp(argv[i], "--help")==0) {
1328 print_help(argv[0]);
1329 exit(0);
1330 } else if (argv[i][0] != '-') {
1331 image_name = argv[i];
1332 } else {
1333 printf("%s: invalid argument '%s'\n", argv[0], argv[i]);
1334 printf("Try '%s --help' for more information\n", argv[0]);
1335 exit(1);
1338 if (!image_name && !texture && !helperMode) {
1339 printf("%s: you must specify a image file name or a texture\n",
1340 argv[0]);
1341 printf("Try '%s --help' for more information\n", argv[0]);
1342 exit(1);
1346 PixmapPath = getPixmapPath(domain);
1348 dpy = XOpenDisplay(display);
1349 if (!dpy) {
1350 wfatal("could not open display");
1351 exit(1);
1353 #if 0
1354 XSynchronize(dpy, 1);
1355 #endif
1357 root = DefaultRootWindow(dpy);
1359 scr = DefaultScreen(dpy);
1361 scrWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
1362 scrHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
1364 if (!obey_user && DefaultDepth(dpy, scr) <= 8)
1365 render_mode = RDitheredRendering;
1367 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_DefaultVisual;
1368 rattr.render_mode = render_mode;
1369 rattr.colors_per_channel = cpc;
1371 rc = RCreateContext(dpy, scr, &rattr);
1373 if (helperMode) {
1374 /* lower priority, so that it wont use all the CPU */
1375 nice(1000);
1377 helperLoop(rc);
1378 } else {
1379 BackgroundTexture *tex;
1380 char buffer[4098];
1382 if (!texture) {
1383 sprintf(buffer, "(%s, \"%s\", %s)", style, image_name, back_color);
1384 texture = (char*)buffer;
1387 if (update && workspace < 0) {
1388 updateDomain(domain, "WorkspaceBack", texture);
1391 tex = parseTexture(rc, texture);
1392 if (!tex)
1393 exit(1);
1395 if (workspace<0)
1396 changeTexture(tex);
1397 else {
1398 /* always update domain */
1399 changeTextureForWorkspace(domain, texture, workspace-1);
1403 return 0;