1 /* wmsetbg.c- sets root window background image and also works as
2 * workspace background setting helper for wmaker
4 * WindowMaker window manager
6 * Copyright (c) 1998-2003 Alfredo K. Kojima
7 * Copyright (c) 1998-2003 Dan Pascu
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 along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * TODO: rewrite, too dirty
33 #include <X11/Xutil.h>
34 #include <X11/Xatom.h>
39 #include <sys/types.h>
43 # ifdef SOLARIS_XINERAMA /* sucks */
44 # include <X11/extensions/xinerama.h>
46 # include <X11/extensions/Xinerama.h>
50 #ifdef HAVE_STDNORETURN
51 #include <stdnoreturn.h>
54 #include "../src/wconfig.h"
56 #ifndef GLOBAL_DEFAULTS_SUBDIR
57 #define GLOBAL_DEFAULTS_SUBDIR "WindowMaker"
60 #include <WINGs/WINGs.h>
65 int count
; /* screen count, 0 = inactive */
68 #define WORKSPACE_COUNT (MAX_WORKSPACES+1)
78 WXineramaInfo xineInfo
;
82 Bool xineStretch
= False
;
85 Pixmap CurrentPixmap
= None
;
86 char *PixmapPath
= NULL
;
88 static const char *prog_name
;
90 typedef struct BackgroundTexture
{
98 Pixmap pixmap
; /* for all textures, including solid */
99 int width
; /* size of the pixmap */
103 static noreturn
void quit(int rcode
)
105 WMReleaseApplication();
109 static void initXinerama(void)
111 xineInfo
.screens
= NULL
;
114 # ifdef SOLARIS_XINERAMA
115 if (XineramaGetState(dpy
, scr
)) {
116 XRectangle head
[MAXFRAMEBUFFERS
];
117 unsigned char hints
[MAXFRAMEBUFFERS
];
120 if (XineramaGetInfo(dpy
, scr
, head
, hints
, &xineInfo
.count
)) {
122 xineInfo
.screens
= wmalloc(sizeof(WMRect
) * (xineInfo
.count
+ 1));
124 for (i
= 0; i
< xineInfo
.count
; i
++) {
125 xineInfo
.screens
[i
].pos
.x
= head
[i
].x
;
126 xineInfo
.screens
[i
].pos
.y
= head
[i
].y
;
127 xineInfo
.screens
[i
].size
.width
= head
[i
].width
;
128 xineInfo
.screens
[i
].size
.height
= head
[i
].height
;
132 # else /* !SOLARIS_XINERAMA */
133 if (XineramaIsActive(dpy
)) {
134 XineramaScreenInfo
*xine_screens
;
137 xine_screens
= XineramaQueryScreens(dpy
, &xineInfo
.count
);
139 xineInfo
.screens
= wmalloc(sizeof(WMRect
) * (xineInfo
.count
+ 1));
141 for (i
= 0; i
< xineInfo
.count
; i
++) {
142 xineInfo
.screens
[i
].pos
.x
= xine_screens
[i
].x_org
;
143 xineInfo
.screens
[i
].pos
.y
= xine_screens
[i
].y_org
;
144 xineInfo
.screens
[i
].size
.width
= xine_screens
[i
].width
;
145 xineInfo
.screens
[i
].size
.height
= xine_screens
[i
].height
;
149 # endif /* !SOLARIS_XINERAMA */
150 #endif /* USE_XINERAMA */
153 static RImage
*loadImage(RContext
* rc
, const char *file
)
158 if (access(file
, F_OK
) != 0) {
159 path
= wfindfile(PixmapPath
, file
);
161 wwarning("%s:could not find image file used in texture", file
);
165 path
= wstrdup(file
);
168 image
= RLoadImage(rc
, path
, 0);
170 wwarning("%s:could not load image file used in texture:%s", path
, RMessageForError(RErrorCode
));
178 applyImage(RContext
* rc
, BackgroundTexture
* texture
, RImage
* image
, char type
,
179 int x
, int y
, int width
, int height
)
184 switch (toupper(type
)) {
188 if (toupper(type
) == 'S') {
191 } else if(toupper(type
) == 'F') {
192 if (image
->width
* height
> image
->height
* width
) {
193 w
= (height
* image
->width
) / image
->height
;
197 h
= (width
* image
->height
) / image
->width
;
200 if (image
->width
* height
> image
->height
* width
) {
202 h
= (width
* image
->height
) / image
->width
;
204 w
= (height
* image
->width
) / image
->height
;
209 if (w
!= image
->width
|| h
!= image
->height
) {
213 simage
= RSmoothScaleImage(image
, w
, h
);
215 simage
= RScaleImage(image
, w
, h
);
219 wwarning("could not scale image:%s", RMessageForError(RErrorCode
));
231 if (!RConvertImage(rc
, image
, &pixmap
)) {
232 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
234 RReleaseImage(image
);
238 if (image
->width
!= width
|| image
->height
!= height
) {
241 if (image
->height
< height
) {
243 y
+= (height
- h
) / 2;
246 sy
= (image
->height
- height
) / 2;
249 if (image
->width
< width
) {
251 x
+= (width
- w
) / 2;
254 sx
= (image
->width
- width
) / 2;
258 XCopyArea(dpy
, pixmap
, texture
->pixmap
, DefaultGC(dpy
, scr
), sx
, sy
, w
, h
, x
, y
);
260 XCopyArea(dpy
, pixmap
, texture
->pixmap
, DefaultGC(dpy
, scr
), 0, 0, width
, height
,
263 XFreePixmap(dpy
, pixmap
);
265 RReleaseImage(image
);
272 static BackgroundTexture
*parseTexture(RContext
* rc
, char *text
)
274 BackgroundTexture
*texture
= NULL
;
275 WMPropList
*texarray
;
281 #define GETSTRORGOTO(val, str, i, label) \
282 val = WMGetFromPLArray(texarray, i);\
283 if (!WMIsPLString(val)) {\
284 wwarning("could not parse texture %s", text);\
287 str = WMGetFromPLString(val)
289 texarray
= WMCreatePropListFromDescription(text
);
290 if (!texarray
|| !WMIsPLArray(texarray
)
291 || (count
= WMGetPropListItemCount(texarray
)) < 2) {
293 wwarning("could not parse texture %s", text
);
295 WMReleasePropList(texarray
);
299 texture
= wmalloc(sizeof(BackgroundTexture
));
301 GETSTRORGOTO(val
, type
, 0, error
);
303 if (strcasecmp(type
, "solid") == 0) {
309 GETSTRORGOTO(val
, tmp
, 1, error
);
311 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
312 wwarning("could not parse color %s in texture %s", tmp
, text
);
315 XAllocColor(dpy
, DefaultColormap(dpy
, scr
), &color
);
317 pixmap
= XCreatePixmap(dpy
, root
, 8, 8, DefaultDepth(dpy
, scr
));
318 XSetForeground(dpy
, DefaultGC(dpy
, scr
), color
.pixel
);
319 XFillRectangle(dpy
, pixmap
, DefaultGC(dpy
, scr
), 0, 0, 8, 8);
321 texture
->pixmap
= pixmap
;
322 texture
->color
= color
;
325 } else if (strcasecmp(type
, "vgradient") == 0
326 || strcasecmp(type
, "dgradient") == 0 || strcasecmp(type
, "hgradient") == 0) {
328 RColor color1
, color2
;
331 RGradientStyle gtype
;
334 GETSTRORGOTO(val
, tmp
, 1, error
);
336 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
337 wwarning("could not parse color %s in texture %s", tmp
, text
);
341 color1
.red
= color
.red
>> 8;
342 color1
.green
= color
.green
>> 8;
343 color1
.blue
= color
.blue
>> 8;
345 GETSTRORGOTO(val
, tmp
, 2, error
);
347 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
348 wwarning("could not parse color %s in texture %s", tmp
, text
);
352 color2
.red
= color
.red
>> 8;
353 color2
.green
= color
.green
>> 8;
354 color2
.blue
= color
.blue
>> 8;
359 gtype
= RHorizontalGradient
;
365 gtype
= RVerticalGradient
;
370 gtype
= RDiagonalGradient
;
376 image
= RRenderGradient(iwidth
, iheight
, &color1
, &color2
, gtype
);
379 wwarning("could not render gradient texture:%s", RMessageForError(RErrorCode
));
383 if (!RConvertImage(rc
, image
, &pixmap
)) {
384 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
385 RReleaseImage(image
);
389 texture
->width
= image
->width
;
390 texture
->height
= image
->height
;
391 RReleaseImage(image
);
393 texture
->pixmap
= pixmap
;
394 } else if (strcasecmp(type
, "mvgradient") == 0
395 || strcasecmp(type
, "mdgradient") == 0 || strcasecmp(type
, "mhgradient") == 0) {
401 RGradientStyle gtype
;
404 colors
= malloc(sizeof(RColor
*) * (count
- 1));
406 wwarning("out of memory while parsing texture");
409 memset(colors
, 0, sizeof(RColor
*) * (count
- 1));
411 for (i
= 2; i
< count
; i
++) {
412 val
= WMGetFromPLArray(texarray
, i
);
413 if (!WMIsPLString(val
)) {
414 wwarning("could not parse texture %s", text
);
416 for (j
= 0; colors
[j
] != NULL
; j
++)
421 tmp
= WMGetFromPLString(val
);
423 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
424 wwarning("could not parse color %s in texture %s", tmp
, text
);
426 for (j
= 0; colors
[j
] != NULL
; j
++)
431 if (!(colors
[i
- 2] = malloc(sizeof(RColor
)))) {
432 wwarning("out of memory while parsing texture");
434 for (j
= 0; colors
[j
] != NULL
; j
++)
440 colors
[i
- 2]->red
= color
.red
>> 8;
441 colors
[i
- 2]->green
= color
.green
>> 8;
442 colors
[i
- 2]->blue
= color
.blue
>> 8;
448 gtype
= RHorizontalGradient
;
454 gtype
= RVerticalGradient
;
459 gtype
= RDiagonalGradient
;
465 image
= RRenderMultiGradient(iwidth
, iheight
, colors
, gtype
);
467 for (j
= 0; colors
[j
] != NULL
; j
++)
472 wwarning("could not render gradient texture:%s", RMessageForError(RErrorCode
));
476 if (!RConvertImage(rc
, image
, &pixmap
)) {
477 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
478 RReleaseImage(image
);
482 texture
->width
= image
->width
;
483 texture
->height
= image
->height
;
484 RReleaseImage(image
);
486 texture
->pixmap
= pixmap
;
487 } else if (strcasecmp(type
, "cpixmap") == 0
488 || strcasecmp(type
, "spixmap") == 0 || strcasecmp(type
, "fpixmap") == 0
489 || strcasecmp(type
, "mpixmap") == 0 || strcasecmp(type
, "tpixmap") == 0) {
491 Pixmap pixmap
= None
;
492 RImage
*image
= NULL
;
493 int iwidth
= 0, iheight
= 0;
496 GETSTRORGOTO(val
, tmp
, 1, error
);
498 if (toupper(type[0]) == 'T' || toupper(type[0]) == 'C')
499 pixmap = LoadJPEG(rc, tmp, &iwidth, &iheight);
503 image
= loadImage(rc
, tmp
);
507 iwidth
= image
->width
;
508 iheight
= image
->height
;
511 GETSTRORGOTO(val
, tmp
, 2, error
);
513 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
514 wwarning("could not parse color %s in texture %s", tmp
, text
);
515 RReleaseImage(image
);
518 if (!XAllocColor(dpy
, DefaultColormap(dpy
, scr
), &color
)) {
519 rcolor
.red
= color
.red
>> 8;
520 rcolor
.green
= color
.green
>> 8;
521 rcolor
.blue
= color
.blue
>> 8;
522 RGetClosestXColor(rc
, &rcolor
, &color
);
528 /* for images with a transparent color */
529 if (image
&& image
->data
[3])
530 RCombineImageWithColor(image
, &rcolor
);
532 switch (toupper(type
[0])) {
534 texture
->width
= iwidth
;
535 texture
->height
= iheight
;
536 if (!pixmap
&& !RConvertImage(rc
, image
, &pixmap
)) {
537 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
538 RReleaseImage(image
);
542 texture
->pixmap
= pixmap
;
543 texture
->color
= color
;
551 XCreatePixmap(dpy
, root
, scrWidth
, scrHeight
, DefaultDepth(dpy
, scr
));
552 XSetForeground(dpy
, DefaultGC(dpy
, scr
), color
.pixel
);
553 XFillRectangle(dpy
, tpixmap
, DefaultGC(dpy
, scr
), 0, 0, scrWidth
, scrHeight
);
555 texture
->pixmap
= tpixmap
;
556 texture
->color
= color
;
557 texture
->width
= scrWidth
;
558 texture
->height
= scrHeight
;
564 if (xineInfo
.count
&& ! xineStretch
) {
566 for (i
= 0; i
< xineInfo
.count
; ++i
) {
567 applyImage(rc
, texture
, image
, type
[0],
568 xineInfo
.screens
[i
].pos
.x
, xineInfo
.screens
[i
].pos
.y
,
569 xineInfo
.screens
[i
].size
.width
,
570 xineInfo
.screens
[i
].size
.height
);
573 applyImage(rc
, texture
, image
, type
[0], 0, 0, scrWidth
, scrHeight
);
575 #else /* !USE_XINERAMA */
576 applyImage(rc
, texture
, image
, type
[0], 0, 0, scrWidth
, scrHeight
);
577 #endif /* !USE_XINERAMA */
582 RReleaseImage(image
);
584 } else if (strcasecmp(type
, "thgradient") == 0
585 || strcasecmp(type
, "tvgradient") == 0 || strcasecmp(type
, "tdgradient") == 0) {
587 RColor color1
, color2
;
594 RGradientStyle gtype
;
597 GETSTRORGOTO(val
, file
, 1, error
);
599 GETSTRORGOTO(val
, tmp
, 2, error
);
603 GETSTRORGOTO(val
, tmp
, 3, error
);
605 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
606 wwarning("could not parse color %s in texture %s", tmp
, text
);
610 color1
.red
= color
.red
>> 8;
611 color1
.green
= color
.green
>> 8;
612 color1
.blue
= color
.blue
>> 8;
614 GETSTRORGOTO(val
, tmp
, 4, error
);
616 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
617 wwarning("could not parse color %s in texture %s", tmp
, text
);
621 color2
.red
= color
.red
>> 8;
622 color2
.green
= color
.green
>> 8;
623 color2
.blue
= color
.blue
>> 8;
625 image
= loadImage(rc
, file
);
633 gtype
= RHorizontalGradient
;
635 theight
= image
->height
> scrHeight
? scrHeight
: image
->height
;
639 gtype
= RVerticalGradient
;
640 twidth
= image
->width
> scrWidth
? scrWidth
: image
->width
;
644 gtype
= RDiagonalGradient
;
649 gradient
= RRenderGradient(twidth
, theight
, &color1
, &color2
, gtype
);
652 wwarning("could not render texture:%s", RMessageForError(RErrorCode
));
653 RReleaseImage(image
);
657 tiled
= RMakeTiledImage(image
, twidth
, theight
);
659 wwarning("could not render texture:%s", RMessageForError(RErrorCode
));
660 RReleaseImage(gradient
);
661 RReleaseImage(image
);
664 RReleaseImage(image
);
666 RCombineImagesWithOpaqueness(tiled
, gradient
, opaq
);
667 RReleaseImage(gradient
);
669 if (!RConvertImage(rc
, tiled
, &pixmap
)) {
670 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
671 RReleaseImage(tiled
);
674 texture
->width
= tiled
->width
;
675 texture
->height
= tiled
->height
;
677 RReleaseImage(tiled
);
679 texture
->pixmap
= pixmap
;
680 } else if (strcasecmp(type
, "function") == 0) {
681 /* Leave this in to handle the unlikely case of
682 * someone actually having function textures configured */
683 wwarning("function texture support has been removed");
686 wwarning("invalid texture type %s", text
);
690 texture
->spec
= wstrdup(text
);
698 WMReleasePropList(texarray
);
703 static void freeTexture(BackgroundTexture
* texture
)
705 if (texture
->solid
) {
706 unsigned long pixel
[1];
708 pixel
[0] = texture
->color
.pixel
;
709 /* dont free black/white pixels */
710 if (pixel
[0] != BlackPixelOfScreen(DefaultScreenOfDisplay(dpy
))
711 && pixel
[0] != WhitePixelOfScreen(DefaultScreenOfDisplay(dpy
)))
712 XFreeColors(dpy
, DefaultColormap(dpy
, scr
), pixel
, 1, 0);
714 if (texture
->pixmap
) {
715 XFreePixmap(dpy
, texture
->pixmap
);
717 wfree(texture
->spec
);
721 static void setupTexture(RContext
* rc
, BackgroundTexture
** textures
, int *maxTextures
, int workspace
, char *texture
)
723 BackgroundTexture
*newTexture
= NULL
;
726 /* unset the texture */
728 if (textures
[workspace
] != NULL
) {
729 textures
[workspace
]->refcount
--;
731 if (textures
[workspace
]->refcount
== 0)
732 freeTexture(textures
[workspace
]);
734 textures
[workspace
] = NULL
;
738 if (textures
[workspace
]
739 && strcasecmp(textures
[workspace
]->spec
, texture
) == 0) {
740 /* texture did not change */
744 /* check if the same texture is already created */
745 for (i
= 0; i
< *maxTextures
; i
++) {
746 if (textures
[i
] && strcasecmp(textures
[i
]->spec
, texture
) == 0) {
747 newTexture
= textures
[i
];
753 /* create the texture */
754 newTexture
= parseTexture(rc
, texture
);
759 if (textures
[workspace
] != NULL
) {
761 textures
[workspace
]->refcount
--;
763 if (textures
[workspace
]->refcount
== 0)
764 freeTexture(textures
[workspace
]);
767 newTexture
->refcount
++;
768 textures
[workspace
] = newTexture
;
770 if (*maxTextures
< workspace
)
771 *maxTextures
= workspace
;
774 static Pixmap
duplicatePixmap(Pixmap pixmap
, int width
, int height
)
779 /* must open a new display or the RetainPermanent will
780 * leave stuff allocated in RContext unallocated after exit */
781 tmpDpy
= XOpenDisplay(display
);
783 wwarning("could not open display to update background image information");
789 copyP
= XCreatePixmap(tmpDpy
, root
, width
, height
, DefaultDepth(tmpDpy
, scr
));
790 XCopyArea(tmpDpy
, pixmap
, copyP
, DefaultGC(tmpDpy
, scr
), 0, 0, width
, height
, 0, 0);
791 XSync(tmpDpy
, False
);
793 XSetCloseDownMode(tmpDpy
, RetainPermanent
);
794 XCloseDisplay(tmpDpy
);
800 static int dummyErrorHandler(Display
* dpy
, XErrorEvent
* err
)
802 /* Parameter not used, but tell the compiler that it is ok */
809 static void setPixmapProperty(Pixmap pixmap
)
811 static Atom prop
= 0;
814 unsigned long length
, after
;
819 prop
= XInternAtom(dpy
, "_XROOTPMAP_ID", False
);
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
));
832 XSetErrorHandler(NULL
);
833 mode
= PropModeReplace
;
835 mode
= PropModeAppend
;
838 XChangeProperty(dpy
, root
, prop
, XA_PIXMAP
, 32, mode
, (unsigned char *)&pixmap
, 1);
840 XDeleteProperty(dpy
, root
, prop
);
846 static void changeTexture(BackgroundTexture
* texture
)
852 if (texture
->solid
) {
853 XSetWindowBackground(dpy
, root
, texture
->color
.pixel
);
855 XSetWindowBackgroundPixmap(dpy
, root
, texture
->pixmap
);
857 XClearWindow(dpy
, root
);
864 pixmap
= duplicatePixmap(texture
->pixmap
, texture
->width
, texture
->height
);
866 setPixmapProperty(pixmap
);
870 static int readmsg(int fd
, char *buffer
, int size
)
875 count
= read(fd
, buffer
, size
);
888 * sizeSntexture_spec - sets the texture for workspace n
889 * sizeCn - change background texture to the one for workspace n
890 * sizePpath - set the pixmap search path
893 * size = 4 bytes for length of the message data
895 static noreturn
void helperLoop(RContext
* rc
)
897 BackgroundTexture
*textures
[WORKSPACE_COUNT
];
899 char buffer
[2048], buf
[8];
903 memset(textures
, 0, WORKSPACE_COUNT
* sizeof(BackgroundTexture
*));
908 /* get length of message */
909 if (readmsg(0, buffer
, 4) < 0) {
910 werror("error reading message from Window Maker");
918 memcpy(buf
, buffer
, 4);
921 if (size
< 0 || size
> sizeof(buffer
)) {
922 wfatal("received invalid size %d for message from WindowMaker", size
);
926 werror("received 0-sized message from WindowMaker, trying to continue");
931 if (readmsg(0, buffer
, size
) < 0) {
932 werror("error reading message from Window Maker");
941 printf("RECEIVED %s\n", buffer
);
943 if (buffer
[0] != 'P' && buffer
[0] != 'K') {
944 memcpy(buf
, &buffer
[1], 4);
946 workspace
= atoi(buf
);
947 if (workspace
< 0 || workspace
>= WORKSPACE_COUNT
) {
948 wwarning("received message with invalid workspace number %i", workspace
);
956 printf("set texture %s\n", &buffer
[5]);
958 setupTexture(rc
, textures
, &maxTextures
, workspace
, &buffer
[5]);
963 printf("change texture %i\n", workspace
);
965 if (!textures
[workspace
]) {
966 changeTexture(textures
[0]);
968 changeTexture(textures
[workspace
]);
974 printf("change pixmappath %s\n", &buffer
[1]);
978 PixmapPath
= wstrdup(&buffer
[1]);
983 printf("unset workspace %i\n", workspace
);
985 setupTexture(rc
, textures
, &maxTextures
, workspace
, NULL
);
990 printf("exit command\n");
995 wwarning("unknown message received");
1001 static void updateDomain(const char *domain
, const char *key
, const char *texture
)
1004 char *program
= "wdwrite";
1005 char cmd_smooth
[1024];
1007 snprintf(cmd_smooth
, sizeof(cmd_smooth
),
1008 "wdwrite %s SmoothWorkspaceBack %s",
1009 domain
, smooth
? "YES" : "NO");
1010 result
= system(cmd_smooth
);
1012 werror("error executing system(\"%s\")", cmd_smooth
);
1014 execlp(program
, program
, domain
, key
, texture
, NULL
);
1015 wwarning("warning could not run \"%s\"", program
);
1018 static WMPropList
*getValueForKey(const char *domain
, const char *keyName
)
1021 WMPropList
*key
, *val
, *d
;
1023 key
= WMCreatePLString(keyName
);
1025 /* try to find PixmapPath in user defaults */
1026 path
= wdefaultspathfordomain(domain
);
1027 d
= WMReadPropListFromFile(path
);
1029 wwarning("could not open domain file %s", path
);
1033 if (d
&& !WMIsPLDictionary(d
)) {
1034 WMReleasePropList(d
);
1038 val
= WMGetFromPLDictionary(d
, key
);
1042 /* try to find PixmapPath in global defaults */
1044 path
= wglobaldefaultspathfordomain(domain
);
1046 wwarning("could not locate file for domain %s", domain
);
1049 d
= WMReadPropListFromFile(path
);
1053 if (d
&& !WMIsPLDictionary(d
)) {
1054 WMReleasePropList(d
);
1058 val
= WMGetFromPLDictionary(d
, key
);
1066 WMRetainPropList(val
);
1068 WMReleasePropList(key
);
1070 WMReleasePropList(d
);
1075 static char *getPixmapPath(const char *domain
)
1081 val
= getValueForKey(domain
, "PixmapPath");
1083 if (!val
|| !WMIsPLArray(val
)) {
1085 WMReleasePropList(val
);
1089 count
= WMGetPropListItemCount(val
);
1091 for (i
= 0; i
< count
; i
++) {
1094 v
= WMGetFromPLArray(val
, i
);
1095 if (!v
|| !WMIsPLString(v
)) {
1098 len
+= strlen(WMGetFromPLString(v
)) + 1;
1101 ptr
= data
= wmalloc(len
+ 1);
1104 for (i
= 0; i
< count
; i
++) {
1107 v
= WMGetFromPLArray(val
, i
);
1108 if (!v
|| !WMIsPLString(v
)) {
1111 strcpy(ptr
, WMGetFromPLString(v
));
1113 ptr
+= strlen(WMGetFromPLString(v
));
1121 WMReleasePropList(val
);
1126 static char *getFullPixmapPath(const char *file
)
1130 if (!PixmapPath
|| !(tmp
= wfindfile(PixmapPath
, file
))) {
1132 char *path
= wmalloc(bsize
);
1134 while (!getcwd(path
, bsize
)) {
1136 path
= wrealloc(path
, bsize
);
1139 tmp
= wstrconcat(path
, "/");
1141 path
= wstrconcat(tmp
, file
);
1147 /* the file is in the PixmapPath */
1150 return wstrdup(file
);
1153 static void print_help(void)
1155 printf("Usage: %s [options] [image]\n", prog_name
);
1156 puts("Sets the workspace background to the specified image or a texture and");
1157 puts("optionally update Window Maker configuration");
1159 puts(" -display display to use");
1160 puts(" -d, --dither dither image");
1161 puts(" -m, --match match colors");
1162 puts(" -S, --smooth smooth scaled image");
1164 puts(" -X, --xinerama stretch image across Xinerama heads");
1166 puts(" -b, --back-color <color> background color");
1167 puts(" -t, --tile tile image");
1168 puts(" -e, --center center image");
1169 puts(" -s, --scale scale image (default)");
1170 puts(" -a, --maxscale scale image and keep aspect ratio");
1171 puts(" -f, --fillscale scale image to fill screen and keep aspect ratio");
1172 puts(" -u, --update-wmaker update WindowMaker domain database");
1173 puts(" -D, --update-domain <domain> update <domain> database");
1174 puts(" -c, --colors <cpc> colors per channel to use");
1175 puts(" -p, --parse <texture> proplist style texture specification");
1176 puts(" -w, --workspace <workspace> update background for the specified workspace");
1177 puts(" -v, --version show version of wmsetbg and exit");
1178 puts(" -h, --help show this help and exit");
1181 static void changeTextureForWorkspace(const char *domain
, char *texture
, int workspace
)
1183 WMPropList
*array
, *val
;
1187 val
= WMCreatePropListFromDescription(texture
);
1189 wwarning("could not parse texture %s", texture
);
1193 array
= getValueForKey("WindowMaker", "WorkspaceSpecificBack");
1196 array
= WMCreatePLArray(NULL
, NULL
);
1199 j
= WMGetPropListItemCount(array
);
1200 if (workspace
>= j
) {
1203 empty
= WMCreatePLArray(NULL
, NULL
);
1205 while (j
++ < workspace
- 1) {
1206 WMAddToPLArray(array
, empty
);
1208 WMAddToPLArray(array
, val
);
1210 WMReleasePropList(empty
);
1212 WMDeleteFromPLArray(array
, workspace
);
1213 WMInsertInPLArray(array
, workspace
, val
);
1216 value
= WMGetPropListDescription(array
, False
);
1217 updateDomain(domain
, "WorkspaceSpecificBack", value
);
1219 WMReleasePropList(array
);
1222 int main(int argc
, char **argv
)
1227 RContextAttributes rattr
;
1228 char *style
= "spixmap";
1229 char *back_color
= "gray20";
1230 char *image_name
= NULL
;
1231 char *domain
= "WindowMaker";
1232 int update
= 0, cpc
= 4, obey_user
= 0;
1233 RRenderingMode render_mode
= RDitheredRendering
;
1234 char *texture
= NULL
;
1237 signal(SIGINT
, SIG_DFL
);
1238 signal(SIGTERM
, SIG_DFL
);
1239 signal(SIGQUIT
, SIG_DFL
);
1240 signal(SIGSEGV
, SIG_DFL
);
1241 signal(SIGBUS
, SIG_DFL
);
1242 signal(SIGFPE
, SIG_DFL
);
1243 signal(SIGABRT
, SIG_DFL
);
1244 signal(SIGHUP
, SIG_DFL
);
1245 signal(SIGPIPE
, SIG_DFL
);
1246 signal(SIGCHLD
, SIG_DFL
);
1248 WMInitializeApplication("wmsetbg", &argc
, argv
);
1250 prog_name
= argv
[0];
1251 for (i
= 1; i
< argc
; i
++) {
1252 if (strcmp(argv
[i
], "-helper") == 0) {
1254 } else if (strcmp(argv
[i
], "-display") == 0) {
1257 wfatal("too few arguments for %s", argv
[i
- 1]);
1261 } else if (strcmp(argv
[i
], "-s") == 0 || strcmp(argv
[i
], "--scale") == 0) {
1263 } else if (strcmp(argv
[i
], "-t") == 0 || strcmp(argv
[i
], "--tile") == 0) {
1265 } else if (strcmp(argv
[i
], "-e") == 0 || strcmp(argv
[i
], "--center") == 0) {
1267 } else if (strcmp(argv
[i
], "-a") == 0 || strcmp(argv
[i
], "--maxscale") == 0) {
1269 } else if (strcmp(argv
[i
], "-f") == 0 || strcmp(argv
[i
], "--fillscale") == 0) {
1271 } else if (strcmp(argv
[i
], "-d") == 0 || strcmp(argv
[i
], "--dither") == 0) {
1272 render_mode
= RDitheredRendering
;
1274 } else if (strcmp(argv
[i
], "-m") == 0 || strcmp(argv
[i
], "--match") == 0) {
1275 render_mode
= RBestMatchRendering
;
1277 } else if (strcmp(argv
[i
], "-S") == 0 || strcmp(argv
[i
], "--smooth") == 0) {
1280 } else if (strcmp(argv
[i
], "-X") == 0 || strcmp(argv
[i
], "--xinerama") == 0) {
1283 } else if (strcmp(argv
[i
], "-u") == 0 || strcmp(argv
[i
], "--update-wmaker") == 0) {
1285 } else if (strcmp(argv
[i
], "-D") == 0 || strcmp(argv
[i
], "--update-domain") == 0) {
1289 wfatal("too few arguments for %s", argv
[i
- 1]);
1292 domain
= wstrdup(argv
[i
]);
1293 } else if (strcmp(argv
[i
], "-c") == 0 || strcmp(argv
[i
], "--colors") == 0) {
1296 wfatal("too few arguments for %s", argv
[i
- 1]);
1299 if (sscanf(argv
[i
], "%i", &cpc
) != 1) {
1300 wfatal("bad value for colors per channel: \"%s\"", argv
[i
]);
1303 } else if (strcmp(argv
[i
], "-b") == 0 || strcmp(argv
[i
], "--back-color") == 0) {
1306 wfatal("too few arguments for %s", argv
[i
- 1]);
1309 back_color
= argv
[i
];
1310 } else if (strcmp(argv
[i
], "-p") == 0 || strcmp(argv
[i
], "--parse") == 0) {
1313 wfatal("too few arguments for %s", argv
[i
- 1]);
1317 } else if (strcmp(argv
[i
], "-w") == 0 || strcmp(argv
[i
], "--workspace") == 0) {
1320 wfatal("too few arguments for %s", argv
[i
- 1]);
1323 if (sscanf(argv
[i
], "%i", &workspace
) != 1) {
1324 wfatal("bad value for workspace number: \"%s\"", argv
[i
]);
1327 } else if (strcmp(argv
[i
], "-v") == 0 || strcmp(argv
[i
], "--version") == 0) {
1328 printf("%s (Window Maker %s)\n", prog_name
, VERSION
);
1330 } else if (strcmp(argv
[i
], "-h") == 0 || strcmp(argv
[i
], "--help") == 0) {
1333 } else if (argv
[i
][0] != '-') {
1334 image_name
= argv
[i
];
1336 printf("%s: invalid argument '%s'\n", prog_name
, argv
[i
]);
1337 printf("Try '%s --help' for more information\n", prog_name
);
1341 if (!image_name
&& !texture
&& !helperMode
) {
1342 printf("%s: you must specify a image file name or a texture\n", prog_name
);
1343 printf("Try '%s --help' for more information\n", prog_name
);
1347 PixmapPath
= getPixmapPath(domain
);
1350 /* carlos, don't remove this */
1351 #if 0 /* some problem with Alpha... TODO: check if its right */
1352 val
= WMGetFromPLDictionary(domain
, WMCreatePLString("SmoothWorkspaceBack"));
1354 val
= getValueForKey(domain
, "SmoothWorkspaceBack");
1357 if (val
&& WMIsPLString(val
) && strcasecmp(WMGetFromPLString(val
), "YES") == 0)
1361 dpy
= XOpenDisplay(display
);
1363 wfatal("could not open display");
1367 XSynchronize(dpy
, 1);
1370 root
= DefaultRootWindow(dpy
);
1372 scr
= DefaultScreen(dpy
);
1374 scrWidth
= WidthOfScreen(DefaultScreenOfDisplay(dpy
));
1375 scrHeight
= HeightOfScreen(DefaultScreenOfDisplay(dpy
));
1380 if (!obey_user
&& DefaultDepth(dpy
, scr
) <= 8)
1381 render_mode
= RDitheredRendering
;
1383 rattr
.flags
= RC_RenderMode
| RC_ColorsPerChannel
| RC_StandardColormap
| RC_DefaultVisual
;
1384 rattr
.render_mode
= render_mode
;
1385 rattr
.colors_per_channel
= cpc
;
1386 rattr
.standard_colormap_mode
= RCreateStdColormap
;
1388 rc
= RCreateContext(dpy
, scr
, &rattr
);
1391 rattr
.standard_colormap_mode
= RIgnoreStdColormap
;
1392 rc
= RCreateContext(dpy
, scr
, &rattr
);
1396 wfatal("could not initialize wrlib: %s", RMessageForError(RErrorCode
));
1403 /* lower priority, so that it wont use all the CPU */
1406 wwarning("error could not nice process");
1410 BackgroundTexture
*tex
;
1414 char *image_path
= getFullPixmapPath(image_name
);
1415 snprintf(buffer
, sizeof(buffer
), "(%s, \"%s\", %s)", style
, image_path
, back_color
);
1417 texture
= (char *)buffer
;
1420 if (update
&& workspace
< 0) {
1421 updateDomain(domain
, "WorkspaceBack", texture
);
1424 tex
= parseTexture(rc
, texture
);
1431 /* always update domain */
1432 changeTextureForWorkspace(domain
, texture
, workspace
);
1436 WMReleaseApplication();