1 /* wmsetbg.c- sets root window background image
3 * WindowMaker window manager
5 * Copyright (c) 1998 Dan Pascu
6 * Copyright (c) 1998 Alfredo K. Kojima
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
29 #include <X11/Xutil.h>
30 #include <X11/Xatom.h>
34 #include <sys/types.h>
36 #include "../src/wconfig.h"
53 /* Alfredo please take a look at this function. I don't like the way
54 * it sends the XKillClient. Should it interfere this way with the rest?
55 * This was added by the patch to allow the transparent background for Eterm.
56 * Also for this purpose Eterm have a program named Esetroot.
57 * People wanting that feature can use that instead of wmsetbg. Why do we
58 * need to patch wmsetbg to do this?
59 * In case you want to keep it, please also check the way it does
60 * the PropModeAppend. -Dan */
62 setPixmapProperty(Pixmap pixmap
, Display
*dpy
, Window root
)
66 unsigned long length
, after
;
69 /* This will locate the property, creating it if it doesn't exist */
70 prop
= XInternAtom(dpy
, "_XROOTPMAP_ID", False
);
75 /* Clear out the old pixmap */
76 XGetWindowProperty(dpy
, root
, prop
, 0L, 1L, True
, AnyPropertyType
,
77 &type
, &format
, &length
, &after
, &data
);
79 if ((type
== XA_PIXMAP
) && (format
== 32) && (length
== 1)) {
80 XKillClient(dpy
, *((Pixmap
*)data
));
82 XDeleteProperty(dpy
, root
, prop
);
84 prop
= XInternAtom(dpy
, "_XROOTPMAP_ID", True
);
88 /* Now add the new one. We use PropModeAppend because PropModeReplace
89 doesn't seem to work if there isn't already a property there. */
90 XChangeProperty(dpy
, root
, prop
, XA_PIXMAP
, 32, PropModeAppend
,
91 (unsigned char *) &pixmap
, 1);
94 XSetCloseDownMode(dpy
, RetainPermanent
);
114 char *home
= getenv("HOME");
120 user
= getpwuid(getuid());
143 printf("usage: %s [-options] image\n", ProgName
);
145 puts(" -d dither image");
146 puts(" -m match colors");
147 puts(" -b <color> background color");
148 puts(" -t tile image");
149 puts(" -e center image");
150 puts(" -s scale image (default)");
151 puts(" -u update WindowMaker domain database");
152 puts(" -D <domain> update <domain> database");
153 puts(" -c <cpc> colors per channel to use");
158 defaultsPathForDomain(char *domain
)
163 gspath
= getenv("GNUSTEP_USER_ROOT");
165 strcpy(path
, gspath
);
168 strcpy(path
, gethomedir());
169 strcat(path
, "/GNUstep/");
171 strcat(path
, DEFAULTS_DIR
);
173 strcat(path
, domain
);
175 tmp
= wmalloc(strlen(path
)+2);
182 char *wstrdup(char *str
)
184 return strcpy(wmalloc(strlen(str
)+1), str
);
188 /* Returns an array of pointers to the pixmap paths, doing ~ expansion */
190 getPixmapPath(char *domain
)
194 proplist_t prop
, pixmap_path
, key
, value
;
197 path
= defaultsPathForDomain(domain
);
201 prop
= PLGetProplistWithPath(path
);
202 if (!prop
|| !PLIsDictionary(prop
))
205 key
= PLMakeString("PixmapPath");
206 pixmap_path
= PLGetDictionaryEntry(prop
, key
);
208 if (!pixmap_path
|| !PLIsArray(pixmap_path
))
211 count
= PLGetNumberOfElements(pixmap_path
);
215 ret
= wmalloc(sizeof(char*)*(count
+1));
217 for (i
=0; i
<count
; i
++) {
218 value
= PLGetArrayElement(pixmap_path
, i
);
219 if (!value
|| !PLIsString(value
))
221 ret
[i
] = wstrdup(PLGetString(value
));
222 if (ret
[i
][0]=='~' && ret
[i
][1]=='/') {
223 /* home is statically allocated. Don't free it */
224 char *fullpath
, *home
=gethomedir();
226 fullpath
= wmalloc(strlen(home
)+strlen(ret
[i
]));
227 strcpy(fullpath
, home
);
228 strcat(fullpath
, &ret
[i
][1]);
239 main(int argc
, char **argv
)
243 RContextAttributes rattr
;
244 int screen_number
, default_depth
, i
, style
= WTP_SCALE
;
245 int scr_width
, scr_height
;
248 Pixmap secretBuffer
= None
;
251 char *back_color
= "black";
252 char *image_name
= NULL
;
253 char *domain
= "WindowMaker";
254 char *program
= "wdwrite";
255 int update
=0, cpc
=4, render_mode
=RM_MATCH
, obey_user
=0;
257 double t1
, t2
, total
, t
;
258 struct timeval timev
;
262 ProgName
= strrchr(argv
[0],'/');
269 for (i
=1; i
<argc
; i
++) {
270 if (strcmp(argv
[i
], "-s")==0) {
272 } else if (strcmp(argv
[i
], "-t")==0) {
274 } else if (strcmp(argv
[i
], "-e")==0) {
276 } else if (strcmp(argv
[i
], "-d")==0) {
277 render_mode
= RM_DITHER
;
279 } else if (strcmp(argv
[i
], "-m")==0) {
280 render_mode
= RM_MATCH
;
282 } else if (strcmp(argv
[i
], "-u")==0) {
284 } else if (strcmp(argv
[i
], "-D")==0) {
288 fprintf(stderr
, "too few arguments for %s\n", argv
[i
-1]);
291 domain
= wstrdup(argv
[i
]);
292 } else if (strcmp(argv
[i
], "-c")==0) {
295 fprintf(stderr
, "too few arguments for %s\n", argv
[i
-1]);
298 if (sscanf(argv
[i
], "%i", &cpc
)!=1) {
299 fprintf(stderr
, "bad value for colors per channel: \"%s\"\n", argv
[i
]);
302 } else if (strcmp(argv
[i
], "-b")==0) {
305 fprintf(stderr
, "too few arguments for %s\n", argv
[i
-1]);
308 back_color
= argv
[i
];
309 } else if (strcmp(argv
[i
], "-x")==0) {
310 /* secret option:renders the pixmap in the supplied drawable */
313 sscanf(argv
[i
], "%x", (unsigned*)&secretBuffer
)!=1) {
317 } else if (argv
[i
][0] != '-') {
318 image_name
= argv
[i
];
326 if (image_name
== NULL
) {
331 char *value
= wmalloc(sizeof(image_name
) + 30);
332 char *tmp
=image_name
, **paths
;
335 /* should we read PixmapPath from the same file as we write into ? */
336 paths
= getPixmapPath("WindowMaker");
338 for(i
=0; paths
[i
]!=NULL
; i
++) {
339 if ((tmp
= strstr(image_name
, paths
[i
])) != NULL
&&
341 tmp
+= strlen(paths
[i
]);
342 while(*tmp
=='/') tmp
++;
351 if (style
== WTP_TILE
)
352 strcpy(value
, "(tpixmap, \"");
353 else if (style
== WTP_SCALE
)
354 strcpy(value
, "(spixmap, \"");
356 strcpy(value
, "(cpixmap, \"");
358 strcat(value
, "\", \"");
359 strcat(value
, back_color
);
360 strcat(value
, "\")");
361 execlp(program
, program
, domain
, "WorkspaceBack", value
, NULL
);
362 printf("%s: warning could not run \"%s\"\n", ProgName
, program
);
363 /* Do not exit. At least try to put the image in the background */
364 /* Won't this waste CPU for nothing? We're going to be called again,
365 * anyways. -Alfredo */
366 /* If it fails to update the WindowMaker domain with "wdwrite" we
367 * won't be called again, because Window Maker will not notice any
368 * change. If it reaches this point, this means it failed.
369 * On success it will never get here. -Dan */
373 dpy
= XOpenDisplay("");
375 puts("Could not open display!");
379 XSynchronize(dpy
, True
);
381 screen_number
= DefaultScreen(dpy
);
382 root_win
= RootWindow(dpy
, screen_number
);
383 default_depth
= DefaultDepth(dpy
, screen_number
);
384 scr_width
= WidthOfScreen(ScreenOfDisplay(dpy
, screen_number
));
385 scr_height
= HeightOfScreen(ScreenOfDisplay(dpy
, screen_number
));
387 if (!XParseColor(dpy
, DefaultColormap(dpy
, screen_number
), back_color
,
389 printf("invalid color %s\n", back_color
);
393 if (!obey_user
&& default_depth
<= 8)
394 render_mode
= RM_DITHER
;
396 rattr
.flags
= RC_RenderMode
| RC_ColorsPerChannel
| RC_DefaultVisual
;
397 rattr
.render_mode
= render_mode
;
398 rattr
.colors_per_channel
= cpc
;
400 rcontext
= RCreateContext(dpy
, screen_number
, &rattr
);
402 printf("could not initialize graphics library context: %s\n",
408 gettimeofday(&timev
, NULL
);
409 t1
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
412 image
= RLoadImage(rcontext
, image_name
, 0);
414 gettimeofday(&timev
, NULL
);
415 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
417 printf("load image in %f sec\n", total
);
421 printf("could not load image %s:%s\n", image_name
, RErrorString
);
426 gettimeofday(&timev
, NULL
);
427 t1
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
429 if (style
== WTP_SCALE
) {
430 tmp
= RScaleImage(image
, scr_width
, scr_height
);
432 printf("could not scale image: %s\n", image_name
);
435 RDestroyImage(image
);
437 } else if (style
==WTP_CENTER
&& (image
->width
!=scr_width
438 || image
->height
!=scr_height
)) {
441 color
.red
= xcolor
.red
>>8;
442 color
.green
= xcolor
.green
>>8;
443 color
.blue
= xcolor
.blue
>>8;
445 tmp
= RMakeCenteredImage(image
, scr_width
, scr_height
, &color
);
447 printf("could not create centered image: %s\n", image_name
);
450 RDestroyImage(image
);
454 gettimeofday(&timev
, NULL
);
455 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
457 printf("scale image in %f sec\n", total
);
459 gettimeofday(&timev
, NULL
);
460 t1
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
462 RConvertImage(rcontext
, image
, &pixmap
);
464 gettimeofday(&timev
, NULL
);
465 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
467 printf("convert image to pixmap in %f sec\n", total
);
469 printf("total image proccessing in %f sec\n", total
);
471 RDestroyImage(image
);
472 if (secretBuffer
==None
) {
473 setPixmapProperty(pixmap
, dpy
, root_win
);
474 XSetWindowBackgroundPixmap(dpy
, root_win
, pixmap
);
475 XClearWindow(dpy
, root_win
);
477 XCopyArea(dpy
, pixmap
, secretBuffer
, DefaultGC(dpy
, screen_number
),
478 0, 0, scr_width
, scr_height
, 0, 0);
483 gettimeofday(&timev
, NULL
);
484 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
486 printf("total proccessing time: %f sec\n", total
);