1 /* Copyright (C) 1993, 1992 Nathan Sidwell */ 2 /* RCS $Id: makecom.c,v 4.27 1995/12/21 15:55:04 nathan Exp $ */ 3 /* common make stuff for xmris and xmred, 4 * included from makemris and makemred 5 */ 6 7 /*{{{ interesting color stuff*/ 8 /* 9 * color is spelt as it is, 'cos its just too complicated spelling it as 10 * it should be, when X doesn't. 11 * The colour allocation is done by first parsing all the colour names 12 * to RGB values (using a type convertor from the resources). Each RGB 13 * value is converted to a 3space coordinate in a colour 'cone' (the 14 * colour circle, (well, hexagon in this case), and a height, 15 * corresponding to brightness). With that we can work out the 16 * perceived distances between different colours. 17 * These are then allocated in turn, by picking the unallocated colour 18 * farthest from the allocated colours. If the allocation fails, we pick 19 * the allocated colour which is nearest the desired colour. This way 20 * we try to get the most diverse set of colours possible with the 21 * colormap that's being used. Remember, black and white have already 22 * been allocated so we don't need to allocate those, and it gives us 23 * a starting ix in the allocation loop. 24 * The board background colours only need allocating, if it is a read 25 * only visual (Direct Colour or something). For writable visuals, 26 * we allocate two colorcells and set these as required, allowing 27 * dynamic colour changes, and saving entries in the colormap. 28 * You can see the order in which this is done by giving the -colours arg. 29 * There is a bug (IMHO) in the way that X parses hex color names to XColor. 30 * #FA5 is parsed as #F000A0005000, not #FFFFAAAA5555 as I would have 31 * expected it to be. That's why I've specified colours accurately. 32 * When the color #F000A0005000 is allocated, the rgb values are set, 33 * as I expected, to #F0F0A0A05050, on an 8 bit visual. There doesn't 34 * seem to be a way to get X to tell you what colour it would 35 * allocate on a colormap, assuming that there's a space. 36 */ 37 /*}}}*/ 38 /*{{{ static tables*/ 39 /*{{{ static char CONST *names[] =*/ 40 static char CONST *names[] = 41 { 42 "xmris", 43 "xmsit" 44 }; 45 /*}}}*/ 46 /*}}}*/ 47 /*{{{ prototypes*/ 48 static Boolean convert_string2color PROTOARG((Display *, XrmValue *, 49 Cardinal *, XrmValue *, XrmValue *, XtPointer *)); 50 static Boolean convert_string2gender PROTOARG((Display *, XrmValue *, 51 Cardinal *, XrmValue *, XrmValue *, XtPointer *)); 52 static VOIDFUNC create_resources PROTOARG((Widget)); 53 static VOIDFUNC extract_options 54 PROTOARG((int *, String *, CommandOptionDesc CONST *)); 55 static VOIDFUNC gettoplevelresources PROTOARG((VOIDARG)); 56 static VOIDFUNC list_color_resource 57 PROTOARG((unsigned, char CONST *, char CONST *)); 58 static VOIDFUNC make_color_image 59 PROTOARG((SPRITE *, SPRITE_DEF *, Window, unsigned, Pixmap)); 60 static VOIDFUNC make_mono_image 61 PROTOARG((SPRITE *, SPRITE_DEF *, Window, unsigned, Pixmap)); 62 static VOIDFUNC make_mask_image 63 PROTOARG((SPRITE *, SPRITE_DEF *, Window, unsigned, Pixmap)); 64 /*}}}*/ 65 /*{{{ Boolean convert_string2color(display, args, num_args, from, to, data)*/ 66 static Boolean convert_string2color 67 /* ARGSUSED */ 68 FUNCARG((display, args, num_args, from, to, data), 69 Display *display 70 ARGSEP XrmValue *args 71 ARGSEP Cardinal *num_args 72 ARGSEP XrmValue *from 73 ARGSEP XrmValue *to 74 ARGSEP XtPointer *data 75 ) 76 /* 77 * converts a string to a colordef 78 */ 79 { 80 static XColor result; 81 Status status; 82 Colormap colormap; 83 84 if(to->size < sizeof(XColor)) 85 { 86 to->size = sizeof(XColor); 87 return False; 88 } 89 if(args && *num_args > 1) 90 colormap = *(Colormap *)args[1].addr; 91 else 92 { 93 Screen *screen; 94 95 if(args && *num_args) 96 screen = *(Screen **)args[0].addr; 97 else 98 screen = DefaultScreenOfDisplay(display); 99 colormap = DefaultColormapOfScreen(screen); 100 } 101 status = XParseColor(display, colormap, 102 (char CONST *)from->addr, to->addr ? (XColor *)to->addr : &result); 103 if(status) 104 { 105 to->size = sizeof(XColor); 106 if(to->addr) 107 ((XColor *)to->addr)->flags = DoRed | DoGreen | DoBlue; 108 else 109 { 110 result.flags = DoRed | DoGreen | DoBlue; 111 to->addr = (XtPointer)&result; 112 } 113 return True; 114 } 115 else 116 { 117 XtDisplayStringConversionWarning(display, from->addr, XtRColor); 118 return False; 119 } 120 } 121 /*}}}*/ 122 /*{{{ Boolean convert_string2gender(display, args, num_args, from, to, data)*/ 123 static Boolean convert_string2gender 124 /* ARGSUSED */ 125 FUNCARG((display, args, num_args, from, to, data), 126 Display *display 127 ARGSEP XrmValue *args 128 ARGSEP Cardinal *num_args 129 ARGSEP XrmValue *from 130 ARGSEP XrmValue *to 131 ARGSEP XtPointer *data 132 ) 133 /* 134 * converts a string to a gender boolean (my new type XtRGender) 135 */ 136 { 137 static char CONST *genders[] = 138 {"he", "she", "male", "female", "mris", "msit", "boy", "girl", NULL}; 139 char CONST **ptr; 140 static Boolean result; 141 142 if(to->size < sizeof(Boolean)) 143 { 144 to->size = sizeof(Boolean); 145 return False; 146 } 147 for(ptr = genders; *ptr; ptr++) 148 if(!strcmp(*ptr, (char CONST *)from->addr)) 149 { 150 to->size = sizeof(Boolean); 151 result = (ptr - genders) & 1 ? True : False; 152 if(to->addr) 153 *(Boolean *)to->addr = result; 154 else 155 to->addr = (XtPointer)&result; 156 return True; 157 } 158 XtDisplayStringConversionWarning(display, from->addr, XtRGender); 159 return False; 160 } 161 /*}}}*/ 162 /*{{{ void create_resources(widget)*/ 163 static VOIDFUNC create_resources 164 FUNCARG((widget), 165 Widget widget 166 ) 167 /* 168 * Create the graphics contexts, sprites and colours and stuff. 169 * sets visual and stuff for the toplevel widget 170 */ 171 { 172 Window root; 173 unsigned depth; 174 XVisualInfo visualinfo; 175 176 /*{{{ get visual info*/ 177 { 178 XVisualInfo *list; 179 int found; 180 181 visualinfo.visualid = XVisualIDFromVisual(display.visual); 182 list = XGetVisualInfo(display.display, VisualIDMask, &visualinfo, &found); 183 while(found--) 184 if(list[found].visual == display.visual) 185 { 186 memcpy(&visualinfo, &list[found], sizeof(XVisualInfo)); 187 break; 188 } 189 XFree((VOID *)list); 190 } 191 /*}}}*/ 192 depth = display.depth; 193 if(visualinfo.colormap_size < 16) 194 data.mono = True; 195 root = RootWindow(display.display, display.screen); 196 if(XDefaultVisual(display.display, display.screen) != display.visual && 197 data.private == False) 198 fprintf(stderr, "Warning:Non-default visual with shared colormap\n"); 199 /*{{{ show visual class?*/ 200 if(data.colors != False) 201 { 202 VISUAL_CLASS CONST *vptr; 203 204 for(vptr = visual_class; vptr->name; vptr++) 205 if(vptr->class == visualinfo.class) 206 break; 207 fprintf(stdout, "Using %s visual with %s colormap of %d entries\n", 208 vptr->name ? vptr->name : vptr->class & 1 ? 209 "UnknownDynamic" : "UnknownStatic", 210 data.private != False ? "private" : "shared", 211 visualinfo.colormap_size); 212 } 213 /*}}}*/ 214 /*{{{ make black and white*/ 215 { 216 Status status; 217 XColor color; 218 219 color.red = color.green = color.blue = 0xFFFF; 220 color.flags = DoRed | DoGreen | DoBlue; 221 status = XAllocColor(display.display, display.colormap, &color); 222 if(status) 223 { 224 display.white = color.pixel; 225 color.red = color.green = color.blue = 0x0000; 226 color.flags = DoRed | DoGreen | DoBlue; 227 status = XAllocColor(display.display, display.colormap, &color); 228 display.black = color.pixel; 229 } 230 if(!status) 231 fatal_error("Cannot get hold of black and white pixels"); 232 if(data.colors != False) 233 { 234 fprintf(stdout, "Color white pixel %lu\n", display.white); 235 fprintf(stdout, "Color black pixel %lu\n", display.black); 236 } 237 } 238 /*}}}*/ 239 XtAppSetTypeConverter(display.context, XtRString, XtRColor, 240 convert_string2color, (XtConvertArgList)colorConvertArgs, 2, 241 XtCacheNone, (void (*)PROTOARG((XtAppContext, XrmValue *, XtPointer, 242 XrmValue *, Cardinal *)))NULL); 243 color_one = ((unsigned long)1 << depth) - (unsigned long)1; 244 if(data.mono == False) 245 { 246 unsigned ix; 247 COLOR_DEF *nptr; 248 XColor *cptr; 249 unsigned count; 250 unsigned new; 251 unsigned share; 252 253 /*{{{ get resources*/ 254 { 255 XtResource *resources; 256 size_t length; 257 char *text; 258 char *tptr; 259 XtResource *rptr; 260 unsigned source; 261 unsigned mask; 262 263 resources = (XtResource *)XtMalloc(COLORS * sizeof(XtResource)); 264 length = COLORS; 265 for(nptr = color_names, count = COLORS; count--; nptr++) 266 length += strlen(nptr->name); 267 text = XtMalloc(length); 268 colors[COLOR_WHITE].flags = DoRed | DoGreen | DoBlue; 269 colors[COLOR_WHITE].red = 0xFF00; 270 colors[COLOR_WHITE].green = 0xFF00; 271 colors[COLOR_WHITE].blue = 0xFF00; 272 colors[COLOR_BLACK].flags = DoRed | DoGreen | DoBlue; 273 colors[COLOR_BLACK].red = 0; 274 colors[COLOR_BLACK].green = 0; 275 colors[COLOR_BLACK].blue = 0; 276 source = (data.gender != False ? 2 : 0) + 277 (data.swap != False ? 1 : 0); 278 mask = (2 << source) - 1; 279 if(source == 2) 280 mask ^= 2; 281 /*{{{ build the resource table*/ 282 { 283 for(nptr = color_names, rptr = resources, tptr = text, ix = 0; 284 ix != COLORS; ix++, nptr++) 285 { 286 char CONST **sptr; 287 unsigned bit; 288 289 rptr->resource_name = tptr; 290 strcpy(tptr, nptr->name); 291 if(isupper(*tptr)) 292 *tptr = lowercase(*tptr); 293 tptr += strlen(tptr) + 1; 294 rptr->resource_class = (String)nptr->name; 295 rptr->resource_type = XtRColor; 296 rptr->resource_size = sizeof(XColor); 297 rptr->resource_offset = sizeof(XColor) * ix; 298 rptr->default_type = XtRString; 299 for(sptr = &nptr->source[source], bit = 1 << source; 300 (!*sptr || !(bit & mask)) && bit; bit >>= 1, sptr--) 301 /* EMPTY */; 302 if(bit) 303 rptr++->default_addr = (XtPointer)*sptr; 304 } 305 assert(tptr - text == length); 306 } 307 /*}}}*/ 308 if(data.swap != False) 309 XtGetSubresources(widget, (XtPointer)colors, "swap", "Swap", 310 resources, rptr - resources, NULL, 0); 311 else 312 XtGetApplicationResources(widget, colors, 313 resources, rptr - resources, NULL, 0); 314 XtFree(text); 315 XtFree((char *)resources); 316 } 317 /*}}}*/ 318 display.dynamic = 0; 319 #ifndef XMRED 320 /*{{{ dynamic colors*/ 321 if(data.nodynamic == False && visualinfo.class & 1) 322 { 323 unsigned long pixels[2]; 324 unsigned long planes; 325 326 if(XAllocColorCells (display.display, display.colormap, False, 327 &planes, 0, pixels, 2)) 328 { 329 display.dynamic = 1; 330 colors[COLOR_DYNAMIC].pixel = pixels[0]; 331 colors[COLOR_DYNAMIC + 1].pixel = pixels[1]; 332 if(data.colors != False) 333 fprintf(stdout, "Dynamic: background %lu, foreground %lu\n", 334 pixels[0], pixels[1]); 335 } 336 } 337 /*}}}*/ 338 #endif /* XMRED */ 339 count = new = 0; 340 /*{{{ parse all the colors*/ 341 { 342 unsigned mask; 343 344 mask = (data.gender != False ? 4 : 1) << (data.swap != False); 345 for(cptr = colors, nptr = color_names, ix = COLORS; 346 ix--; nptr++, cptr++) 347 if(cptr->flags) 348 { 349 nptr->coord[0] = RGB2X(cptr->red, cptr->green, cptr->blue); 350 nptr->coord[1] = RGB2Y(cptr->red, cptr->green, cptr->blue); 351 nptr->coord[2] = RGB2H(cptr->red, cptr->green, cptr->blue); 352 nptr->distance = 0; 353 nptr->nearest = NULL; 354 if(nptr->type & mask) 355 { 356 if(nptr->type & 16 && display.dynamic) 357 nptr->alloc = 5; 358 else if(nptr->type & 32 && !display.dynamic) 359 nptr->alloc = 4; 360 else 361 { 362 nptr->alloc = 0; 363 count++; 364 } 365 } 366 else 367 nptr->alloc = 4; 368 } 369 else if(nptr->type & mask) 370 fatal_error("Have no color for %s", nptr->name); 371 } 372 /*}}}*/ 373 share = 2; 374 /*{{{ allocate them in optimum order*/ 375 for(colors[COLOR_WHITE].pixel = display.white, 376 nptr = &color_names[COLOR_WHITE], nptr->alloc = 1; 377 --count;) 378 { 379 if(nptr->alloc == 1) 380 /*{{{ work out distance of just allocated color*/ 381 { 382 unsigned ix; 383 COLOR_DEF *optr; 384 385 for(optr = color_names, ix = COLORS; ix--; optr++) 386 if(!optr->alloc) 387 { 388 unsigned long distance; 389 unsigned ix; 390 391 distance = 0; 392 for(ix = 3; ix--;) 393 /* 394 * must be very careful about type promotion and 395 * overflow here 396 */ 397 { 398 unsigned delta; 399 400 delta = nptr->coord[ix] < optr->coord[ix] ? 401 optr->coord[ix] - nptr->coord[ix] : 402 nptr->coord[ix] - optr->coord[ix]; 403 distance += ((unsigned long)delta * 404 (unsigned long)delta) / 4; 405 } 406 if(distance < optr->distance || !optr->nearest) 407 { 408 optr->distance = distance; 409 optr->nearest = nptr; 410 } 411 } 412 } 413 /*}}}*/ 414 if(nptr == &color_names[COLOR_WHITE]) 415 { 416 nptr = &color_names[COLOR_BLACK]; 417 nptr->alloc = 1; 418 colors[COLOR_BLACK].pixel = display.black; 419 } 420 else 421 /*{{{ allocate the farthest one*/ 422 { 423 unsigned long distance; 424 COLOR_DEF *optr; 425 Status status; 426 unsigned ix; 427 XColor *fptr; 428 429 nptr = NULL; 430 distance = 0; 431 for(optr = color_names, ix = COLORS; ix--; optr++) 432 if(!optr->alloc && distance <= optr->distance) 433 { 434 nptr = optr; 435 distance = nptr->distance; 436 } 437 assert(nptr && nptr->nearest); 438 cptr = &colors[nptr - color_names]; 439 fptr = &colors[nptr->nearest - color_names]; 440 if(distance) 441 /*{{{ different*/ 442 { 443 if(data.colors != False) 444 fprintf(stdout, 445 "Color %s:#%04X%04X%04X near %s:#%04X%04X%04X (%lu)", 446 nptr->name, cptr->red, cptr->green, cptr->blue, 447 nptr->nearest->name, 448 fptr->red, fptr->green, fptr->blue, distance); 449 if(data.distinct) 450 status = XAllocColor(display.display, display.colormap, 451 cptr); 452 else 453 status = 0; 454 } 455 /*}}}*/ 456 else 457 /*{{{ same*/ 458 { 459 if(data.colors != False) 460 fprintf(stdout, 461 "Color %s:#%04X%04X%04X at %s:#%04X%04X%04X", 462 nptr->name, cptr->red, cptr->green, cptr->blue, 463 nptr->nearest->name, 464 fptr->red, fptr->green, fptr->blue); 465 status = 0; 466 } 467 /*}}}*/ 468 /*{{{ fixup*/ 469 if(status) 470 { 471 new++; 472 nptr->alloc = 1; 473 distance = 0; 474 data.distinct--; 475 } 476 else 477 { 478 nptr->alloc = 2 + !!distance; 479 cptr->pixel = fptr->pixel; 480 share++; 481 } 482 /*}}}*/ 483 if(data.colors != False) 484 fprintf(stdout, nptr->alloc == 1 ? 485 " pixel %lu\n" : " sharing %lu\n", cptr->pixel); 486 /*{{{ error message?*/ 487 if(distance) 488 { 489 fprintf(stderr, 490 "No color %s:#%04X%04X%04X used %s:#%04X%04X%04X\n", 491 nptr->name, cptr->red, cptr->green, cptr->blue, 492 nptr->nearest->name, 493 fptr->red, fptr->green, fptr->blue); 494 } 495 /*}}}*/ 496 } 497 /*}}}*/ 498 } 499 /*}}}*/ 500 if(data.colors != False) 501 fprintf(stdout, "%u new colours and %u shared\n", new, share); 502 for(nptr = color_names, count = COLORS; count--; nptr++) 503 assert(nptr->alloc); 504 } 505 /*{{{ swap b & w?*/ 506 if(data.swap != False) 507 { 508 unsigned long temp; 509 510 temp = display.black; 511 display.black = display.white; 512 display.white = temp; 513 } 514 /*}}}*/ 515 if(data.mono == False) 516 { 517 display.white = colors[COLOR_BACKGROUND].pixel; 518 display.black = colors[COLOR_FOREGROUND].pixel; 519 display.border = colors[COLOR_BORDER].pixel; 520 } 521 else 522 display.border = display.black; 523 /*{{{ nadger created widgets*/ 524 { 525 Widget root; 526 Widget parent; 527 528 for(root = widget; (parent = XtParent(root)); root = parent) 529 /* EMPTY */; 530 nadger_widget_colors(root, (WidgetClass)NULL); 531 } 532 /*}}}*/ 533 display.xor = display.black ^ display.white; 534 /*{{{ set foreground & background types*/ 535 { 536 unsigned long set; 537 unsigned long clear; 538 unsigned ix; 539 540 set = color_zero; 541 clear = color_one; 542 /*{{{ set on and off*/ 543 if(data.mono != False) 544 { 545 set |= display.white; 546 clear &= display.white; 547 set |= display.black; 548 clear &= display.black; 549 } 550 else 551 { 552 for(ix = COLORS; ix--;) 553 { 554 set |= colors[ix].pixel; 555 clear &= colors[ix].pixel; 556 } 557 } 558 /*}}}*/ 559 display.background = display.white == clear ? COLOUR_ZERO : 560 display.white == set ? COLOUR_ONE : COLOUR_WEIRD; 561 display.foreground = display.black == clear ? COLOUR_ZERO : 562 display.black == set ? COLOUR_ONE : COLOUR_WEIRD; 563 } 564 /*}}}*/ 565 display.copy = XCreatePixmap(display.display, root, 566 WINDOW_WIDTH, WINDOW_HEIGHT, depth); 567 #ifndef XMRED 568 display.back = XCreatePixmap(display.display, root, 569 WINDOW_WIDTH, WINDOW_HEIGHT, depth); 570 { 571 Cursor cursor; 572 String cursor_name; 573 574 cursor_name = NULL; 575 XtVaGetValues(widget, XtNcursor, (XtArgVal)&cursor, 576 #ifdef XtNcursorName 577 XtNcursorName, (XtArgVal)&cursor_name, 578 #endif 579 (String)NULL); 580 if(cursor == None && !cursor_name) 581 { 582 Pixmap blank; 583 XColor color; 584 char data; 585 586 data = 0; 587 blank = XCreatePixmapFromBitmapData(display.display, root, 588 &data, 1, 1, (long)0, (long)0, 1); 589 color.pixel = display.black; 590 XQueryColor(display.display, display.colormap, &color); 591 cursor = XCreatePixmapCursor(display.display, blank, blank, 592 &color, &color, 0, 0); 593 XFreePixmap(display.display, blank); 594 XtVaSetValues(widget, XtNcursor, (XtArgVal)cursor, (String)NULL); 595 } 596 } 597 #endif /* XMRED */ 598 /*{{{ create graphics contexts*/ 599 { 600 XGCValues gcv; 601 CONTEXT *cptr; 602 unsigned count; 603 604 gcv.font = data.font; 605 gcv.graphics_exposures = False; 606 gcv.line_width = 1; 607 gcv.cap_style = CapNotLast; 608 for(cptr = gcsdefine, count = 0; count != GCS; count++, cptr++) 609 { 610 gcv.function = cptr->function; 611 gcv.foreground = *cptr->fgp; 612 gcv.background = *cptr->bgp; 613 GCN(count) = XCreateGC(display.display, display.copy, 614 GCForeground | GCBackground | GCFunction | GCFont | 615 GCGraphicsExposures | GCCapStyle | GCLineWidth, &gcv); 616 } 617 } 618 /*}}}*/ 619 XFillRectangle(display.display, display.copy, GCN(GC_CLEAR), 620 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); 621 { 622 SPRITE_DEF CONST *sptr; 623 int nsizes; 624 XIconSize *sizes; 625 Status status; 626 SIZE size; 627 628 #ifndef XMRED 629 sptr = &icons[data.gender != False]; 630 #else 631 sptr = &icons[0]; 632 #endif /* XMRED */ 633 status = XGetIconSizes(display.display, root, &sizes, &nsizes); 634 if(status) 635 /*{{{ find best size*/ 636 { 637 int ix; 638 SIZE undersize; 639 int found; 640 641 size.x = size.y = 128; 642 undersize.x = undersize.y = 1; 643 found = 0; 644 for(ix = nsizes; ix--; sizes++) 645 { 646 SIZE this; 647 648 if(sptr->size.x < sizes->min_width) 649 this.x = sizes->min_width; 650 else if(sptr->size.x > sizes->max_width) 651 this.x = sizes->max_width; 652 else 653 this.x = (sptr->size.x - sizes->min_width + 654 sizes->width_inc - 1) / sizes->width_inc * 655 sizes->width_inc + sizes->min_width; 656 if(sptr->size.y < sizes->min_height) 657 this.y = sizes->min_height; 658 else if(sptr->size.y > sizes->max_height) 659 this.y = sizes->max_height; 660 else 661 this.y = (sptr->size.y - sizes->min_height + 662 sizes->height_inc - 1) / sizes->height_inc * 663 sizes->height_inc + sizes->min_height; 664 if(this.x < sptr->size.x || this.y < sptr->size.y) 665 { 666 if(this.x * this.y > undersize.x * undersize.y) 667 { 668 undersize.x = this.x; 669 undersize.y = this.y; 670 } 671 } 672 else if(this.x * this.y < size.x * size.y) 673 { 674 found = 1; 675 size.x = this.x; 676 size.y = this.y; 677 } 678 } 679 if(!found) 680 { 681 size.x = undersize.x; 682 size.y = undersize.y; 683 } 684 } 685 /*}}}*/ 686 else 687 { 688 size.x = sptr->size.x; 689 size.y = sptr->size.y; 690 } 691 display.icon = XCreateBitmapFromData(display.display, root, 692 (char CONST *)sptr->bitmap, sptr->size.x, sptr->size.y); 693 /*{{{ create correct sized icon*/ 694 if(size.x != sptr->size.x || size.y != sptr->size.y) 695 { 696 Pixmap temp; 697 GC gc; 698 XGCValues gcv; 699 700 temp = XCreatePixmap(display.display, root, size.x, size.y, 1); 701 gc = XCreateGC(display.display, temp, 0, &gcv); 702 XSetFunction(display.display, gc, GXclear); 703 XFillRectangle(display.display, temp, gc, 0, 0, size.x, size.y); 704 XSetFunction(display.display, gc, GXcopy); 705 XCopyArea(display.display, display.icon, temp, gc, 0, 0, 706 sptr->size.x, sptr->size.y, 707 (size.x - sptr->size.x) / 2, (size.y - sptr->size.y) / 2); 708 XFreeGC(display.display, gc); 709 XFreePixmap(display.display, display.icon); 710 display.icon = temp; 711 } 712 /*}}}*/ 713 XtVaSetValues(display.toplevel, XtNiconPixmap, (XtArgVal)display.icon, 714 NULL); 715 } 716 /*{{{ get a font*/ 717 { 718 char CONST *string = "09\'\""; 719 int direction; 720 XCharStruct chars; 721 722 XQueryTextExtents(display.display, data.font, string, 4, 723 &direction, &font.ascent, &font.descent, &chars); 724 font.width = chars.width / 4; 725 font.center = (font.ascent - font.descent) / 2; 726 font.digitup = chars.ascent; 727 font.digitdown = chars.descent; 728 } 729 /*}}}*/ 730 if(data.gender != False) 731 { 732 SPRITE_DEF *dptr; 733 SPRITE_DEF CONST *sptr; 734 735 for(sptr = she_nadger; sptr->copy; sptr++) 736 { 737 dptr = &sprites_def[sptr->copy]; 738 dptr->bitmap = sptr->bitmap; 739 dptr->planes = sptr->bitmap ? sptr->planes : 0; 740 dptr->flags = sptr->flags; 741 dptr->copy = sptr->bitmap ? 0 : sptr->planes; 742 memcpy(&dptr->size, &sptr->size, sizeof(sptr->size)); 743 memcpy(dptr->colors, sptr->colors, sizeof(sptr->colors)); 744 } 745 #ifndef XMRED 746 memcpy(ball_hold, she_hold, sizeof(ball_hold)); 747 lettering[0] = letter_msit; 748 #endif /* XMRED */ 749 } 750 /*{{{ create sprites*/ 751 { 752 unsigned i; 753 SPRITE *dptr; 754 SPRITE_DEF *sptr; 755 unsigned unknown; 756 unsigned changed; 757 758 /*{{{ generate all the ones from bitmaps*/ 759 for(i = 0, sptr = sprites_def, dptr = sprites; 760 i != SPRITES; i++, sptr++, dptr++) 761 { 762 /* check that its the size we expected */ 763 if(sptr->bitmap) 764 { 765 Pixmap bitmap; 766 767 assert(!sptr->expected.x || sptr->expected.x == sptr->size.x); 768 assert(!sptr->expected.y || sptr->expected.y * sptr->planes == sptr->size.y); 769 assert(sptr->size.x && sptr->size.y && !sptr->copy); 770 dptr->size.x = sptr->size.x; 771 dptr->size.y = sptr->size.y / sptr->planes; 772 bitmap = XCreatePixmapFromBitmapData(display.display, 773 root, (char *)sptr->bitmap, 774 sptr->size.x, sptr->size.y, color_one, color_zero, depth); 775 dptr->image = XCreatePixmap(display.display, root, 776 dptr->size.x, dptr->size.y, depth); 777 dptr->mask = XCreatePixmap(display.display, root, 778 dptr->size.x, dptr->size.y, depth); 779 if(!sptr->colors[0]) 780 XFillRectangle(display.display, dptr->image, GCN(GC_CLEAR), 781 0, 0, sptr->size.x, sptr->size.y); 782 else if(data.mono != False) 783 make_mono_image(dptr, sptr, root, depth, bitmap); 784 else 785 make_color_image(dptr, sptr, root, depth, bitmap); 786 make_mask_image(dptr, sptr, root, depth, bitmap); 787 XFreePixmap(display.display, bitmap); 788 } 789 } 790 /*}}}*/ 791 do 792 { 793 unknown = SPRITES; 794 changed = 0; 795 /*{{{ do what copies we can*/ 796 for(sptr = sprites_def, dptr = sprites, i = SPRITES; 797 i--; sptr++, dptr++) 798 if(!sptr->copy) 799 { 800 /* 801 * Sun's assert macro is broken, so I have to 802 * put it in a scope 803 */ 804 assert(sptr->bitmap); 805 } 806 else if(!dptr->mask && !dptr->image) 807 { 808 SPRITE *optr; 809 810 optr = &sprites[sptr->copy]; 811 if(!optr->size.x || !optr->size.y) 812 unknown = i; 813 else 814 { 815 changed = 1; 816 dptr->size.x = optr->size.x; 817 dptr->size.y = optr->size.y; 818 switch(sptr->flags) 819 { 820 /*{{{ case REFLECT_ALIAS:*/ 821 case REFLECT_ALIAS: 822 dptr->mask = optr->mask; 823 dptr->image = optr->image; 824 break; 825 /*}}}*/ 826 /*{{{ case REFLECT_VERTICAL:*/ 827 case REFLECT_VERTICAL: 828 { 829 int i; 830 831 dptr->mask = XCreatePixmap(display.display, root, 832 dptr->size.x, dptr->size.y, depth); 833 dptr->image = XCreatePixmap(display.display, root, 834 dptr->size.x, dptr->size.y, depth); 835 for(i = dptr->size.x; i--;) 836 { 837 XCopyArea(display.display, optr->mask, dptr->mask, 838 GCN(GC_COPY), i, 0, 1, dptr->size.y, 839 (int)dptr->size.x - i - 1, 0); 840 XCopyArea(display.display, optr->image, dptr->image, 841 GCN(GC_COPY), i, 0, 1, dptr->size.y, 842 (int)dptr->size.x - i - 1, 0); 843 } 844 break; 845 } 846 /*}}}*/ 847 /*{{{ case REFLECT_HORIZONTAL:*/ 848 case REFLECT_HORIZONTAL: 849 { 850 int i; 851 852 dptr->mask = XCreatePixmap(display.display, root, 853 dptr->size.x, dptr->size.y, depth); 854 dptr->image = XCreatePixmap(display.display, root, 855 dptr->size.x, dptr->size.y, depth); 856 for(i = dptr->size.y; i--;) 857 { 858 XCopyArea(display.display, optr->mask, dptr->mask, 859 GCN(GC_COPY), 0, i, dptr->size.x, 1, 860 0, (int)dptr->size.y - i - 1); 861 XCopyArea(display.display, optr->image, dptr->image, 862 GCN(GC_COPY), 0, i, dptr->size.x, 1, 863 0, (int)dptr->size.y - i - 1); 864 } 865 break; 866 } 867 /*}}}*/ 868 /*{{{ case REFLECT_DIAGONAL:*/ 869 case REFLECT_DIAGONAL: 870 { 871 int x, y; 872 873 dptr->size.x = optr->size.y; 874 dptr->size.y = optr->size.x; 875 dptr->mask = XCreatePixmap(display.display, root, 876 dptr->size.x, dptr->size.y, depth); 877 dptr->image = XCreatePixmap(display.display, root, 878 dptr->size.x, dptr->size.y, depth); 879 for(x = optr->size.x; x--;) 880 for(y = optr->size.y; y--;) 881 { 882 XCopyArea(display.display, optr->mask, dptr->mask, 883 GCN(GC_COPY), x, y, 1, 1, y, x); 884 XCopyArea(display.display, 885 optr->image, dptr->image, 886 GCN(GC_COPY), x, y, 1, 1, y, x); 887 } 888 break; 889 } 890 /*}}}*/ 891 /*{{{ default*/ 892 default: 893 assert(0); 894 /*}}}*/ 895 } 896 } 897 } 898 /*}}}*/ 899 } 900 while(unknown != SPRITES && changed); 901 assert(unknown == SPRITES); /* check no circular definitions */ 902 } 903 /*}}}*/ 904 #ifndef XMRED 905 /*{{{ digits special*/ 906 { 907 Pixmap bitmap; 908 SPRITE *dptr; 909 910 dptr = &sprites[SPRITE_DIGITS]; 911 bitmap = XCreatePixmap(display.display, root, 912 dptr->size.x, dptr->size.y, depth); 913 XFillRectangle(display.display, bitmap, GCN(GC_CLEAR), 914 0, 0, dptr->size.x, dptr->size.y); 915 XCopyArea(display.display, dptr->mask, bitmap, GCN(GC_MASK), 916 0, 0, dptr->size.x, dptr->size.y, 0, 0); 917 XCopyArea(display.display, bitmap, dptr->image, GCN(GC_OR), 918 0, 0, dptr->size.x, dptr->size.y, 0, 0); 919 XFreePixmap(display.display, bitmap); 920 } 921 /*}}}*/ 922 #else 923 /*{{{ visual special*/ 924 if(data.mono == False && visualinfo.class != StaticGray && 925 visualinfo.class != GrayScale) 926 { 927 int count; 928 COLOR_DEF *cptr; 929 SPRITE *dptr; 930 931 for(cptr = &color_names[COLOR_BACKGROUNDS], count = BACKGROUNDS * 2; 932 count--; cptr++) 933 if(cptr->alloc == 3) 934 break; 935 if(count < 0) 936 for(dptr = &sprites[SPRITE_COLORS], count = BACKGROUNDS; count--; dptr++) 937 { 938 XFreePixmap(display.display, dptr->mask); 939 dptr->mask = 0; 940 XFreePixmap(display.display, dptr->image); 941 dptr->image = 0; 942 } 943 } 944 /*}}}*/ 945 /*{{{ sprite build*/ 946 { 947 unsigned ix; 948 SPRITE *sptr; 949 SPRITE *aptr; 950 951 for(sptr = &sprites[SPRITE_APPLES], ix = 0; ix != 5; sptr++, ix++) 952 { 953 unsigned count; 954 955 for(count = 0; count != 4; count++) 956 { 957 aptr = &sprites[SPRITE_SMALL_APPLE + (count != ix)]; 958 XCopyArea(display.display, aptr->mask, sptr->mask, GCN(GC_COPY), 959 0, 0, aptr->size.x, aptr->size.y, 960 (count % 2) * aptr->size.x, (count / 2) * aptr->size.y); 961 XCopyArea(display.display, aptr->image, sptr->image, GCN(GC_COPY), 962 0, 0, aptr->size.x, aptr->size.y, 963 (count % 2) * aptr->size.x, (count / 2) * aptr->size.y); 964 } 965 } 966 sptr = &sprites[SPRITE_APPLE_DROP]; 967 aptr = &sprites[SPRITE_BIG_APPLE]; 968 XCopyArea(display.display, aptr[1].mask, sptr->mask, GCN(GC_COPY), 969 0, 0, sptr->size.x, sptr->size.y, 0, 0); 970 XCopyArea(display.display, aptr[1].image, sptr->image, GCN(GC_COPY), 971 0, 0, sptr->size.x, sptr->size.y, 0, 0); 972 XCopyArea(display.display, aptr[3].mask, sptr->mask, GCN(GC_OR), 973 0, 0, sptr->size.x, sptr->size.y, 0, 0); 974 XCopyArea(display.display, aptr[3].image, sptr->image, GCN(GC_OR), 975 0, 0, sptr->size.x, sptr->size.y, 0, 0); 976 } 977 /*}}}*/ 978 #endif /* XMRED */ 979 #ifndef NDEBUG 980 /* check we've used all the colors we allocated */ 981 if(data.mono == False) 982 { 983 unsigned ix; 984 COLOR_DEF *cptr; 985 986 color_names[COLOR_FOREGROUND].name = NULL; 987 color_names[COLOR_BACKGROUND].name = NULL; 988 color_names[COLOR_BORDER].name = NULL; 989 #ifndef XMRED 990 color_names[COLOR_DYNAMIC].name = NULL; 991 color_names[COLOR_DYNAMIC + 1].name = NULL; 992 #endif /* XMRED */ 993 for(cptr = color_names, ix = COLORS; ix--; cptr++) 994 { 995 /* again some broken compilers can't cope with asserts 996 * over several lines */ 997 int check; 998 999 check = cptr->alloc > 3 || !cptr->name || 1000 (cptr->type & 16 && !display.dynamic); 1001 assert(check); 1002 } 1003 } 1004 #endif /* NDEBUG */ 1005 if(display.background == COLOUR_ZERO) 1006 { 1007 SPRITE *sptr; 1008 unsigned ix; 1009 1010 for(sptr = &sprites[SPRITE_CENTER_BASE], ix = 4; ix--; sptr++) 1011 XCopyArea(display.display, sptr->image, sptr->mask, GCN(GC_MASK), 1012 0, 0, sptr->size.x, sptr->size.y, 0, 0); 1013 } 1014 /*{{{ create fills*/ 1015 { 1016 unsigned i; 1017 SPRITE *dptr; 1018 SPRITE_DEF *sptr; 1019 1020 for(i = 0, sptr = fills_def, dptr = fills; 1021 i != FILLS; i++, sptr++, dptr++) 1022 { 1023 int x, y; 1024 char c; 1025 unsigned char *ptr; 1026 1027 assert(sptr->size.x && sptr->size.y); 1028 dptr->size.x = sptr->size.x; 1029 dptr->size.y = sptr->size.y; 1030 if(data.mono) 1031 { 1032 if(data.swap != False) 1033 for(ptr = sptr->bitmap, 1034 x = (sptr->size.x + 7) / 8 * sptr->size.y; x--; ptr++) 1035 *ptr ^= 0xFF; 1036 for(ptr = sptr->bitmap, y = sptr->size.y; y--;) 1037 for(c = 0x55 << (y & 1), x = (sptr->size.x + 7) / 8; x--; ptr++) 1038 *ptr |= c; 1039 } 1040 dptr->mask = XCreateBitmapFromData(display.display, root, 1041 (char CONST *)sptr->bitmap, sptr->size.x, sptr->size.y); 1042 } 1043 } 1044 /*}}}*/ 1045 #ifndef XMRED 1046 /*{{{ create score pixmaps*/ 1047 { 1048 unsigned i; 1049 1050 for(i = BOARD_SCORES; i--;) 1051 { 1052 update.score.list[i].image = XCreatePixmap(display.display, 1053 root, DIGIT_WIDTH * 4, DIGIT_HEIGHT, depth); 1054 update.score.list[i].mask = XCreatePixmap(display.display, 1055 root, DIGIT_WIDTH * 4, DIGIT_HEIGHT, depth); 1056 } 1057 } 1058 /*}}}*/ 1059 #endif /* XMRED */ 1060 return; 1061 } 1062 /*}}}*/ 1063 #ifndef NDEBUG 1064 /*{{{ int error_handler(display, event)*/ 1065 extern int error_handler 1066 FUNCARG((dpy, event), 1067 Display *dpy 1068 ARGSEP XErrorEvent *event 1069 ) 1070 { 1071 char msg[80]; 1072 1073 XGetErrorText(dpy, event->error_code, msg, 80); 1074 fprintf(stderr, "X Error: %s\n", msg); 1075 fprintf(stderr, " Major opcode: %d\n", event->request_code); 1076 fprintf(stderr, " Minor opcode: %d\n", event->minor_code); 1077 fprintf(stderr, " Resource id: 0x%lx\n", (long)event->resourceid); 1078 fprintf(stderr, " Serial number: %ld\n", (long)event->serial); 1079 #ifdef DEBUGEVENTLOOP 1080 while(QLength(display.display)) 1081 { 1082 XEvent buffered; 1083 1084 XNextEvent(display.display, &buffered); 1085 fprintf(stderr, "0x%lx type %d\n", buffered.xany.window, buffered.type); 1086 } 1087 #endif /* DEBUGEVENTLOOP */ 1088 fflush(stderr); 1089 abort(); 1090 return 0; 1091 } 1092 /*}}}*/ 1093 #endif /* NDEBUG */ 1094 /*{{{ void extract_options(argcp, argv, options)*/ 1095 static VOIDFUNC extract_options 1096 FUNCARG((argcp, argv, options), 1097 int *argcp 1098 ARGSEP String *argv 1099 ARGSEP CommandOptionDesc CONST *options 1100 ) 1101 { 1102 CommandOptionDesc CONST *ptr; 1103 unsigned ix; 1104 unsigned copy; 1105 1106 for(ptr = options; ptr->option; ptr++) 1107 if(ptr->optional) 1108 *(char **)((char *)&data + ptr->offset) = NULL; 1109 else 1110 *(Boolean *)((char *)&data + ptr->offset) = False; 1111 for(ix = copy = 1; ix != *argcp; ix++) 1112 { 1113 size_t length; 1114 1115 length = strlen(argv[ix]); 1116 for(ptr = options; ptr->option; ptr++) 1117 { 1118 if(!strncmp(argv[ix], ptr->option, length)) 1119 { 1120 if(ptr->optional) 1121 { 1122 if(ix < *argcp - 1) 1123 { 1124 *(char CONST **)((char *)&data + ptr->offset) = 1125 argv[ix + 1]; 1126 ix++; 1127 } 1128 else 1129 { 1130 data.help = True; 1131 data.colors = False; 1132 fprintf(stderr, "Argument expected for %s\n", 1133 ptr->option); 1134 } 1135 } 1136 else 1137 *(Boolean *)((char *)&data + ptr->offset) = True; 1138 break; 1139 } 1140 } 1141 if(!ptr->option) 1142 argv[copy++] = argv[ix]; 1143 } 1144 *argcp = copy; 1145 return; 1146 } 1147 /*}}}*/ 1148 /*{{{ void gettoplevelresources()*/ 1149 static VOIDFUNC gettoplevelresources FUNCARGVOID 1150 /* 1151 * get toplevel resources and 1152 * create a private colormap, if required 1153 * must be done before creating other widgets, in order 1154 * to get the visual inheritance correct 1155 */ 1156 { 1157 Screen *screenptr; 1158 1159 XtVaGetValues(display.toplevel, XtNvisual, (XtArgVal)&display.visual, 1160 XtNdepth, (XtArgVal)&display.depth, XtNscreen, (XtArgVal)&screenptr, 1161 XtNcolormap, (XtArgVal)&display.colormap, NULL); 1162 display.screen = XScreenNumberOfScreen(screenptr); 1163 if(!display.visual) 1164 display.visual = DefaultVisualOfScreen(screenptr); 1165 if(data.private != False) 1166 { 1167 display.colormap = XCreateColormap(display.display, 1168 RootWindowOfScreen(screenptr), display.visual, AllocNone); 1169 XtVaSetValues(display.toplevel, 1170 XtNcolormap, (XtArgVal)display.colormap, NULL); 1171 } 1172 return; 1173 } 1174 /*}}}*/ 1175 /*{{{ void fatal_error(text, ...)*/ 1176 extern VOIDFUNC fatal_error 1177 FUNCVARARG((text, VARARGDEF), 1178 char CONST *text 1179 ) 1180 { 1181 va_list args; 1182 1183 fputs(myname, stderr); 1184 fputc(':', stderr); 1185 VARARGSET(args, text); 1186 vfprintf(stderr, text, args); 1187 fputc('\n', stderr); 1188 exit(1); 1189 return; 1190 } 1191 /*}}}*/ 1192 /*{{{ void list_color_resource(mask, resource, value)*/ 1193 static VOIDFUNC list_color_resource 1194 FUNCARG((mask, resource, value), 1195 unsigned mask 1196 ARGSEP char CONST *resource 1197 ARGSEP char CONST *value 1198 ) 1199 { 1200 unsigned len; 1201 1202 assert(mask && mask != 6 && mask != 9); 1203 if(((mask + 1) | mask) == 0xF) 1204 mask = 15; 1205 fputs("Xmris", stderr); 1206 len = 5; 1207 if(mask == 15 || mask == 5) 1208 { 1209 fputc('*', stderr); 1210 len++; 1211 } 1212 else 1213 { 1214 if(!(mask & 3)) 1215 { 1216 fputs("*msit", stderr); 1217 len += 5; 1218 } 1219 else if(!(mask & 12)) 1220 { 1221 fputs("*mris", stderr); 1222 len += 5; 1223 } 1224 if(!(mask & 10)) 1225 { 1226 fputc('.', stderr); 1227 len++; 1228 } 1229 else if(mask == 12 || mask == 3) 1230 { 1231 fputc('*', stderr); 1232 len++; 1233 } 1234 else if(mask == 10) 1235 { 1236 fputs("*swap.", stderr); 1237 len += 6; 1238 } 1239 else 1240 { 1241 fputs(".swap.", stderr); 1242 len += 6; 1243 } 1244 } 1245 len += strlen(resource); 1246 fprintf(stderr, "%s:%*s%s\n", resource, 1247 len < 32 ? (int)(32 - len) : 1, "", value); 1248 return; 1249 } 1250 /*}}}*/ 1251 /*{{{ void list_help(name)*/ 1252 extern VOIDFUNC list_help 1253 FUNCARG((name), 1254 char CONST *name 1255 ) 1256 { 1257 if(data.colors != False) 1258 /*{{{ color resources*/ 1259 { 1260 COLOR_DEF CONST *cptr; 1261 unsigned count; 1262 1263 fprintf(stderr, "!Colour resources\n"); 1264 fprintf(stderr, "!Xmris*{mris,msit}.{swap}.<name>:<color>\n"); 1265 for(cptr = &color_names[4], count = COLORS - 4; count--; cptr++) 1266 { 1267 unsigned mask; 1268 char CONST *values[4]; 1269 unsigned point; 1270 1271 mask = cptr->type & 15; 1272 memcpy(values, cptr->source, sizeof(values)); 1273 if(!values[1]) 1274 values[1] = values[0]; 1275 if(!values[3]) 1276 values[3] = values[2]; 1277 if(!values[3]) 1278 values[3] = values[1]; 1279 if(!values[2]) 1280 values[2] = values[0]; 1281 for(point = 0; mask && point < 4; point++) 1282 { 1283 unsigned ix; 1284 unsigned select; 1285 1286 for(select = 0, ix = 4; ix--;) 1287 if(!strcmp(values[ix], values[point])) 1288 select |= 1 << ix; 1289 select &= mask; 1290 if(select) 1291 list_color_resource(select, cptr->name, values[point]); 1292 mask ^= select; 1293 } 1294 } 1295 } 1296 /*}}}*/ 1297 else 1298 { 1299 HELP CONST *hptr; 1300 1301 fprintf(stderr, "%s [-option ...] [-toolkitoption ...]\n", name); 1302 fprintf(stderr, "%s %s %s %s\n", 1303 #ifndef XMRED 1304 names[0], XMRISVERSION, 1305 #else 1306 "xmred", XMREDVERSION, 1307 #endif /* XMRED */ 1308 DATE, COPYRIGHT); 1309 fprintf(stderr, " Option Resource Argument\n"); 1310 for(hptr = help; hptr->help; hptr++) 1311 fprintf(stderr, "%-10s %-16s %-16s %s\n", 1312 hptr->arg, hptr->resource, hptr->option, hptr->help); 1313 } 1314 return; 1315 } 1316 /*}}}*/ 1317 /*{{{ void make_color_image(dptr, sptr, root, depth, bitmap)*/ 1318 static VOIDFUNC make_color_image 1319 FUNCARG((dptr, sptr, root, depth, bitmap), 1320 SPRITE *dptr 1321 ARGSEP SPRITE_DEF *sptr 1322 ARGSEP Window root 1323 ARGSEP unsigned depth 1324 ARGSEP Pixmap bitmap 1325 ) 1326 /* 1327 * The colour sprite image is generated from the bitmap, which 1328 * is treated as a set of n planes vertically alligned. 1329 * The allows 2^n different colours per sprite (including the mask). The 1330 * mapping from the sprite planes to the colour map is 1331 * controlled by the sprite's colour table, which pointes the game's 1332 * colour table, which contains the pixel value to use. 1333 * We go through the bit planes, once for each colour, generating colour 1334 * stencils which we or together for the image. Rather like colour 1335 * printing really. 1336 */ 1337 { 1338 Pixmap temp; 1339 unsigned ix; 1340 1341 temp = XCreatePixmap(display.display, root, 1342 dptr->size.x, dptr->size.y, depth); 1343 XSetForeground(display.display, GCN(GC_BOARD), color_zero); 1344 XFillRectangle(display.display, dptr->image, GCN(GC_BOARD), 1345 0, 0, dptr->size.x, dptr->size.y); 1346 for(ix = 1 << sptr->planes; --ix;) 1347 { 1348 unsigned long color; 1349 1350 color = sptr->colors[data.swap != False][ix]; 1351 if(color != ~(unsigned long)0) 1352 { 1353 unsigned count; 1354 1355 { 1356 /* stupid compilers with broken stringizizing 1357 * and stupid compilers which don't understand \ 1358 * outside of #define */ 1359 unsigned alloc; 1360 1361 alloc = color_names[(unsigned)color].alloc; 1362 assert(alloc == 1 || alloc == 2 || alloc == 3); 1363 } 1364 #ifndef NDEBUG 1365 color_names[(unsigned)color].name = NULL; 1366 #endif /* NDEBUG */ 1367 XSetForeground(display.display, GCN(GC_BOARD), 1368 colors[(unsigned)color].pixel); 1369 XFillRectangle(display.display, temp, GCN(GC_BOARD), 1370 0, 0, dptr->size.x, dptr->size.y); 1371 for(count = sptr->planes; count--;) 1372 XCopyArea(display.display, bitmap, temp, 1373 GCN(ix & (1 << count) ? GC_AND : GC_MASK), 1374 0, (int)(count * dptr->size.y), 1375 dptr->size.x, dptr->size.y, 0, 0); 1376 XCopyArea(display.display, temp, dptr->image, GCN(GC_OR), 1377 0, 0, dptr->size.x, dptr->size.y, 0, 0); 1378 } 1379 } 1380 XFreePixmap(display.display, temp); 1381 return; 1382 } 1383 /*}}}*/ 1384 /*{{{ void make_mask_image(dptr, sptr, root, depth, bitmap)*/ 1385 static VOIDFUNC make_mask_image 1386 FUNCARG((dptr, sptr, root, depth, bitmap), 1387 SPRITE *dptr 1388 ARGSEP SPRITE_DEF *sptr 1389 ARGSEP Window root 1390 ARGSEP unsigned depth 1391 ARGSEP Pixmap bitmap 1392 ) 1393 /* 1394 * the mask is made from logical color ~0, ie or all the bitmap 1395 * planes together, and that's the mask. 1396 * the mask halo is generated from the mask by oring the mask ontop 1397 * of itself, offset by the 4 adjacent pixels. This grows the mask too. 1398 * the halo is the xor of the grown mask and the original mask. 1399 */ 1400 { 1401 unsigned ix; 1402 1403 XSetForeground(display.display, GCN(GC_BOARD), color_zero); 1404 XFillRectangle(display.display, dptr->mask, GCN(GC_BOARD), 1405 0, 0, dptr->size.x, dptr->size.y); 1406 for(ix = sptr->planes; ix--;) 1407 XCopyArea(display.display, bitmap, dptr->mask, GCN(GC_OR), 1408 0, (int)(dptr->size.y * ix), dptr->size.x, dptr->size.y, 0, 0); 1409 XCopyArea(display.display, 1410 dptr->mask, dptr->image, GCN(GC_AND), 1411 0, 0, dptr->size.x, dptr->size.y, 0, 0); 1412 if(sptr->flags & BORDER_HALO_MASK) 1413 /*{{{ make the halo*/ 1414 { 1415 Pixmap halo; 1416 1417 halo = XCreatePixmap(display.display, root, 1418 dptr->size.x, dptr->size.y, depth); 1419 XFillRectangle(display.display, halo, GCN(GC_BOARD), 1420 0, 0, dptr->size.x, dptr->size.y); 1421 XCopyArea(display.display, dptr->mask, halo, GCN(GC_OR), 1422 0, 0, dptr->size.x, dptr->size.y, 0, 1); 1423 XCopyArea(display.display, dptr->mask, halo, GCN(GC_OR), 1424 0, 0, dptr->size.x, dptr->size.y, 0, -1); 1425 XCopyArea(display.display, dptr->mask, halo, GCN(GC_OR), 1426 0, 0, dptr->size.x, dptr->size.y, 1, 0); 1427 XCopyArea(display.display, dptr->mask, halo, GCN(GC_OR), 1428 0, 0, dptr->size.x, dptr->size.y, -1, 0); 1429 XCopyArea(display.display, dptr->mask, halo, GCN(GC_MASK), 1430 0, 0, dptr->size.x, dptr->size.y, 0, 0); 1431 XCopyArea(display.display, halo, dptr->mask, GCN(GC_OR), 1432 0, 0, dptr->size.x, dptr->size.y, 0, 0); 1433 XSetForeground(display.display, GCN(GC_BOARD), 1434 data.swap != False && sptr->flags & (data.mono != False ? 1435 BORDER_MONOSWAP_EDGE_MASK : BORDER_WHITE_EDGE_MASK) ? 1436 display.black : display.white); 1437 XSetFunction(display.display, GCN(GC_BOARD), GXand); 1438 XFillRectangle(display.display, halo, GCN(GC_BOARD), 1439 0, 0, dptr->size.x, dptr->size.y); 1440 XSetFunction(display.display, GCN(GC_BOARD), GXcopy); 1441 XCopyArea(display.display, halo, dptr->image, GCN(GC_OR), 1442 0, 0, dptr->size.x, dptr->size.y, 0, 0); 1443 XFreePixmap(display.display, halo); 1444 } 1445 /*}}}*/ 1446 return; 1447 } 1448 /*}}}*/ 1449 /*{{{ void make_mono_image(dptr, sptr, root, depth, bitmap)*/ 1450 static VOIDFUNC make_mono_image 1451 FUNCARG((dptr, sptr, root, depth, bitmap), 1452 SPRITE *dptr 1453 ARGSEP SPRITE_DEF *sptr 1454 ARGSEP Window root 1455 ARGSEP unsigned depth 1456 ARGSEP Pixmap bitmap 1457 ) 1458 /* 1459 * As with the colour sprite image, the monochrome is generated from the 1460 * same bitmap and logical colors, but these either map to black or white 1461 * only. 1462 */ 1463 { 1464 Pixmap temp; 1465 unsigned long colors; 1466 unsigned ix; 1467 1468 temp = XCreatePixmap(display.display, root, 1469 dptr->size.x, dptr->size.y, depth); 1470 XSetForeground(display.display, GCN(GC_BOARD), color_zero); 1471 XFillRectangle(display.display, dptr->image, GCN(GC_BOARD), 1472 0, 0, dptr->size.x, dptr->size.y); 1473 colors = sptr->colors[data.swap != False][0]; 1474 if(data.swap != False) 1475 colors = ~colors; 1476 for(ix = 1 << sptr->planes; ix; ix--) 1477 { 1478 unsigned count; 1479 1480 if(sptr->colors[data.swap != False][ix] != ~(unsigned long)0) 1481 { 1482 XSetForeground(display.display, GCN(GC_BOARD), 1483 colors & (unsigned long)1 << ix ? 1484 display.black : display.white); 1485 XFillRectangle(display.display, temp, GCN(GC_BOARD), 1486 0, 0, dptr->size.x, dptr->size.y); 1487 for(count = sptr->planes; count--;) 1488 XCopyArea(display.display, bitmap, temp, 1489 GCN(ix & (1 << count) ? GC_AND : GC_MASK), 1490 0, (int)(count * dptr->size.y), 1491 dptr->size.x, dptr->size.y, 0, 0); 1492 XCopyArea(display.display, temp, dptr->image, GCN(GC_OR), 1493 0, 0, dptr->size.x, dptr->size.y, 0, 0); 1494 } 1495 } 1496 XFreePixmap(display.display, temp); 1497 return; 1498 } 1499 /*}}}*/ 1500 /*{{{ void nadger_widget_colors(root, class)*/ 1501 extern VOIDFUNC nadger_widget_colors 1502 FUNCARG((root, class), 1503 Widget root 1504 ARGSEP WidgetClass class 1505 ) 1506 /* traverse the widget tree and set the foreground, background and border 1507 * colors. 1508 * This has to be done, so that the swap attribute works as expected. 1509 * Without it, swap doesn't affect some widget's colors, which is wrong. 1510 */ 1511 { 1512 /*{{{ typedef struct Stack*/ 1513 typedef struct Stack 1514 { 1515 Widget *children; 1516 Cardinal count; 1517 } STACK; 1518 /*}}}*/ 1519 /*{{{ static Arg nadger[] =*/ 1520 static Arg nadger[] = 1521 { 1522 {XtNforeground}, 1523 {XtNbackground}, 1524 {XtNborderColor}, 1525 {XtNinternalBorderColor}, 1526 }; 1527 /*}}}*/ 1528 /*{{{ static Arg values[] =*/ 1529 static Arg values[] = 1530 { 1531 {XtNchildren}, 1532 {XtNnumChildren}, 1533 }; 1534 /*}}}*/ 1535 STACK stack[8]; 1536 STACK *sptr; 1537 1538 nadger[0].value = (XtArgVal)display.black; 1539 nadger[1].value = (XtArgVal)display.white; 1540 nadger[2].value = (XtArgVal)display.border; 1541 nadger[3].value = (XtArgVal)display.border; 1542 /* Ha, work this one out then! */ 1543 for(sptr = stack; 1; root = *(sptr->children++), sptr++) 1544 { 1545 if(!class || XtIsSubclass(root, class) != False) 1546 XtSetValues(root, nadger, XtNumber(nadger)); 1547 if(XtIsComposite(root)) 1548 { 1549 values[0].value = (XtArgVal)&sptr->children; 1550 values[1].value = (XtArgVal)&sptr->count; 1551 sptr->count = 0; 1552 XtGetValues(root, values, XtNumber(values)); 1553 } 1554 else if(sptr != stack) 1555 sptr--; 1556 while(sptr != stack && !sptr->count) 1557 sptr--; 1558 if(!sptr->count--) 1559 break; 1560 } 1561 return; 1562 } 1563 /*}}}*/ 1564