- Fixed text in info panel for multibyte (Seiichi SATO <ssato@sh.rim.or.jp>)
[wmaker-crm.git] / util / wmsetbg.c
blob74423e0f05fe0f940234a744fe5acedee5343615
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-2002 Alfredo K. Kojima
7 * Copyright (c) 1998-2002 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 <wraster.h>
53 #define PROG_VERSION "wmsetbg (Window Maker) 2.7"
56 #define WORKSPACE_COUNT (MAX_WORKSPACES+1)
59 Display *dpy;
60 char *display = "";
61 Window root;
62 int scr;
63 int scrWidth;
64 int scrHeight;
67 Bool smooth = False;
70 Pixmap CurrentPixmap = None;
71 char *PixmapPath = NULL;
74 extern Pixmap LoadJPEG(RContext *rc, char *file_name, int *width, int *height);
77 typedef struct BackgroundTexture {
78 int refcount;
80 int solid;
82 char *spec;
84 XColor color;
85 Pixmap pixmap; /* for all textures, including solid */
86 int width; /* size of the pixmap */
87 int height;
88 } BackgroundTexture;
92 RImage*
93 loadImage(RContext *rc, char *file)
95 char *path;
96 RImage *image;
98 if (access(file, F_OK)!=0) {
99 path = wfindfile(PixmapPath, file);
100 if (!path) {
101 wwarning("%s:could not find image file used in texture", file);
102 return NULL;
104 } else {
105 path = wstrdup(file);
108 image = RLoadImage(rc, path, 0);
109 if (!image) {
110 wwarning("%s:could not load image file used in texture:%s", path,
111 RMessageForError(RErrorCode));
113 wfree(path);
115 return image;
119 BackgroundTexture*
120 parseTexture(RContext *rc, char *text)
122 BackgroundTexture *texture = NULL;
123 WMPropList *texarray;
124 WMPropList *val;
125 int count;
126 char *tmp;
127 char *type;
129 #define GETSTRORGOTO(val, str, i, label) \
130 val = WMGetFromPLArray(texarray, i);\
131 if (!WMIsPLString(val)) {\
132 wwarning("could not parse texture %s", text);\
133 goto label;\
135 str = WMGetFromPLString(val)
137 texarray = WMCreatePropListFromDescription(text);
138 if (!texarray || !WMIsPLArray(texarray)
139 || (count = WMGetPropListItemCount(texarray)) < 2) {
141 wwarning("could not parse texture %s", text);
142 if (texarray)
143 WMReleasePropList(texarray);
144 return NULL;
147 texture = wmalloc(sizeof(BackgroundTexture));
148 memset(texture, 0, sizeof(BackgroundTexture));
150 GETSTRORGOTO(val, type, 0, error);
152 if (strcasecmp(type, "solid")==0) {
153 XColor color;
154 Pixmap pixmap;
156 texture->solid = 1;
158 GETSTRORGOTO(val, tmp, 1, error);
160 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
161 wwarning("could not parse color %s in texture %s", tmp, text);
162 goto error;
164 XAllocColor(dpy, DefaultColormap(dpy, scr), &color);
166 pixmap = XCreatePixmap(dpy, root, 8, 8, DefaultDepth(dpy, scr));
167 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
168 XFillRectangle(dpy, pixmap, DefaultGC(dpy, scr), 0, 0, 8, 8);
170 texture->pixmap = pixmap;
171 texture->color = color;
172 texture->width = 8;
173 texture->height = 8;
174 } else if (strcasecmp(type, "vgradient")==0
175 || strcasecmp(type, "dgradient")==0
176 || strcasecmp(type, "hgradient")==0) {
177 XColor color;
178 RColor color1, color2;
179 RImage *image;
180 Pixmap pixmap;
181 int gtype;
182 int iwidth, iheight;
184 GETSTRORGOTO(val, tmp, 1, error);
186 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
187 wwarning("could not parse color %s in texture %s", tmp, text);
188 goto error;
191 color1.red = color.red >> 8;
192 color1.green = color.green >> 8;
193 color1.blue = color.blue >> 8;
195 GETSTRORGOTO(val, tmp, 2, error);
197 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
198 wwarning("could not parse color %s in texture %s", tmp, text);
199 goto error;
202 color2.red = color.red >> 8;
203 color2.green = color.green >> 8;
204 color2.blue = color.blue >> 8;
206 switch (type[0]) {
207 case 'h':
208 case 'H':
209 gtype = RHorizontalGradient;
210 iwidth = scrWidth;
211 iheight = 32;
212 break;
213 case 'V':
214 case 'v':
215 gtype = RVerticalGradient;
216 iwidth = 32;
217 iheight = scrHeight;
218 break;
219 default:
220 gtype = RDiagonalGradient;
221 iwidth = scrWidth;
222 iheight = scrHeight;
223 break;
226 image = RRenderGradient(iwidth, iheight, &color1, &color2, gtype);
228 if (!image) {
229 wwarning("could not render gradient texture:%s",
230 RMessageForError(RErrorCode));
231 goto error;
234 if (!RConvertImage(rc, image, &pixmap)) {
235 wwarning("could not convert texture:%s",
236 RMessageForError(RErrorCode));
237 RReleaseImage(image);
238 goto error;
241 texture->width = image->width;
242 texture->height = image->height;
243 RReleaseImage(image);
245 texture->pixmap = pixmap;
246 } else if (strcasecmp(type, "mvgradient")==0
247 || strcasecmp(type, "mdgradient")==0
248 || strcasecmp(type, "mhgradient")==0) {
249 XColor color;
250 RColor **colors;
251 RImage *image;
252 Pixmap pixmap;
253 int i, j;
254 int gtype;
255 int iwidth, iheight;
257 colors = malloc(sizeof(RColor*)*(count-1));
258 if (!colors) {
259 wwarning("out of memory while parsing texture");
260 goto error;
262 memset(colors, 0, sizeof(RColor*)*(count-1));
264 for (i = 2; i < count; i++) {
265 val = WMGetFromPLArray(texarray, i);
266 if (!WMIsPLString(val)) {
267 wwarning("could not parse texture %s", text);
269 for (j = 0; colors[j]!=NULL; j++)
270 wfree(colors[j]);
271 wfree(colors);
272 goto error;
274 tmp = WMGetFromPLString(val);
276 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
277 wwarning("could not parse color %s in texture %s",
278 tmp, text);
280 for (j = 0; colors[j]!=NULL; j++)
281 wfree(colors[j]);
282 wfree(colors);
283 goto error;
285 if (!(colors[i-2] = malloc(sizeof(RColor)))) {
286 wwarning("out of memory while parsing texture");
288 for (j = 0; colors[j]!=NULL; j++)
289 wfree(colors[j]);
290 wfree(colors);
291 goto error;
294 colors[i-2]->red = color.red >> 8;
295 colors[i-2]->green = color.green >> 8;
296 colors[i-2]->blue = color.blue >> 8;
299 switch (type[1]) {
300 case 'h':
301 case 'H':
302 gtype = RHorizontalGradient;
303 iwidth = scrWidth;
304 iheight = 32;
305 break;
306 case 'V':
307 case 'v':
308 gtype = RVerticalGradient;
309 iwidth = 32;
310 iheight = scrHeight;
311 break;
312 default:
313 gtype = RDiagonalGradient;
314 iwidth = scrWidth;
315 iheight = scrHeight;
316 break;
319 image = RRenderMultiGradient(iwidth, iheight, colors, gtype);
321 for (j = 0; colors[j]!=NULL; j++)
322 wfree(colors[j]);
323 wfree(colors);
325 if (!image) {
326 wwarning("could not render gradient texture:%s",
327 RMessageForError(RErrorCode));
328 goto error;
331 if (!RConvertImage(rc, image, &pixmap)) {
332 wwarning("could not convert texture:%s",
333 RMessageForError(RErrorCode));
334 RReleaseImage(image);
335 goto error;
338 texture->width = image->width;
339 texture->height = image->height;
340 RReleaseImage(image);
342 texture->pixmap = pixmap;
343 } else if (strcasecmp(type, "cpixmap")==0
344 || strcasecmp(type, "spixmap")==0
345 || strcasecmp(type, "mpixmap")==0
346 || strcasecmp(type, "tpixmap")==0) {
347 XColor color;
348 Pixmap pixmap = None;
349 RImage *image = NULL;
350 int w, h;
351 int iwidth, iheight;
352 RColor rcolor;
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 RReleaseImage(image);
375 goto error;
377 if (!XAllocColor(dpy, DefaultColormap(dpy, scr), &color)) {
378 rcolor.red = color.red >> 8;
379 rcolor.green = color.green >> 8;
380 rcolor.blue = color.blue >> 8;
381 RGetClosestXColor(rc, &rcolor, &color);
382 } else {
383 rcolor.red = 0;
384 rcolor.green = 0;
385 rcolor.blue = 0;
387 /* for images with a transparent color */
388 if (image->data[3]) {
389 RCombineImageWithColor(image, &rcolor);
392 switch (toupper(type[0])) {
393 case 'T':
394 texture->width = iwidth;
395 texture->height = iheight;
396 if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
397 wwarning("could not convert texture:%s",
398 RMessageForError(RErrorCode));
399 RReleaseImage(image);
400 goto error;
402 if (image)
403 RReleaseImage(image);
404 break;
405 case 'S':
406 case 'M':
407 if (toupper(type[0])=='S') {
408 w = scrWidth;
409 h = scrHeight;
410 } else {
411 if (iwidth*scrHeight > iheight*scrWidth) {
412 w = scrWidth;
413 h = (scrWidth*iheight)/iwidth;
414 } else {
415 h = scrHeight;
416 w = (scrHeight*iwidth)/iheight;
419 if (w != image->width || h != image->height) {
420 RImage *simage;
422 if (smooth)
423 simage = RSmoothScaleImage(image, w, h);
424 else
425 simage = RScaleImage(image, w, h);
426 if (!simage) {
427 wwarning("could not scale image:%s",
428 RMessageForError(RErrorCode));
429 RReleaseImage(image);
430 goto error;
432 RReleaseImage(image);
433 image = simage;
435 iwidth = image->width;
436 iheight = image->height;
438 /* fall through */
439 case 'C':
441 Pixmap cpixmap;
443 if (!pixmap && !RConvertImage(rc, image, &pixmap)) {
444 wwarning("could not convert texture:%s",
445 RMessageForError(RErrorCode));
446 RReleaseImage(image);
447 goto error;
450 if (iwidth != scrWidth || iheight != scrHeight) {
451 int x, y, sx, sy, w, h;
453 cpixmap = XCreatePixmap(dpy, root, scrWidth, scrHeight,
454 DefaultDepth(dpy, scr));
456 XSetForeground(dpy, DefaultGC(dpy, scr), color.pixel);
457 XFillRectangle(dpy, cpixmap, DefaultGC(dpy, scr),
458 0, 0, scrWidth, scrHeight);
460 if (iheight < scrHeight) {
461 h = iheight;
462 y = (scrHeight - h)/2;
463 sy = 0;
464 } else {
465 sy = (iheight - scrHeight)/2;
466 y = 0;
467 h = scrHeight;
469 if (iwidth < scrWidth) {
470 w = iwidth;
471 x = (scrWidth - w)/2;
472 sx = 0;
473 } else {
474 sx = (iwidth - scrWidth)/2;
475 x = 0;
476 w = scrWidth;
479 XCopyArea(dpy, pixmap, cpixmap, DefaultGC(dpy, scr),
480 sx, sy, w, h, x, y);
481 XFreePixmap(dpy, pixmap);
482 pixmap = cpixmap;
484 if (image)
485 RReleaseImage(image);
487 texture->width = scrWidth;
488 texture->height = scrHeight;
490 break;
493 texture->pixmap = pixmap;
494 texture->color = color;
495 } else if (strcasecmp(type, "thgradient")==0
496 || strcasecmp(type, "tvgradient")==0
497 || strcasecmp(type, "tdgradient")==0) {
498 XColor color;
499 RColor color1, color2;
500 RImage *image;
501 RImage *gradient;
502 RImage *tiled;
503 Pixmap pixmap;
504 int opaq;
505 char *file;
506 int gtype;
507 int twidth, theight;
509 GETSTRORGOTO(val, file, 1, error);
511 GETSTRORGOTO(val, tmp, 2, error);
513 opaq = atoi(tmp);
515 GETSTRORGOTO(val, tmp, 3, error);
517 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
518 wwarning("could not parse color %s in texture %s", tmp, text);
519 goto error;
522 color1.red = color.red >> 8;
523 color1.green = color.green >> 8;
524 color1.blue = color.blue >> 8;
526 GETSTRORGOTO(val, tmp, 4, error);
528 if (!XParseColor(dpy, DefaultColormap(dpy, scr), tmp, &color)) {
529 wwarning("could not parse color %s in texture %s", tmp, text);
530 goto error;
533 color2.red = color.red >> 8;
534 color2.green = color.green >> 8;
535 color2.blue = color.blue >> 8;
537 image = loadImage(rc, file);
538 if (!image) {
539 goto error;
542 switch (type[1]) {
543 case 'h':
544 case 'H':
545 gtype = RHorizontalGradient;
546 twidth = scrWidth;
547 theight = image->height > scrHeight ? scrHeight : image->height;
548 break;
549 case 'V':
550 case 'v':
551 gtype = RVerticalGradient;
552 twidth = image->width > scrWidth ? scrWidth : image->width;
553 theight = scrHeight;
554 break;
555 default:
556 gtype = RDiagonalGradient;
557 twidth = scrWidth;
558 theight = scrHeight;
559 break;
561 gradient = RRenderGradient(twidth, theight, &color1, &color2, gtype);
563 if (!gradient) {
564 wwarning("could not render texture:%s",
565 RMessageForError(RErrorCode));
566 RReleaseImage(gradient);
567 RReleaseImage(image);
568 goto error;
571 tiled = RMakeTiledImage(image, twidth, theight);
572 if (!tiled) {
573 wwarning("could not render texture:%s",
574 RMessageForError(RErrorCode));
575 RReleaseImage(gradient);
576 RReleaseImage(image);
577 goto error;
579 RReleaseImage(image);
581 RCombineImagesWithOpaqueness(tiled, gradient, opaq);
582 RReleaseImage(gradient);
584 if (!RConvertImage(rc, tiled, &pixmap)) {
585 wwarning("could not convert texture:%s",
586 RMessageForError(RErrorCode));
587 RReleaseImage(tiled);
588 goto error;
590 texture->width = tiled->width;
591 texture->height = tiled->height;
593 RReleaseImage(tiled);
595 texture->pixmap = pixmap;
596 } else if (strcasecmp(type, "function")==0) {
597 #ifdef HAVE_DLFCN_H
598 void (*initFunc) (Display*, Colormap);
599 RImage* (*mainFunc) (int, char**, int, int, int);
600 Pixmap pixmap;
601 RImage *image = 0;
602 int success = 0;
603 char *lib, *func, **argv = 0;
604 void *handle = 0;
605 int i, argc;
607 if (count < 3)
608 goto function_cleanup;
610 /* get the library name */
611 GETSTRORGOTO(val, lib, 1, function_cleanup);
613 /* get the function name */
614 GETSTRORGOTO(val, func, 2, function_cleanup);
616 argc = count - 2;
617 argv = (char**)wmalloc(argc * sizeof(char*));
619 /* get the parameters */
620 argv[0] = func;
621 for (i=0; i<argc-1; i++) {
622 GETSTRORGOTO(val, tmp, 3+i, function_cleanup);
623 argv[i+1] = wstrdup(tmp);
626 handle = dlopen(lib, RTLD_LAZY);
627 if (!handle) {
628 wwarning("could not find library %s", lib);
629 goto function_cleanup;
632 initFunc = dlsym(handle, "initWindowMaker");
633 if (!initFunc) {
634 wwarning("could not initialize library %s", lib);
635 goto function_cleanup;
637 initFunc(dpy, DefaultColormap(dpy, scr));
639 mainFunc = dlsym(handle, func);
640 if (!mainFunc) {
641 wwarning("could not find function %s::%s", lib, func);
642 goto function_cleanup;
644 image = mainFunc(argc, argv, scrWidth, scrHeight, 0);
646 if (!RConvertImage(rc, image, &pixmap)) {
647 wwarning("could not convert texture:%s",
648 RMessageForError(RErrorCode));
649 goto function_cleanup;
651 texture->width = scrWidth;
652 texture->height = scrHeight;
653 texture->pixmap = pixmap;
654 success = 1;
656 function_cleanup:
657 if (argv) {
658 int i;
659 for (i=0; i<argc; i++) {
660 wfree(argv[i]);
663 if (handle) {
664 dlclose(handle);
666 if (image) {
667 RReleaseImage(image);
669 if (!success) {
670 goto error;
672 #else
673 wwarning("function textures not supported");
674 goto error;
675 #endif
676 } else {
677 wwarning("invalid texture type %s", text);
678 goto error;
681 texture->spec = wstrdup(text);
683 return texture;
685 error:
686 if (texture)
687 wfree(texture);
688 if (texarray)
689 WMReleasePropList(texarray);
691 return NULL;
695 void
696 freeTexture(BackgroundTexture *texture)
698 if (texture->solid) {
699 long pixel[1];
701 pixel[0] = texture->color.pixel;
702 /* dont free black/white pixels */
703 if (pixel[0]!=BlackPixelOfScreen(DefaultScreenOfDisplay(dpy))
704 && pixel[0]!=WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)))
705 XFreeColors(dpy, DefaultColormap(dpy, scr), pixel, 1, 0);
707 if (texture->pixmap) {
708 XFreePixmap(dpy, texture->pixmap);
710 wfree(texture->spec);
711 wfree(texture);
715 void
716 setupTexture(RContext *rc, BackgroundTexture **textures, int *maxTextures,
717 int workspace, char *texture)
719 BackgroundTexture *newTexture = NULL;
720 int i;
722 /* unset the texture */
723 if (!texture) {
724 if (textures[workspace]!=NULL) {
725 textures[workspace]->refcount--;
727 if (textures[workspace]->refcount == 0)
728 freeTexture(textures[workspace]);
730 textures[workspace] = NULL;
731 return;
734 if (textures[workspace]
735 && strcasecmp(textures[workspace]->spec, texture)==0) {
736 /* texture did not change */
737 return;
740 /* check if the same texture is already created */
741 for (i = 0; i < *maxTextures; i++) {
742 if (textures[i] && strcasecmp(textures[i]->spec, texture)==0) {
743 newTexture = textures[i];
744 break;
748 if (!newTexture) {
749 /* create the texture */
750 newTexture = parseTexture(rc, texture);
752 if (!newTexture)
753 return;
755 if (textures[workspace]!=NULL) {
757 textures[workspace]->refcount--;
759 if (textures[workspace]->refcount == 0)
760 freeTexture(textures[workspace]);
763 newTexture->refcount++;
764 textures[workspace] = newTexture;
766 if (*maxTextures < workspace)
767 *maxTextures = workspace;
772 Pixmap
773 duplicatePixmap(Pixmap pixmap, int width, int height)
775 Display *tmpDpy;
776 Pixmap copyP;
778 /* must open a new display or the RetainPermanent will
779 * leave stuff allocated in RContext unallocated after exit */
780 tmpDpy = XOpenDisplay(display);
781 if (!tmpDpy) {
782 wwarning("could not open display to update background image information");
784 return None;
785 } else {
786 XSync(dpy, False);
788 copyP = XCreatePixmap(tmpDpy, root, width, height,
789 DefaultDepth(tmpDpy, scr));
790 XCopyArea(tmpDpy, pixmap, copyP, DefaultGC(tmpDpy, scr),
791 0, 0, width, height, 0, 0);
792 XSync(tmpDpy, False);
794 XSetCloseDownMode(tmpDpy, RetainPermanent);
795 XCloseDisplay(tmpDpy);
798 return copyP;
802 static int
803 dummyErrorHandler(Display *dpy, XErrorEvent *err)
805 return 0;
808 void
809 setPixmapProperty(Pixmap pixmap)
811 static Atom prop = 0;
812 Atom type;
813 int format;
814 unsigned long length, after;
815 unsigned char *data;
816 int mode;
818 if (!prop) {
819 prop = XInternAtom(dpy, "_XROOTPMAP_ID", False);
822 XGrabServer(dpy);
824 /* Clear out the old pixmap */
825 XGetWindowProperty(dpy, root, prop, 0L, 1L, False, AnyPropertyType,
826 &type, &format, &length, &after, &data);
828 if ((type == XA_PIXMAP) && (format == 32) && (length == 1)) {
829 XSetErrorHandler(dummyErrorHandler);
830 XKillClient(dpy, *((Pixmap *)data));
831 XSync(dpy, False);
832 XSetErrorHandler(NULL);
833 mode = PropModeReplace;
834 } else {
835 mode = PropModeAppend;
837 if (pixmap)
838 XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, mode,
839 (unsigned char *) &pixmap, 1);
840 else
841 XDeleteProperty(dpy, root, prop);
844 XUngrabServer(dpy);
845 XFlush(dpy);
850 void
851 changeTexture(BackgroundTexture *texture)
853 if (!texture) {
854 return;
857 if (texture->solid) {
858 XSetWindowBackground(dpy, root, texture->color.pixel);
859 } else {
860 XSetWindowBackgroundPixmap(dpy, root, texture->pixmap);
862 XClearWindow(dpy, root);
864 XSync(dpy, False);
867 Pixmap pixmap;
869 pixmap = duplicatePixmap(texture->pixmap, texture->width,
870 texture->height);
872 setPixmapProperty(pixmap);
878 readmsg(int fd, unsigned char *buffer, int size)
880 int count;
882 count = 0;
883 while (size>0) {
884 count = read(fd, buffer, size);
885 if (count < 0)
886 return -1;
887 size -= count;
888 buffer += count;
889 *buffer = 0;
892 return size;
897 * Message Format:
898 * sizeSntexture_spec - sets the texture for workspace n
899 * sizeCn - change background texture to the one for workspace n
900 * sizePpath - set the pixmap search path
902 * n is 4 bytes
903 * size = 4 bytes for length of the message data
905 void
906 helperLoop(RContext *rc)
908 BackgroundTexture *textures[WORKSPACE_COUNT];
909 int maxTextures = 0;
910 unsigned char buffer[2048], buf[8];
911 int size;
912 int errcount = 4;
914 memset(textures, 0, WORKSPACE_COUNT*sizeof(BackgroundTexture*));
917 while (1) {
918 int workspace;
920 /* get length of message */
921 if (readmsg(0, buffer, 4) < 0) {
922 wsyserror("error reading message from Window Maker");
923 errcount--;
924 if (errcount == 0) {
925 wfatal("quitting");
926 exit(1);
928 continue;
930 memcpy(buf, buffer, 4);
931 buf[4] = 0;
932 size = atoi(buf);
934 /* get message */
935 if (readmsg(0, buffer, size) < 0) {
936 wsyserror("error reading message from Window Maker");
937 errcount--;
938 if (errcount == 0) {
939 wfatal("quitting");
940 exit(1);
942 continue;
944 #ifdef DEBUG
945 printf("RECEIVED %s\n",buffer);
946 #endif
947 if (buffer[0]!='P' && buffer[0]!='K') {
948 memcpy(buf, &buffer[1], 4);
949 buf[4] = 0;
950 workspace = atoi(buf);
951 if (workspace < 0 || workspace >= WORKSPACE_COUNT) {
952 wwarning("received message with invalid workspace number %i\n",
953 workspace);
954 continue;
958 switch (buffer[0]) {
959 case 'S':
960 #ifdef DEBUG
961 printf("set texture %s\n", &buffer[5]);
962 #endif
963 setupTexture(rc, textures, &maxTextures, workspace, &buffer[5]);
964 break;
966 case 'C':
967 #ifdef DEBUG
968 printf("change texture %i\n", workspace);
969 #endif
970 if (!textures[workspace]) {
971 changeTexture(textures[0]);
972 } else {
973 changeTexture(textures[workspace]);
975 break;
977 case 'P':
978 #ifdef DEBUG
979 printf("change pixmappath %s\n", &buffer[1]);
980 #endif
981 if (PixmapPath)
982 wfree(PixmapPath);
983 PixmapPath = wstrdup(&buffer[1]);
984 break;
986 case 'U':
987 #ifdef DEBUG
988 printf("unset workspace %i\n", workspace);
989 #endif
990 setupTexture(rc, textures, &maxTextures, workspace, NULL);
991 break;
993 case 'K':
994 #ifdef DEBUG
995 printf("exit command\n");
996 #endif
997 exit(0);
999 default:
1000 wwarning("unknown message received");
1001 break;
1007 void
1008 updateDomain(char *domain, char *key, char *texture)
1010 char *program = "wdwrite";
1012 /* here is a mem leak */
1013 system(wstrconcat("wdwrite ",
1014 wstrconcat(domain, smooth ? " SmoothWorkspaceBack YES"
1015 : " SmoothWorkspaceBack NO")));
1017 execlp(program, program, domain, key, texture, NULL);
1018 wwarning("warning could not run \"%s\"", program);
1023 char*
1024 globalDefaultsPathForDomain(char *domain)
1026 char path[1024];
1028 sprintf(path, "%s/WindowMaker/%s", SYSCONFDIR, domain);
1030 return wstrdup(path);
1034 static WMPropList*
1035 getValueForKey(char *domain, char *keyName)
1037 char *path;
1038 WMPropList *key, *val, *d;
1040 key = WMCreatePLString(keyName);
1042 /* try to find PixmapPath in user defaults */
1043 path = wdefaultspathfordomain(domain);
1044 d = WMReadPropListFromFile(path);
1045 if (!d) {
1046 wwarning("could not open domain file %s", path);
1048 wfree(path);
1050 if (d && !WMIsPLDictionary(d)) {
1051 WMReleasePropList(d);
1052 d = NULL;
1054 if (d) {
1055 val = WMGetFromPLDictionary(d, key);
1056 } else {
1057 val = NULL;
1059 /* try to find PixmapPath in global defaults */
1060 if (!val) {
1061 path = globalDefaultsPathForDomain(domain);
1062 if (!path) {
1063 wwarning("could not locate file for domain %s", domain);
1064 d = NULL;
1065 } else {
1066 d = WMReadPropListFromFile(path);
1067 wfree(path);
1070 if (d && !WMIsPLDictionary(d)) {
1071 WMReleasePropList(d);
1072 d = NULL;
1074 if (d) {
1075 val = WMGetFromPLDictionary(d, key);
1077 } else {
1078 val = NULL;
1082 if (val)
1083 WMRetainPropList(val);
1085 WMReleasePropList(key);
1086 if (d)
1087 WMReleasePropList(d);
1089 return val;
1094 char*
1095 getPixmapPath(char *domain)
1097 WMPropList *val;
1098 char *ptr, *data;
1099 int len, i, count;
1101 val = getValueForKey(domain, "PixmapPath");
1103 if (!val || !WMIsPLArray(val)) {
1104 if (val)
1105 WMReleasePropList(val);
1106 return wstrdup("");
1109 count = WMGetPropListItemCount(val);
1110 len = 0;
1111 for (i=0; i<count; i++) {
1112 WMPropList *v;
1114 v = WMGetFromPLArray(val, i);
1115 if (!v || !WMIsPLString(v)) {
1116 continue;
1118 len += strlen(WMGetFromPLString(v))+1;
1121 ptr = data = wmalloc(len+1);
1122 *ptr = 0;
1124 for (i=0; i<count; i++) {
1125 WMPropList *v;
1127 v = WMGetFromPLArray(val, i);
1128 if (!v || !WMIsPLString(v)) {
1129 continue;
1131 strcpy(ptr, WMGetFromPLString(v));
1133 ptr += strlen(WMGetFromPLString(v));
1134 *ptr = ':';
1135 ptr++;
1137 if (i>0)
1138 ptr--; *(ptr--) = 0;
1140 WMReleasePropList(val);
1142 return data;
1146 char*
1147 getFullPixmapPath(char *file)
1149 char *tmp;
1151 if (!PixmapPath || !(tmp = wfindfile(PixmapPath, file))) {
1152 int bsize = 512;
1153 char *path = wmalloc(bsize);
1155 while (!getcwd(path, bsize)) {
1156 bsize += bsize/2;
1157 path = wrealloc(path, bsize);
1160 tmp = wstrconcat(path, "/");
1161 wfree(path);
1162 path = wstrconcat(tmp, file);
1163 wfree(tmp);
1165 return path;
1168 /* the file is in the PixmapPath */
1169 wfree(tmp);
1171 return wstrdup(file);
1176 void
1177 wAbort()
1179 wfatal("aborting");
1180 exit(1);
1185 void
1186 print_help(char *ProgName)
1188 printf("Usage: %s [options] [image]\n", ProgName);
1189 puts("Sets the workspace background to the specified image or a texture and optionally update Window Maker configuration");
1190 puts("");
1191 #define P(m) puts(m)
1192 P(" -display display to use");
1193 P(" -d, --dither dither image");
1194 P(" -m, --match match colors");
1195 P(" -S, --smooth smooth scaled image");
1196 P(" -b, --back-color <color> background color");
1197 P(" -t, --tile tile image");
1198 P(" -e, --center center image");
1199 P(" -s, --scale scale image (default)");
1200 P(" -a, --maxscale scale image and keep aspect ratio");
1201 P(" -u, --update-wmaker update WindowMaker domain database");
1202 P(" -D, --update-domain <domain> update <domain> database");
1203 P(" -c, --colors <cpc> colors per channel to use");
1204 P(" -p, --parse <texture> proplist style texture specification");
1205 P(" -w, --workspace <workspace> update background for the specified workspace");
1206 P(" --version show version of wmsetbg and exit");
1207 P(" --help show this help and exit");
1208 #undef P
1213 void
1214 changeTextureForWorkspace(char *domain, char *texture, int workspace)
1216 WMPropList *array, *val;
1217 char *value;
1218 int j;
1220 val = WMCreatePropListFromDescription(texture);
1221 if (!val) {
1222 wwarning("could not parse texture %s", texture);
1223 return;
1226 array = getValueForKey("WindowMaker", "WorkspaceSpecificBack");
1228 if (!array) {
1229 array = WMCreatePLArray(NULL, NULL);
1232 j = WMGetPropListItemCount(array);
1233 if (workspace >= j) {
1234 WMPropList *empty;
1236 empty = WMCreatePLArray(NULL, NULL);
1238 while (j++ < workspace-1) {
1239 WMAddToPLArray(array, empty);
1241 WMAddToPLArray(array, val);
1242 } else {
1243 WMDeleteFromPLArray(array, workspace);
1244 WMInsertInPLArray(array, workspace, val);
1247 value = WMGetPropListDescription(array, False);
1248 updateDomain(domain, "WorkspaceSpecificBack", value);
1253 main(int argc, char **argv)
1255 int i;
1256 int helperMode = 0;
1257 RContext *rc;
1258 RContextAttributes rattr;
1259 char *style = "spixmap";
1260 char *back_color = "gray20";
1261 char *image_name = NULL;
1262 char *domain = "WindowMaker";
1263 int update=0, cpc=4, render_mode=RDitheredRendering, obey_user=0;
1264 char *texture = NULL;
1265 int workspace = -1;
1267 signal(SIGINT, SIG_DFL);
1268 signal(SIGTERM, SIG_DFL);
1269 signal(SIGQUIT, SIG_DFL);
1270 signal(SIGSEGV, SIG_DFL);
1271 signal(SIGBUS, SIG_DFL);
1272 signal(SIGFPE, SIG_DFL);
1273 signal(SIGABRT, SIG_DFL);
1274 signal(SIGHUP, SIG_DFL);
1275 signal(SIGPIPE, SIG_DFL);
1276 signal(SIGCHLD, SIG_DFL);
1278 WMInitializeApplication("wmsetbg", &argc, argv);
1280 for (i=1; i<argc; i++) {
1281 if (strcmp(argv[i], "-helper")==0) {
1282 helperMode = 1;
1283 } else if (strcmp(argv[i], "-display")==0) {
1284 i++;
1285 if (i>=argc) {
1286 wfatal("too few arguments for %s\n", argv[i-1]);
1287 exit(1);
1289 display = argv[i];
1290 } else if (strcmp(argv[i], "-s")==0
1291 || strcmp(argv[i], "--scale")==0) {
1292 style = "spixmap";
1293 } else if (strcmp(argv[i], "-t")==0
1294 || strcmp(argv[i], "--tile")==0) {
1295 style = "tpixmap";
1296 } else if (strcmp(argv[i], "-e")==0
1297 || strcmp(argv[i], "--center")==0) {
1298 style = "cpixmap";
1299 } else if (strcmp(argv[i], "-a")==0
1300 || strcmp(argv[i], "--maxscale")==0) {
1301 style = "mpixmap";
1302 } else if (strcmp(argv[i], "-d")==0
1303 || strcmp(argv[i], "--dither")==0) {
1304 render_mode = RDitheredRendering;
1305 obey_user++;
1306 } else if (strcmp(argv[i], "-m")==0
1307 || strcmp(argv[i], "--match")==0) {
1308 render_mode = RBestMatchRendering;
1309 obey_user++;
1310 } else if (strcmp(argv[i], "-S")==0
1311 || strcmp(argv[i], "--smooth")==0) {
1312 smooth = True;
1313 } else if (strcmp(argv[i], "-u")==0
1314 || strcmp(argv[i], "--update-wmaker")==0) {
1315 update++;
1316 } else if (strcmp(argv[i], "-D")==0
1317 || strcmp(argv[i], "--update-domain")==0) {
1318 update++;
1319 i++;
1320 if (i>=argc) {
1321 wfatal("too few arguments for %s\n", argv[i-1]);
1322 exit(1);
1324 domain = wstrdup(argv[i]);
1325 } else if (strcmp(argv[i], "-c")==0
1326 || strcmp(argv[i], "--colors")==0) {
1327 i++;
1328 if (i>=argc) {
1329 wfatal("too few arguments for %s\n", argv[i-1]);
1330 exit(1);
1332 if (sscanf(argv[i], "%i", &cpc)!=1) {
1333 wfatal("bad value for colors per channel: \"%s\"\n", argv[i]);
1334 exit(1);
1336 } else if (strcmp(argv[i], "-b")==0
1337 || strcmp(argv[i], "--back-color")==0) {
1338 i++;
1339 if (i>=argc) {
1340 wfatal("too few arguments for %s\n", argv[i-1]);
1341 exit(1);
1343 back_color = argv[i];
1344 } else if (strcmp(argv[i], "-p")==0
1345 || strcmp(argv[i], "--parse")==0) {
1346 i++;
1347 if (i>=argc) {
1348 wfatal("too few arguments for %s\n", argv[i-1]);
1349 exit(1);
1351 texture = argv[i];
1352 } else if (strcmp(argv[i], "-w")==0
1353 || strcmp(argv[i], "--workspace")==0) {
1354 i++;
1355 if (i>=argc) {
1356 wfatal("too few arguments for %s\n", argv[i-1]);
1357 exit(1);
1359 if (sscanf(argv[i], "%i", &workspace)!=1) {
1360 wfatal("bad value for workspace number: \"%s\"",
1361 argv[i]);
1362 exit(1);
1364 } else if (strcmp(argv[i], "--version")==0) {
1366 printf(PROG_VERSION);
1367 exit(0);
1369 } else if (strcmp(argv[i], "--help")==0) {
1370 print_help(argv[0]);
1371 exit(0);
1372 } else if (argv[i][0] != '-') {
1373 image_name = argv[i];
1374 } else {
1375 printf("%s: invalid argument '%s'\n", argv[0], argv[i]);
1376 printf("Try '%s --help' for more information\n", argv[0]);
1377 exit(1);
1380 if (!image_name && !texture && !helperMode) {
1381 printf("%s: you must specify a image file name or a texture\n",
1382 argv[0]);
1383 printf("Try '%s --help' for more information\n", argv[0]);
1384 exit(1);
1388 PixmapPath = getPixmapPath(domain);
1389 if (!smooth) {
1390 WMPropList *val;
1391 #if 0 /* some problem with Alpha... TODO: check if its right */
1392 val = WMGetFromPLDictionary(domain,
1393 WMCreatePLString("SmoothWorkspaceBack"));
1394 #else
1395 val = getValueForKey(domain, "SmoothWorkspaceBack");
1396 #endif
1398 if (val && WMIsPLString(val) && strcasecmp(WMGetFromPLString(val), "YES")==0)
1399 smooth = True;
1402 dpy = XOpenDisplay(display);
1403 if (!dpy) {
1404 wfatal("could not open display");
1405 exit(1);
1407 #if 0
1408 XSynchronize(dpy, 1);
1409 #endif
1411 root = DefaultRootWindow(dpy);
1413 scr = DefaultScreen(dpy);
1415 scrWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
1416 scrHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
1418 if (!obey_user && DefaultDepth(dpy, scr) <= 8)
1419 render_mode = RDitheredRendering;
1421 rattr.flags = RC_RenderMode | RC_ColorsPerChannel
1422 | RC_StandardColormap | RC_DefaultVisual;
1423 rattr.render_mode = render_mode;
1424 rattr.colors_per_channel = cpc;
1425 rattr.standard_colormap_mode = RCreateStdColormap;
1427 rc = RCreateContext(dpy, scr, &rattr);
1429 if (!rc) {
1430 rattr.standard_colormap_mode = RIgnoreStdColormap;
1431 rc = RCreateContext(dpy, scr, &rattr);
1434 if (!rc) {
1435 wfatal("could not initialize wrlib: %s",
1436 RMessageForError(RErrorCode));
1437 exit(1);
1440 if (helperMode) {
1441 /* lower priority, so that it wont use all the CPU */
1442 nice(15);
1444 helperLoop(rc);
1445 } else {
1446 BackgroundTexture *tex;
1447 char buffer[4098];
1449 if (!texture) {
1450 char *image_path = getFullPixmapPath(image_name);
1452 sprintf(buffer, "(%s, \"%s\", %s)", style, image_path, back_color);
1453 wfree(image_path);
1454 texture = (char*)buffer;
1457 if (update && workspace < 0) {
1458 updateDomain(domain, "WorkspaceBack", texture);
1461 tex = parseTexture(rc, texture);
1462 if (!tex)
1463 exit(1);
1465 if (workspace<0)
1466 changeTexture(tex);
1467 else {
1468 /* always update domain */
1469 changeTextureForWorkspace(domain, texture, workspace);
1473 return 0;