applied hadess patch for gnome panel
[wmaker-crm.git] / util / wmsetbg.c
blob8cd202f1629df3e8a4701bc97329845b83b24a9a
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.h>
50 #include <wraster.h>
52 #include <proplist.h>
54 #define PROG_VERSION "wmsetbg (Window Maker) 2.7"
57 #define WORKSPACE_COUNT (MAX_WORKSPACES+1)
60 Display *dpy;
61 char *display = "";
62 Window root;
63 int scr;
64 int scrWidth;
65 int scrHeight;
68 Bool smooth = False;
71 Pixmap CurrentPixmap = None;
72 char *PixmapPath = NULL;
75 extern Pixmap LoadJPEG(RContext *rc, char *file_name, int *width, int *height);
78 typedef struct BackgroundTexture {
79 int refcount;
81 int solid;
83 char *spec;
85 XColor color;
86 Pixmap pixmap; /* for all textures, including solid */
87 int width; /* size of the pixmap */
88 int height;
89 } BackgroundTexture;
93 RImage*
94 loadImage(RContext *rc, char *file)
96 char *path;
97 RImage *image;
99 if (access(file, F_OK)!=0) {
100 path = wfindfile(PixmapPath, file);
101 if (!path) {
102 wwarning("%s:could not find image file used in texture", file);
103 return NULL;
105 } else {
106 path = wstrdup(file);
109 image = RLoadImage(rc, path, 0);
110 if (!image) {
111 wwarning("%s:could not load image file used in texture:%s", path,
112 RMessageForError(RErrorCode));
114 wfree(path);
116 return image;
120 BackgroundTexture*
121 parseTexture(RContext *rc, char *text)
123 BackgroundTexture *texture = NULL;
124 proplist_t texarray;
125 proplist_t val;
126 int count;
127 char *tmp;
128 char *type;
130 #define GETSTRORGOTO(val, str, i, label) \
131 val = PLGetArrayElement(texarray, i);\
132 if (!PLIsString(val)) {\
133 wwarning("could not parse texture %s", text);\
134 goto label;\
136 str = PLGetString(val)
138 texarray = PLGetProplistWithDescription(text);
139 if (!texarray || !PLIsArray(texarray)
140 || (count = PLGetNumberOfElements(texarray)) < 2) {
142 wwarning("could not parse texture %s", text);
143 if (texarray)
144 PLRelease(texarray);
145 return NULL;
148 texture = wmalloc(sizeof(BackgroundTexture));
149 memset(texture, 0, sizeof(BackgroundTexture));
151 GETSTRORGOTO(val, type, 0, error);
153 if (strcasecmp(type, "solid")==0) {
154 XColor color;
155 Pixmap pixmap;
157 texture->solid = 1;
159 GETSTRORGOTO(val, tmp, 1, error);
161 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
162 wwarning("could not parse color %s in texture %s", tmp, text);
163 goto error;
165 XAllocColor(dpy, DefaultColormap(dpy, scr), &color);
167 pixmap = XCreatePixmap(dpy, root, 8, 8, DefaultDepth(dpy, scr));
168 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
169 XFillRectangle(dpy, pixmap, DefaultGC(dpy, scr), 0, 0, 8, 8);
171 texture->pixmap = pixmap;
172 texture->color = color;
173 texture->width = 8;
174 texture->height = 8;
175 } else if (strcasecmp(type, "vgradient")==0
176 || strcasecmp(type, "dgradient")==0
177 || strcasecmp(type, "hgradient")==0) {
178 XColor color;
179 RColor color1, color2;
180 RImage *image;
181 Pixmap pixmap;
182 int gtype;
183 int iwidth, iheight;
185 GETSTRORGOTO(val, tmp, 1, error);
187 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
188 wwarning("could not parse color %s in texture %s", tmp, text);
189 goto error;
192 color1.red = color.red >> 8;
193 color1.green = color.green >> 8;
194 color1.blue = color.blue >> 8;
196 GETSTRORGOTO(val, tmp, 2, error);
198 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
199 wwarning("could not parse color %s in texture %s", tmp, text);
200 goto error;
203 color2.red = color.red >> 8;
204 color2.green = color.green >> 8;
205 color2.blue = color.blue >> 8;
207 switch (type[0]) {
208 case 'h':
209 case 'H':
210 gtype = RHorizontalGradient;
211 iwidth = scrWidth;
212 iheight = 32;
213 break;
214 case 'V':
215 case 'v':
216 gtype = RVerticalGradient;
217 iwidth = 32;
218 iheight = scrHeight;
219 break;
220 default:
221 gtype = RDiagonalGradient;
222 iwidth = scrWidth;
223 iheight = scrHeight;
224 break;
227 image = RRenderGradient(iwidth, iheight, &color1, &color2, gtype);
229 if (!image) {
230 wwarning("could not render gradient texture:%s",
231 RMessageForError(RErrorCode));
232 goto error;
235 if (!RConvertImage(rc, image, &pixmap)) {
236 wwarning("could not convert texture:%s",
237 RMessageForError(RErrorCode));
238 RDestroyImage(image);
239 goto error;
242 texture->width = image->width;
243 texture->height = image->height;
244 RDestroyImage(image);
246 texture->pixmap = pixmap;
247 } else if (strcasecmp(type, "mvgradient")==0
248 || strcasecmp(type, "mdgradient")==0
249 || strcasecmp(type, "mhgradient")==0) {
250 XColor color;
251 RColor **colors;
252 RImage *image;
253 Pixmap pixmap;
254 int i, j;
255 int gtype;
256 int iwidth, iheight;
258 colors = malloc(sizeof(RColor*)*(count-1));
259 if (!colors) {
260 wwarning("out of memory while parsing texture");
261 goto error;
263 memset(colors, 0, sizeof(RColor*)*(count-1));
265 for (i = 2; i < count; i++) {
266 val = PLGetArrayElement(texarray, i);
267 if (!PLIsString(val)) {
268 wwarning("could not parse texture %s", text);
270 for (j = 0; colors[j]!=NULL; j++)
271 wfree(colors[j]);
272 wfree(colors);
273 goto error;
275 tmp = PLGetString(val);
277 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
278 wwarning("could not parse color %s in texture %s",
279 tmp, text);
281 for (j = 0; colors[j]!=NULL; j++)
282 wfree(colors[j]);
283 wfree(colors);
284 goto error;
286 if (!(colors[i-2] = malloc(sizeof(RColor)))) {
287 wwarning("out of memory while parsing texture");
289 for (j = 0; colors[j]!=NULL; j++)
290 wfree(colors[j]);
291 wfree(colors);
292 goto error;
295 colors[i-2]->red = color.red >> 8;
296 colors[i-2]->green = color.green >> 8;
297 colors[i-2]->blue = color.blue >> 8;
300 switch (type[1]) {
301 case 'h':
302 case 'H':
303 gtype = RHorizontalGradient;
304 iwidth = scrWidth;
305 iheight = 32;
306 break;
307 case 'V':
308 case 'v':
309 gtype = RVerticalGradient;
310 iwidth = 32;
311 iheight = scrHeight;
312 break;
313 default:
314 gtype = RDiagonalGradient;
315 iwidth = scrWidth;
316 iheight = scrHeight;
317 break;
320 image = RRenderMultiGradient(iwidth, iheight, colors, gtype);
322 for (j = 0; colors[j]!=NULL; j++)
323 wfree(colors[j]);
324 wfree(colors);
326 if (!image) {
327 wwarning("could not render gradient texture:%s",
328 RMessageForError(RErrorCode));
329 goto error;
332 if (!RConvertImage(rc, image, &pixmap)) {
333 wwarning("could not convert texture:%s",
334 RMessageForError(RErrorCode));
335 RDestroyImage(image);
336 goto error;
339 texture->width = image->width;
340 texture->height = image->height;
341 RDestroyImage(image);
343 texture->pixmap = pixmap;
344 } else if (strcasecmp(type, "cpixmap")==0
345 || strcasecmp(type, "spixmap")==0
346 || strcasecmp(type, "mpixmap")==0
347 || strcasecmp(type, "tpixmap")==0) {
348 XColor color;
349 Pixmap pixmap = None;
350 RImage *image = NULL;
351 int w, h;
352 int iwidth, iheight;
353 RColor rcolor;
356 GETSTRORGOTO(val, tmp, 1, error);
358 if (toupper(type[0]) == 'T' || toupper(type[0]) == 'C')
359 pixmap = LoadJPEG(rc, tmp, &iwidth, &iheight);
362 if (!pixmap) {
363 image = loadImage(rc, tmp);
364 if (!image) {
365 goto error;
367 iwidth = image->width;
368 iheight = image->height;
371 GETSTRORGOTO(val, tmp, 2, error);
373 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
374 wwarning("could not parse color %s in texture %s\n", tmp, text);
375 RDestroyImage(image);
376 goto error;
378 if (!XAllocColor(dpy, DefaultColormap(dpy, scr), &color)) {
379 rcolor.red = color.red >> 8;
380 rcolor.green = color.green >> 8;
381 rcolor.blue = color.blue >> 8;
382 RGetClosestXColor(rc, &rcolor, &color);
383 } else {
384 rcolor.red = 0;
385 rcolor.green = 0;
386 rcolor.blue = 0;
388 /* for images with a transparent color */
389 if (image->data[3]) {
390 RCombineImageWithColor(image, &rcolor);
393 switch (toupper(type[0])) {
394 case 'T':
395 texture->width = iwidth;
396 texture->height = iheight;
397 if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
398 wwarning("could not convert texture:%s",
399 RMessageForError(RErrorCode));
400 RDestroyImage(image);
401 goto error;
403 if (image)
404 RDestroyImage(image);
405 break;
406 case 'S':
407 case 'M':
408 if (toupper(type[0])=='S') {
409 w = scrWidth;
410 h = scrHeight;
411 } else {
412 if (iwidth*scrHeight > iheight*scrWidth) {
413 w = scrWidth;
414 h = (scrWidth*iheight)/iwidth;
415 } else {
416 h = scrHeight;
417 w = (scrHeight*iwidth)/iheight;
420 if (w != image->width || h != image->height) {
421 RImage *simage;
423 if (smooth)
424 simage = RSmoothScaleImage(image, w, h);
425 else
426 simage = RScaleImage(image, w, h);
427 if (!simage) {
428 wwarning("could not scale image:%s",
429 RMessageForError(RErrorCode));
430 RDestroyImage(image);
431 goto error;
433 RDestroyImage(image);
434 image = simage;
436 iwidth = image->width;
437 iheight = image->height;
439 /* fall through */
440 case 'C':
442 Pixmap cpixmap;
444 if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
445 wwarning("could not convert texture:%s",
446 RMessageForError(RErrorCode));
447 RDestroyImage(image);
448 goto error;
451 if (iwidth != scrWidth || iheight != scrHeight) {
452 int x, y, sx, sy, w, h;
454 cpixmap = XCreatePixmap(dpy, root, scrWidth, scrHeight,
455 DefaultDepth(dpy, scr));
457 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
458 XFillRectangle(dpy, cpixmap, DefaultGC(dpy, scr),
459 0, 0, scrWidth, scrHeight);
461 if (iheight < scrHeight) {
462 h = iheight;
463 y = (scrHeight - h)/2;
464 sy = 0;
465 } else {
466 sy = (iheight - scrHeight)/2;
467 y = 0;
468 h = scrHeight;
470 if (iwidth < scrWidth) {
471 w = iwidth;
472 x = (scrWidth - w)/2;
473 sx = 0;
474 } else {
475 sx = (iwidth - scrWidth)/2;
476 x = 0;
477 w = scrWidth;
480 XCopyArea(dpy, pixmap, cpixmap, DefaultGC(dpy, scr),
481 sx, sy, w, h, x, y);
482 XFreePixmap(dpy, pixmap);
483 pixmap = cpixmap;
485 if (image)
486 RDestroyImage(image);
488 texture->width = scrWidth;
489 texture->height = scrHeight;
491 break;
494 texture->pixmap = pixmap;
495 texture->color = color;
496 } else if (strcasecmp(type, "thgradient")==0
497 || strcasecmp(type, "tvgradient")==0
498 || strcasecmp(type, "tdgradient")==0) {
499 XColor color;
500 RColor color1, color2;
501 RImage *image;
502 RImage *gradient;
503 RImage *tiled;
504 Pixmap pixmap;
505 int opaq;
506 char *file;
507 int gtype;
508 int twidth, theight;
510 GETSTRORGOTO(val, file, 1, error);
512 GETSTRORGOTO(val, tmp, 2, error);
514 opaq = atoi(tmp);
516 GETSTRORGOTO(val, tmp, 3, error);
518 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
519 wwarning("could not parse color %s in texture %s", tmp, text);
520 goto error;
523 color1.red = color.red >> 8;
524 color1.green = color.green >> 8;
525 color1.blue = color.blue >> 8;
527 GETSTRORGOTO(val, tmp, 4, error);
529 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
530 wwarning("could not parse color %s in texture %s", tmp, text);
531 goto error;
534 color2.red = color.red >> 8;
535 color2.green = color.green >> 8;
536 color2.blue = color.blue >> 8;
538 image = loadImage(rc, file);
539 if (!image) {
540 goto error;
543 switch (type[1]) {
544 case 'h':
545 case 'H':
546 gtype = RHorizontalGradient;
547 twidth = scrWidth;
548 theight = image->height > scrHeight ? scrHeight : image->height;
549 break;
550 case 'V':
551 case 'v':
552 gtype = RVerticalGradient;
553 twidth = image->width > scrWidth ? scrWidth : image->width;
554 theight = scrHeight;
555 break;
556 default:
557 gtype = RDiagonalGradient;
558 twidth = scrWidth;
559 theight = scrHeight;
560 break;
562 gradient = RRenderGradient(twidth, theight, &color1, &color2, gtype);
564 if (!gradient) {
565 wwarning("could not render texture:%s",
566 RMessageForError(RErrorCode));
567 RDestroyImage(gradient);
568 RDestroyImage(image);
569 goto error;
572 tiled = RMakeTiledImage(image, twidth, theight);
573 if (!tiled) {
574 wwarning("could not render texture:%s",
575 RMessageForError(RErrorCode));
576 RDestroyImage(gradient);
577 RDestroyImage(image);
578 goto error;
580 RDestroyImage(image);
582 RCombineImagesWithOpaqueness(tiled, gradient, opaq);
583 RDestroyImage(gradient);
585 if (!RConvertImage(rc, tiled, &pixmap)) {
586 wwarning("could not convert texture:%s",
587 RMessageForError(RErrorCode));
588 RDestroyImage(tiled);
589 goto error;
591 texture->width = tiled->width;
592 texture->height = tiled->height;
594 RDestroyImage(tiled);
596 texture->pixmap = pixmap;
597 } else if (strcasecmp(type, "function")==0) {
598 #ifdef HAVE_DLFCN_H
599 void (*initFunc) (Display*, Colormap);
600 RImage* (*mainFunc) (int, char**, int, int, int);
601 Pixmap pixmap;
602 RImage *image = 0;
603 int success = 0;
604 char *lib, *func, **argv = 0;
605 void *handle = 0;
606 int i, argc;
608 if (count < 3)
609 goto function_cleanup;
611 /* get the library name */
612 GETSTRORGOTO(val, lib, 1, function_cleanup);
614 /* get the function name */
615 GETSTRORGOTO(val, func, 2, function_cleanup);
617 argc = count - 2;
618 argv = (char**)wmalloc(argc * sizeof(char*));
620 /* get the parameters */
621 argv[0] = func;
622 for (i=0; i<argc-1; i++) {
623 GETSTRORGOTO(val, tmp, 3+i, function_cleanup);
624 argv[i+1] = wstrdup(tmp);
627 handle = dlopen(lib, RTLD_LAZY);
628 if (!handle) {
629 wwarning("could not find library %s", lib);
630 goto function_cleanup;
633 initFunc = dlsym(handle, "initWindowMaker");
634 if (!initFunc) {
635 wwarning("could not initialize library %s", lib);
636 goto function_cleanup;
638 initFunc(dpy, DefaultColormap(dpy, scr));
640 mainFunc = dlsym(handle, func);
641 if (!mainFunc) {
642 wwarning("could not find function %s::%s", lib, func);
643 goto function_cleanup;
645 image = mainFunc(argc, argv, scrWidth, scrHeight, 0);
647 if (!RConvertImage(rc, image, &pixmap)) {
648 wwarning("could not convert texture:%s",
649 RMessageForError(RErrorCode));
650 goto function_cleanup;
652 texture->width = scrWidth;
653 texture->height = scrHeight;
654 texture->pixmap = pixmap;
655 success = 1;
657 function_cleanup:
658 if (argv) {
659 int i;
660 for (i=0; i<argc; i++) {
661 wfree(argv[i]);
664 if (handle) {
665 dlclose(handle);
667 if (image) {
668 RDestroyImage(image);
670 if (!success) {
671 goto error;
673 #else
674 wwarning("function textures not supported");
675 goto error;
676 #endif
677 } else {
678 wwarning("invalid texture type %s", text);
679 goto error;
682 texture->spec = wstrdup(text);
684 return texture;
686 error:
687 if (texture)
688 wfree(texture);
689 if (texarray)
690 PLRelease(texarray);
692 return NULL;
696 void
697 freeTexture(BackgroundTexture *texture)
699 if (texture->solid) {
700 long pixel[1];
702 pixel[0] = texture->color.pixel;
703 /* dont free black/white pixels */
704 if (pixel[0]!=BlackPixelOfScreen(DefaultScreenOfDisplay(dpy))
705 && pixel[0]!=WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
706 XFreeColors(dpy, DefaultColormap(dpy, scr), pixel, 1, 0);
708 if (texture->pixmap) {
709 XFreePixmap(dpy, texture->pixmap);
711 wfree(texture->spec);
712 wfree(texture);
716 void
717 setupTexture(RContext *rc, BackgroundTexture **textures, int *maxTextures,
718 int workspace, char *texture)
720 BackgroundTexture *newTexture = NULL;
721 int i;
723 /* unset the texture */
724 if (!texture) {
725 if (textures[workspace]!=NULL) {
726 textures[workspace]->refcount--;
728 if (textures[workspace]->refcount == 0)
729 freeTexture(textures[workspace]);
731 textures[workspace] = NULL;
732 return;
735 if (textures[workspace]
736 && strcasecmp(textures[workspace]->spec, texture)==0) {
737 /* texture did not change */
738 return;
741 /* check if the same texture is already created */
742 for (i = 0; i < *maxTextures; i++) {
743 if (textures[i] && strcasecmp(textures[i]->spec, texture)==0) {
744 newTexture = textures[i];
745 break;
749 if (!newTexture) {
750 /* create the texture */
751 newTexture = parseTexture(rc, texture);
753 if (!newTexture)
754 return;
756 if (textures[workspace]!=NULL) {
758 textures[workspace]->refcount--;
760 if (textures[workspace]->refcount == 0)
761 freeTexture(textures[workspace]);
764 newTexture->refcount++;
765 textures[workspace] = newTexture;
767 if (*maxTextures < workspace)
768 *maxTextures = workspace;
773 Pixmap
774 duplicatePixmap(Pixmap pixmap, int width, int height)
776 Display *tmpDpy;
777 Pixmap copyP;
779 /* must open a new display or the RetainPermanent will
780 * leave stuff allocated in RContext unallocated after exit */
781 tmpDpy = XOpenDisplay(display);
782 if (!tmpDpy) {
783 wwarning("could not open display to update background image information");
785 return None;
786 } else {
787 XSync(dpy, False);
789 copyP = XCreatePixmap(tmpDpy, root, width, height,
790 DefaultDepth(tmpDpy, scr));
791 XCopyArea(tmpDpy, pixmap, copyP, DefaultGC(tmpDpy, scr),
792 0, 0, width, height, 0, 0);
793 XSync(tmpDpy, False);
795 XSetCloseDownMode(tmpDpy, RetainPermanent);
796 XCloseDisplay(tmpDpy);
799 return copyP;
803 static int
804 dummyErrorHandler(Display *dpy, XErrorEvent *err)
806 return 0;
809 void
810 setPixmapProperty(Pixmap pixmap)
812 static Atom prop = 0;
813 Atom type;
814 int format;
815 unsigned long length, after;
816 unsigned char *data;
817 int mode;
819 if (!prop) {
820 prop = XInternAtom(dpy, "_XROOTPMAP_ID", False);
823 XGrabServer(dpy);
825 /* Clear out the old pixmap */
826 XGetWindowProperty(dpy, root, prop, 0L, 1L, False, AnyPropertyType,
827 &type, &format, &length, &after, &data);
829 if ((type == XA_PIXMAP) && (format == 32) && (length == 1)) {
830 XSetErrorHandler(dummyErrorHandler);
831 XKillClient(dpy, *((Pixmap *)data));
832 XSync(dpy, False);
833 XSetErrorHandler(NULL);
834 mode = PropModeReplace;
835 } else {
836 mode = PropModeAppend;
838 if (pixmap)
839 XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, mode,
840 (unsigned char *) &pixmap, 1);
841 else
842 XDeleteProperty(dpy, root, prop);
845 XUngrabServer(dpy);
846 XFlush(dpy);
851 void
852 changeTexture(BackgroundTexture *texture)
854 if (!texture) {
855 return;
858 if (texture->solid) {
859 XSetWindowBackground(dpy, root, texture->color.pixel);
860 } else {
861 XSetWindowBackgroundPixmap(dpy, root, texture->pixmap);
863 XClearWindow(dpy, root);
865 XSync(dpy, False);
868 Pixmap pixmap;
870 pixmap = duplicatePixmap(texture->pixmap, texture->width,
871 texture->height);
873 setPixmapProperty(pixmap);
879 readmsg(int fd, unsigned char *buffer, int size)
881 int count;
883 count = 0;
884 while (size>0) {
885 count = read(fd, buffer, size);
886 if (count < 0)
887 return -1;
888 size -= count;
889 buffer += count;
890 *buffer = 0;
893 return size;
898 * Message Format:
899 * sizeSntexture_spec - sets the texture for workspace n
900 * sizeCn - change background texture to the one for workspace n
901 * sizePpath - set the pixmap search path
903 * n is 4 bytes
904 * size = 4 bytes for length of the message data
906 void
907 helperLoop(RContext *rc)
909 BackgroundTexture *textures[WORKSPACE_COUNT];
910 int maxTextures = 0;
911 unsigned char buffer[2048], buf[8];
912 int size;
913 int errcount = 4;
915 memset(textures, 0, WORKSPACE_COUNT*sizeof(BackgroundTexture*));
918 while (1) {
919 int workspace;
921 /* get length of message */
922 if (readmsg(0, buffer, 4) < 0) {
923 wsyserror("error reading message from Window Maker");
924 errcount--;
925 if (errcount == 0) {
926 wfatal("quitting");
927 exit(1);
929 continue;
931 memcpy(buf, buffer, 4);
932 buf[4] = 0;
933 size = atoi(buf);
935 /* get message */
936 if (readmsg(0, buffer, size) < 0) {
937 wsyserror("error reading message from Window Maker");
938 errcount--;
939 if (errcount == 0) {
940 wfatal("quitting");
941 exit(1);
943 continue;
945 #ifdef DEBUG
946 printf("RECEIVED %s\n",buffer);
947 #endif
948 if (buffer[0]!='P' && buffer[0]!='K') {
949 memcpy(buf, &buffer[1], 4);
950 buf[4] = 0;
951 workspace = atoi(buf);
952 if (workspace < 0 || workspace >= WORKSPACE_COUNT) {
953 wwarning("received message with invalid workspace number %i\n",
954 workspace);
955 continue;
959 switch (buffer[0]) {
960 case 'S':
961 #ifdef DEBUG
962 printf("set texture %s\n", &buffer[5]);
963 #endif
964 setupTexture(rc, textures, &maxTextures, workspace, &buffer[5]);
965 break;
967 case 'C':
968 #ifdef DEBUG
969 printf("change texture %i\n", workspace);
970 #endif
971 if (!textures[workspace]) {
972 changeTexture(textures[0]);
973 } else {
974 changeTexture(textures[workspace]);
976 break;
978 case 'P':
979 #ifdef DEBUG
980 printf("change pixmappath %s\n", &buffer[1]);
981 #endif
982 if (PixmapPath)
983 wfree(PixmapPath);
984 PixmapPath = wstrdup(&buffer[1]);
985 break;
987 case 'U':
988 #ifdef DEBUG
989 printf("unset workspace %i\n", workspace);
990 #endif
991 setupTexture(rc, textures, &maxTextures, workspace, NULL);
992 break;
994 case 'K':
995 #ifdef DEBUG
996 printf("exit command\n");
997 #endif
998 exit(0);
1000 default:
1001 wwarning("unknown message received");
1002 break;
1008 void
1009 updateDomain(char *domain, char *key, char *texture)
1011 char *program = "wdwrite";
1013 /* here is a mem leak */
1014 system(wstrconcat("wdwrite ",
1015 wstrconcat(domain, smooth ? " SmoothWorkspaceBack YES"
1016 : " SmoothWorkspaceBack NO")));
1018 execlp(program, program, domain, key, texture, NULL);
1019 wwarning("warning could not run \"%s\"", program);
1024 char*
1025 globalDefaultsPathForDomain(char *domain)
1027 char path[1024];
1029 sprintf(path, "%s/WindowMaker/%s", SYSCONFDIR, domain);
1031 return wstrdup(path);
1035 proplist_t
1036 getValueForKey(char *domain, char *keyName)
1038 char *path;
1039 proplist_t key;
1040 proplist_t d;
1041 proplist_t val;
1043 key = PLMakeString(keyName);
1045 /* try to find PixmapPath in user defaults */
1046 path = wdefaultspathfordomain(domain);
1047 d = PLGetProplistWithPath(path);
1048 if (!d) {
1049 wwarning("could not open domain file %s", path);
1051 wfree(path);
1053 if (d && !PLIsDictionary(d)) {
1054 PLRelease(d);
1055 d = NULL;
1057 if (d) {
1058 val = PLGetDictionaryEntry(d, key);
1059 } else {
1060 val = NULL;
1062 /* try to find PixmapPath in global defaults */
1063 if (!val) {
1064 path = globalDefaultsPathForDomain(domain);
1065 if (!path) {
1066 wwarning("could not locate file for domain %s", domain);
1067 d = NULL;
1068 } else {
1069 d = PLGetProplistWithPath(path);
1070 wfree(path);
1073 if (d && !PLIsDictionary(d)) {
1074 PLRelease(d);
1075 d = NULL;
1077 if (d) {
1078 val = PLGetDictionaryEntry(d, key);
1080 } else {
1081 val = NULL;
1085 if (val)
1086 PLRetain(val);
1088 PLRelease(key);
1089 if (d)
1090 PLRelease(d);
1092 return val;
1097 char*
1098 getPixmapPath(char *domain)
1100 proplist_t val;
1101 char *ptr, *data;
1102 int len, i, count;
1104 val = getValueForKey(domain, "PixmapPath");
1106 if (!val || !PLIsArray(val)) {
1107 if (val)
1108 PLRelease(val);
1109 return wstrdup("");
1112 count = PLGetNumberOfElements(val);
1113 len = 0;
1114 for (i=0; i<count; i++) {
1115 proplist_t v;
1117 v = PLGetArrayElement(val, i);
1118 if (!v || !PLIsString(v)) {
1119 continue;
1121 len += strlen(PLGetString(v))+1;
1124 ptr = data = wmalloc(len+1);
1125 *ptr = 0;
1127 for (i=0; i<count; i++) {
1128 proplist_t v;
1130 v = PLGetArrayElement(val, i);
1131 if (!v || !PLIsString(v)) {
1132 continue;
1134 strcpy(ptr, PLGetString(v));
1136 ptr += strlen(PLGetString(v));
1137 *ptr = ':';
1138 ptr++;
1140 if (i>0)
1141 ptr--; *(ptr--) = 0;
1143 PLRelease(val);
1145 return data;
1149 char*
1150 getFullPixmapPath(char *file)
1152 char *tmp;
1154 if (!PixmapPath || !(tmp = wfindfile(PixmapPath, file))) {
1155 int bsize = 512;
1156 char *path = wmalloc(bsize);
1158 while (!getcwd(path, bsize)) {
1159 wfree(path);
1160 bsize += bsize/2;
1161 path = malloc(bsize);
1164 tmp = wstrconcat(path, "/");
1165 wfree(path);
1166 path = wstrconcat(tmp, file);
1167 wfree(tmp);
1169 return path;
1172 /* the file is in the PixmapPath */
1173 wfree(tmp);
1175 return wstrdup(file);
1180 void
1181 wAbort()
1183 wfatal("aborting");
1184 exit(1);
1189 void
1190 print_help(char *ProgName)
1192 printf("Usage: %s [options] [image]\n", ProgName);
1193 puts("Sets the workspace background to the specified image or a texture and optionally update Window Maker configuration");
1194 puts("");
1195 #define P(m) puts(m)
1196 P(" -display display to use");
1197 P(" -d, --dither dither image");
1198 P(" -m, --match match colors");
1199 P(" -S, --smooth smooth scaled image");
1200 P(" -b, --back-color <color> background color");
1201 P(" -t, --tile tile image");
1202 P(" -e, --center center image");
1203 P(" -s, --scale scale image (default)");
1204 P(" -a, --maxscale scale image and keep aspect ratio");
1205 P(" -u, --update-wmaker update WindowMaker domain database");
1206 P(" -D, --update-domain <domain> update <domain> database");
1207 P(" -c, --colors <cpc> colors per channel to use");
1208 P(" -p, --parse <texture> proplist style texture specification");
1209 P(" -w, --workspace <workspace> update background for the specified workspace");
1210 P(" --version show version of wmsetbg and exit");
1211 P(" --help show this help and exit");
1212 #undef P
1217 void
1218 changeTextureForWorkspace(char *domain, char *texture, int workspace)
1220 proplist_t array;
1221 proplist_t val;
1222 char *value;
1223 int j;
1225 val = PLGetProplistWithDescription(texture);
1226 if (!val) {
1227 wwarning("could not parse texture %s", texture);
1228 return;
1231 array = getValueForKey("WindowMaker", "WorkspaceSpecificBack");
1233 if (!array) {
1234 array = PLMakeArrayFromElements(NULL, NULL);
1237 j = PLGetNumberOfElements(array);
1238 if (workspace >= j) {
1239 proplist_t empty;
1241 empty = PLMakeArrayFromElements(NULL, NULL);
1243 while (j++ < workspace-1) {
1244 PLAppendArrayElement(array, empty);
1246 PLAppendArrayElement(array, val);
1247 } else {
1248 PLRemoveArrayElement(array, workspace);
1249 PLInsertArrayElement(array, val, workspace);
1252 value = PLGetDescription(array);
1253 updateDomain(domain, "WorkspaceSpecificBack", value);
1258 main(int argc, char **argv)
1260 int i;
1261 int helperMode = 0;
1262 RContext *rc;
1263 RContextAttributes rattr;
1264 char *style = "spixmap";
1265 char *back_color = "gray20";
1266 char *image_name = NULL;
1267 char *domain = "WindowMaker";
1268 int update=0, cpc=4, render_mode=RDitheredRendering, obey_user=0;
1269 char *texture = NULL;
1270 int workspace = -1;
1272 signal(SIGINT, SIG_DFL);
1273 signal(SIGTERM, SIG_DFL);
1274 signal(SIGQUIT, SIG_DFL);
1275 signal(SIGSEGV, SIG_DFL);
1276 signal(SIGBUS, SIG_DFL);
1277 signal(SIGFPE, SIG_DFL);
1278 signal(SIGABRT, SIG_DFL);
1279 signal(SIGHUP, SIG_DFL);
1280 signal(SIGPIPE, SIG_DFL);
1281 signal(SIGCHLD, SIG_DFL);
1283 WMInitializeApplication("wmsetbg", &argc, argv);
1285 for (i=1; i<argc; i++) {
1286 if (strcmp(argv[i], "-helper")==0) {
1287 helperMode = 1;
1288 } else if (strcmp(argv[i], "-display")==0) {
1289 i++;
1290 if (i>=argc) {
1291 wfatal("too few arguments for %s\n", argv[i-1]);
1292 exit(1);
1294 display = argv[i];
1295 } else if (strcmp(argv[i], "-s")==0
1296 || strcmp(argv[i], "--scale")==0) {
1297 style = "spixmap";
1298 } else if (strcmp(argv[i], "-t")==0
1299 || strcmp(argv[i], "--tile")==0) {
1300 style = "tpixmap";
1301 } else if (strcmp(argv[i], "-e")==0
1302 || strcmp(argv[i], "--center")==0) {
1303 style = "cpixmap";
1304 } else if (strcmp(argv[i], "-a")==0
1305 || strcmp(argv[i], "--maxscale")==0) {
1306 style = "mpixmap";
1307 } else if (strcmp(argv[i], "-d")==0
1308 || strcmp(argv[i], "--dither")==0) {
1309 render_mode = RDitheredRendering;
1310 obey_user++;
1311 } else if (strcmp(argv[i], "-m")==0
1312 || strcmp(argv[i], "--match")==0) {
1313 render_mode = RBestMatchRendering;
1314 obey_user++;
1315 } else if (strcmp(argv[i], "-S")==0
1316 || strcmp(argv[i], "--smooth")==0) {
1317 smooth = True;
1318 } else if (strcmp(argv[i], "-u")==0
1319 || strcmp(argv[i], "--update-wmaker")==0) {
1320 update++;
1321 } else if (strcmp(argv[i], "-D")==0
1322 || strcmp(argv[i], "--update-domain")==0) {
1323 update++;
1324 i++;
1325 if (i>=argc) {
1326 wfatal("too few arguments for %s\n", argv[i-1]);
1327 exit(1);
1329 domain = wstrdup(argv[i]);
1330 } else if (strcmp(argv[i], "-c")==0
1331 || strcmp(argv[i], "--colors")==0) {
1332 i++;
1333 if (i>=argc) {
1334 wfatal("too few arguments for %s\n", argv[i-1]);
1335 exit(1);
1337 if (sscanf(argv[i], "%i", &cpc)!=1) {
1338 wfatal("bad value for colors per channel: \"%s\"\n", argv[i]);
1339 exit(1);
1341 } else if (strcmp(argv[i], "-b")==0
1342 || strcmp(argv[i], "--back-color")==0) {
1343 i++;
1344 if (i>=argc) {
1345 wfatal("too few arguments for %s\n", argv[i-1]);
1346 exit(1);
1348 back_color = argv[i];
1349 } else if (strcmp(argv[i], "-p")==0
1350 || strcmp(argv[i], "--parse")==0) {
1351 i++;
1352 if (i>=argc) {
1353 wfatal("too few arguments for %s\n", argv[i-1]);
1354 exit(1);
1356 texture = argv[i];
1357 } else if (strcmp(argv[i], "-w")==0
1358 || strcmp(argv[i], "--workspace")==0) {
1359 i++;
1360 if (i>=argc) {
1361 wfatal("too few arguments for %s\n", argv[i-1]);
1362 exit(1);
1364 if (sscanf(argv[i], "%i", &workspace)!=1) {
1365 wfatal("bad value for workspace number: \"%s\"",
1366 argv[i]);
1367 exit(1);
1369 } else if (strcmp(argv[i], "--version")==0) {
1371 printf(PROG_VERSION);
1372 exit(0);
1374 } else if (strcmp(argv[i], "--help")==0) {
1375 print_help(argv[0]);
1376 exit(0);
1377 } else if (argv[i][0] != '-') {
1378 image_name = argv[i];
1379 } else {
1380 printf("%s: invalid argument '%s'\n", argv[0], argv[i]);
1381 printf("Try '%s --help' for more information\n", argv[0]);
1382 exit(1);
1385 if (!image_name && !texture && !helperMode) {
1386 printf("%s: you must specify a image file name or a texture\n",
1387 argv[0]);
1388 printf("Try '%s --help' for more information\n", argv[0]);
1389 exit(1);
1393 PixmapPath = getPixmapPath(domain);
1394 if (!smooth) {
1395 proplist_t val;
1396 #if 0 /* some problem with Alpha... TODO: check if its right */
1397 val = PLGetDictionaryEntry(domain,
1398 PLMakeString("SmoothWorkspaceBack"));
1399 #else
1400 val = getValueForKey(domain, "SmoothWorkspaceBack");
1401 #endif
1403 if (val && PLIsString(val) && strcasecmp(PLGetString(val), "YES")==0)
1404 smooth = True;
1407 dpy = XOpenDisplay(display);
1408 if (!dpy) {
1409 wfatal("could not open display");
1410 exit(1);
1412 #if 0
1413 XSynchronize(dpy, 1);
1414 #endif
1416 root = DefaultRootWindow(dpy);
1418 scr = DefaultScreen(dpy);
1420 scrWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
1421 scrHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
1423 if (!obey_user && DefaultDepth(dpy, scr) <= 8)
1424 render_mode = RDitheredRendering;
1426 rattr.flags = RC_RenderMode | RC_ColorsPerChannel
1427 | RC_StandardColormap;
1428 rattr.render_mode = render_mode;
1429 rattr.colors_per_channel = cpc;
1430 rattr.standard_colormap_mode = RCreateStdColormap;
1432 rc = RCreateContext(dpy, scr, &rattr);
1434 if (!rc) {
1435 rattr.standard_colormap_mode = RIgnoreStdColormap;
1436 rc = RCreateContext(dpy, scr, &rattr);
1439 if (!rc) {
1440 wfatal("could not initialize wrlib: %s",
1441 RMessageForError(RErrorCode));
1442 exit(1);
1445 if (helperMode) {
1446 /* lower priority, so that it wont use all the CPU */
1447 nice(15);
1449 helperLoop(rc);
1450 } else {
1451 BackgroundTexture *tex;
1452 char buffer[4098];
1454 if (!texture) {
1455 char *image_path = getFullPixmapPath(image_name);
1457 sprintf(buffer, "(%s, \"%s\", %s)", style, image_path, back_color);
1458 wfree(image_path);
1459 texture = (char*)buffer;
1462 if (update && workspace < 0) {
1463 updateDomain(domain, "WorkspaceBack", texture);
1466 tex = parseTexture(rc, texture);
1467 if (!tex)
1468 exit(1);
1470 if (workspace<0)
1471 changeTexture(tex);
1472 else {
1473 /* always update domain */
1474 changeTextureForWorkspace(domain, texture, workspace);
1478 return 0;