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"
54 /* Alfredo please take a look at this function. I don't like the way
55 * it sends the XKillClient. Should it interfere this way with the rest?
56 * This was added by the patch to allow the transparent background for Eterm.
57 * Also for this purpose Eterm have a program named Esetroot.
58 * People wanting that feature can use that instead of wmsetbg. Why do we
59 * need to patch wmsetbg to do this?
60 * In case you want to keep it, please also check the way it does
61 * the PropModeAppend. -Dan */
63 setPixmapProperty(Pixmap pixmap
, Display
*dpy
, Window root
)
67 unsigned long length
, after
;
70 /* This will locate the property, creating it if it doesn't exist */
71 prop
= XInternAtom(dpy
, "_XROOTPMAP_ID", False
);
76 /* Clear out the old pixmap */
77 XGetWindowProperty(dpy
, root
, prop
, 0L, 1L, True
, AnyPropertyType
,
78 &type
, &format
, &length
, &after
, &data
);
80 /* I think this is OK -Alfredo */
81 if ((type
== XA_PIXMAP
) && (format
== 32) && (length
== 1)) {
82 XKillClient(dpy
, *((Pixmap
*)data
));
84 XDeleteProperty(dpy
, root
, prop
);
86 /* I don't understand this one. The atom is *always* created in
87 the previous XInternAtom() -Alfredo */
88 prop
= XInternAtom(dpy
, "_XROOTPMAP_ID", True
);
92 /* Now add the new one. We use PropModeAppend because PropModeReplace
93 doesn't seem to work if there isn't already a property there. */
94 /* Must be something wrong with this code.
95 * Anyways, better do a XGrabServer() between the XDeleteProperty() and
96 * this XChangeProperty() if things will be this way. -Alfredo */
97 XChangeProperty(dpy
, root
, prop
, XA_PIXMAP
, 32, PropModeAppend
,
98 (unsigned char *) &pixmap
, 1);
101 /* Potential resource leak. Must check the rest of the
102 * program for other resources that rely on XCloseDisplay() to
103 * free them. -Alfredo */
104 XSetCloseDownMode(dpy
, RetainPermanent
);
124 char *home
= getenv("HOME");
130 user
= getpwuid(getuid());
153 printf("usage: %s [-options] image\n", ProgName
);
155 puts(" -d dither image");
156 puts(" -m match colors");
157 puts(" -b <color> background color");
158 puts(" -t tile image");
159 puts(" -e center image");
160 puts(" -s scale image (default)");
161 puts(" -u update WindowMaker domain database");
162 puts(" -D <domain> update <domain> database");
163 puts(" -c <cpc> colors per channel to use");
168 defaultsPathForDomain(char *domain
)
173 gspath
= getenv("GNUSTEP_USER_ROOT");
175 strcpy(path
, gspath
);
178 strcpy(path
, gethomedir());
179 strcat(path
, "/GNUstep/");
181 strcat(path
, DEFAULTS_DIR
);
183 strcat(path
, domain
);
185 tmp
= wmalloc(strlen(path
)+2);
192 char *wstrdup(char *str
)
194 return strcpy(wmalloc(strlen(str
)+1), str
);
198 /* Returns an array of pointers to the pixmap paths, doing ~ expansion */
200 getPixmapPath(char *domain
)
204 proplist_t prop
, pixmap_path
, key
, value
;
207 path
= defaultsPathForDomain(domain
);
211 prop
= PLGetProplistWithPath(path
);
212 if (!prop
|| !PLIsDictionary(prop
))
215 key
= PLMakeString("PixmapPath");
216 pixmap_path
= PLGetDictionaryEntry(prop
, key
);
218 if (!pixmap_path
|| !PLIsArray(pixmap_path
))
221 count
= PLGetNumberOfElements(pixmap_path
);
225 ret
= wmalloc(sizeof(char*)*(count
+1));
227 for (i
=0; i
<count
; i
++) {
228 value
= PLGetArrayElement(pixmap_path
, i
);
229 if (!value
|| !PLIsString(value
))
231 ret
[i
] = wstrdup(PLGetString(value
));
232 if (ret
[i
][0]=='~' && ret
[i
][1]=='/') {
233 /* home is statically allocated. Don't free it */
234 char *fullpath
, *home
=gethomedir();
236 fullpath
= wmalloc(strlen(home
)+strlen(ret
[i
]));
237 strcpy(fullpath
, home
);
238 strcat(fullpath
, &ret
[i
][1]);
254 main(int argc
, char **argv
)
258 RContextAttributes rattr
;
259 int screen_number
, default_depth
, i
, style
= WTP_SCALE
;
260 int scr_width
, scr_height
;
263 Pixmap secretBuffer
= None
;
266 char *back_color
= "black";
267 char *image_name
= NULL
;
268 char *domain
= "WindowMaker";
269 char *program
= "wdwrite";
270 int update
=0, cpc
=4, render_mode
=RM_MATCH
, obey_user
=0;
272 double t1
, t2
, total
, t
;
273 struct timeval timev
;
277 ProgName
= strrchr(argv
[0],'/');
284 for (i
=1; i
<argc
; i
++) {
285 if (strcmp(argv
[i
], "-s")==0) {
287 } else if (strcmp(argv
[i
], "-t")==0) {
289 } else if (strcmp(argv
[i
], "-e")==0) {
291 } else if (strcmp(argv
[i
], "-d")==0) {
292 render_mode
= RM_DITHER
;
294 } else if (strcmp(argv
[i
], "-m")==0) {
295 render_mode
= RM_MATCH
;
297 } else if (strcmp(argv
[i
], "-u")==0) {
299 } else if (strcmp(argv
[i
], "-D")==0) {
303 fprintf(stderr
, "too few arguments for %s\n", argv
[i
-1]);
306 domain
= wstrdup(argv
[i
]);
307 } else if (strcmp(argv
[i
], "-c")==0) {
310 fprintf(stderr
, "too few arguments for %s\n", argv
[i
-1]);
313 if (sscanf(argv
[i
], "%i", &cpc
)!=1) {
314 fprintf(stderr
, "bad value for colors per channel: \"%s\"\n", argv
[i
]);
317 } else if (strcmp(argv
[i
], "-b")==0) {
320 fprintf(stderr
, "too few arguments for %s\n", argv
[i
-1]);
323 back_color
= argv
[i
];
324 } else if (strcmp(argv
[i
], "-x")==0) {
325 /* secret option:renders the pixmap in the supplied drawable */
328 sscanf(argv
[i
], "%x", (unsigned*)&secretBuffer
)!=1) {
332 } else if (argv
[i
][0] != '-') {
333 image_name
= argv
[i
];
341 if (image_name
== NULL
) {
346 char *value
= wmalloc(sizeof(image_name
) + 30);
347 char *tmp
=image_name
, **paths
;
350 /* should we read PixmapPath from the same file as we write into ? */
351 paths
= getPixmapPath("WindowMaker");
353 for(i
=0; paths
[i
]!=NULL
; i
++) {
354 if ((tmp
= strstr(image_name
, paths
[i
])) != NULL
&&
356 tmp
+= strlen(paths
[i
]);
357 while(*tmp
=='/') tmp
++;
366 if (style
== WTP_TILE
)
367 strcpy(value
, "(tpixmap, \"");
368 else if (style
== WTP_SCALE
)
369 strcpy(value
, "(spixmap, \"");
371 strcpy(value
, "(cpixmap, \"");
373 strcat(value
, "\", \"");
374 strcat(value
, back_color
);
375 strcat(value
, "\")");
376 execlp(program
, program
, domain
, "WorkspaceBack", value
, NULL
);
377 printf("%s: warning could not run \"%s\"\n", ProgName
, program
);
378 /* Do not exit. At least try to put the image in the background */
379 /* Won't this waste CPU for nothing? We're going to be called again,
380 * anyways. -Alfredo */
381 /* If it fails to update the WindowMaker domain with "wdwrite" we
382 * won't be called again, because Window Maker will not notice any
383 * change. If it reaches this point, this means it failed.
384 * On success it will never get here. -Dan */
388 dpy
= XOpenDisplay("");
390 puts("Could not open display!");
394 XSynchronize(dpy
, True
);
396 screen_number
= DefaultScreen(dpy
);
397 root_win
= RootWindow(dpy
, screen_number
);
398 default_depth
= DefaultDepth(dpy
, screen_number
);
399 scr_width
= WidthOfScreen(ScreenOfDisplay(dpy
, screen_number
));
400 scr_height
= HeightOfScreen(ScreenOfDisplay(dpy
, screen_number
));
402 if (!XParseColor(dpy
, DefaultColormap(dpy
, screen_number
), back_color
,
404 printf("invalid color %s\n", back_color
);
408 if (!obey_user
&& default_depth
<= 8)
409 render_mode
= RM_DITHER
;
411 rattr
.flags
= RC_RenderMode
| RC_ColorsPerChannel
| RC_DefaultVisual
;
412 rattr
.render_mode
= render_mode
;
413 rattr
.colors_per_channel
= cpc
;
415 rcontext
= RCreateContext(dpy
, screen_number
, &rattr
);
417 printf("could not initialize graphics library context: %s\n",
418 RMessageForError(RErrorCode
));
423 gettimeofday(&timev
, NULL
);
424 t1
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
427 image
= RLoadImage(rcontext
, image_name
, 0);
429 gettimeofday(&timev
, NULL
);
430 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
432 printf("load image in %f sec\n", total
);
436 printf("could not load image %s:%s\n", image_name
, RMessageForError(RErrorCode
));
441 gettimeofday(&timev
, NULL
);
442 t1
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
444 if (style
== WTP_SCALE
) {
445 tmp
= RScaleImage(image
, scr_width
, scr_height
);
447 printf("could not scale image: %s\n", image_name
);
450 RDestroyImage(image
);
452 } else if (style
==WTP_CENTER
&& (image
->width
!=scr_width
453 || image
->height
!=scr_height
)) {
456 color
.red
= xcolor
.red
>>8;
457 color
.green
= xcolor
.green
>>8;
458 color
.blue
= xcolor
.blue
>>8;
460 tmp
= RMakeCenteredImage(image
, scr_width
, scr_height
, &color
);
462 printf("could not create centered image: %s\n", image_name
);
465 RDestroyImage(image
);
469 gettimeofday(&timev
, NULL
);
470 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
472 printf("scale image in %f sec\n", total
);
474 gettimeofday(&timev
, NULL
);
475 t1
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
477 RConvertImage(rcontext
, image
, &pixmap
);
479 gettimeofday(&timev
, NULL
);
480 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
482 printf("convert image to pixmap in %f sec\n", total
);
484 printf("total image proccessing in %f sec\n", total
);
486 RDestroyImage(image
);
487 if (secretBuffer
==None
) {
489 setPixmapProperty(pixmap
, dpy
, root_win
);
491 XSetWindowBackgroundPixmap(dpy
, root_win
, pixmap
);
492 XClearWindow(dpy
, root_win
);
494 XCopyArea(dpy
, pixmap
, secretBuffer
, DefaultGC(dpy
, screen_number
),
495 0, 0, scr_width
, scr_height
, 0, 0);
500 gettimeofday(&timev
, NULL
);
501 t2
= (double)timev
.tv_sec
+ (((double)timev
.tv_usec
)/1000000);
503 printf("total proccessing time: %f sec\n", total
);