xsetroot.c revision f40e0d56
1/*
2 * $Xorg: xsetroot.c,v 1.4 2001/02/09 02:05:59 xorgcvs Exp $
3 *
4Copyright 1987, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25 */
26
27/*
28 * xsetroot.c 	MIT Project Athena, X Window System root window
29 *		parameter setting utility.  This program will set
30 *		various parameters of the X root window.
31 *
32 *  Author:	Mark Lillibridge, MIT Project Athena
33 *		11-Jun-87
34 */
35/* $XFree86: xc/programs/xsetroot/xsetroot.c,v 1.7 2001/04/01 14:00:24 tsi Exp $ */
36
37#include <X11/Xlib.h>
38#include <X11/Xutil.h>
39#include <X11/Xatom.h>
40#include <X11/Xmu/CurUtil.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include "X11/bitmaps/gray"
45
46#define Dynamic 1
47
48static char *program_name;
49static Display *dpy;
50static int screen;
51static Window root;
52static char *fore_color = NULL;
53static char *back_color = NULL;
54static int reverse = 0;
55static int save_colors = 0;
56static int unsave_past = 0;
57static Pixmap save_pixmap = (Pixmap)None;
58
59static void usage(void);
60static void FixupState(void);
61static void SetBackgroundToBitmap(Pixmap bitmap,
62				  unsigned int width, unsigned int height);
63static Cursor CreateCursorFromFiles(char *cursor_file, char *mask_file);
64static Cursor CreateCursorFromName(char *name);
65static Pixmap MakeModulaBitmap(int mod_x, int mod_y);
66static XColor NameToXColor(char *name, unsigned long pixel);
67static unsigned long NameToPixel(char *name, unsigned long pixel);
68static Pixmap ReadBitmapFile(char *filename, unsigned int *width, unsigned int *height, int *x_hot, int *y_hot);
69
70static void
71usage(void)
72{
73    fprintf(stderr, "usage: %s [options]\n", program_name);
74    fprintf(stderr, "  where options are:\n");
75    fprintf(stderr, "  -display <display>   or   -d <display>\n");
76    fprintf(stderr, "  -fg <color>   or   -foreground <color>\n");
77    fprintf(stderr, "  -bg <color>   or   -background <color>\n");
78    fprintf(stderr, "  -rv   or   -reverse\n");
79    fprintf(stderr, "  -help\n");
80    fprintf(stderr, "  -def   or   -default\n");
81    fprintf(stderr, "  -name <string>\n");
82    fprintf(stderr, "  -cursor <cursor file> <mask file>\n");
83    fprintf(stderr, "  -cursor_name <cursor-font name>\n");
84    fprintf(stderr, "  -solid <color>\n");
85    fprintf(stderr, "  -gray   or   -grey\n");
86    fprintf(stderr, "  -bitmap <filename>\n");
87    fprintf(stderr, "  -mod <x> <y>\n");
88    exit(1);
89    /*NOTREACHED*/
90}
91
92
93int
94main(int argc, char *argv[])
95{
96    int excl = 0;
97    int nonexcl = 0;
98    int restore_defaults = 0;
99    char *display_name = NULL;
100    char *name = NULL;
101    char *cursor_file = NULL;
102    char *cursor_mask = NULL;
103    char *cursor_name = NULL;
104    char *solid_color = NULL;
105    Cursor cursor;
106    int gray = 0;
107    char *bitmap_file = NULL;
108    int mod_x = 0;
109    int mod_y = 0;
110    register int i;
111    unsigned int ww, hh;
112    Pixmap bitmap;
113
114    program_name=argv[0];
115
116    for (i = 1; i < argc; i++) {
117	if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) {
118	    if (++i>=argc) usage ();
119	    display_name = argv[i];
120	    continue;
121	}
122	if (!strcmp("-help", argv[i])) {
123	    usage();
124	}
125	if (!strcmp("-def", argv[i]) || !strcmp("-default", argv[i])) {
126	    restore_defaults = 1;
127	    continue;
128	}
129	if (!strcmp("-name", argv[i])) {
130	    if (++i>=argc) usage();
131	    name = argv[i];
132	    nonexcl++;
133	    continue;
134	}
135	if (!strcmp("-cursor", argv[i])) {
136	    if (++i>=argc) usage();
137	    cursor_file = argv[i];
138	    if (++i>=argc) usage();
139	    cursor_mask = argv[i];
140	    nonexcl++;
141	    continue;
142	}
143	if (!strcmp("-cursor_name", argv[i])) {
144	    if (++i>=argc) usage();
145	    cursor_name = argv[i];
146	    nonexcl++;
147	    continue;
148	}
149	if (!strcmp("-fg",argv[i]) || !strcmp("-foreground",argv[i])) {
150	    if (++i>=argc) usage();
151	    fore_color = argv[i];
152	    continue;
153	}
154	if (!strcmp("-bg",argv[i]) || !strcmp("-background",argv[i])) {
155	    if (++i>=argc) usage();
156	    back_color = argv[i];
157	    continue;
158	}
159	if (!strcmp("-solid", argv[i])) {
160	    if (++i>=argc) usage();
161	    solid_color = argv[i];
162	    excl++;
163	    continue;
164	}
165	if (!strcmp("-gray", argv[i]) || !strcmp("-grey", argv[i])) {
166	    gray = 1;
167	    excl++;
168	    continue;
169	}
170	if (!strcmp("-bitmap", argv[i])) {
171	    if (++i>=argc) usage();
172	    bitmap_file = argv[i];
173	    excl++;
174	    continue;
175	}
176	if (!strcmp("-mod", argv[i])) {
177	    if (++i>=argc) usage();
178	    mod_x = atoi(argv[i]);
179	    if (mod_x <= 0) mod_x = 1;
180	    if (++i>=argc) usage();
181	    mod_y = atoi(argv[i]);
182	    if (mod_y <= 0) mod_y = 1;
183	    excl++;
184	    continue;
185	}
186	if (!strcmp("-rv",argv[i]) || !strcmp("-reverse",argv[i])) {
187	    reverse = 1;
188	    continue;
189	}
190	usage();
191    }
192
193    /* Check for multiple use of exclusive options */
194    if (excl > 1) {
195	fprintf(stderr, "%s: choose only one of {solid, gray, bitmap, mod}\n",
196		program_name);
197	usage();
198    }
199
200    dpy = XOpenDisplay(display_name);
201    if (!dpy) {
202	fprintf(stderr, "%s:  unable to open display '%s'\n",
203		program_name, XDisplayName (display_name));
204	exit (2);
205    }
206    screen = DefaultScreen(dpy);
207    root = RootWindow(dpy, screen);
208
209    /* If there are no arguments then restore defaults. */
210    if (!excl && !nonexcl)
211	restore_defaults = 1;
212
213    /* Handle a cursor file */
214    if (cursor_file) {
215	cursor = CreateCursorFromFiles(cursor_file, cursor_mask);
216	XDefineCursor(dpy, root, cursor);
217	XFreeCursor(dpy, cursor);
218    }
219
220    if (cursor_name) {
221	cursor = CreateCursorFromName (cursor_name);
222	if (cursor)
223	{
224	    XDefineCursor (dpy, root, cursor);
225	    XFreeCursor (dpy, cursor);
226	}
227    }
228    /* Handle -gray and -grey options */
229    if (gray) {
230	bitmap = XCreateBitmapFromData(dpy, root, gray_bits,
231				       gray_width, gray_height);
232	SetBackgroundToBitmap(bitmap, gray_width, gray_height);
233    }
234
235    /* Handle -solid option */
236    if (solid_color) {
237	XSetWindowBackground(dpy, root, NameToPixel(solid_color,
238						    BlackPixel(dpy, screen)));
239	XClearWindow(dpy, root);
240	unsave_past = 1;
241    }
242
243    /* Handle -bitmap option */
244    if (bitmap_file) {
245	bitmap = ReadBitmapFile(bitmap_file, &ww, &hh, (int *)NULL, (int *)NULL);
246	SetBackgroundToBitmap(bitmap, ww, hh);
247    }
248
249    /* Handle set background to a modula pattern */
250    if (mod_x) {
251	bitmap = MakeModulaBitmap(mod_x, mod_y);
252	SetBackgroundToBitmap(bitmap, 16, 16);
253    }
254
255    /* Handle set name */
256    if (name)
257	XStoreName(dpy, root, name);
258
259    /* Handle restore defaults */
260    if (restore_defaults) {
261	if (!cursor_file)
262	    XUndefineCursor(dpy, root);
263	if (!excl) {
264	    XSetWindowBackgroundPixmap(dpy, root, (Pixmap) None);
265	    XClearWindow(dpy, root);
266	    unsave_past = 1;
267	}
268    }
269
270    FixupState();
271    XCloseDisplay(dpy);
272    exit (0);
273}
274
275
276/* Free past incarnation if needed, and retain state if needed. */
277static void
278FixupState(void)
279{
280    Atom prop, type;
281    int format;
282    unsigned long length, after;
283    unsigned char *data;
284
285    if (!(DefaultVisual(dpy, screen)->class & Dynamic))
286	unsave_past = 0;
287    if (!unsave_past && !save_colors)
288	return;
289    prop = XInternAtom(dpy, "_XSETROOT_ID", False);
290    if (unsave_past) {
291	(void)XGetWindowProperty(dpy, root, prop, 0L, 1L, True, AnyPropertyType,
292				 &type, &format, &length, &after, &data);
293	if ((type == XA_PIXMAP) && (format == 32) &&
294	    (length == 1) && (after == 0))
295	    XKillClient(dpy, *((Pixmap *)data));
296	else if (type != None)
297	    fprintf(stderr, "%s: warning: _XSETROOT_ID property is garbage\n",
298		    program_name);
299    }
300    if (save_colors) {
301	if (!save_pixmap)
302	    save_pixmap = XCreatePixmap(dpy, root, 1, 1, 1);
303	XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, PropModeReplace,
304			(unsigned char *) &save_pixmap, 1);
305	XSetCloseDownMode(dpy, RetainPermanent);
306    }
307}
308
309/*
310 * SetBackgroundToBitmap: Set the root window background to a caller supplied
311 *                        bitmap.
312 */
313static void
314SetBackgroundToBitmap(Pixmap bitmap, unsigned int width, unsigned int height)
315{
316    Pixmap pix;
317    GC gc;
318    XGCValues gc_init;
319
320    gc_init.foreground = NameToPixel(fore_color, BlackPixel(dpy, screen));
321    gc_init.background = NameToPixel(back_color, WhitePixel(dpy, screen));
322    if (reverse) {
323	unsigned long temp=gc_init.foreground;
324	gc_init.foreground=gc_init.background;
325	gc_init.background=temp;
326    }
327    gc = XCreateGC(dpy, root, GCForeground|GCBackground, &gc_init);
328    pix = XCreatePixmap(dpy, root, width, height,
329			(unsigned int)DefaultDepth(dpy, screen));
330    XCopyPlane(dpy, bitmap, pix, gc, 0, 0, width, height, 0, 0, (unsigned long)1);
331    XSetWindowBackgroundPixmap(dpy, root, pix);
332    XFreeGC(dpy, gc);
333    XFreePixmap(dpy, bitmap);
334    if (save_colors)
335	save_pixmap = pix;
336    else
337	XFreePixmap(dpy, pix);
338    XClearWindow(dpy, root);
339    unsave_past = 1;
340}
341
342
343/*
344 * CreateCursorFromFiles: make a cursor of the right colors from two bitmap
345 *                        files.
346 */
347#define BITMAP_HOT_DEFAULT 8
348
349static Cursor
350CreateCursorFromFiles(char *cursor_file, char *mask_file)
351{
352    Pixmap cursor_bitmap, mask_bitmap;
353    unsigned int width, height, ww, hh;
354    int x_hot, y_hot;
355    Cursor cursor;
356    XColor fg, bg, temp;
357
358    fg = NameToXColor(fore_color, BlackPixel(dpy, screen));
359    bg = NameToXColor(back_color, WhitePixel(dpy, screen));
360    if (reverse) {
361	temp = fg; fg = bg; bg = temp;
362    }
363
364    cursor_bitmap = ReadBitmapFile(cursor_file, &width, &height, &x_hot, &y_hot);
365    mask_bitmap = ReadBitmapFile(mask_file, &ww, &hh, (int *)NULL, (int *)NULL);
366
367    if (width != ww || height != hh) {
368	fprintf(stderr,
369"%s: dimensions of cursor bitmap and cursor mask bitmap are different\n",
370		program_name);
371	exit(1);
372	/*NOTREACHED*/
373    }
374
375    if ((x_hot == -1) && (y_hot == -1)) {
376	x_hot = BITMAP_HOT_DEFAULT;
377	y_hot = BITMAP_HOT_DEFAULT;
378    }
379    if ((x_hot < 0) || (x_hot >= width) ||
380	(y_hot < 0) || (y_hot >= height)) {
381	fprintf(stderr, "%s: hotspot is outside cursor bounds\n", program_name);
382	exit(1);
383	/*NOTREACHED*/
384    }
385
386    cursor = XCreatePixmapCursor(dpy, cursor_bitmap, mask_bitmap, &fg, &bg,
387				 (unsigned int)x_hot, (unsigned int)y_hot);
388    XFreePixmap(dpy, cursor_bitmap);
389    XFreePixmap(dpy, mask_bitmap);
390
391    return(cursor);
392}
393
394static Cursor
395CreateCursorFromName(char *name)
396{
397    XColor fg, bg, temp;
398    int	    i;
399    Font    fid;
400
401    fg = NameToXColor(fore_color, BlackPixel(dpy, screen));
402    bg = NameToXColor(back_color, WhitePixel(dpy, screen));
403    if (reverse) {
404	temp = fg; fg = bg; bg = temp;
405    }
406    i = XmuCursorNameToIndex (name);
407    if (i == -1)
408	return (Cursor) 0;
409    fid = XLoadFont (dpy, "cursor");
410    if (!fid)
411	return (Cursor) 0;
412    return XCreateGlyphCursor (dpy, fid, fid,
413			       i, i+1, &fg, &bg);
414}
415
416/*
417 * MakeModulaBitmap: Returns a modula bitmap based on an x & y mod.
418 */
419static Pixmap
420MakeModulaBitmap(int mod_x, int mod_y)
421{
422    int i;
423    long pattern_line = 0;
424    char modula_data[16*16/8];
425
426    for (i=16; i--; ) {
427	pattern_line <<=1;
428	if ((i % mod_x) == 0) pattern_line |= 0x0001;
429    }
430    for (i=0; i<16; i++) {
431	if ((i % mod_y) == 0) {
432	    modula_data[i*2] = (char)0xff;
433	    modula_data[i*2+1] = (char)0xff;
434	} else {
435	    modula_data[i*2] = pattern_line & 0xff;
436	    modula_data[i*2+1] = (pattern_line>>8) & 0xff;
437	}
438    }
439
440    return(XCreateBitmapFromData(dpy, root, modula_data, 16, 16));
441}
442
443
444/*
445 * NameToXColor: Convert the name of a color to its Xcolor value.
446 */
447static XColor
448NameToXColor(char *name, unsigned long pixel)
449{
450    XColor c;
451
452    if (!name || !*name) {
453	c.pixel = pixel;
454	XQueryColor(dpy, DefaultColormap(dpy, screen), &c);
455    } else if (!XParseColor(dpy, DefaultColormap(dpy, screen), name, &c)) {
456	fprintf(stderr, "%s: unknown color or bad color format: %s\n",
457			program_name, name);
458	exit(1);
459	/*NOTREACHED*/
460    }
461    return(c);
462}
463
464static unsigned long
465NameToPixel(char *name, unsigned long pixel)
466{
467    XColor ecolor;
468
469    if (!name || !*name)
470	return pixel;
471    if (!XParseColor(dpy,DefaultColormap(dpy,screen),name,&ecolor)) {
472	fprintf(stderr,"%s:  unknown color \"%s\"\n",program_name,name);
473	exit(1);
474	/*NOTREACHED*/
475    }
476    if (!XAllocColor(dpy, DefaultColormap(dpy, screen),&ecolor)) {
477	fprintf(stderr, "%s:  unable to allocate color for \"%s\"\n",
478		program_name, name);
479	exit(1);
480	/*NOTREACHED*/
481    }
482    if ((ecolor.pixel != BlackPixel(dpy, screen)) &&
483	(ecolor.pixel != WhitePixel(dpy, screen)) &&
484	(DefaultVisual(dpy, screen)->class & Dynamic))
485	save_colors = 1;
486    return(ecolor.pixel);
487}
488
489static Pixmap
490ReadBitmapFile(char *filename, unsigned int *width, unsigned int *height,
491	       int *x_hot, int *y_hot)
492{
493    Pixmap bitmap;
494    int status;
495
496    status = XReadBitmapFile(dpy, root, filename, width,
497			     height, &bitmap, x_hot, y_hot);
498    if (status == BitmapSuccess)
499      return(bitmap);
500    else if (status == BitmapOpenFailed)
501	fprintf(stderr, "%s: can't open file: %s\n", program_name, filename);
502    else if (status == BitmapFileInvalid)
503	fprintf(stderr, "%s: bad bitmap format file: %s\n",
504			program_name, filename);
505    else
506	fprintf(stderr, "%s: insufficient memory for bitmap: %s",
507			program_name, filename);
508    exit(1);
509    /*NOTREACHED*/
510}
511