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,
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
33 #include <sys/types.h>
35 #include "../src/wconfig.h"
51 #ifdef at_one_step_from_the_trash
52 /* Alfredo please take a look at this function. I don't like the way
53 * it sends the XKillClient. Should it interfere this way with the rest?
54 * This was added by the patch to allow the transparent background for Eterm.
55 * Also for this purpose Eterm have a program named Esetroot.
56 * People wanting that feature can use that instead of wmsetbg. Why do we
57 * need to patch wmsetbg to do this?
58 * In case you want to keep it, please also check the way it does
59 * the PropModeAppend. -Dan */
61 setPixmapProperty(Pixmap pixmap
, Display
*dpy
, Window root
)
65 unsigned long length
, after
;
68 /* This will locate the property, creating it if it doesn't exist */
69 prop
= XInternAtom(dpy
, "_XROOTPMAP_ID", False
);
74 /* Clear out the old pixmap */
75 XGetWindowProperty(dpy
, root
, prop
, 0L, 1L, True
, AnyPropertyType
,
76 &type
, &format
, &length
, &after
, &data
);
78 /* I think this is OK -Alfredo */
79 if ((type
== XA_PIXMAP
) && (format
== 32) && (length
== 1)) {
80 XKillClient(dpy
, *((Pixmap
*)data
));
82 XDeleteProperty(dpy
, root
, prop
);
84 /* I don't understand this one. The atom is *always* created in
85 the previous XInternAtom() -Alfredo */
86 prop
= XInternAtom(dpy
, "_XROOTPMAP_ID", True
);
90 /* Now add the new one. We use PropModeAppend because PropModeReplace
91 doesn't seem to work if there isn't already a property there. */
92 /* Must be something wrong with this code.
93 * Anyways, better do a XGrabServer() between the XDeleteProperty() and
94 * this XChangeProperty() if things will be this way. -Alfredo */
95 XChangeProperty(dpy
, root
, prop
, XA_PIXMAP
, 32, PropModeAppend
,
96 (unsigned char *) &pixmap
, 1);
99 /* Potential resource leak. Must check the rest of the
100 * program for other resources that rely on XCloseDisplay() to
101 * free them. -Alfredo */
102 XSetCloseDownMode(dpy
, RetainPermanent
);
122 char *home
= getenv("HOME");
128 user
= getpwuid(getuid());
151 printf("usage: %s [-options] image\n", ProgName
);
153 puts(" -d dither image");
154 puts(" -m match colors");
155 puts(" -b <color> background color");
156 puts(" -t tile image");
157 puts(" -e center image");
158 puts(" -s scale image (default)");
159 puts(" -u update WindowMaker domain database");
160 puts(" -D <domain> update <domain> database");
161 puts(" -c <cpc> colors per channel to use");
166 defaultsPathForDomain(char *domain
)
171 gspath
= getenv("GNUSTEP_USER_ROOT");
173 strcpy(path
, gspath
);
176 strcpy(path
, gethomedir());
177 strcat(path
, "/GNUstep/");
179 strcat(path
, DEFAULTS_DIR
);
181 strcat(path
, domain
);
183 tmp
= wmalloc(strlen(path
)+2);
190 char *wstrdup(char *str
)
192 return strcpy(wmalloc(strlen(str
)+1), str
);
196 /* Returns an array of pointers to the pixmap paths, doing ~ expansion */
198 getPixmapPath(char *domain
)
202 proplist_t prop
, pixmap_path
, key
, value
;
205 path
= defaultsPathForDomain(domain
);
209 prop
= PLGetProplistWithPath(path
);
210 if (!prop
|| !PLIsDictionary(prop
))
213 key
= PLMakeString("PixmapPath");
214 pixmap_path
= PLGetDictionaryEntry(prop
, key
);
216 if (!pixmap_path
|| !PLIsArray(pixmap_path
))
219 count
= PLGetNumberOfElements(pixmap_path
);
223 ret
= wmalloc(sizeof(char*)*(count
+1));
225 for (i
=0; i
<count
; i
++) {
226 value
= PLGetArrayElement(pixmap_path
, i
);
227 if (!value
|| !PLIsString(value
))
229 ret
[i
] = wstrdup(PLGetString(value
));
230 if (ret
[i
][0]=='~' && ret
[i
][1]=='/') {
231 /* home is statically allocated. Don't free it */
232 char *fullpath
, *home
=gethomedir();
234 fullpath
= wmalloc(strlen(home
)+strlen(ret
[i
]));
235 strcpy(fullpath
, home
);
236 strcat(fullpath
, &ret
[i
][1]);
252 main(int argc
, char **argv
)
256 RContextAttributes rattr
;
257 int screen_number
, default_depth
, i
, style
= WTP_SCALE
;
258 int scr_width
, scr_height
;
261 Pixmap secretBuffer
= None
;
264 char *back_color
= "black";
265 char *image_name
= NULL
;
266 char *domain
= "WindowMaker";
267 char *program
= "wdwrite";
268 int update
=0, cpc
=4, render_mode
=RM_MATCH
, obey_user
=0;
270 double t1
, t2
, total
, t
;
271 struct timeval timev
;
275 ProgName
= strrchr(argv
[0],'/');
282 for (i
=1; i
<argc
; i
++) {
283 if (strcmp(argv
[i
], "-s")==0) {
285 } else if (strcmp(argv
[i
], "-t")==0) {
287 } else if (strcmp(argv
[i
], "-e")==0) {
289 } else if (strcmp(argv
[i
], "-d")==0) {
290 render_mode
= RM_DITHER
;
292 } else if (strcmp(argv
[i
], "-m")==0) {
293 render_mode
= RM_MATCH
;
295 } else if (strcmp(argv
[i
], "-u")==0) {
297 } else if (strcmp(argv
[i
], "-D")==0) {
301 fprintf(stderr
, "too few arguments for %s\n", argv
[i
-1]);
304 domain
= wstrdup(argv
[i
]);
305 } else if (strcmp(argv
[i
], "-c")==0) {
308 fprintf(stderr
, "too few arguments for %s\n", argv
[i
-1]);
311 if (sscanf(argv
[i
], "%i", &cpc
)!=1) {
312 fprintf(stderr
, "bad value for colors per channel: \"%s\"\n", argv
[i
]);
315 } else if (strcmp(argv
[i
], "-b")==0) {
318 fprintf(stderr
, "too few arguments for %s\n", argv
[i
-1]);
321 back_color
= argv
[i
];
322 } else if (strcmp(argv
[i
], "-x")==0) {
323 /* secret option:renders the pixmap in the supplied drawable */
326 sscanf(argv
[i
], "%x", (unsigned*)&secretBuffer
)!=1) {
330 } else if (argv
[i
][0] != '-') {
331 image_name
= argv
[i
];
339 if (image_name
== NULL
) {
344 char *value
= wmalloc(sizeof(image_name
) + 30);
345 char *tmp
=image_name
, **paths
;
348 /* should we read PixmapPath from the same file as we write into ? */
349 paths
= getPixmapPath("WindowMaker");
351 for(i
=0; paths
[i
]!=NULL
; i
++) {
352 if ((tmp
= strstr(image_name
, paths
[i
])) != NULL
&&
354 tmp
+= strlen(paths
[i
]);
355 while(*tmp
=='/') tmp
++;
364 if (style
== WTP_TILE
)
365 strcpy(value
, "(tpixmap, \"");
366 else if (style
== WTP_SCALE
)
367 strcpy(value
, "(spixmap, \"");
369 strcpy(value
, "(cpixmap, \"");
371 strcat(value
, "\", \"");
372 strcat(value
, back_color
);
373 strcat(value
, "\")");
374 execlp(program
, program
, domain
, "WorkspaceBack", value
, NULL
);
375 printf("%s: warning could not run \"%s\"\n", ProgName
, program
);
376 /* Do not exit. At least try to put the image in the background */
377 /* Won't this waste CPU for nothing? We're going to be called again,
378 * anyways. -Alfredo */
379 /* If it fails to update the WindowMaker domain with "wdwrite" we
380 * won't be called again, because Window Maker will not notice any
381 * change. If it reaches this point, this means it failed.
382 * On success it will never get here. -Dan */
386 dpy
= XOpenDisplay("");
388 puts("Could not open display!");
392 XSynchronize(dpy
, True
);
394 screen_number
= DefaultScreen(dpy
);
395 root_win
= RootWindow(dpy
, screen_number
);
396 default_depth
= DefaultDepth(dpy
, screen_number
);
397 scr_width
= WidthOfScreen(ScreenOfDisplay(dpy
, screen_number
));
398 scr_height
= HeightOfScreen(ScreenOfDisplay(dpy
, screen_number
));
400 if (!XParseColor(dpy
, DefaultColormap(dpy
, screen_number
), back_color
,
402 printf("invalid color %s\n", back_color
);
406 if (!obey_user
&& default_depth
<= 8)
407 render_mode
= RM_DITHER
;
409 rattr
.flags
= RC_RenderMode
| RC_ColorsPerChannel
| RC_DefaultVisual
;
410 rattr
.render_mode
= render_mode
;
411 rattr
.colors_per_channel
= cpc
;
413 rcontext
= RCreateContext(dpy
, screen_number
, &rattr
);
415 printf("could not initialize graphics library context: %s\n",
416 RMessageForError(RErrorCode
));
421 gettimeofday(&timev
, NULL
);
422 t1
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
425 image
= RLoadImage(rcontext
, image_name
, 0);
427 gettimeofday(&timev
, NULL
);
428 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
430 printf("load image in %f sec\n", total
);
434 printf("could not load image %s:%s\n", image_name
, RMessageForError(RErrorCode
));
439 gettimeofday(&timev
, NULL
);
440 t1
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
442 if (style
== WTP_SCALE
) {
443 tmp
= RScaleImage(image
, scr_width
, scr_height
);
445 printf("could not scale image: %s\n", image_name
);
448 RDestroyImage(image
);
450 } else if (style
==WTP_CENTER
&& (image
->width
!=scr_width
451 || image
->height
!=scr_height
)) {
454 color
.red
= xcolor
.red
>>8;
455 color
.green
= xcolor
.green
>>8;
456 color
.blue
= xcolor
.blue
>>8;
458 tmp
= RMakeCenteredImage(image
, scr_width
, scr_height
, &color
);
460 printf("could not create centered image: %s\n", image_name
);
463 RDestroyImage(image
);
467 gettimeofday(&timev
, NULL
);
468 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
470 printf("scale image in %f sec\n", total
);
472 gettimeofday(&timev
, NULL
);
473 t1
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
475 RConvertImage(rcontext
, image
, &pixmap
);
477 gettimeofday(&timev
, NULL
);
478 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
480 printf("convert image to pixmap in %f sec\n", total
);
482 printf("total image proccessing in %f sec\n", total
);
484 RDestroyImage(image
);
485 if (secretBuffer
==None
) {
486 #ifdef at_one_step_from_the_trash
487 setPixmapProperty(pixmap
, dpy
, root_win
);
489 XSetWindowBackgroundPixmap(dpy
, root_win
, pixmap
);
490 XClearWindow(dpy
, root_win
);
492 XCopyArea(dpy
, pixmap
, secretBuffer
, DefaultGC(dpy
, screen_number
),
493 0, 0, scr_width
, scr_height
, 0, 0);
498 gettimeofday(&timev
, NULL
);
499 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
501 printf("total proccessing time: %f sec\n", total
);