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 unsigned int ww, hh; 121 Pixmap bitmap; 122 123 program_name=argv[0]; 124 125 for (int i = 1; i < argc; i++) { 126 if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) { 127 if (++i>=argc) usage ("-display requires an argument"); 128 display_name = argv[i]; 129 continue; 130 } 131 if (!strcmp("-help", argv[i])) { 132 usage(NULL); 133 } 134 if (!strcmp("-version", argv[i])) { 135 printf("%s\n", PACKAGE_STRING); 136 exit(0); 137 } 138 if (!strcmp("-def", argv[i]) || !strcmp("-default", argv[i])) { 139 restore_defaults = 1; 140 continue; 141 } 142 if (!strcmp("-name", argv[i])) { 143 if (++i>=argc) usage("-name requires an argument"); 144 name = argv[i]; 145 nonexcl++; 146 continue; 147 } 148 if (!strcmp("-cursor", argv[i])) { 149 if (++i>=argc) 150 usage("missing cursorfile & maskfile arguments for -cursor"); 151 cursor_file = argv[i]; 152 if (++i>=argc) 153 usage("missing maskfile argument for -cursor"); 154 cursor_mask = argv[i]; 155 nonexcl++; 156 continue; 157 } 158 if (!strcmp("-cursor_name", argv[i])) { 159 if (++i>=argc) usage("-cursor_name requires an argument"); 160 cursor_name = argv[i]; 161 nonexcl++; 162 continue; 163 } 164 if (!strcmp("-xcf", argv[i])) { 165 if (++i>=argc) 166 usage("missing cursorfile & cursorsize arguments for -xcf"); 167 xcf = argv[i]; 168 if (++i>=argc) 169 usage("missing cursorsize argument for -xcf"); 170 xcf_size = atoi(argv[i]); 171 if (xcf_size <= 0) 172 xcf_size = 32; 173 nonexcl++; 174 continue; 175 } 176 if (!strcmp("-fg",argv[i]) || !strcmp("-foreground",argv[i])) { 177 if (++i>=argc) usage("-foreground requires an argument"); 178 fore_color = argv[i]; 179 continue; 180 } 181 if (!strcmp("-bg",argv[i]) || !strcmp("-background",argv[i])) { 182 if (++i>=argc) usage("-background requires an argument"); 183 back_color = argv[i]; 184 continue; 185 } 186 if (!strcmp("-solid", argv[i])) { 187 if (++i>=argc) usage("-solid requires an argument"); 188 solid_color = argv[i]; 189 excl++; 190 continue; 191 } 192 if (!strcmp("-gray", argv[i]) || !strcmp("-grey", argv[i])) { 193 gray = 1; 194 excl++; 195 continue; 196 } 197 if (!strcmp("-bitmap", argv[i])) { 198 if (++i>=argc) usage("-bitmap requires an argument"); 199 bitmap_file = argv[i]; 200 excl++; 201 continue; 202 } 203 if (!strcmp("-mod", argv[i])) { 204 if (++i>=argc) usage("missing x & y arguments for -mod"); 205 mod_x = atoi(argv[i]); 206 if (mod_x <= 0) mod_x = 1; 207 if (++i>=argc) usage("missing y argument for -mod"); 208 mod_y = atoi(argv[i]); 209 if (mod_y <= 0) mod_y = 1; 210 excl++; 211 continue; 212 } 213 if (!strcmp("-rv",argv[i]) || !strcmp("-reverse",argv[i])) { 214 reverse = 1; 215 continue; 216 } 217 fprintf(stderr, "%s: unrecognized argument '%s'\n", 218 program_name, argv[i]); 219 usage(NULL); 220 } 221 222 /* Check for multiple use of exclusive options */ 223 if (excl > 1) { 224 fprintf(stderr, "%s: choose only one of {solid, gray, bitmap, mod}\n", 225 program_name); 226 usage(NULL); 227 } 228 229 dpy = XOpenDisplay(display_name); 230 if (!dpy) { 231 fprintf(stderr, "%s: unable to open display '%s'\n", 232 program_name, XDisplayName (display_name)); 233 exit (2); 234 } 235 screen = DefaultScreen(dpy); 236 root = RootWindow(dpy, screen); 237 238 /* If there are no arguments then restore defaults. */ 239 if (!excl && !nonexcl) 240 restore_defaults = 1; 241 242 /* Handle a cursor file */ 243 if (cursor_file) { 244 cursor = CreateCursorFromFiles(cursor_file, cursor_mask); 245 XDefineCursor(dpy, root, cursor); 246 XFreeCursor(dpy, cursor); 247 } 248 249 if (cursor_name) { 250 cursor = CreateCursorFromName (cursor_name); 251 if (cursor) 252 { 253 XDefineCursor (dpy, root, cursor); 254 XFreeCursor (dpy, cursor); 255 } 256 } 257 if (xcf) { 258 XcursorImages *images = XcursorFilenameLoadImages(xcf, xcf_size); 259 if (!images) { 260 fprintf(stderr, "Invalid cursor file \"%s\"\n", xcf); 261 } else { 262 cursor = XcursorImagesLoadCursor(dpy, images); 263 if (cursor) 264 { 265 XDefineCursor (dpy, root, cursor); 266 XFreeCursor (dpy, cursor); 267 } 268 } 269 } 270 /* Handle -gray and -grey options */ 271 if (gray) { 272 bitmap = XCreateBitmapFromData(dpy, root, gray_bits, 273 gray_width, gray_height); 274 SetBackgroundToBitmap(bitmap, gray_width, gray_height); 275 } 276 277 /* Handle -solid option */ 278 if (solid_color) { 279 XSetWindowBackground(dpy, root, NameToPixel(solid_color, 280 BlackPixel(dpy, screen))); 281 XClearWindow(dpy, root); 282 unsave_past = 1; 283 } 284 285 /* Handle -bitmap option */ 286 if (bitmap_file) { 287 bitmap = ReadBitmapFile(bitmap_file, &ww, &hh, (int *)NULL, (int *)NULL); 288 SetBackgroundToBitmap(bitmap, ww, hh); 289 } 290 291 /* Handle set background to a modula pattern */ 292 if (mod_x) { 293 bitmap = MakeModulaBitmap(mod_x, mod_y); 294 SetBackgroundToBitmap(bitmap, 16, 16); 295 } 296 297 /* Handle set name */ 298 if (name) 299 XStoreName(dpy, root, name); 300 301 /* Handle restore defaults */ 302 if (restore_defaults) { 303 if (!cursor_file) 304 XUndefineCursor(dpy, root); 305 if (!excl) { 306 XSetWindowBackgroundPixmap(dpy, root, (Pixmap) None); 307 XClearWindow(dpy, root); 308 unsave_past = 1; 309 } 310 } 311 312 FixupState(); 313 XCloseDisplay(dpy); 314 exit (0); 315} 316 317 318/* Free past incarnation if needed, and retain state if needed. */ 319static void 320FixupState(void) 321{ 322 Atom prop, type; 323 int format; 324 unsigned long length, after; 325 unsigned char *data; 326 327 if (!(DefaultVisual(dpy, screen)->class & Dynamic)) 328 unsave_past = 0; 329 if (!unsave_past && !save_colors) 330 return; 331 prop = XInternAtom(dpy, "_XSETROOT_ID", False); 332 if (unsave_past) { 333 if (XGetWindowProperty(dpy, root, prop, 0L, 1L, True, AnyPropertyType, 334 &type, &format, &length, &after, &data) != Success) 335 fprintf(stderr, 336 "%s: warning: cannot get _XSETROOT_ID property from root window\n", 337 program_name); 338 else if ((type == XA_PIXMAP) && (format == 32) && 339 (length == 1) && (after == 0)) 340 XKillClient(dpy, *((Pixmap *)data)); 341 else if (type != None) 342 fprintf(stderr, "%s: warning: _XSETROOT_ID property is garbage\n", 343 program_name); 344 } 345 if (save_colors) { 346 if (!save_pixmap) 347 save_pixmap = XCreatePixmap(dpy, root, 1, 1, 1); 348 XChangeProperty(dpy, root, prop, XA_PIXMAP, 32, PropModeReplace, 349 (unsigned char *) &save_pixmap, 1); 350 XSetCloseDownMode(dpy, RetainPermanent); 351 } 352} 353 354/* 355 * SetBackgroundToBitmap: Set the root window background to a caller supplied 356 * bitmap. 357 */ 358static void 359SetBackgroundToBitmap(Pixmap bitmap, unsigned int width, unsigned int height) 360{ 361 Pixmap pix; 362 GC gc; 363 XGCValues gc_init; 364 365 gc_init.foreground = NameToPixel(fore_color, BlackPixel(dpy, screen)); 366 gc_init.background = NameToPixel(back_color, WhitePixel(dpy, screen)); 367 if (reverse) { 368 unsigned long temp=gc_init.foreground; 369 gc_init.foreground=gc_init.background; 370 gc_init.background=temp; 371 } 372 gc = XCreateGC(dpy, root, GCForeground|GCBackground, &gc_init); 373 pix = XCreatePixmap(dpy, root, width, height, 374 (unsigned int)DefaultDepth(dpy, screen)); 375 XCopyPlane(dpy, bitmap, pix, gc, 0, 0, width, height, 0, 0, (unsigned long)1); 376 XSetWindowBackgroundPixmap(dpy, root, pix); 377 XFreeGC(dpy, gc); 378 XFreePixmap(dpy, bitmap); 379 if (save_colors) 380 save_pixmap = pix; 381 else 382 XFreePixmap(dpy, pix); 383 XClearWindow(dpy, root); 384 unsave_past = 1; 385} 386 387 388/* 389 * CreateCursorFromFiles: make a cursor of the right colors from two bitmap 390 * files. 391 */ 392#define BITMAP_HOT_DEFAULT 8 393 394static Cursor 395CreateCursorFromFiles(char *cursor_file, char *mask_file) 396{ 397 Pixmap cursor_bitmap, mask_bitmap; 398 unsigned int width, height, ww, hh; 399 int x_hot, y_hot; 400 Cursor cursor; 401 XColor fg, bg; 402 403 fg = NameToXColor(fore_color, BlackPixel(dpy, screen)); 404 bg = NameToXColor(back_color, WhitePixel(dpy, screen)); 405 if (reverse) { 406 XColor temp = fg; 407 fg = bg; 408 bg = temp; 409 } 410 411 cursor_bitmap = ReadBitmapFile(cursor_file, &width, &height, &x_hot, &y_hot); 412 mask_bitmap = ReadBitmapFile(mask_file, &ww, &hh, (int *)NULL, (int *)NULL); 413 414 if (width != ww || height != hh) { 415 fprintf(stderr, 416"%s: dimensions of cursor bitmap and cursor mask bitmap are different\n", 417 program_name); 418 exit(1); 419 /*NOTREACHED*/ 420 } 421 422 if ((x_hot == -1) && (y_hot == -1)) { 423 x_hot = BITMAP_HOT_DEFAULT; 424 y_hot = BITMAP_HOT_DEFAULT; 425 } 426 if ((x_hot < 0) || ((unsigned int)x_hot >= width) || 427 (y_hot < 0) || ((unsigned int)y_hot >= height)) { 428 fprintf(stderr, "%s: hotspot is outside cursor bounds\n", program_name); 429 exit(1); 430 /*NOTREACHED*/ 431 } 432 433 cursor = XCreatePixmapCursor(dpy, cursor_bitmap, mask_bitmap, &fg, &bg, 434 (unsigned int)x_hot, (unsigned int)y_hot); 435 XFreePixmap(dpy, cursor_bitmap); 436 XFreePixmap(dpy, mask_bitmap); 437 438 return(cursor); 439} 440 441static Cursor 442CreateCursorFromName(char *name) 443{ 444 XColor fg, bg; 445 int i; 446 Font fid; 447 448 fg = NameToXColor(fore_color, BlackPixel(dpy, screen)); 449 bg = NameToXColor(back_color, WhitePixel(dpy, screen)); 450 if (reverse) { 451 XColor temp = fg; 452 fg = bg; 453 bg = temp; 454 } 455 i = XmuCursorNameToIndex (name); 456 if (i == -1) 457 return (Cursor) 0; 458 fid = XLoadFont (dpy, "cursor"); 459 if (!fid) 460 return (Cursor) 0; 461 return XCreateGlyphCursor (dpy, fid, fid, 462 i, i+1, &fg, &bg); 463} 464 465/* 466 * MakeModulaBitmap: Returns a modula bitmap based on an x & y mod. 467 */ 468static Pixmap 469MakeModulaBitmap(int mod_x, int mod_y) 470{ 471 long pattern_line = 0; 472 char modula_data[16*16/8]; 473 474 for (int i = 16; i--; ) { 475 pattern_line <<=1; 476 if ((i % mod_x) == 0) pattern_line |= 0x0001; 477 } 478 for (int i = 0; i < 16; i++) { 479 if ((i % mod_y) == 0) { 480 modula_data[i*2] = (char)0xff; 481 modula_data[i*2+1] = (char)0xff; 482 } else { 483 modula_data[i*2] = pattern_line & 0xff; 484 modula_data[i*2+1] = (pattern_line>>8) & 0xff; 485 } 486 } 487 488 return(XCreateBitmapFromData(dpy, root, modula_data, 16, 16)); 489} 490 491 492/* 493 * NameToXColor: Convert the name of a color to its Xcolor value. 494 */ 495static XColor 496NameToXColor(char *name, unsigned long pixel) 497{ 498 XColor c; 499 500 if (!name || !*name) { 501 c.pixel = pixel; 502 XQueryColor(dpy, DefaultColormap(dpy, screen), &c); 503 } else if (!XParseColor(dpy, DefaultColormap(dpy, screen), name, &c)) { 504 fprintf(stderr, "%s: unknown color or bad color format: %s\n", 505 program_name, name); 506 exit(1); 507 /*NOTREACHED*/ 508 } 509 return(c); 510} 511 512static unsigned long 513NameToPixel(char *name, unsigned long pixel) 514{ 515 XColor ecolor; 516 517 if (!name || !*name) 518 return pixel; 519 if (!XParseColor(dpy,DefaultColormap(dpy,screen),name,&ecolor)) { 520 fprintf(stderr,"%s: unknown color \"%s\"\n",program_name,name); 521 exit(1); 522 /*NOTREACHED*/ 523 } 524 if (!XAllocColor(dpy, DefaultColormap(dpy, screen),&ecolor)) { 525 fprintf(stderr, "%s: unable to allocate color for \"%s\"\n", 526 program_name, name); 527 exit(1); 528 /*NOTREACHED*/ 529 } 530 if ((ecolor.pixel != BlackPixel(dpy, screen)) && 531 (ecolor.pixel != WhitePixel(dpy, screen)) && 532 (DefaultVisual(dpy, screen)->class & Dynamic)) 533 save_colors = 1; 534 return(ecolor.pixel); 535} 536 537static Pixmap 538ReadBitmapFile(char *filename, unsigned int *width, unsigned int *height, 539 int *x_hot, int *y_hot) 540{ 541 Pixmap bitmap; 542 int status; 543 544 status = XReadBitmapFile(dpy, root, filename, width, 545 height, &bitmap, x_hot, y_hot); 546 if (status == BitmapSuccess) 547 return(bitmap); 548 else if (status == BitmapOpenFailed) 549 fprintf(stderr, "%s: can't open file: %s\n", program_name, filename); 550 else if (status == BitmapFileInvalid) 551 fprintf(stderr, "%s: bad bitmap format file: %s\n", 552 program_name, filename); 553 else 554 fprintf(stderr, "%s: insufficient memory for bitmap: %s", 555 program_name, filename); 556 exit(1); 557 /*NOTREACHED*/ 558} 559