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