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
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
26 * TODO: rewrite, too dirty
32 #include <X11/Xutil.h>
33 #include <X11/Xatom.h>
37 #include <sys/types.h>
40 #include "../src/config.h"
43 # ifdef SOLARIS_XINERAMA /* sucks */
44 # include <X11/extensions/xinerama.h>
46 # include <X11/extensions/Xinerama.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 PROG_VERSION "wmsetbg (Window Maker) 2.8"
70 #define WORKSPACE_COUNT (MAX_WORKSPACES+1)
80 WXineramaInfo xineInfo
;
84 Bool xineStretch
= False
;
87 Pixmap CurrentPixmap
= None
;
88 char *PixmapPath
= NULL
;
90 extern Pixmap
LoadJPEG(RContext
* rc
, char *file_name
, int *width
, int *height
);
92 typedef struct BackgroundTexture
{
100 Pixmap pixmap
; /* for all textures, including solid */
101 int width
; /* size of the pixmap */
107 xineInfo
.screens
= NULL
;
110 # ifdef SOLARIS_XINERAMA
111 if (XineramaGetState(dpy
, scr
)) {
112 XRectangle head
[MAXFRAMEBUFFERS
];
113 unsigned char hints
[MAXFRAMEBUFFERS
];
116 if (XineramaGetInfo(dpy
, scr
, head
, hints
, &xineInfo
.count
)) {
118 xineInfo
.screens
= wmalloc(sizeof(WMRect
) * (xineInfo
.count
+ 1));
120 for (i
= 0; i
< xineInfo
.count
; i
++) {
121 xineInfo
.screens
[i
].pos
.x
= head
[i
].x
;
122 xineInfo
.screens
[i
].pos
.y
= head
[i
].y
;
123 xineInfo
.screens
[i
].size
.width
= head
[i
].width
;
124 xineInfo
.screens
[i
].size
.height
= head
[i
].height
;
128 # else /* !SOLARIS_XINERAMA */
129 if (XineramaIsActive(dpy
)) {
130 XineramaScreenInfo
*xine_screens
;
133 xine_screens
= XineramaQueryScreens(dpy
, &xineInfo
.count
);
135 xineInfo
.screens
= wmalloc(sizeof(WMRect
) * (xineInfo
.count
+ 1));
137 for (i
= 0; i
< xineInfo
.count
; i
++) {
138 xineInfo
.screens
[i
].pos
.x
= xine_screens
[i
].x_org
;
139 xineInfo
.screens
[i
].pos
.y
= xine_screens
[i
].y_org
;
140 xineInfo
.screens
[i
].size
.width
= xine_screens
[i
].width
;
141 xineInfo
.screens
[i
].size
.height
= xine_screens
[i
].height
;
145 # endif /* !SOLARIS_XINERAMA */
146 #endif /* XINERAMA */
149 RImage
*loadImage(RContext
* rc
, char *file
)
154 if (access(file
, F_OK
) != 0) {
155 path
= wfindfile(PixmapPath
, file
);
157 wwarning("%s:could not find image file used in texture", file
);
161 path
= wstrdup(file
);
164 image
= RLoadImage(rc
, path
, 0);
166 wwarning("%s:could not load image file used in texture:%s", path
, RMessageForError(RErrorCode
));
174 applyImage(RContext
* rc
, BackgroundTexture
* texture
, RImage
* image
, char type
,
175 int x
, int y
, int width
, int height
)
180 switch (toupper(type
)) {
183 if (toupper(type
) == 'S') {
187 if (image
->width
* height
> image
->height
* width
) {
189 h
= (width
* image
->height
) / image
->width
;
191 w
= (height
* image
->width
) / image
->height
;
196 if (w
!= image
->width
|| h
!= image
->height
) {
200 simage
= RSmoothScaleImage(image
, w
, h
);
202 simage
= RScaleImage(image
, w
, h
);
206 wwarning("could not scale image:%s", RMessageForError(RErrorCode
));
218 if (!RConvertImage(rc
, image
, &pixmap
)) {
219 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
223 if (image
->width
!= width
|| image
->height
!= height
) {
226 if (image
->height
< height
) {
228 y
+= (height
- h
) / 2;
231 sy
= (image
->height
- height
) / 2;
234 if (image
->width
< width
) {
236 x
+= (width
- w
) / 2;
239 sx
= (image
->width
- width
) / 2;
243 XCopyArea(dpy
, pixmap
, texture
->pixmap
, DefaultGC(dpy
, scr
), sx
, sy
, w
, h
, x
, y
);
245 XCopyArea(dpy
, pixmap
, texture
->pixmap
, DefaultGC(dpy
, scr
), 0, 0, width
, height
,
248 XFreePixmap(dpy
, pixmap
);
250 RReleaseImage(image
);
257 BackgroundTexture
*parseTexture(RContext
* rc
, char *text
)
259 BackgroundTexture
*texture
= NULL
;
260 WMPropList
*texarray
;
266 #define GETSTRORGOTO(val, str, i, label) \
267 val = WMGetFromPLArray(texarray, i);\
268 if (!WMIsPLString(val)) {\
269 wwarning("could not parse texture %s", text);\
272 str = WMGetFromPLString(val)
274 texarray
= WMCreatePropListFromDescription(text
);
275 if (!texarray
|| !WMIsPLArray(texarray
)
276 || (count
= WMGetPropListItemCount(texarray
)) < 2) {
278 wwarning("could not parse texture %s", text
);
280 WMReleasePropList(texarray
);
284 texture
= wmalloc(sizeof(BackgroundTexture
));
285 memset(texture
, 0, sizeof(BackgroundTexture
));
287 GETSTRORGOTO(val
, type
, 0, error
);
289 if (strcasecmp(type
, "solid") == 0) {
295 GETSTRORGOTO(val
, tmp
, 1, error
);
297 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
298 wwarning("could not parse color %s in texture %s", tmp
, text
);
301 XAllocColor(dpy
, DefaultColormap(dpy
, scr
), &color
);
303 pixmap
= XCreatePixmap(dpy
, root
, 8, 8, DefaultDepth(dpy
, scr
));
304 XSetForeground(dpy
, DefaultGC(dpy
, scr
), color
.pixel
);
305 XFillRectangle(dpy
, pixmap
, DefaultGC(dpy
, scr
), 0, 0, 8, 8);
307 texture
->pixmap
= pixmap
;
308 texture
->color
= color
;
311 } else if (strcasecmp(type
, "vgradient") == 0
312 || strcasecmp(type
, "dgradient") == 0 || strcasecmp(type
, "hgradient") == 0) {
314 RColor color1
, color2
;
320 GETSTRORGOTO(val
, tmp
, 1, error
);
322 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
323 wwarning("could not parse color %s in texture %s", tmp
, text
);
327 color1
.red
= color
.red
>> 8;
328 color1
.green
= color
.green
>> 8;
329 color1
.blue
= color
.blue
>> 8;
331 GETSTRORGOTO(val
, tmp
, 2, error
);
333 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
334 wwarning("could not parse color %s in texture %s", tmp
, text
);
338 color2
.red
= color
.red
>> 8;
339 color2
.green
= color
.green
>> 8;
340 color2
.blue
= color
.blue
>> 8;
345 gtype
= RHorizontalGradient
;
351 gtype
= RVerticalGradient
;
356 gtype
= RDiagonalGradient
;
362 image
= RRenderGradient(iwidth
, iheight
, &color1
, &color2
, gtype
);
365 wwarning("could not render gradient texture:%s", RMessageForError(RErrorCode
));
369 if (!RConvertImage(rc
, image
, &pixmap
)) {
370 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
371 RReleaseImage(image
);
375 texture
->width
= image
->width
;
376 texture
->height
= image
->height
;
377 RReleaseImage(image
);
379 texture
->pixmap
= pixmap
;
380 } else if (strcasecmp(type
, "mvgradient") == 0
381 || strcasecmp(type
, "mdgradient") == 0 || strcasecmp(type
, "mhgradient") == 0) {
390 colors
= malloc(sizeof(RColor
*) * (count
- 1));
392 wwarning("out of memory while parsing texture");
395 memset(colors
, 0, sizeof(RColor
*) * (count
- 1));
397 for (i
= 2; i
< count
; i
++) {
398 val
= WMGetFromPLArray(texarray
, i
);
399 if (!WMIsPLString(val
)) {
400 wwarning("could not parse texture %s", text
);
402 for (j
= 0; colors
[j
] != NULL
; j
++)
407 tmp
= WMGetFromPLString(val
);
409 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
410 wwarning("could not parse color %s in texture %s", tmp
, text
);
412 for (j
= 0; colors
[j
] != NULL
; j
++)
417 if (!(colors
[i
- 2] = malloc(sizeof(RColor
)))) {
418 wwarning("out of memory while parsing texture");
420 for (j
= 0; colors
[j
] != NULL
; j
++)
426 colors
[i
- 2]->red
= color
.red
>> 8;
427 colors
[i
- 2]->green
= color
.green
>> 8;
428 colors
[i
- 2]->blue
= color
.blue
>> 8;
434 gtype
= RHorizontalGradient
;
440 gtype
= RVerticalGradient
;
445 gtype
= RDiagonalGradient
;
451 image
= RRenderMultiGradient(iwidth
, iheight
, colors
, gtype
);
453 for (j
= 0; colors
[j
] != NULL
; j
++)
458 wwarning("could not render gradient texture:%s", RMessageForError(RErrorCode
));
462 if (!RConvertImage(rc
, image
, &pixmap
)) {
463 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
464 RReleaseImage(image
);
468 texture
->width
= image
->width
;
469 texture
->height
= image
->height
;
470 RReleaseImage(image
);
472 texture
->pixmap
= pixmap
;
473 } else if (strcasecmp(type
, "cpixmap") == 0
474 || strcasecmp(type
, "spixmap") == 0
475 || strcasecmp(type
, "mpixmap") == 0 || strcasecmp(type
, "tpixmap") == 0) {
477 Pixmap pixmap
= None
;
478 RImage
*image
= NULL
;
482 GETSTRORGOTO(val
, tmp
, 1, error
);
484 if (toupper(type[0]) == 'T' || toupper(type[0]) == 'C')
485 pixmap = LoadJPEG(rc, tmp, &iwidth, &iheight);
489 image
= loadImage(rc
, tmp
);
493 iwidth
= image
->width
;
494 iheight
= image
->height
;
497 GETSTRORGOTO(val
, tmp
, 2, error
);
499 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
500 wwarning("could not parse color %s in texture %s\n", tmp
, text
);
501 RReleaseImage(image
);
504 if (!XAllocColor(dpy
, DefaultColormap(dpy
, scr
), &color
)) {
505 rcolor
.red
= color
.red
>> 8;
506 rcolor
.green
= color
.green
>> 8;
507 rcolor
.blue
= color
.blue
>> 8;
508 RGetClosestXColor(rc
, &rcolor
, &color
);
514 /* for images with a transparent color */
515 if (image
->data
[3]) {
516 RCombineImageWithColor(image
, &rcolor
);
519 switch (toupper(type
[0])) {
521 texture
->width
= iwidth
;
522 texture
->height
= iheight
;
523 if (!pixmap
&& !RConvertImage(rc
, image
, &pixmap
)) {
524 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
525 RReleaseImage(image
);
529 RReleaseImage(image
);
531 texture
->pixmap
= pixmap
;
532 texture
->color
= color
;
539 XCreatePixmap(dpy
, root
, scrWidth
, scrHeight
, DefaultDepth(dpy
, scr
));
540 XSetForeground(dpy
, DefaultGC(dpy
, scr
), color
.pixel
);
541 XFillRectangle(dpy
, tpixmap
, DefaultGC(dpy
, scr
), 0, 0, scrWidth
, scrHeight
);
543 texture
->pixmap
= tpixmap
;
544 texture
->color
= color
;
545 texture
->width
= scrWidth
;
546 texture
->height
= scrHeight
;
549 if (xineInfo
.count
&& ! xineStretch
) {
551 for (i
= 0; i
< xineInfo
.count
; ++i
) {
552 applyImage(rc
, texture
, image
, type
[0],
553 xineInfo
.screens
[i
].pos
.x
, xineInfo
.screens
[i
].pos
.y
,
554 xineInfo
.screens
[i
].size
.width
,
555 xineInfo
.screens
[i
].size
.height
);
558 applyImage(rc
, texture
, image
, type
[0], 0, 0, scrWidth
, scrHeight
);
560 #else /* !XINERAMA */
561 applyImage(rc
, texture
, image
, type
[0], 0, 0, scrWidth
, scrHeight
);
562 #endif /* !XINERAMA */
563 RReleaseImage(image
);
567 } else if (strcasecmp(type
, "thgradient") == 0
568 || strcasecmp(type
, "tvgradient") == 0 || strcasecmp(type
, "tdgradient") == 0) {
570 RColor color1
, color2
;
580 GETSTRORGOTO(val
, file
, 1, error
);
582 GETSTRORGOTO(val
, tmp
, 2, error
);
586 GETSTRORGOTO(val
, tmp
, 3, error
);
588 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
589 wwarning("could not parse color %s in texture %s", tmp
, text
);
593 color1
.red
= color
.red
>> 8;
594 color1
.green
= color
.green
>> 8;
595 color1
.blue
= color
.blue
>> 8;
597 GETSTRORGOTO(val
, tmp
, 4, error
);
599 if (!XParseColor(dpy
, DefaultColormap(dpy
, scr
), tmp
, &color
)) {
600 wwarning("could not parse color %s in texture %s", tmp
, text
);
604 color2
.red
= color
.red
>> 8;
605 color2
.green
= color
.green
>> 8;
606 color2
.blue
= color
.blue
>> 8;
608 image
= loadImage(rc
, file
);
616 gtype
= RHorizontalGradient
;
618 theight
= image
->height
> scrHeight
? scrHeight
: image
->height
;
622 gtype
= RVerticalGradient
;
623 twidth
= image
->width
> scrWidth
? scrWidth
: image
->width
;
627 gtype
= RDiagonalGradient
;
632 gradient
= RRenderGradient(twidth
, theight
, &color1
, &color2
, gtype
);
635 wwarning("could not render texture:%s", RMessageForError(RErrorCode
));
636 RReleaseImage(gradient
);
637 RReleaseImage(image
);
641 tiled
= RMakeTiledImage(image
, twidth
, theight
);
643 wwarning("could not render texture:%s", RMessageForError(RErrorCode
));
644 RReleaseImage(gradient
);
645 RReleaseImage(image
);
648 RReleaseImage(image
);
650 RCombineImagesWithOpaqueness(tiled
, gradient
, opaq
);
651 RReleaseImage(gradient
);
653 if (!RConvertImage(rc
, tiled
, &pixmap
)) {
654 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
655 RReleaseImage(tiled
);
658 texture
->width
= tiled
->width
;
659 texture
->height
= tiled
->height
;
661 RReleaseImage(tiled
);
663 texture
->pixmap
= pixmap
;
664 } else if (strcasecmp(type
, "function") == 0) {
666 void (*initFunc
) (Display
*, Colormap
);
667 RImage
*(*mainFunc
) (int, char **, int, int, int);
671 char *lib
, *func
, **argv
= 0;
676 goto function_cleanup
;
678 /* get the library name */
679 GETSTRORGOTO(val
, lib
, 1, function_cleanup
);
681 /* get the function name */
682 GETSTRORGOTO(val
, func
, 2, function_cleanup
);
685 argv
= (char **)wmalloc(argc
* sizeof(char *));
687 /* get the parameters */
689 for (i
= 0; i
< argc
- 1; i
++) {
690 GETSTRORGOTO(val
, tmp
, 3 + i
, function_cleanup
);
691 argv
[i
+ 1] = wstrdup(tmp
);
694 handle
= dlopen(lib
, RTLD_LAZY
);
696 wwarning("could not find library %s", lib
);
697 goto function_cleanup
;
700 initFunc
= dlsym(handle
, "initWindowMaker");
702 wwarning("could not initialize library %s", lib
);
703 goto function_cleanup
;
705 initFunc(dpy
, DefaultColormap(dpy
, scr
));
707 mainFunc
= dlsym(handle
, func
);
709 wwarning("could not find function %s::%s", lib
, func
);
710 goto function_cleanup
;
712 image
= mainFunc(argc
, argv
, scrWidth
, scrHeight
, 0);
714 if (!RConvertImage(rc
, image
, &pixmap
)) {
715 wwarning("could not convert texture:%s", RMessageForError(RErrorCode
));
716 goto function_cleanup
;
718 texture
->width
= scrWidth
;
719 texture
->height
= scrHeight
;
720 texture
->pixmap
= pixmap
;
726 for (i
= 0; i
< argc
; i
++) {
734 RReleaseImage(image
);
740 wwarning("function textures not supported");
744 wwarning("invalid texture type %s", text
);
748 texture
->spec
= wstrdup(text
);
756 WMReleasePropList(texarray
);
761 void freeTexture(BackgroundTexture
* texture
)
763 if (texture
->solid
) {
764 unsigned long pixel
[1];
766 pixel
[0] = texture
->color
.pixel
;
767 /* dont free black/white pixels */
768 if (pixel
[0] != BlackPixelOfScreen(DefaultScreenOfDisplay(dpy
))
769 && pixel
[0] != WhitePixelOfScreen(DefaultScreenOfDisplay(dpy
)))
770 XFreeColors(dpy
, DefaultColormap(dpy
, scr
), pixel
, 1, 0);
772 if (texture
->pixmap
) {
773 XFreePixmap(dpy
, texture
->pixmap
);
775 wfree(texture
->spec
);
779 void setupTexture(RContext
* rc
, BackgroundTexture
** textures
, int *maxTextures
, int workspace
, char *texture
)
781 BackgroundTexture
*newTexture
= NULL
;
784 /* unset the texture */
786 if (textures
[workspace
] != NULL
) {
787 textures
[workspace
]->refcount
--;
789 if (textures
[workspace
]->refcount
== 0)
790 freeTexture(textures
[workspace
]);
792 textures
[workspace
] = NULL
;
796 if (textures
[workspace
]
797 && strcasecmp(textures
[workspace
]->spec
, texture
) == 0) {
798 /* texture did not change */
802 /* check if the same texture is already created */
803 for (i
= 0; i
< *maxTextures
; i
++) {
804 if (textures
[i
] && strcasecmp(textures
[i
]->spec
, texture
) == 0) {
805 newTexture
= textures
[i
];
811 /* create the texture */
812 newTexture
= parseTexture(rc
, texture
);
817 if (textures
[workspace
] != NULL
) {
819 textures
[workspace
]->refcount
--;
821 if (textures
[workspace
]->refcount
== 0)
822 freeTexture(textures
[workspace
]);
825 newTexture
->refcount
++;
826 textures
[workspace
] = newTexture
;
828 if (*maxTextures
< workspace
)
829 *maxTextures
= workspace
;
832 Pixmap
duplicatePixmap(Pixmap pixmap
, int width
, int height
)
837 /* must open a new display or the RetainPermanent will
838 * leave stuff allocated in RContext unallocated after exit */
839 tmpDpy
= XOpenDisplay(display
);
841 wwarning("could not open display to update background image information");
847 copyP
= XCreatePixmap(tmpDpy
, root
, width
, height
, DefaultDepth(tmpDpy
, scr
));
848 XCopyArea(tmpDpy
, pixmap
, copyP
, DefaultGC(tmpDpy
, scr
), 0, 0, width
, height
, 0, 0);
849 XSync(tmpDpy
, False
);
851 XSetCloseDownMode(tmpDpy
, RetainPermanent
);
852 XCloseDisplay(tmpDpy
);
858 static int dummyErrorHandler(Display
* dpy
, XErrorEvent
* err
)
863 void setPixmapProperty(Pixmap pixmap
)
865 static Atom prop
= 0;
868 unsigned long length
, after
;
873 prop
= XInternAtom(dpy
, "_XROOTPMAP_ID", False
);
878 /* Clear out the old pixmap */
879 XGetWindowProperty(dpy
, root
, prop
, 0L, 1L, False
, AnyPropertyType
,
880 &type
, &format
, &length
, &after
, &data
);
882 if ((type
== XA_PIXMAP
) && (format
== 32) && (length
== 1)) {
883 XSetErrorHandler(dummyErrorHandler
);
884 XKillClient(dpy
, *((Pixmap
*) data
));
886 XSetErrorHandler(NULL
);
887 mode
= PropModeReplace
;
889 mode
= PropModeAppend
;
892 XChangeProperty(dpy
, root
, prop
, XA_PIXMAP
, 32, mode
, (unsigned char *)&pixmap
, 1);
894 XDeleteProperty(dpy
, root
, prop
);
900 void changeTexture(BackgroundTexture
* texture
)
906 if (texture
->solid
) {
907 XSetWindowBackground(dpy
, root
, texture
->color
.pixel
);
909 XSetWindowBackgroundPixmap(dpy
, root
, texture
->pixmap
);
911 XClearWindow(dpy
, root
);
918 pixmap
= duplicatePixmap(texture
->pixmap
, texture
->width
, texture
->height
);
920 setPixmapProperty(pixmap
);
924 int readmsg(int fd
, char *buffer
, int size
)
930 count
= read(fd
, buffer
, size
);
943 * sizeSntexture_spec - sets the texture for workspace n
944 * sizeCn - change background texture to the one for workspace n
945 * sizePpath - set the pixmap search path
948 * size = 4 bytes for length of the message data
950 void helperLoop(RContext
* rc
)
952 BackgroundTexture
*textures
[WORKSPACE_COUNT
];
954 char buffer
[2048], buf
[8];
958 memset(textures
, 0, WORKSPACE_COUNT
* sizeof(BackgroundTexture
*));
963 /* get length of message */
964 if (readmsg(0, buffer
, 4) < 0) {
965 wsyserror("error reading message from Window Maker");
973 memcpy(buf
, buffer
, 4);
978 if (readmsg(0, buffer
, size
) < 0) {
979 wsyserror("error reading message from Window Maker");
988 printf("RECEIVED %s\n", buffer
);
990 if (buffer
[0] != 'P' && buffer
[0] != 'K') {
991 memcpy(buf
, &buffer
[1], 4);
993 workspace
= atoi(buf
);
994 if (workspace
< 0 || workspace
>= WORKSPACE_COUNT
) {
995 wwarning("received message with invalid workspace number %i\n", workspace
);
1000 switch (buffer
[0]) {
1003 printf("set texture %s\n", &buffer
[5]);
1005 setupTexture(rc
, textures
, &maxTextures
, workspace
, &buffer
[5]);
1010 printf("change texture %i\n", workspace
);
1012 if (!textures
[workspace
]) {
1013 changeTexture(textures
[0]);
1015 changeTexture(textures
[workspace
]);
1021 printf("change pixmappath %s\n", &buffer
[1]);
1025 PixmapPath
= wstrdup(&buffer
[1]);
1030 printf("unset workspace %i\n", workspace
);
1032 setupTexture(rc
, textures
, &maxTextures
, workspace
, NULL
);
1037 printf("exit command\n");
1042 wwarning("unknown message received");
1048 void updateDomain(char *domain
, char *key
, char *texture
)
1050 char *program
= "wdwrite";
1052 /* here is a mem leak */
1053 system(wstrconcat("wdwrite ",
1054 wstrconcat(domain
, smooth
? " SmoothWorkspaceBack YES" : " SmoothWorkspaceBack NO")));
1056 execlp(program
, program
, domain
, key
, texture
, NULL
);
1057 wwarning("warning could not run \"%s\"", program
);
1060 char *globalDefaultsPathForDomain(char *domain
)
1064 sprintf(path
, "%s/%s/%s", SYSCONFDIR
, GLOBAL_DEFAULTS_SUBDIR
, domain
);
1066 return wstrdup(path
);
1069 static WMPropList
*getValueForKey(char *domain
, char *keyName
)
1072 WMPropList
*key
, *val
, *d
;
1074 key
= WMCreatePLString(keyName
);
1076 /* try to find PixmapPath in user defaults */
1077 path
= wdefaultspathfordomain(domain
);
1078 d
= WMReadPropListFromFile(path
);
1080 wwarning("could not open domain file %s", path
);
1084 if (d
&& !WMIsPLDictionary(d
)) {
1085 WMReleasePropList(d
);
1089 val
= WMGetFromPLDictionary(d
, key
);
1093 /* try to find PixmapPath in global defaults */
1095 path
= globalDefaultsPathForDomain(domain
);
1097 wwarning("could not locate file for domain %s", domain
);
1100 d
= WMReadPropListFromFile(path
);
1104 if (d
&& !WMIsPLDictionary(d
)) {
1105 WMReleasePropList(d
);
1109 val
= WMGetFromPLDictionary(d
, key
);
1117 WMRetainPropList(val
);
1119 WMReleasePropList(key
);
1121 WMReleasePropList(d
);
1126 char *getPixmapPath(char *domain
)
1132 val
= getValueForKey(domain
, "PixmapPath");
1134 if (!val
|| !WMIsPLArray(val
)) {
1136 WMReleasePropList(val
);
1140 count
= WMGetPropListItemCount(val
);
1142 for (i
= 0; i
< count
; i
++) {
1145 v
= WMGetFromPLArray(val
, i
);
1146 if (!v
|| !WMIsPLString(v
)) {
1149 len
+= strlen(WMGetFromPLString(v
)) + 1;
1152 ptr
= data
= wmalloc(len
+ 1);
1155 for (i
= 0; i
< count
; i
++) {
1158 v
= WMGetFromPLArray(val
, i
);
1159 if (!v
|| !WMIsPLString(v
)) {
1162 strcpy(ptr
, WMGetFromPLString(v
));
1164 ptr
+= strlen(WMGetFromPLString(v
));
1172 WMReleasePropList(val
);
1177 char *getFullPixmapPath(char *file
)
1181 if (!PixmapPath
|| !(tmp
= wfindfile(PixmapPath
, file
))) {
1183 char *path
= wmalloc(bsize
);
1185 while (!getcwd(path
, bsize
)) {
1187 path
= wrealloc(path
, bsize
);
1190 tmp
= wstrconcat(path
, "/");
1192 path
= wstrconcat(tmp
, file
);
1198 /* the file is in the PixmapPath */
1201 return wstrdup(file
);
1210 void print_help(char *ProgName
)
1212 printf("Usage: %s [options] [image]\n", ProgName
);
1213 puts("Sets the workspace background to the specified image or a texture and optionally update Window Maker configuration");
1215 #define P(m) puts(m)
1216 P(" -display display to use");
1217 P(" -d, --dither dither image");
1218 P(" -m, --match match colors");
1219 P(" -S, --smooth smooth scaled image");
1221 P(" -X, --xinerama stretch image across Xinerama heads");
1223 P(" -b, --back-color <color> background color");
1224 P(" -t, --tile tile image");
1225 P(" -e, --center center image");
1226 P(" -s, --scale scale image (default)");
1227 P(" -a, --maxscale scale image and keep aspect ratio");
1228 P(" -u, --update-wmaker update WindowMaker domain database");
1229 P(" -D, --update-domain <domain> update <domain> database");
1230 P(" -c, --colors <cpc> colors per channel to use");
1231 P(" -p, --parse <texture> proplist style texture specification");
1232 P(" -w, --workspace <workspace> update background for the specified workspace");
1233 P(" --version show version of wmsetbg and exit");
1234 P(" --help show this help and exit");
1238 void changeTextureForWorkspace(char *domain
, char *texture
, int workspace
)
1240 WMPropList
*array
, *val
;
1244 val
= WMCreatePropListFromDescription(texture
);
1246 wwarning("could not parse texture %s", texture
);
1250 array
= getValueForKey("WindowMaker", "WorkspaceSpecificBack");
1253 array
= WMCreatePLArray(NULL
, NULL
);
1256 j
= WMGetPropListItemCount(array
);
1257 if (workspace
>= j
) {
1260 empty
= WMCreatePLArray(NULL
, NULL
);
1262 while (j
++ < workspace
- 1) {
1263 WMAddToPLArray(array
, empty
);
1265 WMAddToPLArray(array
, val
);
1267 WMDeleteFromPLArray(array
, workspace
);
1268 WMInsertInPLArray(array
, workspace
, val
);
1271 value
= WMGetPropListDescription(array
, False
);
1272 updateDomain(domain
, "WorkspaceSpecificBack", value
);
1275 int main(int argc
, char **argv
)
1280 RContextAttributes rattr
;
1281 char *style
= "spixmap";
1282 char *back_color
= "gray20";
1283 char *image_name
= NULL
;
1284 char *domain
= "WindowMaker";
1285 int update
= 0, cpc
= 4, render_mode
= RDitheredRendering
, obey_user
= 0;
1286 char *texture
= NULL
;
1289 signal(SIGINT
, SIG_DFL
);
1290 signal(SIGTERM
, SIG_DFL
);
1291 signal(SIGQUIT
, SIG_DFL
);
1292 signal(SIGSEGV
, SIG_DFL
);
1293 signal(SIGBUS
, SIG_DFL
);
1294 signal(SIGFPE
, SIG_DFL
);
1295 signal(SIGABRT
, SIG_DFL
);
1296 signal(SIGHUP
, SIG_DFL
);
1297 signal(SIGPIPE
, SIG_DFL
);
1298 signal(SIGCHLD
, SIG_DFL
);
1300 WMInitializeApplication("wmsetbg", &argc
, argv
);
1302 for (i
= 1; i
< argc
; i
++) {
1303 if (strcmp(argv
[i
], "-helper") == 0) {
1305 } else if (strcmp(argv
[i
], "-display") == 0) {
1308 wfatal("too few arguments for %s\n", argv
[i
- 1]);
1312 } else if (strcmp(argv
[i
], "-s") == 0 || strcmp(argv
[i
], "--scale") == 0) {
1314 } else if (strcmp(argv
[i
], "-t") == 0 || strcmp(argv
[i
], "--tile") == 0) {
1316 } else if (strcmp(argv
[i
], "-e") == 0 || strcmp(argv
[i
], "--center") == 0) {
1318 } else if (strcmp(argv
[i
], "-a") == 0 || strcmp(argv
[i
], "--maxscale") == 0) {
1320 } else if (strcmp(argv
[i
], "-d") == 0 || strcmp(argv
[i
], "--dither") == 0) {
1321 render_mode
= RDitheredRendering
;
1323 } else if (strcmp(argv
[i
], "-m") == 0 || strcmp(argv
[i
], "--match") == 0) {
1324 render_mode
= RBestMatchRendering
;
1326 } else if (strcmp(argv
[i
], "-S") == 0 || strcmp(argv
[i
], "--smooth") == 0) {
1329 } else if (strcmp(argv
[i
], "-X") == 0 || strcmp(argv
[i
], "--xinerama") == 0) {
1332 } else if (strcmp(argv
[i
], "-u") == 0 || strcmp(argv
[i
], "--update-wmaker") == 0) {
1334 } else if (strcmp(argv
[i
], "-D") == 0 || strcmp(argv
[i
], "--update-domain") == 0) {
1338 wfatal("too few arguments for %s\n", argv
[i
- 1]);
1341 domain
= wstrdup(argv
[i
]);
1342 } else if (strcmp(argv
[i
], "-c") == 0 || strcmp(argv
[i
], "--colors") == 0) {
1345 wfatal("too few arguments for %s\n", argv
[i
- 1]);
1348 if (sscanf(argv
[i
], "%i", &cpc
) != 1) {
1349 wfatal("bad value for colors per channel: \"%s\"\n", argv
[i
]);
1352 } else if (strcmp(argv
[i
], "-b") == 0 || strcmp(argv
[i
], "--back-color") == 0) {
1355 wfatal("too few arguments for %s\n", argv
[i
- 1]);
1358 back_color
= argv
[i
];
1359 } else if (strcmp(argv
[i
], "-p") == 0 || strcmp(argv
[i
], "--parse") == 0) {
1362 wfatal("too few arguments for %s\n", argv
[i
- 1]);
1366 } else if (strcmp(argv
[i
], "-w") == 0 || strcmp(argv
[i
], "--workspace") == 0) {
1369 wfatal("too few arguments for %s\n", argv
[i
- 1]);
1372 if (sscanf(argv
[i
], "%i", &workspace
) != 1) {
1373 wfatal("bad value for workspace number: \"%s\"", argv
[i
]);
1376 } else if (strcmp(argv
[i
], "--version") == 0) {
1378 printf(PROG_VERSION
);
1381 } else if (strcmp(argv
[i
], "--help") == 0) {
1382 print_help(argv
[0]);
1384 } else if (argv
[i
][0] != '-') {
1385 image_name
= argv
[i
];
1387 printf("%s: invalid argument '%s'\n", argv
[0], argv
[i
]);
1388 printf("Try '%s --help' for more information\n", argv
[0]);
1392 if (!image_name
&& !texture
&& !helperMode
) {
1393 printf("%s: you must specify a image file name or a texture\n", argv
[0]);
1394 printf("Try '%s --help' for more information\n", argv
[0]);
1398 PixmapPath
= getPixmapPath(domain
);
1401 #if 0 /* some problem with Alpha... TODO: check if its right */
1402 val
= WMGetFromPLDictionary(domain
, WMCreatePLString("SmoothWorkspaceBack"));
1404 val
= getValueForKey(domain
, "SmoothWorkspaceBack");
1407 if (val
&& WMIsPLString(val
) && strcasecmp(WMGetFromPLString(val
), "YES") == 0)
1411 dpy
= XOpenDisplay(display
);
1413 wfatal("could not open display");
1417 XSynchronize(dpy
, 1);
1420 root
= DefaultRootWindow(dpy
);
1422 scr
= DefaultScreen(dpy
);
1424 scrWidth
= WidthOfScreen(DefaultScreenOfDisplay(dpy
));
1425 scrHeight
= HeightOfScreen(DefaultScreenOfDisplay(dpy
));
1430 if (!obey_user
&& DefaultDepth(dpy
, scr
) <= 8)
1431 render_mode
= RDitheredRendering
;
1433 rattr
.flags
= RC_RenderMode
| RC_ColorsPerChannel
| RC_StandardColormap
| RC_DefaultVisual
;
1434 rattr
.render_mode
= render_mode
;
1435 rattr
.colors_per_channel
= cpc
;
1436 rattr
.standard_colormap_mode
= RCreateStdColormap
;
1438 rc
= RCreateContext(dpy
, scr
, &rattr
);
1441 rattr
.standard_colormap_mode
= RIgnoreStdColormap
;
1442 rc
= RCreateContext(dpy
, scr
, &rattr
);
1446 wfatal("could not initialize wrlib: %s", RMessageForError(RErrorCode
));
1451 /* lower priority, so that it wont use all the CPU */
1456 BackgroundTexture
*tex
;
1460 char *image_path
= getFullPixmapPath(image_name
);
1462 sprintf(buffer
, "(%s, \"%s\", %s)", style
, image_path
, back_color
);
1464 texture
= (char *)buffer
;
1467 if (update
&& workspace
< 0) {
1468 updateDomain(domain
, "WorkspaceBack", texture
);
1471 tex
= parseTexture(rc
, texture
);
1478 /* always update domain */
1479 changeTextureForWorkspace(domain
, texture
, workspace
);