1: #include <X/mit-copyright.h> 2: 3: /* Copyright Massachusetts Institute of Technology 1985 */ 4: 5: /* Routines to manage various kinds of resources: 6: * 7: * Add_resource, Free_resource, Free_client_resources, 8: * Bit_size, Pix_size, 9: * Get_font, Store_cursor, 10: * Define_self, Reset_hosts, Add_host, Remove_host, Invalid_host, 11: * Store_cut, Fetch_cut, Rotate_cuts, Reset_cuts, 12: * Init_colormap, 13: * Get_color, Get_cells, Free_colors, Store_colors, Query_color, 14: * Alloc_rectangle, Free_rectangles, Free_rectangle_storage, 15: * Xalloc, Xrealloc 16: */ 17: #ifndef lint 18: static char *rcsid_resource_c = "$Header: resource.c,v 10.11 86/02/01 15:17:05 tony Rel $"; 19: #endif 20: 21: #include "Xint.h" 22: #include <errno.h> 23: #include <sys/socket.h> 24: #include <sys/ioctl.h> 25: #include <net/if.h> 26: #include <netinet/in.h> 27: #include <netdb.h> 28: #ifdef DNETCONN 29: #include <netdnet/dn.h> 30: #include <netdnet/dnetdb.h> 31: #endif 32: 33: extern int errno; 34: extern u_char Xstatus; 35: extern DEVICE device; 36: 37: char *Xalloc(), *Xrealloc(), *malloc(), *realloc(); 38: char *index(), *strcpy(), *strcat(); 39: FONT *GetFont(); 40: CURSOR *StoreCursor(); 41: 42: #define resalloc 50 43: 44: /* Each resource is indexed (by the low bits of the resource id) through 45: * Resources, and chained through ClientResources. 46: */ 47: RESOURCE **Resources = NULL; 48: static RESOURCE *ClientResources[maxsocks]; 49: 50: int MaxResource = 0; 51: static RESOURCE *FreeResource = NULL; 52: 53: #define ridinc (1 << 16) 54: #define ridmask ((1 << 29) - 1) 55: static long ridseed = 0; 56: 57: typedef struct _host { 58: short family; 59: short len; 60: char addr[4]; /* will need to be bigger eventually */ 61: struct _host *next; 62: } HOST; 63: 64: static HOST *selfhosts = NULL; 65: static HOST *validhosts = NULL; 66: 67: typedef struct _cmentry { 68: short refcnt; /* reference count (-1 means writable) */ 69: ushort red; /* color value */ 70: ushort green; 71: ushort blue; 72: } CMENTRY; 73: 74: static CMENTRY *colormap; /* the color map */ 75: static int free_entries; /* number of unallocated entries */ 76: 77: static int numpixels[maxsocks]; /* number of pixel held by each client */ 78: static ushort *clientpixels[maxsocks]; /* lists of pixels held by each client */ 79: 80: #define NUMCUTS 8 81: static char *cutbuf[NUMCUTS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; 82: static int cutbuflen[NUMCUTS] = {0, 0, 0, 0, 0, 0, 0, 0}; 83: static unsigned base_cut = 0; /* Base cut buffer */ 84: 85: RECTANGLE *free_rectangles = NULL; 86: 87: /* Define a client visible resource */ 88: 89: long Add_resource (type, client, value) 90: int type, client; 91: caddr_t value; 92: { 93: register RESOURCE *rptr, **res; 94: register int ridx; 95: 96: if ((rptr = FreeResource) == NULL) { 97: /* no room, expand the resource table */ 98: rptr = (RESOURCE *) Xalloc (resalloc * sizeof (RESOURCE)); 99: if (ridx = MaxResource) { 100: res = (RESOURCE **) Xrealloc ((caddr_t) Resources, 101: (ridx + resalloc) << 2); 102: } else { 103: res = (RESOURCE **) Xalloc (resalloc << 2); 104: ridx++; 105: rptr++; 106: } 107: Resources = res; 108: res += ridx; 109: MaxResource += resalloc; 110: /* initialize the spares */ 111: while (ridx < MaxResource) { 112: *res++ = rptr; 113: rptr->type = RT_FREE; 114: rptr->id = ridx; 115: rptr->next = FreeResource; 116: FreeResource = rptr; 117: ridx++; 118: rptr++; 119: } 120: rptr = FreeResource; 121: } 122: FreeResource = rptr->next; 123: rptr->type = type; 124: rptr->value = value; 125: res = &ClientResources[client]; 126: rptr->prev = (RESOURCE *) res; 127: if (rptr->next = *res) 128: (*res)->prev = rptr; 129: *res = rptr; 130: ridseed += ridinc; 131: ridseed &= ridmask; 132: return (rptr->id = ridseed + RESIDX(rptr->id)); 133: } 134: 135: /* Free a client visible resource */ 136: 137: Free_resource (rptr) 138: register RESOURCE *rptr; 139: { 140: switch (rptr->type) { 141: case RT_WINDOW: 142: Destroy_window ((WINDOW *) rptr->value); 143: break; 144: case RT_FONT: 145: if (--((FONT *) rptr->value)->refcnt == 0) 146: FreeFont ((FONT *) rptr->value); 147: break; 148: case RT_BITMAP: 149: if (--((BITMAP *) rptr->value)->refcnt == 0) 150: FreeBitmap ((BITMAP *) rptr->value); 151: break; 152: case RT_PIXMAP: 153: if (--((PIXMAP *) rptr->value)->refcnt == 0) 154: FreePixmap ((PIXMAP *) rptr->value); 155: break; 156: case RT_CURSOR: 157: if (--((CURSOR *) rptr->value)->refcnt == 0) 158: FreeCursor ((CURSOR *) rptr->value); 159: break; 160: } 161: /* unchain from client and put on free list */ 162: rptr->type = RT_FREE; 163: if ((rptr->prev)->next = rptr->next) 164: (rptr->next)->prev = rptr->prev; 165: rptr->next = FreeResource; 166: FreeResource = rptr; 167: } 168: 169: /* Free all resources owned by a client */ 170: 171: Free_client_resources (client) 172: register int client; 173: { 174: register RESOURCE *rptr, **res; 175: register int rval; 176: register WINDOW *w; 177: 178: Ungrab_client (client); 179: Free_client_colors (client); 180: /* this is slightly expensive in time, but cheap in space */ 181: res = Resources+1; 182: rval = MaxResource; 183: while (--rval > 0) { 184: rptr = *res++; 185: if (rptr->type != RT_WINDOW) 186: continue; 187: w = (WINDOW *) rptr->value; 188: if (w->client == client) { 189: w->mask = NoEvent; 190: w->client = 0; 191: } 192: } 193: res = &ClientResources[client]; 194: if ((rptr = *res) == NULL) return; 195: while (rptr->next) 196: rptr = rptr->next; 197: /* freeing in creation order avoids destroying subwindows one by one */ 198: for (; rptr != (RESOURCE *) res; rptr = rptr->prev) { 199: if (rptr->type != RT_FREE) 200: Free_resource (rptr); 201: } 202: } 203: 204: /* Determine the number of bytes in a bitmap (including padding) */ 205: 206: Bit_size (height, width) 207: register int height, width; 208: { 209: if (height > 0 && width > 0) 210: return (WordPad(BitmapSize(width, height))); 211: Xstatus = BadValue; 212: return (0); 213: } 214: 215: /* Determine the number of bytes in a pixmap (including padding) */ 216: 217: Pix_size (format, height, width) 218: register int format, height, width; 219: { 220: if (height > 0 && width > 0) { 221: if (format == XYFormat) 222: return (WordPad(XYPixmapSize(width, height, device.planes))); 223: else if (format == ZFormat) { 224: if (device.planes > 8) 225: return (WordPad(WZPixmapSize(width, height))); 226: else if (device.planes > 1) 227: return (BytePad(BZPixmapSize(width, height))); 228: } 229: } 230: Xstatus = BadValue; 231: return (0); 232: } 233: 234: /* Create a font */ 235: 236: FONT *Get_font (name) 237: char *name; 238: { 239: register RESOURCE *rptr, **res; 240: register int rval; 241: register FONT *f; 242: 243: /* First see if the font already exists somewhere */ 244: /* Could have a separate font list, but probably not worth it */ 245: res = Resources+1; 246: rval = MaxResource; 247: while (--rval > 0) { 248: rptr = *res++; 249: if (rptr->type == RT_FONT) { 250: f = (FONT *) rptr->value; 251: if (strcmp (f->name, name) == 0) { 252: f->refcnt++; 253: return (f); 254: } 255: } 256: } 257: /* Try to create it */ 258: if ((f = GetFont (name)) == NULL) 259: Xstatus = BadFont; 260: return (f); 261: } 262: 263: /* Create a cursor */ 264: 265: CURSOR *Store_cursor (image, mask, fore, back, xoff, yoff, func) 266: register BITMAP *image, *mask; 267: int back, fore, xoff, yoff; 268: unsigned func; 269: { 270: register CURSOR *c = NULL; 271: 272: if (func >= 16 || xoff < 0 || yoff < 0 || 273: xoff >= image->width || yoff >= image->height || 274: fore < 0 || (fore > WhitePixel && fore >= device.entries) || 275: back < 0 || (back > WhitePixel && back >= device.entries)) 276: Xstatus = BadValue; 277: else if (mask && (mask->width != image->width || 278: mask->height != image->height)) 279: Xstatus = BadMatch; 280: else if ((c = StoreCursor ((int) func, image, fore, back, 281: mask, xoff, yoff)) == NULL) 282: Xstatus = BadAlloc; 283: return (c); 284: } 285: 286: /* Define this host for access control */ 287: 288: Define_self (fd) 289: int fd; 290: { 291: char buf[2048]; 292: struct ifconf ifc; 293: register struct ifreq *ifr; 294: register int n; 295: int len; 296: caddr_t addr; 297: short family; 298: register HOST *host; 299: 300: ifc.ifc_len = sizeof (buf); 301: ifc.ifc_buf = buf; 302: if (ioctl (fd, (int) SIOCGIFCONF, (caddr_t) &ifc) < 0) 303: Error ("Getting interface configuration"); 304: for (ifr = ifc.ifc_req, n = ifc.ifc_len / sizeof (struct ifreq); 305: --n >= 0; 306: ifr++) { 307: if ((family = Convert_addr (&ifr->ifr_addr, &len, &addr)) <= 0) 308: continue; 309: for (host = selfhosts; 310: host && (family != host->family || 311: bcmp (addr, host->addr, len)); 312: host = host->next) ; 313: if (host) continue; 314: host = (HOST *) Xalloc (sizeof (HOST)); 315: host->family = family; 316: host->len = len; 317: bcopy(addr, host->addr, len); 318: host->next = selfhosts; 319: selfhosts = host; 320: } 321: } 322: 323: /* Reset access control list to initial hosts */ 324: 325: Reset_hosts (display) 326: char *display; 327: { 328: register HOST *host, *self; 329: char hostname[120]; 330: char fname[32]; 331: FILE *fd; 332: char *ptr; 333: register struct hostent *hp; 334: union { 335: struct sockaddr sa; 336: struct sockaddr_in in; 337: #ifdef DNETCONN 338: struct sockaddr_dn dn; 339: #endif 340: } saddr; 341: #ifdef DNETCONN 342: struct nodeent *np; 343: struct dn_naddr dnaddr, *dnaddrp, *dnet_addr(); 344: #endif 345: short family; 346: int len; 347: caddr_t addr; 348: 349: while (host = validhosts) { 350: validhosts = host->next; 351: free ((caddr_t) host); 352: } 353: for (self = selfhosts; self; self = self->next) { 354: host = (HOST *) Xalloc (sizeof (HOST)); 355: *host = *self; 356: host->next = validhosts; 357: validhosts = host; 358: } 359: strcpy (fname, "/etc/X"); 360: strcat (fname, display); 361: strcat (fname, ".hosts"); 362: if (fd = fopen (fname, "r")) { 363: while (fgets (hostname, sizeof (hostname), fd)) { 364: if (ptr = index (hostname, '\n')) 365: *ptr = 0; 366: #ifdef DNETCONN 367: if ((ptr = index (hostname, ':')) && (*(ptr + 1) == ':')) { 368: /* node name (DECnet names end in "::") */ 369: *ptr = 0; 370: if (dnaddrp = dnet_addr(hostname)) { 371: /* allow nodes to be specified by address */ 372: Add_host (-1, XAF_DECnet, (caddr_t) dnaddrp); 373: } else { 374: if (np = getnodebyname (hostname)) { 375: /* node was specified by name */ 376: saddr.sa.sa_family = np->n_addrtype; 377: if ((family = Convert_addr (&saddr.sa, &len, &addr)) == XAF_DECnet) { 378: bzero ((caddr_t) &dnaddr, sizeof (dnaddr)); 379: dnaddr.a_len = np->n_length; 380: bcopy (np->n_addr, (caddr_t) dnaddr.a_addr, np->n_length); 381: Add_host (-1, family, (caddr_t) &dnaddr); 382: } 383: } 384: } 385: } else { 386: #endif 387: /* host name */ 388: if (hp = gethostbyname (hostname)) { 389: saddr.sa.sa_family = hp->h_addrtype; 390: if ((family = Convert_addr (&saddr.sa, &len, &addr)) > 0) 391: Add_host (-1, family, hp->h_addr); 392: } 393: #ifdef DNETCONN 394: } 395: #endif 396: } 397: fclose (fd); 398: } 399: } 400: 401: /* Add a host to the access control list */ 402: 403: Add_host (client, family, addr) 404: int client; 405: short family; 406: caddr_t addr; 407: { 408: int len; 409: register HOST *host; 410: 411: if ((len = Check_family (client, family)) < 0) 412: return; 413: for (host = validhosts; host; host = host->next) { 414: if (family == host->family && !bcmp (addr, host->addr, len)) 415: return; 416: } 417: host = (HOST *) Xalloc (sizeof (HOST)); 418: host->family = family; 419: host->len = len; 420: bcopy(addr, host->addr, len); 421: host->next = validhosts; 422: validhosts = host; 423: } 424: 425: /* Remove a host from the access control list */ 426: 427: Remove_host (client, family, addr) 428: int client; 429: short family; 430: caddr_t addr; 431: { 432: int len; 433: register HOST *host, **prev; 434: 435: if ((len = Check_family (client, family)) < 0) 436: return; 437: for (prev = &validhosts; 438: (host = *prev) && 439: (family != host->family || bcmp (addr, host->addr, len)); 440: prev = &host->next) ; 441: if (host) { 442: *prev = host->next; 443: free ((caddr_t) host); 444: } 445: } 446: 447: /* Get all hosts in the access control list */ 448: 449: Get_hosts (family, data) 450: short family; 451: char **data; 452: { 453: int len; 454: register int n; 455: register caddr_t ptr; 456: register HOST *host; 457: 458: if ((len = Check_family (-1, family)) < 0) 459: return (-1); 460: n = 0; 461: for (host = validhosts; host; host = host->next) { 462: if (host->family == family) 463: n += len; 464: } 465: if (n) { 466: *data = ptr = Xalloc (n); 467: for (host = validhosts; host; host = host->next) { 468: if (host->family == family) { 469: bcopy (host->addr, ptr, len); 470: ptr += len; 471: } 472: } 473: } 474: return (n); 475: } 476: 477: /* Check for valid address family, and for local host if client modification. 478: * Return address length. 479: */ 480: 481: Check_family (client, family) 482: int client; 483: short family; 484: { 485: struct sockaddr from; 486: int alen; 487: caddr_t addr; 488: register HOST *host; 489: int len; 490: 491: switch (family) { 492: case XAF_INET: 493: len = sizeof (struct in_addr); 494: break; 495: #ifdef DNETCONN 496: case XAF_DECnet: 497: len = sizeof (struct dn_naddr); 498: break; 499: #endif 500: default: 501: Xstatus = BadValue; 502: return (-1); 503: } 504: if (client < 0) return (len); 505: alen = sizeof (from); 506: if (!getpeername (client, &from, &alen)) { 507: if ((family = Convert_addr (&from, &alen, &addr)) >= 0) { 508: if (family == 0) return (len); 509: for (host = selfhosts; host; host = host->next) { 510: if (family == host->family && 511: !bcmp (addr, host->addr, alen)) 512: return (len); 513: } 514: } 515: } 516: Xstatus = BadAccess; 517: return (-1); 518: } 519: 520: /* Check if a host is not in the access control list */ 521: 522: Invalid_host (saddr, len) 523: register struct sockaddr *saddr; 524: int len; 525: { 526: short family; 527: caddr_t addr; 528: register HOST *host; 529: 530: if ((family = Convert_addr (saddr, &len, &addr)) < 0) 531: return (1); 532: if (family == 0) return (0); 533: for (host = validhosts; host; host = host->next) { 534: if (family == host->family && !bcmp (addr, host->addr, len)) 535: return (0); 536: } 537: return (1); 538: } 539: 540: Convert_addr (saddr, len, addr) 541: register struct sockaddr *saddr; 542: int *len; 543: caddr_t *addr; 544: { 545: if (len == 0) return (0); 546: switch (saddr->sa_family) { 547: case AF_UNSPEC: 548: case AF_UNIX: 549: return (0); 550: case AF_INET: 551: *len = sizeof (struct in_addr); 552: *addr = (caddr_t) &(((struct sockaddr_in *) saddr)->sin_addr); 553: return (XAF_INET); 554: #ifdef DNETCONN 555: case AF_DECnet: 556: *len = sizeof (struct dn_naddr); 557: *addr = (caddr_t) &(((struct sockaddr_dn *) saddr)->sdn_add); 558: return (XAF_DECnet); 559: #endif 560: default: 561: break; 562: } 563: return (-1); 564: } 565: 566: /* Place data in a cut buffer, discarding previous contents */ 567: 568: Store_cut (n, data, len) 569: register unsigned n; 570: char *data; 571: int len; 572: { 573: if (n >= NUMCUTS) 574: Xstatus = BadValue; 575: else { 576: n = (base_cut + n) & (NUMCUTS - 1); 577: if (cutbuf[n]) { 578: free (cutbuf[n]); 579: cutbuf[n] = NULL; 580: } 581: if (cutbuflen[n] = len) { 582: cutbuf[n] = Xalloc (BytePad(len)); 583: bcopy (data, cutbuf[n], len); 584: } 585: } 586: } 587: 588: /* Copy the data from a cut buffer */ 589: 590: Fetch_cut (n, data) 591: register unsigned n; 592: char **data; 593: { 594: if (n >= NUMCUTS) { 595: Xstatus = BadValue; 596: return (-1); 597: } 598: n = (base_cut + n) & (NUMCUTS - 1); 599: *data = cutbuf[n]; 600: return (cutbuflen[n]); 601: } 602: 603: /* Rotate the cut buffers */ 604: 605: Rotate_cuts (n) 606: register unsigned n; 607: { 608: if (n >= NUMCUTS) 609: Xstatus = BadValue; 610: else 611: base_cut = (base_cut + n) & (NUMCUTS - 1); 612: } 613: 614: /* Delete the data from all cut buffers */ 615: 616: Reset_cuts () 617: { 618: register int i; 619: 620: for (i = -1; ++i < NUMCUTS; ) { 621: if (cutbuf[i]) { 622: free (cutbuf[i]); 623: cutbuf[i] = NULL; 624: cutbuflen[i] = 0; 625: } 626: } 627: base_cut = 0; 628: } 629: 630: /* Create and initialize the color map */ 631: 632: Init_colormap () 633: { 634: colormap = (CMENTRY *) Xalloc ((int) device.entries * sizeof (CMENTRY)); 635: bzero ((caddr_t) colormap, device.entries * sizeof (CMENTRY)); 636: free_entries = device.entries; 637: if (device.entries > WhitePixel) { 638: free_entries -= 2; 639: colormap[BlackPixel].refcnt = -1; 640: colormap[WhitePixel].refcnt = -1; 641: } 642: } 643: 644: /* Get a read-only color (probably slow for large maps) */ 645: 646: Get_color (client, red, green, blue) 647: register int client; 648: ushort red, green, blue; 649: { 650: register CMENTRY *ent; 651: register int pixel; 652: int free = 0; 653: register ushort *list; 654: int entries; 655: ColorDef def; 656: 657: ResolveColor (&red, &green, &blue); 658: /* see if there is a match, and also look for a free entry */ 659: entries = device.entries; 660: for (ent = colormap, pixel = -1; ++pixel < entries; ent++) { 661: if (ent->refcnt > 0) { 662: if (ent->red == red && ent->green == green && ent->blue == blue) { 663: ent->refcnt++; 664: goto addit; 665: } 666: } else if (free == 0 && ent->refcnt == 0) 667: free = pixel; 668: } 669: if ((pixel = free) == 0) { 670: Xstatus = BadAlloc; 671: return (0); 672: } 673: free_entries--; 674: /* fill in the entry */ 675: ent = &colormap[pixel]; 676: ent->refcnt = 1; 677: ent->red = red; 678: ent->green = green; 679: ent->blue = blue; 680: def.pixel = pixel; 681: def.red = red; 682: def.green = green; 683: def.blue = blue; 684: StoreColors (1, &def); 685: addit: /* add pixel to client list */ 686: list = (ushort *) Xrealloc ((caddr_t) clientpixels[client], 687: (numpixels[client] + 1) << 1); 688: clientpixels[client] = list; 689: list[numpixels[client]] = pixel; 690: numpixels[client]++; 691: return (pixel); 692: } 693: 694: /* Allocate writeable color cells (probably slow for large maps) */ 695: 696: Get_cells (client, contig, count, planes, pixels) 697: int client, contig, planes; 698: register int count; 699: ushort **pixels; 700: { 701: register ushort *pptr; 702: register CMENTRY *ent; 703: register int pixel; 704: register int maxp, mask; 705: int entries, dplanes, base, found, save; 706: 707: dplanes = device.planes; 708: 709: if (planes == 0) { 710: if (count == 0) 711: return (0); 712: if (count > free_entries) 713: goto bad; 714: free_entries -= count; 715: /* make room for new pixels */ 716: pptr = (ushort *) Xrealloc ((caddr_t) clientpixels[client], 717: (numpixels[client] + count) << 1); 718: clientpixels[client] = pptr; 719: pptr += numpixels[client]; 720: *pixels = pptr; 721: numpixels[client] += count; 722: /* allocate writable entries */ 723: ent = colormap; 724: pixel = 0; 725: while (--count >= 0) { 726: while (ent->refcnt) { 727: ent++; 728: pixel++; 729: } 730: ent->refcnt = -1; 731: *pptr++ = pixel; 732: } 733: return (0); 734: } else if (count == 0) { 735: if (planes >= dplanes) 736: goto bad; 737: entries = device.entries; 738: base = 1 << (dplanes - planes); 739: /* make sure all are free */ 740: for (pixel = base - 1, ent = &colormap[base]; ++pixel < entries; ent++) { 741: if (ent->refcnt) 742: goto bad; 743: } 744: count = entries - base; 745: /* make room for new pixels */ 746: pptr = (ushort *) Xrealloc ((caddr_t) clientpixels[client], 747: (numpixels[client] + count) << 1); 748: clientpixels[client] = pptr; 749: pptr += numpixels[client]; 750: numpixels[client] += count; 751: free_entries -= count; 752: /* allocate them */ 753: for (pixel = base - 1, ent = &colormap[base]; ++pixel < entries; ent++) { 754: ent->refcnt = -1; 755: *pptr++ = pixel; 756: } 757: return (((1 << planes) - 1) << (dplanes - planes)); 758: } else if (planes >= dplanes || (count << planes) > free_entries) 759: goto bad; 760: /* make room for new pixels */ 761: pptr = (ushort *) Xrealloc ((caddr_t) clientpixels[client], 762: (numpixels[client] + (count << planes)) << 1); 763: clientpixels[client] = pptr; 764: *pixels = pptr + numpixels[client]; 765: ent = colormap; 766: /* first try for contiguous planes, since its fastest */ 767: for (mask = (1 << planes) - 1, base = 1, dplanes -= (planes - 1); 768: --dplanes >= 0; 769: mask += mask, base += base) { 770: pptr = *pixels; 771: found = 0; 772: pixel = 0; 773: entries = device.entries - mask; 774: while (pixel < entries) { 775: save = pixel; 776: maxp = pixel + mask + base; 777: /* check if all are free */ 778: while (pixel != maxp && ent[pixel].refcnt == 0) 779: pixel += base; 780: if (pixel == maxp) { 781: /* this one works */ 782: *pptr++ = save; 783: found++; 784: if (found == count) { 785: /* found enough, allocate them all */ 786: numpixels[client] += count << planes; 787: free_entries -= count << planes; 788: while (--count >= 0) { 789: pixel = (*pixels)[count]; 790: maxp = pixel + mask; 791: while (1) { 792: ent[pixel].refcnt = -1; 793: if (pixel == maxp) 794: break; 795: pixel += base; 796: *pptr++ = pixel; 797: } 798: } 799: return (mask); 800: } 801: } 802: pixel = save + 1; 803: if (pixel & mask) 804: pixel += mask; 805: } 806: } 807: if (contig || planes == 1) goto fail; 808: /* this will be very slow for large maps, need a better algorithm */ 809: dplanes = (1 << device.planes) - (1 << planes); 810: for (mask = 0; mask <= dplanes; mask++) { 811: /* next 3 magic statements count number of ones (HAKMEM #169) */ 812: pixel = (mask >> 1) & 03333333333; 813: pixel = mask - pixel - ((pixel >> 1) & 03333333333); 814: if ((((pixel + (pixel >> 3)) & 0707070707) % 077) != planes) 815: continue; 816: pptr = *pixels; 817: found = 0; 818: entries = device.entries - mask; 819: base = 1 << (ffs(mask) - 1); 820: for (pixel = 0; pixel < entries; pixel++) { 821: if (pixel & mask) continue; 822: maxp = 0; 823: /* check if all are free */ 824: while (ent[pixel + maxp].refcnt == 0) { 825: maxp += base; 826: if (maxp > mask) 827: break; 828: while (maxp & ~mask) 829: maxp += (maxp & ~mask); 830: } 831: if (maxp <= mask) 832: continue; 833: /* this one works */ 834: *pptr++ = pixel; 835: found++; 836: if (found < count) 837: continue; 838: /* found enough, allocate them all */ 839: numpixels[client] += count << planes; 840: free_entries -= count << planes; 841: while (--count >= 0) { 842: pixel = (*pixels)[count]; 843: maxp = 0; 844: while (1) { 845: ent[pixel + maxp].refcnt = -1; 846: if (maxp == mask) 847: break; 848: maxp += base; 849: while (maxp & ~mask) 850: maxp += (maxp & ~mask); 851: *pptr++ = pixel + maxp; 852: } 853: } 854: return (mask); 855: } 856: } 857: fail: /* failed to get them, back out of the allocation */ 858: if (count = numpixels[client]) 859: clientpixels[client] = (ushort *) Xrealloc ((caddr_t) clientpixels[client], 860: count << 1); 861: else { 862: free ((caddr_t) clientpixels[client]); 863: clientpixels[client] = NULL; 864: } 865: bad: Xstatus = BadAlloc; 866: return (0); 867: } 868: 869: /* Free colors and/or cells (probably slow for large numbers) */ 870: 871: Free_colors (client, count, pixels, mask) 872: int client, count; 873: ushort *pixels; 874: unsigned mask; 875: { 876: register ushort *pptr, *cptr; 877: unsigned bits, bit; 878: ushort pixel; 879: register CMENTRY *ent; 880: register int n, z; 881: int zapped; 882: 883: if (count == 0) return; 884: bits = 0; 885: zapped = 0; 886: while (1) { 887: /* go through pixel list */ 888: for (pptr = pixels, n = count; --n >= 0; pptr++) { 889: pixel = *pptr | bits; 890: /* find match in client list */ 891: for (cptr = clientpixels[client], z = numpixels[client]; 892: --z >= 0 && *cptr != pixel; 893: cptr++) ; 894: if (z >= 0 && pixel) { 895: ent = &colormap[pixel]; 896: if (ent->refcnt < 0) 897: ent->refcnt = 0; 898: else 899: ent->refcnt--; 900: if (ent->refcnt == 0) 901: free_entries++; 902: *cptr = 0; 903: zapped++; 904: } else if (pixel >= device.entries) 905: Xstatus = BadValue; 906: else 907: Xstatus = BadAccess; 908: } 909: if (bits == mask) 910: break; 911: /* generate next bits value */ 912: bit = 1; 913: while (1) { 914: while (!(mask & bit)) 915: bit += bit; 916: bits ^= bit; 917: if (bits & bit) 918: break; 919: bit += bit; 920: } 921: } 922: if (zapped) { 923: /* delete zeroes from list */ 924: n = numpixels[client] - zapped; 925: if (n) { 926: pixels = (ushort *) Xalloc (n << 1); 927: pptr = pixels; 928: cptr = clientpixels[client]; 929: z = n; 930: while (1) { 931: if (*cptr) { 932: *pptr++ = *cptr; 933: if (--z == 0) 934: break; 935: } 936: cptr++; 937: } 938: } else 939: pixels = NULL; 940: free ((caddr_t) clientpixels[client]); 941: clientpixels[client] = pixels; 942: numpixels[client] = n; 943: } 944: } 945: 946: /* Free all of a client's colors and cells */ 947: 948: Free_client_colors (client) 949: register int client; 950: { 951: register ushort *pptr; 952: register int n; 953: register CMENTRY *ent; 954: 955: if ((pptr = clientpixels[client]) == NULL) 956: return; 957: n = numpixels[client]; 958: while (--n >= 0) { 959: ent = &colormap[*pptr++]; 960: if (ent->refcnt < 0) 961: ent->refcnt = 0; 962: else 963: ent->refcnt--; 964: if (ent->refcnt == 0) 965: free_entries++; 966: } 967: free ((caddr_t) clientpixels[client]); 968: clientpixels[client] = NULL; 969: numpixels[client] = 0; 970: } 971: 972: /* Redefine color values */ 973: 974: Store_colors (count, defs) 975: int count; 976: ColorDef *defs; 977: { 978: register int n; 979: register ColorDef *def; 980: register CMENTRY *ent; 981: 982: /* first make sure all are writable */ 983: for (def = defs, n = count; --n >= 0; def++) { 984: if (def->pixel >= device.entries) { 985: Xstatus = BadValue; 986: return; 987: } else if (colormap[def->pixel].refcnt >= 0) { 988: Xstatus = BadAccess; 989: return; 990: } 991: } 992: /* update them */ 993: for (def = defs, n = count; --n >= 0; def++) { 994: ResolveColor (&def->red, &def->green, &def->blue); 995: ent = &colormap[def->pixel]; 996: ent->red = def->red; 997: ent->green = def->green; 998: ent->blue = def->blue; 999: } 1000: StoreColors (count, defs); 1001: } 1002: 1003: /* Read the color value of a cell */ 1004: 1005: Query_color (pixel, red, green, blue) 1006: register unsigned pixel; 1007: ushort *red, *green, *blue; 1008: { 1009: register CMENTRY *ent; 1010: 1011: if (pixel >= device.entries) 1012: Xstatus = BadValue; 1013: else { 1014: ent = &colormap[pixel]; 1015: *red = ent->red; 1016: *green = ent->green; 1017: *blue = ent->blue; 1018: } 1019: } 1020: 1021: #define alloc_at_once 50 1022: 1023: /* Called from the rectangle macros when the free list is empty. 1024: * We allocate in chunks to minimize fragmentation. 1025: */ 1026: 1027: RECTANGLE *Alloc_rectangle () 1028: { 1029: register RECTANGLE *r, *rec; 1030: register int i; 1031: 1032: rec = (RECTANGLE *) Xalloc (alloc_at_once * sizeof (RECTANGLE)); 1033: r = rec; 1034: rec->internal = 0; 1035: i = alloc_at_once; 1036: while (--i > 0) { 1037: r->next = r + 1; 1038: r++; 1039: r->internal = 1; 1040: } 1041: r->next = NULL; 1042: return (rec); 1043: } 1044: 1045: /* Put all the rectangles back on the free list. */ 1046: 1047: Free_rectangles (rlist) 1048: register RECTANGLE *rlist; 1049: { 1050: register RECTANGLE *rec; 1051: 1052: rec = rlist; 1053: while (rec->next) 1054: rec = rec->next; 1055: rec->next = free_rectangles; 1056: free_rectangles = rlist; 1057: } 1058: 1059: /* Free storage associated with unused rectangles */ 1060: 1061: Free_rectangle_storage () 1062: { 1063: register RECTANGLE *r, **pr; 1064: 1065: /* drop the "internal" rectangles */ 1066: pr = &free_rectangles; 1067: while (r = *pr) { 1068: if TRUE(r->internal) 1069: *pr = r->next; 1070: else 1071: pr = &r->next; 1072: } 1073: /* now free the "head" rectangles */ 1074: while (r = free_rectangles) { 1075: free_rectangles = r->next; 1076: free ((caddr_t) r); 1077: } 1078: } 1079: 1080: /* malloc wrap-around, to take care of the "no memory" case, since 1081: * it would be difficult in many places to "back out" on failure. 1082: */ 1083: 1084: char *Xalloc (amount) 1085: int amount; 1086: { 1087: register char *ptr; 1088: 1089: if (ptr = malloc ((unsigned) amount)) 1090: return (ptr); 1091: errno = ENOMEM; 1092: Error ("Allocating"); 1093: /*NOTREACHED*/ 1094: } 1095: 1096: /* realloc wrap-around, to take care of the "no memory" case, since 1097: * it would be difficult in many places to "back out" on failure. 1098: */ 1099: 1100: char *Xrealloc (ptr, amount) 1101: register char *ptr; 1102: int amount; 1103: { 1104: if (ptr) 1105: ptr = realloc (ptr, (unsigned) amount); 1106: else 1107: ptr = malloc ((unsigned) amount); 1108: if (ptr) 1109: return (ptr); 1110: errno = ENOMEM; 1111: Error ("Allocating"); 1112: /*NOTREACHED*/ 1113: }