1: #include <X/mit-copyright.h> 2: 3: /* Copyright Massachusetts Institute of Technology 1985 */ 4: 5: /* Routines for maintaining windows: 6: * 7: * Create_root_window, Create_window, Destroy_window, 8: * Map_root_window, Map_window, Map_subwindows, 9: * Unmap_window, Unmap_subwindows, Remove_subwindows, 10: * Move_window, Change_window, Change_background, Change_border, 11: * Raise_window, Lower_window, Circulate_window_up, Circulate_window_down, 12: * Draw_window, Windex, Free_window_storage 13: */ 14: #ifndef lint 15: static char *rcsid_window_c = "$Header: window.c,v 10.8 86/02/01 15:17:33 tony Rel $"; 16: #endif 17: 18: #include "Xint.h" 19: 20: extern u_char Xstatus; 21: extern RESOURCE **Resources; 22: extern PIXMAP *roottile; 23: extern RECTANGLE *free_rectangles; 24: extern int mouse_grabber; 25: extern WINDOW *button_window, *mouse_grab_window, *key_window; 26: extern RASTER mbox; 27: 28: char *Xalloc(); 29: long Add_resource(); 30: RECTANGLE *Alloc_rectangle(); 31: WINDOW *Unmap_window(); 32: 33: #define MBOX(w) if (w->vs.top < mbox.bottom && mbox.top < w->vs.bottom &&\ 34: w->vs.left < mbox.right && mbox.left < w->vs.right)\ 35: mbox.bottom = 0 36: 37: #define alloc_at_once 25 38: 39: WINDOW *rootwindow = NULL; /* The background of the whole tree */ 40: static WINDOW *mapped_list = NULL; /* List of windows mapped to the screeen */ 41: WINDOW *free_windows = NULL; 42: 43: /* Create_root_window creates and maps the root window on the screen. 44: * The root window differs from other windows in that it has no parent. 45: */ 46: 47: Create_root_window (height, width, tile) 48: int height, width; 49: PIXMAP *tile; 50: { 51: int root; 52: 53: /* make sure no other windows are in the root's malloc'd area */ 54: free_windows = (WINDOW *) Xalloc (sizeof (WINDOW)); 55: free_windows->next = NULL; 56: root = Create_window (height, width, 0, 0, 0, (PIXMAP *) NULL, 57: tile, IsOpaque, (WINDOW *) NULL, 0); 58: rootwindow = (WINDOW *) Resources[RESIDX(root)]->value; 59: rootwindow->clipmode = ClipModeDrawThru; 60: Map_root_window (); 61: } 62: 63: /* Create_window creates a new window with common parameters filled in. 64: * The window returned is unmapped. 65: */ 66: 67: int Create_window (height, width, x, y, bwidth, border, tile, kind, 68: parent, client) 69: int height, width, x, y, bwidth, kind, client; 70: register WINDOW *parent; 71: PIXMAP *border, *tile; 72: { 73: register WINDOW *w; 74: int i; 75: 76: if (height <= 0 || width <= 0 || bwidth < 0) { 77: Xstatus = BadValue; 78: return (NULL); 79: } else if (kind != IsTransparent) { 80: if (parent && parent->kind == IsTransparent) { 81: Xstatus = BadMatch; 82: return (NULL); 83: } else if (bwidth > 0 && border == NULL) { 84: Xstatus = BadPixmap; 85: return (NULL); 86: } else if ((border && FALSE(border->tile)) || 87: (tile && FALSE(tile->tile))) { 88: Xstatus = BadTile; 89: return (NULL); 90: } else if (tile == NULL) { 91: tile = parent->tile; 92: } 93: } 94: 95: if ((w = free_windows) == NULL) { 96: /* We allocate in chunks to minimize fragmentation. */ 97: w = (WINDOW *) Xalloc (alloc_at_once * sizeof (WINDOW)); 98: free_windows = w; 99: w->internal = 0; 100: i = alloc_at_once; 101: while (--i > 0) { 102: w->next = w + 1; 103: w++; 104: w->internal = 1; 105: } 106: w->next = NULL; 107: w = free_windows; 108: } 109: free_windows = w->next; 110: 111: w->full.left = x + bwidth; 112: w->full.top = y + bwidth; 113: w->full.right = w->full.left + width; 114: w->full.bottom = w->full.top + height; 115: w->bwidth = bwidth; 116: if (w->border = border) 117: border->refcnt++; 118: if (w->tile = tile) 119: tile->refcnt++; 120: if (kind == IsTransparent) 121: w->tilemode = TileModeRelative; 122: else 123: w->tilemode = TileModeAbsolute; 124: w->clipmode = ClipModeClipped; 125: 126: w->cursor = NULL; 127: w->mask = NoEvent; 128: w->client = 0; 129: 130: if (parent) 131: w->level = parent->level + 1; 132: else 133: w->level = 0; 134: w->kind = kind; 135: w->first_child = w->last_child = NULL; 136: w->parent = parent; 137: w->visible = NULL; 138: w->cmvisible = NULL; 139: w->unobscured = OB_NOT; 140: w->mapped = w->should_be_mapped = 0; 141: w->bgrabs = 0; 142: w->name = NULL; 143: w->width0 = w->height0 = 0; 144: w->widthinc = w->heightinc = 1; 145: w->icon = NULL; 146: 147: if (parent) { 148: /* make it the top-most child */ 149: if (parent->last_child) { 150: parent->last_child->next_sib = w; 151: w->prev_sib = parent->last_child; 152: w->next_sib = NULL; 153: parent->last_child = w; 154: } else { 155: parent->first_child = parent->last_child = w; 156: w->next_sib = w->prev_sib = NULL; 157: } 158: } else { 159: w->next_sib = w->prev_sib = NULL; 160: } 161: 162: return (w->rid = Add_resource (RT_WINDOW, client, (caddr_t) w)); 163: } 164: 165: /* Eliminate a window. */ 166: 167: Destroy_window (w) 168: register WINDOW *w; 169: { 170: register WINDOW *icon; 171: 172: /* Check icon status */ 173: 174: if (icon = w->icon) { 175: if (w->kind == IsIcon && TRUE(w->mapped) && FALSE(icon->mapped)) 176: Map_window (icon); 177: else if (icon->kind == IsIcon && TRUE(icon->mapped)) { 178: Unmap_window (icon, 1); 179: Stash_simple (icon, (long) UnmapWindow, 0); 180: } 181: icon->kind = IsOpaque; 182: icon->icon = NULL; 183: } 184: 185: /* Unmap it */ 186: 187: if TRUE(w->mapped) 188: Unmap_window (w, 1); 189: 190: /* Destroy all the children */ 191: 192: if (w->first_child) 193: Zap_subwindows (w, 1); 194: 195: /* Remove from parent's list */ 196: 197: if (w->next_sib) 198: w->next_sib->prev_sib = w->prev_sib; 199: else 200: w->parent->last_child = w->prev_sib; 201: 202: if (w->prev_sib) 203: w->prev_sib->next_sib = w->next_sib; 204: else 205: w->parent->first_child = w->next_sib; 206: 207: /* Get it out of any binds */ 208: 209: if (w == button_window || (mouse_grabber && w == mouse_grab_window)) 210: Stash_ungrabs (); 211: if (w->bgrabs) 212: Unbutton_window (w); 213: if (w == key_window) { 214: key_window = NULL; 215: Focus_keyboard (w->parent); 216: } 217: 218: /* Free the resources */ 219: 220: if (w->cursor) 221: Unregister_cursor (w); 222: 223: if (w->name) 224: free (w->name); 225: 226: if (w->border && --w->border->refcnt == 0) 227: FreePixmap (w->border); 228: if (w->tile && --w->tile->refcnt == 0) 229: FreePixmap (w->tile); 230: 231: w->next = free_windows; 232: free_windows = w; 233: } 234: 235: /* Maps the root window */ 236: 237: Map_root_window () 238: { 239: register WINDOW *w = rootwindow; 240: register RECTANGLE *r; 241: 242: w->vs = w->full; 243: w->ovs = w->full; 244: w->clip.left = w->vs.left; 245: w->clip.top = w->vs.top; 246: w->clip.height = w->vs.bottom - w->vs.top; 247: w->clip.width = w->vs.right - w->vs.left; 248: RASTRECT(r, w->full, contents_rec); 249: r->next = NULL; 250: w->visible = r; 251: RASTRECT(r, w->full, contents_rec); 252: r->next = NULL; 253: w->cmvisible = r; 254: 255: w->next = NULL; 256: mapped_list = w; 257: w->prev = NULL; 258: 259: w->mapped = w->should_be_mapped = 1; 260: w->unobscured = OB_YES; 261: 262: Do_background (w, 1); 263: } 264: 265: /* Map_window raises and displays the specified window on the screen. It also 266: * goes through the window's subwindows and maps all those for whom the 267: * should_be_mapped flag is set. 268: */ 269: 270: Map_window (w) 271: register WINDOW *w; 272: { 273: if FALSE(w->parent->mapped) { 274: w->should_be_mapped = 1; 275: return; 276: } 277: 278: Map_window_main (w, 1, 0); 279: MBOX(w); 280: 281: if (w->first_child) 282: Map_subwindows (w, 0, 0); 283: 284: Draw_window (w, 0, 1); 285: } 286: 287: /* Does the common work of mapping a window. 288: * If top is set, the window is top-most, else it is bottom-most. 289: * If dontMove is set, this window is already placed in the parent's list. 290: */ 291: 292: Map_window_main (w, top, dontMove) 293: register WINDOW *w; 294: int top, dontMove; 295: { 296: register WINDOW *w1 = w->parent; 297: 298: w->mapped = w->should_be_mapped = 1; 299: 300: /* get absolute coordinates */ 301: w->full.left += w1->full.left; 302: w->full.top += w1->full.top; 303: w->full.right += w1->full.left; 304: w->full.bottom += w1->full.top; 305: 306: /* clip to parent */ 307: w->vs = w->full; 308: Clip_raster (&w->vs, &w1->vs); 309: 310: w->ovs.left = w->full.left - w->bwidth; 311: w->ovs.right = w->full.right + w->bwidth; 312: w->ovs.top = w->full.top - w->bwidth; 313: w->ovs.bottom = w->full.bottom + w->bwidth; 314: Clip_raster (&w->ovs, &w1->vs); 315: if (w->ovs.right <= w->ovs.left) 316: w->ovs.right = w->ovs.bottom = -1; 317: 318: w->clip.left = w->vs.left; 319: w->clip.top = w->vs.top; 320: w->clip.height = w->vs.bottom - w->vs.top; 321: w->clip.width = w->vs.right - w->vs.left; 322: 323: if TRUE(top) { 324: /* Search the mapped_list backwards starting at w's parent until we 325: * either find a window with a lower level or we find the beginning 326: * of the list. Insert after it. 327: */ 328: 329: do { 330: w1 = w1->prev; 331: } while (w1 && w1->level >= w->level); 332: 333: if (w1) { 334: w->prev = w1; 335: w->next = w1->next; 336: w->next->prev = w; 337: w1->next = w; 338: } else { 339: w->next = mapped_list; 340: mapped_list->prev = w; 341: mapped_list = w; 342: w->prev = NULL; 343: } 344: 345: /* Move w to be the last child of its parent */ 346: if (w->next_sib && FALSE(dontMove)) 347: Make_top_child (w); 348: 349: /* Get its rectangles and obscure other windows */ 350: if (w->kind != IsTransparent) 351: Obscure_top (w); 352: } else { 353: /* Place w just before its parent in the mapped_list */ 354: 355: w->next = w1; 356: if (w->prev = w1->prev) 357: w->prev->next = w; 358: else 359: mapped_list = w; 360: w1->prev = w; 361: 362: /* Move w to be the first child of its parent */ 363: if (w->prev_sib && FALSE(dontMove)) 364: Make_bottom_child (w); 365: 366: /* Get its rectangles and obscure other windows */ 367: if (w->kind != IsTransparent) 368: Obscure_bottom (w); 369: } 370: } 371: 372: /* Maps the subwindows of a window. 373: * If dontRedraw is set, the subwindows have already been displayed. 374: * If all is set, all subwindows are mapped, not just the should_be_mapped. 375: */ 376: 377: Map_subwindows (w, dontRedraw, all) 378: WINDOW *w; 379: int dontRedraw, all; 380: { 381: register WINDOW *w1; 382: 383: if TRUE(w->mapped) { 384: /* mapping from top to bottom is the most efficient */ 385: for (w1 = w->last_child; w1; w1 = w1->prev_sib) { 386: if (FALSE(w1->mapped) && 387: (TRUE(all) || TRUE(w1->should_be_mapped))) { 388: Map_window_main (w1, 0, 1); 389: if TRUE(all) { 390: MBOX(w1); 391: } 392: if (w1->first_child) 393: Map_subwindows (w1, dontRedraw, 0); 394: if FALSE(dontRedraw) 395: Draw_window (w1, 0, 1); 396: } 397: } 398: } else if TRUE(all) { 399: for (w1 = w->first_child; w1; w1 = w1->next_sib) 400: w1->should_be_mapped = 1; 401: } 402: } 403: 404: /* Unmap_window removes the window from the list of mapped windows and updates 405: * all the windows that it may have been obscuring. All the subwindows are 406: * unmapped but their should_be_mapped flags are unchanged. If cleanup = 1, 407: * then update windows you uncover. If cleanup < 0, then update the 408: * windows you uncover without changing the bits on the screen. 409: * Returns the next mapped window in the mapped_list chain. 410: */ 411: 412: WINDOW *Unmap_window (w, cleanup) 413: register WINDOW *w; 414: int cleanup; 415: { 416: WINDOW *w1; 417: 418: if (w->first_child) { 419: Zap_subwindows (w, 0); 420: Restore_rectangles (w); 421: } 422: MBOX(w); 423: w1 = w->next; 424: Unmap_window_main (w, 0, cleanup); 425: return (w1); 426: } 427: 428: /* Restore the visible rectangles as if there were no subwindows, i.e., 429: * make it a copy of cmvisible plus existing borders. 430: */ 431: 432: Restore_rectangles (w) 433: WINDOW *w; 434: { 435: register RECTANGLE *vr, *cr, **prev; 436: 437: cr = w->cmvisible; 438: prev = &w->visible; 439: /* reuse what we can */ 440: while (vr = *prev) { 441: if (vr->type != border_rec) { 442: if (cr == NULL) { 443: *prev = vr->next; 444: FREERECT(vr); 445: continue; 446: } 447: *(RASTER *) vr = *(RASTER *) cr; 448: vr->type = contents_rec; 449: cr = cr->next; 450: } 451: prev = &vr->next; 452: } 453: /* allocate the rest */ 454: for (; cr; cr = cr->next) { 455: RASTRECT(vr, *(RASTER *) cr, contents_rec); 456: *prev = vr; 457: prev = &vr->next; 458: } 459: *prev = NULL; 460: } 461: 462: /* Do the common work of unmapping a window. 463: * Set should_be_mapped to the indicated state. If cleanup = 1, then update 464: * windows you uncover. If cleanup < 0, then update the windows you uncover 465: * without changing the bits on the screen. 466: */ 467: 468: Unmap_window_main (w, should_be_mapped, cleanup) 469: register WINDOW *w; 470: int should_be_mapped, cleanup; 471: { 472: register WINDOW *w1; 473: 474: /* Remove it from the list */ 475: 476: w1 = w->next; 477: if (w1->prev = w->prev) 478: w->prev->next = w1; 479: else 480: mapped_list = w1; 481: 482: /* Get rid of the rectangles */ 483: 484: if (w->visible) { 485: if (w->cmvisible) { 486: Free_rectangles (w->cmvisible); 487: w->cmvisible = NULL; 488: } 489: Remove_rectangles (w, w1, cleanup); 490: } 491: 492: w->next = w->prev = NULL; 493: 494: /* make coordinates relative */ 495: w1 = w->parent; 496: w->full.left -= w1->full.left; 497: w->full.top -= w1->full.top; 498: w->full.right -= w1->full.left; 499: w->full.bottom -= w1->full.top; 500: 501: w->should_be_mapped = should_be_mapped; 502: w->mapped = 0; 503: w->unobscured = OB_NOT; 504: } 505: 506: /* Unmap all the subwindows of a window. */ 507: 508: Unmap_subwindows (w) 509: WINDOW *w; 510: { 511: register WINDOW *w1; 512: 513: for (w1 = w->first_child; w1; w1 = w1->next_sib) { 514: if TRUE(w1->mapped) 515: Stash_simple (w1, (long) UnmapWindow, 0); 516: } 517: Remove_subwindows (w, 0, 1); 518: } 519: 520: /* Unmap all subwindows, giving space back to parent. Destroy the subwindows 521: * if destroy flag is set. Display the window if cleanup is set. 522: */ 523: 524: Remove_subwindows (w, destroy, cleanup) 525: WINDOW *w; 526: int destroy; 527: { 528: register WINDOW *w1; 529: register RECTANGLE *rec, *rlist, **prev; 530: int vn, cn; 531: 532: /* count visible rectangles */ 533: vn = 0; 534: for (prev = &w->visible; rec = *prev; prev = &rec->next) { 535: if (rec->type != border_rec) 536: vn++; 537: } 538: /* collect new visible rectangles and unmap subwindows */ 539: cn = 0; 540: rlist = NULL; 541: for (w1 = w->first_child; w1; w1 = w1->next_sib) { 542: if TRUE(w1->mapped) { 543: if (rec = w1->cmvisible) { 544: while (1) { 545: rec->type = new_rec; 546: cn++; 547: if (rec->next == NULL) 548: break; 549: rec = rec->next; 550: } 551: rec->next = rlist; 552: rlist = w1->cmvisible; 553: w1->cmvisible = NULL; 554: } 555: while (rec = w1->visible) { 556: w1->visible = rec->next; 557: if (rec->type == border_rec) { 558: rec->type = new_rec; 559: rec->next = rlist; 560: rlist = rec; 561: cn++; 562: } else { 563: FREERECT(rec); 564: } 565: } 566: if TRUE(cleanup) { 567: MBOX(w1); 568: } 569: if (w1->first_child) 570: Zap_subwindows (w1, destroy); 571: Unmap_window_main (w1, cleanup ^ 1, 0); 572: } else if (TRUE(destroy) && w1->first_child) 573: Zap_subwindows (w1, 1); 574: else 575: w1->should_be_mapped = 0; 576: } 577: if TRUE(destroy) { 578: while (w1 = w->first_child) 579: Free_resource (Resources[RESIDX(w1->rid)]); 580: } 581: if (cn == 0) 582: return; 583: else if (vn == 0 && cn > 2) { 584: Free_rectangles (rlist); 585: for (rlist = w->cmvisible; rlist; rlist = rlist->next) { 586: RASTRECT(rec, *(RASTER *) rlist, new_rec); 587: *prev = rec; 588: prev = &rec->next; 589: } 590: *prev = NULL; 591: } else if (w->cmvisible->next == NULL && (cn >> 3) > vn) { 592: Free_rectangles (rlist); 593: RASTRECT(rec, *(RASTER *) w->cmvisible, new_rec); 594: *prev = rec; 595: rec->next = NULL; 596: for (rec = w->visible; ; rec = rec->next) { 597: if (rec->type != border_rec) 598: Calc_overlaps ((RASTER *) rec, prev); 599: if (prev == &rec->next) 600: break; 601: } 602: } else 603: Merge_rectangles (rlist, prev); 604: if TRUE(cleanup) { 605: Do_background (w, 0); 606: Stash_changes (w, 0); 607: } 608: } 609: 610: /* Unmap all subwindows, discarding their rectangles. Destroy the subwindows 611: * if destroy flag is set. 612: */ 613: 614: Zap_subwindows (w, destroy) 615: register WINDOW *w; 616: int destroy; 617: { 618: register WINDOW *w1; 619: 620: for (w1 = w->first_child; w1; w1 = w1->next_sib) { 621: if TRUE(w1->mapped) { 622: if (w1->visible) { 623: Free_rectangles (w1->visible); 624: w1->visible = NULL; 625: } 626: if (w1->cmvisible) { 627: Free_rectangles (w1->cmvisible); 628: w1->cmvisible = NULL; 629: } 630: if (w1->first_child) 631: Zap_subwindows (w1, destroy); 632: Unmap_window_main (w1, 1, 0); 633: } 634: } 635: if TRUE(destroy) { 636: while (w1 = w->first_child) 637: Free_resource (Resources[RESIDX(w1->rid)]); 638: } 639: } 640: 641: /* Change the x-y coordinates of a window */ 642: 643: Move_window (w, new_x, new_y) 644: register WINDOW *w; 645: int new_x, new_y; 646: { 647: short deltax, deltay; 648: register WINDOW *w1 = NULL; 649: register RECTANGLE *r; 650: register WINDOW *head; 651: register RECTANGLE *cr; 652: RECTANGLE *vlist; 653: WINDOW *tail; 654: int unobscured = OB_NOT; 655: 656: deltax = new_x - (w->full.left - w->bwidth); 657: deltay = new_y - (w->full.top - w->bwidth); 658: if TRUE(w->mapped) { 659: MBOX(w); 660: deltax += w->parent->full.left; 661: deltay += w->parent->full.top; 662: /* Check if all visible */ 663: if (FALSE(w->tilemode) && 664: (r = w->cmvisible) && r->next == NULL && 665: r->left == w->full.left && r->top == w->full.top && 666: r->right == w->full.right && r->bottom == w->full.bottom) 667: unobscured = OB_YES; 668: if (w->first_child) { 669: if TRUE(unobscured) { 670: /* Find earliest mapped subwindow */ 671: w1 = w; 672: do { 673: head = w1; 674: for (w1 = head->last_child; 675: w1 && FALSE(w1->mapped); 676: w1 = w1->prev_sib) ; 677: } while (w1); 678: if (head != w) { 679: tail = w->prev; 680: /* Remove all subwindows from list */ 681: if (w->prev = head->prev) 682: head->prev->next = w; 683: else 684: mapped_list = w; 685: /* Extract visible insides */ 686: vlist = NULL; 687: cr = w->visible; 688: w->visible = NULL; 689: while (r = cr) { 690: cr = r->next; 691: if (r->type == border_rec) { 692: r->next = w->visible; 693: w->visible = r; 694: } else { 695: r->left += deltax; 696: r->right += deltax; 697: r->top += deltay; 698: r->bottom += deltay; 699: r->next = vlist; 700: vlist = r; 701: } 702: } 703: Restore_rectangles (w); 704: } 705: } else { 706: Zap_subwindows (w, 0); 707: Restore_rectangles (w); 708: } 709: } 710: w1 = w->next; 711: Unmap_window_main (w, 1, 0); 712: } 713: 714: w->full.left += deltax; 715: w->full.right += deltax; 716: w->full.top += deltay; 717: w->full.bottom += deltay; 718: 719: if (FALSE(w->should_be_mapped) || FALSE(w->parent->mapped)) 720: return; 721: Map_window_main (w, 1, 0); 722: MBOX(w); 723: if (w->first_child) { 724: if FALSE(unobscured) 725: Map_subwindows (w, 0, 0); 726: else if (head != w) { 727: /* Reinsert subwindows */ 728: if (head->prev = w->prev) 729: w->prev->next = head; 730: else 731: mapped_list = head; 732: tail->next = w; 733: w->prev = tail; 734: /* Check if still all visible */ 735: if ((r = w->cmvisible) && r->next == NULL && 736: r->left == w->full.left && r->top == w->full.top && 737: r->right == w->full.right && r->bottom == w->full.bottom) { 738: unobscured = OB_TMP; 739: /* Move all subwindows */ 740: do { 741: tail = head->next; 742: head->full.left += deltax; 743: head->full.right += deltax; 744: head->full.top += deltay; 745: head->full.bottom += deltay; 746: head->vs.left += deltax; 747: head->vs.right += deltax; 748: head->vs.top += deltay; 749: head->vs.bottom += deltay; 750: head->ovs.left += deltax; 751: head->ovs.right += deltax; 752: head->ovs.top += deltay; 753: head->ovs.bottom += deltay; 754: head->clip.left += deltax; 755: head->clip.top += deltay; 756: for (r = head->visible; r; r = r->next) { 757: r->left += deltax; 758: r->right += deltax; 759: r->top += deltay; 760: r->bottom += deltay; 761: } 762: for (r = head->cmvisible; r; r = r->next) { 763: r->left += deltax; 764: r->right += deltax; 765: r->top += deltay; 766: r->bottom += deltay; 767: } 768: } while ((head = tail) != w); 769: cr = w->visible; 770: while (r = cr) { 771: cr = r->next; 772: if (r->type == border_rec) { 773: r->next = vlist; 774: vlist = r; 775: } else { 776: FREERECT(r); 777: } 778: } 779: w->visible = vlist; 780: } else { 781: /* Unmap all subwindows and move children */ 782: do { 783: tail = head->next; 784: if (head->visible) { 785: Free_rectangles (head->visible); 786: head->visible = NULL; 787: } 788: if (head->cmvisible) { 789: Free_rectangles (head->cmvisible); 790: head->cmvisible = NULL; 791: } 792: Unmap_window_main (head, 1, 0); 793: if (head->parent == w) { 794: head->full.left += deltax; 795: head->full.right += deltax; 796: head->full.top += deltay; 797: head->full.bottom += deltay; 798: } 799: } while ((head = tail) != w); 800: if (vlist) 801: Free_rectangles (vlist); 802: /* Remap all subwindows */ 803: Map_subwindows (w, 1, 0); 804: } 805: } 806: } 807: if TRUE(unobscured) 808: Do_refill (w, deltax, deltay); 809: else 810: Draw_window (w, 0, 1); 811: 812: for (; w1; w1 = w1->next) { 813: if (w1->unobscured == OB_TMP) { 814: w1->unobscured = OB_NOT; 815: Draw_window (w1, 0, 0); 816: } 817: } 818: } 819: 820: /* Change the size and position of a window. */ 821: 822: Change_window (w, x, y, height, width) 823: register WINDOW *w; 824: int x, y, height, width; 825: { 826: register WINDOW *w1 = NULL; 827: 828: if (height <= 0 || width <= 0) { 829: Xstatus = BadValue; 830: return; 831: } 832: 833: if TRUE(w->mapped) { 834: w1 = Unmap_window (w, 0); 835: w->should_be_mapped = 1; 836: } 837: 838: x -= w->full.left - w->bwidth; 839: y -= w->full.top - w->bwidth; 840: 841: w->full.left += x; 842: w->full.top += y; 843: w->full.right = w->full.left + width; 844: w->full.bottom = w->full.top + height; 845: 846: if (FALSE(w->should_be_mapped) || FALSE(w->parent->mapped)) 847: return; 848: Map_window (w); 849: for (; w1; w1 = w1->next) { 850: if (w1->unobscured == OB_TMP) { 851: w1->unobscured = OB_NOT; 852: Draw_window (w1, 0, 0); 853: } 854: } 855: } 856: 857: /* Change the background tile of a window */ 858: 859: Change_background (w, tile) 860: register WINDOW *w; 861: register PIXMAP *tile; 862: { 863: if (w->kind == IsTransparent) { 864: Xstatus = BadMatch; 865: return; 866: } else if (tile == NULL) { 867: if (w->parent) 868: tile = w->parent->tile; 869: else 870: tile = roottile; 871: } else if FALSE(tile->tile) { 872: Xstatus = BadTile; 873: return; 874: } 875: if (tile != w->tile) { 876: tile->refcnt++; 877: if (--w->tile->refcnt == 0) 878: FreePixmap (w->tile); 879: w->tile = tile; 880: } 881: } 882: 883: /* Change the border tile of a window. */ 884: 885: Change_border (w, tile) 886: register WINDOW *w; 887: register PIXMAP *tile; 888: { 889: if (w->bwidth == 0) { 890: Xstatus = BadMatch; 891: return; 892: } else if FALSE(tile->tile) { 893: Xstatus = BadTile; 894: return; 895: } 896: if (tile != w->border) { 897: tile->refcnt++; 898: if (--w->border->refcnt == 0) 899: FreePixmap (w->border); 900: w->border = tile; 901: Do_border (w); 902: } 903: } 904: 905: /* Move a window to the top of (depthwise) the screen. */ 906: 907: Raise_window (w) 908: register WINDOW *w; 909: { 910: register WINDOW *ww, *nw; 911: int changed; 912: 913: /* Check if we're already on top. */ 914: 915: if (w->next_sib == NULL) return; 916: 917: /* If w is unmapped, simply put it on top. */ 918: 919: if FALSE(w->mapped) { 920: Make_top_child (w); 921: return; 922: } 923: 924: MBOX(w); 925: 926: /* If w is transparent, simply put it on top. */ 927: 928: if (w->kind == IsTransparent) { 929: Make_top_child (w); 930: return; 931: } 932: 933: changed = 0; 934: 935: /* Lower any of w's siblings that are above it. */ 936: 937: while (ww = w->next_sib) { 938: /* move it over us */ 939: if (w->next_sib = ww->next_sib) 940: ww->next_sib->prev_sib = w; 941: else 942: w->parent->last_child = w; 943: if (ww->prev_sib = w->prev_sib) 944: w->prev_sib->next_sib = ww; 945: else 946: w->parent->first_child = ww; 947: w->prev_sib = ww; 948: ww->next_sib = w; 949: 950: /* If ww is unmapped, we're done. */ 951: if FALSE(ww->mapped) continue; 952: 953: /* If ww is transparent or doesn't overlap, just reposition */ 954: if (ww->kind == IsTransparent || 955: ww->ovs.left >= w->ovs.right || w->ovs.left >= ww->ovs.right || 956: ww->ovs.top >= w->ovs.bottom || w->ovs.top >= ww->ovs.bottom) { 957: /* Find earliest mapped subwindow of ww */ 958: do { 959: nw = ww; 960: for (ww = nw->last_child; 961: ww && FALSE(ww->mapped); 962: ww = ww->prev_sib) ; 963: } while (ww); 964: ww = w->prev_sib; 965: /* Reposition in mapped_list just after w */ 966: if (ww->next->prev = nw->prev) 967: nw->prev->next = ww->next; 968: else 969: mapped_list = ww->next; 970: ww->next = w->next; 971: w->next->prev = ww; 972: w->next = nw; 973: nw->prev = w; 974: continue; 975: } 976: 977: changed = 1; 978: 979: /* Unmap all the children of ww. */ 980: if (ww->first_child) 981: Remove_subwindows (ww, 0, 0); 982: 983: /* Remove ww from its current position. */ 984: nw = ww->next; 985: if (nw->prev = ww->prev) 986: ww->prev->next = nw; 987: else 988: mapped_list = nw; 989: 990: /* Insert ww just after w. */ 991: ww->next = w->next; 992: w->next->prev = ww; 993: ww->prev = w; 994: w->next = ww; 995: 996: /* Remove the rectangles from ww as appropriate */ 997: Remove_rectangles (ww, nw, 1); 998: 999: /* Remap the children without redrawing */ 1000: if (ww->first_child) 1001: Map_subwindows (ww, 1, 0); 1002: } 1003: 1004: if TRUE(changed) 1005: Draw_window (w, 1, 0); 1006: } 1007: 1008: /* Move a window to the bottom of the screen. */ 1009: 1010: Lower_window (w) 1011: register WINDOW *w; 1012: { 1013: register WINDOW *ww, *nw; 1014: 1015: /* Check if we're already on bottom. */ 1016: if ((ww = w->prev_sib) == NULL) return; 1017: 1018: /* If w is unmapped or all higher siblings are unmapped, simply 1019: * put it on the bottom. 1020: */ 1021: if (FALSE(w->mapped) || w->next == w->parent) { 1022: Make_bottom_child (w); 1023: return; 1024: } 1025: 1026: MBOX(w); 1027: 1028: /* If w is transparent, simply put it on the bottom. * 1029: if (w->kind == IsTransparent) { 1030: Make_bottom_child (w); 1031: return; 1032: } 1033: 1034: /* See if w obscures any lower opaque window. */ 1035: while (FALSE(ww->mapped) || 1036: ww->kind == IsTransparent || 1037: ww->ovs.left >= w->ovs.right || w->ovs.left >= ww->ovs.right || 1038: ww->ovs.top >= w->ovs.bottom || w->ovs.top >= ww->ovs.bottom) { 1039: if ((ww = ww->prev_sib) == NULL) 1040: break; 1041: } 1042: 1043: /* Move w to be the first child of its parent. */ 1044: Make_bottom_child (w); 1045: 1046: if (ww == NULL) { 1047: /* w doesn't obscure anything, find earliest mapped subwindow */ 1048: ww = w; 1049: do { 1050: nw = ww; 1051: for (ww = nw->last_child; ww && FALSE(ww->mapped); ww = ww->prev_sib) ; 1052: } while (ww); 1053: /* Reposition in mapped_list just before parent */ 1054: if (w->next->prev = nw->prev) 1055: nw->prev->next = w->next; 1056: else 1057: mapped_list = w->next; 1058: ww = w->parent; 1059: ww->prev->next = nw; 1060: nw->prev = ww->prev; 1061: w->next = ww; 1062: ww->prev = w; 1063: return; 1064: } 1065: 1066: /* w obscures something, unmap all the children. */ 1067: if (w->first_child) 1068: Remove_subwindows (w, 0, 0); 1069: 1070: /* Remove w from its current position. */ 1071: if (w->next->prev = w->prev) 1072: w->prev->next = w->next; 1073: else 1074: mapped_list = w->next; 1075: 1076: nw = w->next; 1077: 1078: /* Put w just in front of its parent. The parent cannot be 1079: * right after w, because we already checked for that. 1080: */ 1081: 1082: ww = w->parent; 1083: w->prev = ww->prev; 1084: ww->prev->next = w; 1085: w->next = ww; 1086: ww->prev = w; 1087: 1088: /* Remove the rectangles from w as appropriate */ 1089: Remove_rectangles (w, nw, 1); 1090: 1091: /* Remap the children */ 1092: if (w->first_child) 1093: Map_subwindows (w, 1, 0); 1094: } 1095: 1096: /* Raise the lowest mapped subwindow obscured by another subwindow. */ 1097: 1098: Circulate_window_up (w) 1099: register WINDOW *w; 1100: { 1101: register WINDOW *ow; 1102: 1103: for (w = w->first_child; w; w = w->next_sib) { 1104: if FALSE(w->should_be_mapped) 1105: continue; 1106: for (ow = w->next_sib; ow; ow = ow->next_sib) { 1107: if (FALSE(ow->should_be_mapped) || ow->kind == IsTransparent || 1108: ow->ovs.left >= w->ovs.right || 1109: w->ovs.left >= ow->ovs.right || 1110: ow->ovs.top >= w->ovs.bottom || 1111: w->ovs.top >= ow->ovs.bottom) 1112: continue; 1113: Raise_window (w); 1114: return; 1115: } 1116: } 1117: } 1118: 1119: /* Lower the highest mapped subwindow obscuring another subwindow. */ 1120: 1121: Circulate_window_down (w) 1122: register WINDOW *w; 1123: { 1124: register WINDOW *ow; 1125: 1126: for (w = w->last_child; w; w = w->prev_sib) { 1127: if FALSE(w->should_be_mapped) 1128: continue; 1129: for (ow = w->prev_sib; ow; ow = ow->prev_sib) { 1130: if (FALSE(ow->should_be_mapped) || ow->kind == IsTransparent || 1131: ow->ovs.left >= w->ovs.right || 1132: w->ovs.left >= ow->ovs.right || 1133: ow->ovs.top >= w->ovs.bottom || 1134: w->ovs.top >= ow->ovs.bottom) 1135: continue; 1136: Lower_window (w); 1137: return; 1138: } 1139: } 1140: } 1141: 1142: /* Make w the last sibling of its parent, making it top-most */ 1143: 1144: Make_top_child (w) 1145: register WINDOW *w; 1146: { 1147: register WINDOW *w1 = w->parent; 1148: 1149: if (w->prev_sib) 1150: w->prev_sib->next_sib = w->next_sib; 1151: else 1152: w1->first_child = w->next_sib; 1153: 1154: w->next_sib->prev_sib = w->prev_sib; 1155: w1->last_child->next_sib = w; 1156: w->prev_sib = w1->last_child; 1157: w1->last_child = w; 1158: w->next_sib = NULL; 1159: } 1160: 1161: /* Make w the first sibling of its parent, making it bottom-most */ 1162: 1163: Make_bottom_child (w) 1164: register WINDOW *w; 1165: { 1166: register WINDOW *w1 = w->parent; 1167: 1168: if (w->next_sib) 1169: w->next_sib->prev_sib = w->prev_sib; 1170: else 1171: w1->last_child = w->prev_sib; 1172: 1173: w->prev_sib->next_sib = w->next_sib; 1174: w1->first_child->prev_sib = w; 1175: w->next_sib = w1->first_child; 1176: w1->first_child = w; 1177: w->prev_sib = NULL; 1178: } 1179: 1180: /* Draw_window draws a window of the appropriate type. If subflag is 1181: set, it also redisplays the windows subwindows. If not_just_new 1182: is set, all the rectangles are redisplayed, not just the new ones. 1183: If not, after the new rectangles have been displayed they are 1184: changed to old ones and the window is Windexed. */ 1185: 1186: Draw_window (w, subflag, not_just_new) 1187: WINDOW *w; 1188: int subflag, not_just_new; 1189: { 1190: register WINDOW *w1; 1191: 1192: if (w->kind == IsTransparent) return; 1193: 1194: if (w->bwidth) 1195: Do_border (w); 1196: Do_background (w, not_just_new); 1197: 1198: if TRUE(subflag) { 1199: for (w1 = w->first_child; w1; w1 = w1->next_sib) { 1200: if TRUE(w1->mapped) 1201: Draw_window (w1, 1, not_just_new); 1202: } 1203: } 1204: 1205: Stash_changes (w, not_just_new); 1206: } 1207: 1208: /* Windex recomputes if the window is obscured. */ 1209: 1210: Windex (w) 1211: WINDOW *w; 1212: { 1213: register RECTANGLE *r1; 1214: 1215: for (r1 = w->visible; r1; r1 = r1->next) { 1216: if (r1->type == border_rec) 1217: continue; 1218: if (r1->type == contents_rec && 1219: r1->left == w->vs.left && r1->top == w->vs.top && 1220: r1->right == w->vs.right && r1->bottom == w->vs.bottom) 1221: w->unobscured = OB_YES; 1222: break; 1223: } 1224: } 1225: 1226: /* Free all storage associated with unused windows */ 1227: 1228: Free_window_storage () 1229: { 1230: register WINDOW *w, **pw; 1231: 1232: /* drop the "internal" windows */ 1233: pw = &free_windows; 1234: while (w = *pw) { 1235: if TRUE(w->internal) 1236: *pw = w->next; 1237: else 1238: pw = &w->next; 1239: } 1240: /* now free the "head" windows */ 1241: while (w = free_windows) { 1242: free_windows = w->next; 1243: free ((caddr_t) w); 1244: } 1245: FREERECT(rootwindow->visible); 1246: FREERECT(rootwindow->cmvisible); 1247: }