screen.c revision 956cc18d
1/* $XTermId: screen.c,v 1.396 2009/08/30 00:06:07 tom Exp $ */ 2 3/* 4 * Copyright 1999-2008,2009 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 * 32 * 33 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34 * 35 * All Rights Reserved 36 * 37 * Permission to use, copy, modify, and distribute this software and its 38 * documentation for any purpose and without fee is hereby granted, 39 * provided that the above copyright notice appear in all copies and that 40 * both that copyright notice and this permission notice appear in 41 * supporting documentation, and that the name of Digital Equipment 42 * Corporation not be used in advertising or publicity pertaining to 43 * distribution of the software without specific, written prior permission. 44 * 45 * 46 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52 * SOFTWARE. 53 */ 54 55/* screen.c */ 56 57#include <stdio.h> 58#include <xterm.h> 59#include <error.h> 60#include <data.h> 61#include <xcharmouse.h> 62#include <xterm_io.h> 63 64#if OPT_WIDE_CHARS 65#include <fontutils.h> 66#include <menu.h> 67#endif 68 69#include <assert.h> 70#include <signal.h> 71 72#define inSaveBuf(screen, buf, inx) \ 73 ((buf) == (screen)->saveBuf_index && \ 74 ((inx) < (screen)->savelines || (screen)->savelines == 0)) 75 76#define getMinRow(screen) ((xw->flags & ORIGIN) ? (screen)->top_marg : 0) 77#define getMaxRow(screen) ((xw->flags & ORIGIN) ? (screen)->bot_marg : (screen)->max_row) 78#define getMinCol(screen) 0 79#define getMaxCol(screen) ((screen)->max_col) 80 81#define MoveLineData(base, dst, src, len) \ 82 memmove(scrnHeadAddr(screen, base, dst), \ 83 scrnHeadAddr(screen, base, src), \ 84 scrnHeadSize(screen, len)) 85 86#define SaveLineData(base, src, len) \ 87 (void) ScrnPointers(screen, len); \ 88 memcpy (screen->save_ptr, \ 89 scrnHeadAddr(screen, base, src), \ 90 scrnHeadSize(screen, len)) 91 92#define RestoreLineData(base, dst, len) \ 93 memcpy (scrnHeadAddr(screen, base, dst), \ 94 screen->save_ptr, \ 95 scrnHeadSize(screen, len)) 96 97#if OPT_SAVE_LINES 98#define VisBuf(screen) screen->editBuf_index[screen->whichBuf] 99#else 100#define VisBuf(screen) scrnHeadAddr(screen, screen->saveBuf_index, (unsigned) savelines) 101#endif 102 103/* 104 * ScrnPtr's can point to different types of data. 105 */ 106#define SizeofScrnPtr(name) \ 107 sizeof(*((LineData *)0)->name) 108 109/* 110 * The pointers in LineData point into a block of text allocated as a single 111 * chunk for the given number of rows. Ensure that these pointers are aligned 112 * at least to int-boundaries. 113 */ 114#define AlignMask() (sizeof(int) - 1) 115#define IsAligned(value) (((unsigned long) (value) & AlignMask()) == 0) 116 117#define AlignValue(value) \ 118 if (!IsAligned(value)) \ 119 value = (value | AlignMask()) + 1 120 121#define SetupScrnPtr(dst,src,type) \ 122 dst = (type *) src; \ 123 assert(IsAligned(dst)); \ 124 src += skipNcol##type 125 126#define ScrnBufAddr(ptrs, offset) (ScrnBuf) ((char *) (ptrs) + (offset)) 127#define LineDataAddr(ptrs, offset) (LineData *) ((char *) (ptrs) + (offset)) 128 129#if OPT_TRACE > 1 130static void 131traceScrnBuf(const char *tag, TScreen * screen, ScrnBuf sb, unsigned len) 132{ 133 unsigned j; 134 135 TRACE(("traceScrnBuf %s\n", tag)); 136 for (j = 0; j < len; ++j) { 137 LineData *src = (LineData *) scrnHeadAddr(screen, sb, j); 138 TRACE(("%p %s%3d:%s\n", 139 src, ((int) j >= screen->savelines) ? "*" : " ", 140 j, visibleIChars(src->charData, src->lineSize))); 141 } 142 TRACE(("...traceScrnBuf %s\n", tag)); 143} 144 145#define TRACE_SCRNBUF(tag, screen, sb, len) traceScrnBuf(tag, screen, sb, len) 146#else 147#define TRACE_SCRNBUF(tag, screen, sb, len) /*nothing */ 148#endif 149 150static unsigned 151scrnHeadSize(TScreen * screen, unsigned count) 152{ 153 unsigned result = SizeOfLineData; 154 155 (void) screen; 156 157#if OPT_WIDE_CHARS 158 if (screen->wide_chars) { 159 result += screen->lineExtra; 160 } 161#endif 162 result *= count; 163 164 return result; 165} 166 167ScrnBuf 168scrnHeadAddr(TScreen * screen, ScrnBuf base, unsigned offset) 169{ 170 unsigned size = scrnHeadSize(screen, offset); 171 ScrnBuf result = ScrnBufAddr(base, size); 172 173 assert((int) offset >= 0); 174 175 return result; 176} 177 178/* 179 * Given a block of data, build index to it in the 'base' parameter. 180 */ 181void 182setupLineData(TScreen * screen, ScrnBuf base, Char * data, unsigned nrow, unsigned ncol) 183{ 184 unsigned i; 185 unsigned offset = 0; 186 unsigned jump = scrnHeadSize(screen, 1); 187 LineData *ptr; 188#if OPT_WIDE_CHARS 189 unsigned j; 190#endif 191 /* these names are based on types */ 192 unsigned skipNcolChar = (ncol * SizeofScrnPtr(attribs)); 193 unsigned skipNcolCharData = (ncol * SizeofScrnPtr(charData)); 194#if OPT_ISO_COLORS 195 unsigned skipNcolCellColor = (ncol * SizeofScrnPtr(color)); 196#endif 197 198 AlignValue(skipNcolChar); 199#if OPT_ISO_COLORS 200 AlignValue(skipNcolCellColor); 201#endif 202 AlignValue(skipNcolCharData); 203 204 for (i = 0; i < nrow; i++, offset += jump) { 205 ptr = LineDataAddr(base, offset); 206 207 ptr->lineSize = (Dimension) ncol; 208 ptr->bufHead = 0; 209#if OPT_DEC_CHRSET 210 SetLineDblCS(ptr, 0); 211#endif 212 SetupScrnPtr(ptr->attribs, data, Char); 213#if OPT_ISO_COLORS 214 SetupScrnPtr(ptr->color, data, CellColor); 215#endif 216 SetupScrnPtr(ptr->charData, data, CharData); 217#if OPT_WIDE_CHARS 218 if (screen->wide_chars) { 219 unsigned extra = (unsigned) screen->max_combining; 220 221 ptr->combSize = (Char) extra; 222 for (j = 0; j < extra; ++j) { 223 SetupScrnPtr(ptr->combData[j], data, CharData); 224 } 225 } 226#endif 227 } 228} 229 230#define ExtractScrnData(name) \ 231 memcpy(dstPtrs->name, \ 232 ((LineData *) srcPtrs)->name,\ 233 dstCols * sizeof(dstPtrs->name[0])); \ 234 nextPtr += (srcCols * sizeof(dstPtrs->name[0])) 235 236/* 237 * As part of reallocating the screen buffer when resizing, extract from 238 * the old copy of the screen buffer the data which will be used in the 239 * new copy of the screen buffer. 240 */ 241static void 242extractScrnData(TScreen * screen, 243 ScrnBuf dstPtrs, 244 ScrnBuf srcPtrs, 245 unsigned nrows, 246 unsigned move_down) 247{ 248 unsigned j; 249 250 TRACE(("extractScrnData(nrows %d)\n", nrows)); 251 252 TRACE_SCRNBUF("extract from", screen, srcPtrs, nrows); 253 for (j = 0; j < nrows; j++) { 254 LineData *dst = (LineData *) scrnHeadAddr(screen, 255 dstPtrs, j + move_down); 256 LineData *src = (LineData *) scrnHeadAddr(screen, 257 srcPtrs, j); 258 copyLineData(dst, src); 259 } 260} 261 262static ScrnPtr * 263allocScrnHead(TScreen * screen, unsigned nrow) 264{ 265 ScrnPtr *result; 266 unsigned size = scrnHeadSize(screen, 1); 267 268 result = (ScrnPtr *) calloc(nrow, size); 269 if (result == 0) 270 SysError(ERROR_SCALLOC); 271 272 TRACE(("allocScrnHead %d -> %d -> %p..%p\n", nrow, nrow * size, 273 result, 274 (char *) result + (nrow * size) - 1)); 275 return result; 276} 277 278/* 279 * Return the size of a line's data. 280 */ 281static unsigned 282sizeofScrnRow(TScreen * screen, unsigned ncol) 283{ 284 unsigned result; 285 unsigned sizeAttribs; 286#if OPT_ISO_COLORS 287 unsigned sizeColors; 288#endif 289 290 (void) screen; 291 292 result = (ncol * sizeof(CharData)); 293 AlignValue(result); 294 295#if OPT_WIDE_CHARS 296 if (screen->wide_chars) { 297 result *= (unsigned) (1 + screen->max_combining); 298 } 299#endif 300 301 sizeAttribs = (ncol * SizeofScrnPtr(attribs)); 302 AlignValue(sizeAttribs); 303 result += sizeAttribs; 304 305#if OPT_ISO_COLORS 306 sizeColors = (ncol * SizeofScrnPtr(color)); 307 AlignValue(sizeColors); 308 result += sizeColors; 309#endif 310 311 return result; 312} 313 314Char * 315allocScrnData(TScreen * screen, unsigned nrow, unsigned ncol) 316{ 317 Char *result; 318 size_t length = (nrow * sizeofScrnRow(screen, ncol)); 319 320 if ((result = (Char *) calloc(length, sizeof(Char))) == 0) 321 SysError(ERROR_SCALLOC2); 322 323 TRACE(("allocScrnData %dx%d -> %d -> %p..%p\n", 324 nrow, ncol, length, result, result + length - 1)); 325 return result; 326} 327 328/* 329 * Allocates memory for a 2-dimensional array of chars and returns a pointer 330 * thereto. Each line is formed from a set of char arrays, with an index 331 * (i.e., the ScrnBuf type). The first pointer in the index is reserved for 332 * per-line flags, and does not point to data. 333 * 334 * After the per-line flags, we have a series of pointers to char arrays: The 335 * first one is the actual character array, the second one is the attributes, 336 * the third is the foreground and background colors, and the fourth denotes 337 * the character set. 338 * 339 * We store it all as pointers, because of alignment considerations. 340 */ 341ScrnBuf 342allocScrnBuf(XtermWidget xw, unsigned nrow, unsigned ncol, Char ** addr) 343{ 344 TScreen *screen = TScreenOf(xw); 345 ScrnBuf base = 0; 346 347 if (nrow != 0) { 348 base = allocScrnHead(screen, nrow); 349 *addr = allocScrnData(screen, nrow, ncol); 350 351 setupLineData(screen, base, *addr, nrow, ncol); 352 } 353 354 TRACE(("allocScrnBuf %dx%d ->%p\n", nrow, ncol, base)); 355 return (base); 356} 357 358#if OPT_SAVE_LINES 359/* 360 * Copy line-data from the visible (edit) buffer to the save-lines buffer. 361 */ 362static void 363saveEditBufLines(TScreen * screen, ScrnBuf sb, unsigned n) 364{ 365 unsigned j; 366 367 TRACE(("...copying %d lines from editBuf to saveBuf\n", n)); 368#if OPT_FIFO_LINES 369 (void) sb; 370#endif 371 for (j = 0; j < n; ++j) { 372#if OPT_FIFO_LINES 373 LineData *dst = addScrollback(screen); 374#else 375 unsigned k = (screen->savelines + j - n); 376 LineData *dst = (LineData *) scrnHeadAddr(screen, sb, k); 377#endif 378 LineData *src = getLineData(screen, (int) j); 379 copyLineData(dst, src); 380 } 381} 382 383/* 384 * Copy line-data from the save-lines buffer to the visible (edit) buffer. 385 */ 386static void 387unsaveEditBufLines(TScreen * screen, ScrnBuf sb, unsigned n) 388{ 389 unsigned j; 390 391 TRACE(("...copying %d lines from saveBuf to editBuf\n", n)); 392 for (j = 0; j < n; ++j) { 393 int extra = (int) (n - j); 394 LineData *dst = (LineData *) scrnHeadAddr(screen, sb, j); 395#if OPT_FIFO_LINES 396 LineData *src; 397 398 if ((screen->saved_fifo - extra) <= 0) { 399 TRACE(("...FIXME: must clear text!\n")); 400 continue; 401 } 402 src = getScrollback(screen, -extra); 403#else 404 unsigned k = (screen->savelines - extra); 405 LineData *src = (LineData *) scrnHeadAddr(screen, 406 screen->saveBuf_index, k); 407#endif 408 copyLineData(dst, src); 409 } 410} 411#endif 412 413/* 414 * This is called when the screen is resized. 415 * Returns the number of lines the text was moved down (neg for up). 416 * (Return value only necessary with SouthWestGravity.) 417 */ 418static int 419Reallocate(XtermWidget xw, 420 ScrnBuf * sbuf, 421 Char ** sbufaddr, 422 unsigned nrow, 423 unsigned ncol, 424 unsigned oldrow, 425 unsigned oldcol) 426{ 427 TScreen *screen = TScreenOf(xw); 428 ScrnBuf oldBufHead; 429 ScrnBuf newBufHead; 430 Char *newBufData; 431 unsigned minrows; 432 unsigned mincols; 433 Char *oldBufData; 434 int move_down = 0, move_up = 0; 435 436 if (sbuf == NULL || *sbuf == NULL) { 437 return 0; 438 } 439 440 oldBufData = *sbufaddr; 441 442 TRACE(("Reallocate %dx%d -> %dx%d\n", oldrow, oldcol, nrow, ncol)); 443 444 /* 445 * realloc sbuf, the pointers to all the lines. 446 * If the screen shrinks, remove lines off the top of the buffer 447 * if resizeGravity resource says to do so. 448 */ 449 TRACE(("Check move_up, nrow %d vs oldrow %d (resizeGravity %s)\n", 450 nrow, oldrow, 451 BtoS(GravityIsSouthWest(xw)))); 452 if (GravityIsSouthWest(xw)) { 453 if (nrow < oldrow) { 454 /* Remove lines off the top of the buffer if necessary. */ 455 move_up = (int) (oldrow - nrow) 456 - (xw->screen.max_row - xw->screen.cur_row); 457 if (move_up < 0) 458 move_up = 0; 459 /* Overlapping move here! */ 460 TRACE(("move_up %d\n", move_up)); 461 if (move_up) { 462 ScrnBuf dst = *sbuf; 463 unsigned len = (unsigned) ((int) oldrow - move_up); 464 465 TRACE_SCRNBUF("before move_up", screen, dst, oldrow); 466 SaveLineData(dst, 0, (size_t) move_up); 467 MoveLineData(dst, 0, (size_t) move_up, len); 468 RestoreLineData(dst, len, (size_t) move_up); 469 TRACE_SCRNBUF("after move_up", screen, dst, oldrow); 470 } 471 } 472 } 473 oldBufHead = *sbuf; 474 *sbuf = allocScrnHead(screen, (unsigned) nrow); 475 newBufHead = *sbuf; 476 477 /* 478 * Create the new buffer space and copy old buffer contents there, line by 479 * line. 480 */ 481 newBufData = allocScrnData(screen, nrow, ncol); 482 *sbufaddr = newBufData; 483 484 minrows = (oldrow < nrow) ? oldrow : nrow; 485 mincols = (oldcol < ncol) ? oldcol : ncol; 486 if (GravityIsSouthWest(xw)) { 487 if (nrow > oldrow) { 488 /* move data down to bottom of expanded screen */ 489 move_down = Min((int) (nrow - oldrow), xw->screen.savedlines); 490 } 491 } 492 493 setupLineData(screen, newBufHead, *sbufaddr, nrow, ncol); 494 extractScrnData(screen, newBufHead, oldBufHead, minrows, 495#if OPT_SAVE_LINES 496 0 497#else 498 (unsigned) move_down 499#endif 500 ); 501 free(oldBufHead); 502 503 /* Now free the old data */ 504 free(oldBufData); 505 506 TRACE(("...Reallocate %dx%d ->%p\n", nrow, ncol, newBufHead)); 507 return move_down ? move_down : -move_up; /* convert to rows */ 508} 509 510#if OPT_WIDE_CHARS 511/* 512 * This function reallocates memory if changing the number of Buf offsets. 513 * The code is based on Reallocate(). 514 */ 515static void 516ReallocateBufOffsets(XtermWidget xw, 517 ScrnBuf * sbuf, 518 Char ** sbufaddr, 519 unsigned nrow, 520 unsigned ncol) 521{ 522 TScreen *screen = TScreenOf(xw); 523 unsigned i; 524 ScrnBuf newBufHead; 525 Char *oldBufData; 526 ScrnBuf oldBufHead; 527 528 unsigned old_jump = scrnHeadSize(screen, 1); 529 unsigned new_jump; 530 unsigned new_ptrs = 1 + (unsigned) (screen->max_combining); 531 unsigned dstCols = ncol; 532 unsigned srcCols = ncol; 533 LineData *dstPtrs; 534 LineData *srcPtrs; 535 Char *nextPtr; 536 537 assert(nrow != 0); 538 assert(ncol != 0); 539 540 oldBufData = *sbufaddr; 541 oldBufHead = *sbuf; 542 543 /* 544 * Allocate a new LineData array, retain the old one until we've copied 545 * the data that it points to, as well as non-pointer data, e.g., bufHead. 546 * 547 * Turn on wide-chars temporarily when constructing pointers, since that is 548 * used to decide whether to address the combData[] array, which affects 549 * the length of the LineData structure. 550 */ 551 screen->wide_chars = True; 552 553 new_jump = scrnHeadSize(screen, 1); 554 newBufHead = allocScrnHead(screen, nrow); 555 *sbufaddr = allocScrnData(screen, nrow, ncol); 556 setupLineData(screen, newBufHead, *sbufaddr, nrow, ncol); 557 558 screen->wide_chars = False; 559 560 nextPtr = *sbufaddr; 561 562 srcPtrs = (LineData *) oldBufHead; 563 dstPtrs = (LineData *) newBufHead; 564 for (i = 0; i < nrow; i++) { 565 dstPtrs->bufHead = srcPtrs->bufHead; 566 ExtractScrnData(attribs); 567#if OPT_ISO_COLORS 568 ExtractScrnData(color); 569#endif 570 ExtractScrnData(charData); 571 572 nextPtr += ncol * new_ptrs; 573 srcPtrs = LineDataAddr(srcPtrs, old_jump); 574 dstPtrs = LineDataAddr(dstPtrs, new_jump); 575 } 576 577 /* Now free the old data */ 578 free(oldBufData); 579 free(oldBufHead); 580 581 *sbuf = newBufHead; 582 583 TRACE(("ReallocateBufOffsets %dx%d ->%p\n", nrow, ncol, *sbufaddr)); 584} 585 586/* 587 * This function dynamically adds support for wide-characters. 588 */ 589void 590ChangeToWide(XtermWidget xw) 591{ 592 TScreen *screen = &(xw->screen); 593 int savelines = screen->scrollWidget ? screen->savelines : 0; 594 595 if (screen->wide_chars) 596 return; 597 598 TRACE(("ChangeToWide\n")); 599 if (xtermLoadWideFonts(xw, True)) { 600 if (savelines < 0) 601 savelines = 0; 602 603 /* 604 * If we're displaying the alternate screen, switch the pointers back 605 * temporarily so ReallocateBufOffsets() will operate on the proper 606 * data in the alternate buffer. 607 */ 608 if (screen->whichBuf) 609 SwitchBufPtrs(screen); 610 611#if OPT_SAVE_LINES 612#if !OPT_FIFO_LINES 613 ReallocateBufOffsets(xw, 614 &screen->saveBuf_index, 615 &screen->saveBuf_data, 616 (unsigned) savelines, 617 (unsigned) MaxCols(screen)); 618#endif 619 if (screen->editBuf_index[0]) { 620 ReallocateBufOffsets(xw, 621 &screen->editBuf_index[0], 622 &screen->editBuf_data[0], 623 (unsigned) MaxRows(screen), 624 (unsigned) MaxCols(screen)); 625 } 626#else 627 ReallocateBufOffsets(xw, 628 &screen->saveBuf_index, 629 &screen->saveBuf_data, 630 (unsigned) (MaxRows(screen) + savelines), 631 (unsigned) MaxCols(screen)); 632#endif 633 if (screen->editBuf_index[1]) { 634 ReallocateBufOffsets(xw, 635 &screen->editBuf_index[1], 636 &screen->editBuf_data[1], 637 (unsigned) MaxRows(screen), 638 (unsigned) MaxCols(screen)); 639 } 640 641 screen->wide_chars = True; 642 screen->visbuf = VisBuf(screen); 643 644 /* 645 * Switch the pointers back before we start painting on the screen. 646 */ 647 if (screen->whichBuf) 648 SwitchBufPtrs(screen); 649 650 update_font_utf8_mode(); 651 SetVTFont(xw, screen->menu_font_number, True, NULL); 652 } 653 TRACE(("...ChangeToWide\n")); 654} 655#endif 656 657/* 658 * Clear cells, no side-effects. 659 */ 660void 661ClearCells(XtermWidget xw, int flags, unsigned len, int row, int col) 662{ 663 if (len != 0) { 664 TScreen *screen = &(xw->screen); 665 LineData *ld; 666 unsigned n; 667 668 ld = getLineData(screen, row); 669 670 flags |= TERM_COLOR_FLAGS(xw); 671 672 for (n = 0; n < len; ++n) 673 ld->charData[(unsigned) col + n] = (CharData) ' '; 674 675 memset(ld->attribs + col, flags, len); 676 677 if_OPT_ISO_COLORS(screen, { 678 CellColor p = xtermColorPair(xw); 679 for (n = 0; n < len; ++n) { 680 ld->color[(unsigned) col + n] = p; 681 } 682 }); 683 if_OPT_WIDE_CHARS(screen, { 684 size_t off; 685 for_each_combData(off, ld) { 686 memset(ld->combData[off] + col, 0, len * sizeof(IChar)); 687 } 688 }); 689 } 690} 691 692/* 693 * Clear data in the screen-structure (no I/O). 694 * Check for wide-character damage as well, clearing the damaged cells. 695 */ 696void 697ScrnClearCells(XtermWidget xw, int row, int col, unsigned len) 698{ 699#if OPT_WIDE_CHARS 700 TScreen *screen = &(xw->screen); 701#endif 702 int flags = 0; 703 704 if_OPT_WIDE_CHARS(screen, { 705 int kl; 706 int kr; 707 if (DamagedCells(screen, len, &kl, &kr, INX2ROW(screen, row), col) 708 && kr >= kl) { 709 ClearCells(xw, flags, (unsigned) (kr - kl + 1), row, kl); 710 } 711 }); 712 ClearCells(xw, flags, len, row, col); 713} 714 715/* 716 * Disown the selection and repaint the area that is highlighted so it is no 717 * longer highlighted. 718 */ 719void 720ScrnDisownSelection(XtermWidget xw) 721{ 722 if (ScrnHaveSelection(&(xw->screen))) { 723 if (xw->screen.keepSelection) { 724 UnhiliteSelection(xw); 725 } else { 726 DisownSelection(xw); 727 } 728 } 729} 730 731/* 732 * Writes str into buf at screen's current row and column. Characters are set 733 * to match flags. 734 */ 735void 736ScrnWriteText(XtermWidget xw, 737 IChar * str, 738 unsigned flags, 739 CellColor cur_fg_bg, 740 unsigned length) 741{ 742 TScreen *screen = &(xw->screen); 743 LineData *ld; 744#if OPT_ISO_COLORS 745 CellColor *fb = 0; 746#endif 747 Char *attrs; 748 int avail = MaxCols(screen) - screen->cur_col; 749 IChar *chars; 750#if OPT_WIDE_CHARS 751 IChar starcol1; 752#endif 753 unsigned n; 754 unsigned real_width = visual_width(str, length); 755 756 (void) cur_fg_bg; 757 758 if (avail <= 0) 759 return; 760 if (length > (unsigned) avail) 761 length = (unsigned) avail; 762 if (length == 0 || real_width == 0) 763 return; 764 765 ld = getLineData(screen, screen->cur_row); 766 767 chars = ld->charData + screen->cur_col; 768 attrs = ld->attribs + screen->cur_col; 769 770 if_OPT_ISO_COLORS(screen, { 771 fb = ld->color + screen->cur_col; 772 }); 773 774#if OPT_WIDE_CHARS 775 starcol1 = *chars; 776#endif 777 778 /* write blanks if we're writing invisible text */ 779 for (n = 0; n < length; ++n) { 780 if ((flags & INVISIBLE)) 781 chars[n] = ' '; 782 else 783 chars[n] = str[n]; 784 } 785 786#if OPT_BLINK_TEXT 787 if ((flags & BLINK) && !(screen->blink_as_bold)) { 788 LineSetBlinked(ld); 789 } 790#endif 791 792 if_OPT_WIDE_CHARS(screen, { 793 794 if (real_width != length) { 795 IChar *char1 = chars; 796 if (screen->cur_col 797 && starcol1 == HIDDEN_CHAR 798 && isWide((int) char1[-1])) { 799 char1[-1] = (CharData) ' '; 800 } 801 /* if we are overwriting the right hand half of a 802 wide character, make the other half vanish */ 803 while (length) { 804 int ch = (int) str[0]; 805 806 *char1++ = *str++; 807 length--; 808 809 if (isWide(ch)) { 810 *char1++ = (CharData) HIDDEN_CHAR; 811 } 812 } 813 814 if (*char1 == HIDDEN_CHAR 815 && char1[-1] == HIDDEN_CHAR) { 816 *char1 = (CharData) ' '; 817 } 818 /* if we are overwriting the left hand half of a 819 wide character, make the other half vanish */ 820 } else { 821 if (screen->cur_col 822 && starcol1 == HIDDEN_CHAR 823 && isWide((int) chars[-1])) { 824 chars[-1] = (CharData) ' '; 825 } 826 /* if we are overwriting the right hand half of a 827 wide character, make the other half vanish */ 828 if (chars[length] == HIDDEN_CHAR 829 && isWide((int) chars[length - 1])) { 830 chars[length] = (CharData) ' '; 831 } 832 } 833 }); 834 835 flags &= ATTRIBUTES; 836 flags |= CHARDRAWN; 837 memset(attrs, (Char) flags, real_width); 838 839 if_OPT_WIDE_CHARS(screen, { 840 size_t off; 841 for_each_combData(off, ld) { 842 memset(ld->combData[off] + screen->cur_col, 843 0, 844 real_width * sizeof(IChar)); 845 } 846 }); 847 if_OPT_ISO_COLORS(screen, { 848 unsigned j; 849 for (j = 0; j < real_width; ++j) 850 fb[j] = cur_fg_bg; 851 }); 852 853 if_OPT_WIDE_CHARS(screen, { 854 screen->last_written_col = screen->cur_col + (int) real_width - 1; 855 screen->last_written_row = screen->cur_row; 856 }); 857 858 if_OPT_XMC_GLITCH(screen, { 859 Resolve_XMC(xw); 860 }); 861 862 return; 863} 864 865/* 866 * Saves pointers to the n lines beginning at sb + where, and clears the lines 867 */ 868static void 869ScrnClearLines(XtermWidget xw, ScrnBuf sb, int where, unsigned n, unsigned size) 870{ 871 TScreen *screen = &(xw->screen); 872 ScrnPtr *base; 873 unsigned jump = scrnHeadSize(screen, 1); 874 unsigned i; 875 LineData *work; 876 unsigned flags = TERM_COLOR_FLAGS(xw); 877#if OPT_ISO_COLORS 878 unsigned j; 879#endif 880 881 TRACE(("ScrnClearLines(%s:where %d, n %d, size %d)\n", 882 (sb == screen->saveBuf_index) ? "save" : "edit", 883 where, n, size)); 884 885 assert(n != 0); 886 assert(size != 0); 887 888 /* save n lines at where */ 889 SaveLineData(sb, (unsigned) where, (size_t) n); 890 891 /* clear contents of old rows */ 892 base = screen->save_ptr; 893 for (i = 0; i < n; ++i) { 894 work = (LineData *) base; 895 work->bufHead = 0; 896#if OPT_DEC_CHRSET 897 SetLineDblCS(work, 0); 898#endif 899 900 memset(work->charData, 0, size * sizeof(IChar)); 901 if (TERM_COLOR_FLAGS(xw)) { 902 memset(work->attribs, (int) flags, size); 903#if OPT_ISO_COLORS 904 { 905 CellColor p = xtermColorPair(xw); 906 for (j = 0; j < size; ++j) { 907 work->color[j] = p; 908 } 909 } 910#endif 911 } else { 912 memset(work->attribs, 0, size); 913#if OPT_ISO_COLORS 914 memset(work->color, 0, size * sizeof(work->color[0])); 915#endif 916 } 917#if OPT_WIDE_CHARS 918 if (screen->wide_chars) { 919 size_t off; 920 921 for (off = 0; off < work->combSize; ++off) { 922 memset(work->combData[off], 0, size * sizeof(IChar)); 923 } 924 } 925#endif 926 base = ScrnBufAddr(base, jump); 927 } 928} 929 930/* 931 * We're always ensured of having a visible buffer, but may not have saved 932 * lines. Check the pointer that's sure to work. 933 */ 934#if OPT_SAVE_LINES 935#define OkAllocBuf(screen) (screen->editBuf_index[0] != 0) 936#else 937#define OkAllocBuf(screen) (screen->saveBuf_index != 0) 938#endif 939 940void 941ScrnAllocBuf(XtermWidget xw) 942{ 943 TScreen *screen = TScreenOf(xw); 944 945 if (!OkAllocBuf(screen)) { 946 int nrows = MaxRows(screen); 947#if !OPT_SAVE_LINES 948 int savelines = screen->scrollWidget ? screen->savelines : 0; 949#endif 950 951 TRACE(("ScrnAllocBuf %dx%d (%d)\n", 952 nrows, MaxCols(screen), screen->savelines)); 953 954#if OPT_SAVE_LINES 955 if (screen->savelines != 0) { 956#if OPT_FIFO_LINES 957 /* for FIFO, we only need space for the index - addScrollback inits */ 958 screen->saveBuf_index = allocScrnHead(screen, 959 (unsigned) (screen->savelines)); 960#else 961 screen->saveBuf_index = allocScrnBuf(xw, 962 (unsigned) screen->savelines, 963 (unsigned) MaxCols(screen), 964 &screen->saveBuf_data); 965#endif 966 } else { 967 screen->saveBuf_index = 0; 968 } 969 screen->editBuf_index[0] = allocScrnBuf(xw, 970 (unsigned) nrows, 971 (unsigned) MaxCols(screen), 972 &screen->editBuf_data[0]); 973#else /* !OPT_SAVE_LINES */ 974 screen->saveBuf_index = allocScrnBuf(xw, 975 (unsigned) (nrows + screen->savelines), 976 (unsigned) (MaxCols(screen)), 977 &screen->saveBuf_data); 978#endif /* OPT_SAVE_LINES */ 979 screen->visbuf = VisBuf(screen); 980 } 981 return; 982} 983 984size_t 985ScrnPointers(TScreen * screen, size_t len) 986{ 987 size_t result = scrnHeadSize(screen, len); 988 989 if (result > screen->save_len) { 990 if (screen->save_len) 991 screen->save_ptr = (ScrnPtr *) realloc(screen->save_ptr, result); 992 else 993 screen->save_ptr = (ScrnPtr *) malloc(result); 994 screen->save_len = len; 995 if (screen->save_ptr == 0) 996 SysError(ERROR_SAVE_PTR); 997 } 998 TRACE2(("ScrnPointers %ld ->%p\n", (long) len, screen->save_ptr)); 999 return result; 1000} 1001 1002/* 1003 * Inserts n blank lines at sb + where, treating last as a bottom margin. 1004 */ 1005void 1006ScrnInsertLine(XtermWidget xw, ScrnBuf sb, int last, int where, unsigned n) 1007{ 1008 TScreen *screen = &(xw->screen); 1009 unsigned size = (unsigned) MaxCols(screen); 1010 1011 TRACE(("ScrnInsertLine(last %d, where %d, n %d, size %d)\n", 1012 last, where, n, size)); 1013 1014 assert(where >= 0); 1015 assert(last >= (int) n); 1016 assert(last >= where); 1017 1018 assert(n != 0); 1019 assert(size != 0); 1020 1021 /* save n lines at bottom */ 1022 ScrnClearLines(xw, sb, (last -= (int) n - 1), n, size); 1023 1024 /* 1025 * WARNING, overlapping copy operation. Move down lines (pointers). 1026 * 1027 * +----|---------|--------+ 1028 * 1029 * is copied in the array to: 1030 * 1031 * +--------|---------|----+ 1032 */ 1033 assert(last >= where); 1034 /* 1035 * This will never shift from the saveBuf to editBuf, so there is no need 1036 * to handle that case. 1037 */ 1038 MoveLineData(sb, 1039 (unsigned) (where + (int) n), 1040 (unsigned) where, 1041 (unsigned) (last - where)); 1042 1043 /* reuse storage for new lines at where */ 1044 RestoreLineData(sb, (unsigned) where, n); 1045} 1046 1047/* 1048 * Deletes n lines at sb + where, treating last as a bottom margin. 1049 */ 1050void 1051ScrnDeleteLine(XtermWidget xw, ScrnBuf sb, int last, int where, unsigned n) 1052{ 1053 TScreen *screen = &(xw->screen); 1054 unsigned size = (unsigned) MaxCols(screen); 1055 1056 TRACE(("ScrnDeleteLine(%s:last %d, where %d, n %d, size %d)\n", 1057 (sb == screen->saveBuf_index) ? "save" : "edit", 1058 last, where, n, size)); 1059 1060 assert(where >= 0); 1061 assert(last >= where + (int) n - 1); 1062 1063 assert(n != 0); 1064 assert(size != 0); 1065 1066 /* move up lines */ 1067 last -= ((int) n - 1); 1068#if OPT_SAVE_LINES 1069 if (inSaveBuf(screen, sb, where)) { 1070#if !OPT_FIFO_LINES 1071 int from = where + n; 1072#endif 1073 1074 /* we shouldn't be editing the saveBuf, only scroll into it */ 1075 assert(last >= screen->savelines); 1076 1077 if (sb != 0) { 1078#if OPT_FIFO_LINES 1079 /* copy lines from editBuf to saveBuf (allocating as we go...) */ 1080 saveEditBufLines(screen, sb, n); 1081#else 1082 ScrnClearLines(xw, sb, where, n, size); 1083 1084 /* move the pointers within saveBuf */ 1085 TRACE(("...%smoving pointers in saveBuf (compare %d %d)\n", 1086 ((screen->savelines > from) 1087 ? "" 1088 : "SKIP "), 1089 screen->savelines, 1090 from)); 1091 if (screen->savelines > from) { 1092 MoveLineData(sb, 1093 (unsigned) where, 1094 (unsigned) from, 1095 (unsigned) (screen->savelines - from)); 1096 } 1097 1098 /* reuse storage in saveBuf */ 1099 TRACE(("...reuse %d lines storage in saveBuf\n", n)); 1100 RestoreLineData(sb, (unsigned) screen->savelines - n, n); 1101 1102 /* copy lines from editBuf to saveBuf (into the reused storage) */ 1103 saveEditBufLines(screen, sb, n); 1104#endif 1105 } 1106 1107 /* adjust variables to fall-thru into changes only to editBuf */ 1108 TRACE(("...adjusting variables, to work on editBuf alone\n")); 1109 last -= screen->savelines; 1110 where = 0; 1111 sb = screen->visbuf; 1112 } 1113#endif 1114 /* 1115 * Scroll the visible buffer (editBuf). 1116 */ 1117 ScrnClearLines(xw, sb, where, n, size); 1118 1119 MoveLineData(sb, 1120 (unsigned) where, 1121 (unsigned) (where + (int) n), 1122 (size_t) (last - where)); 1123 1124 /* reuse storage for new bottom lines */ 1125 RestoreLineData(sb, (unsigned) last, n); 1126} 1127 1128/* 1129 * Inserts n blanks in screen at current row, col. Size is the size of each 1130 * row. 1131 */ 1132void 1133ScrnInsertChar(XtermWidget xw, unsigned n) 1134{ 1135#define MemMove(data) \ 1136 for (j = last - 1; j >= (col + (int) n); --j) \ 1137 data[j] = data[j - (int) n] 1138 1139 TScreen *screen = &(xw->screen); 1140 int last = MaxCols(screen); 1141 int row = screen->cur_row; 1142 int col = screen->cur_col; 1143 int j, nbytes; 1144 LineData *ld; 1145 1146 if (last <= (col + (int) n)) { 1147 if (last <= col) 1148 return; 1149 n = (unsigned) (last - col); 1150 } 1151 nbytes = (last - (col + (int) n)); 1152 1153 assert(screen->cur_col >= 0); 1154 assert(screen->cur_row >= 0); 1155 assert(n > 0); 1156 assert(last > (int) n); 1157 1158 if_OPT_WIDE_CHARS(screen, { 1159 int xx = INX2ROW(screen, screen->cur_row); 1160 int kl; 1161 int kr = screen->cur_col; 1162 if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) { 1163 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl); 1164 } 1165 kr = screen->max_col - (int) n + 1; 1166 if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) { 1167 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl); 1168 } 1169 }); 1170 1171 if ((ld = getLineData(screen, row)) != 0) { 1172 MemMove(ld->charData); 1173 MemMove(ld->attribs); 1174 1175 if_OPT_ISO_COLORS(screen, { 1176 MemMove(ld->color); 1177 }); 1178 if_OPT_WIDE_CHARS(screen, { 1179 size_t off; 1180 for_each_combData(off, ld) { 1181 MemMove(ld->combData[off]); 1182 } 1183 }); 1184 } 1185 ClearCells(xw, CHARDRAWN, n, row, col); 1186 1187#undef MemMove 1188} 1189 1190/* 1191 * Deletes n characters at current row, col. 1192 */ 1193void 1194ScrnDeleteChar(XtermWidget xw, unsigned n) 1195{ 1196#define MemMove(data) \ 1197 for (j = col; j < last - (int) n; ++j) \ 1198 data[j] = data[j + (int) n] 1199 1200 TScreen *screen = &(xw->screen); 1201 int last = MaxCols(screen); 1202 int row = screen->cur_row; 1203 int col = screen->cur_col; 1204 int j, nbytes; 1205 LineData *ld; 1206 1207 if (last <= (col + (int) n)) { 1208 if (last <= col) 1209 return; 1210 n = (unsigned) (last - col); 1211 } 1212 nbytes = (last - (col + (int) n)); 1213 1214 assert(screen->cur_col >= 0); 1215 assert(screen->cur_row >= 0); 1216 assert(n > 0); 1217 assert(last > (int) n); 1218 1219 if_OPT_WIDE_CHARS(screen, { 1220 int kl; 1221 int kr; 1222 if (DamagedCells(screen, n, &kl, &kr, 1223 INX2ROW(screen, screen->cur_row), 1224 screen->cur_col)) 1225 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl); 1226 }); 1227 1228 if ((ld = getLineData(screen, row)) != 0) { 1229 MemMove(ld->charData); 1230 MemMove(ld->attribs); 1231 1232 if_OPT_ISO_COLORS(screen, { 1233 MemMove(ld->color); 1234 }); 1235 if_OPT_WIDE_CHARS(screen, { 1236 size_t off; 1237 for_each_combData(off, ld) { 1238 MemMove(ld->combData[off]); 1239 } 1240 }); 1241 LineClrWrapped(ld); 1242 } 1243 ClearCells(xw, 0, n, row, (last - (int) n)); 1244 1245#undef MemMove 1246} 1247 1248/* 1249 * Repaints the area enclosed by the parameters. 1250 * Requires: (toprow, leftcol), (toprow + nrows, leftcol + ncols) are 1251 * coordinates of characters in screen; 1252 * nrows and ncols positive. 1253 * all dimensions are based on single-characters. 1254 */ 1255void 1256ScrnRefresh(XtermWidget xw, 1257 int toprow, 1258 int leftcol, 1259 int nrows, 1260 int ncols, 1261 Bool force) /* ... leading/trailing spaces */ 1262{ 1263 TScreen *screen = &(xw->screen); 1264 LineData *ld; 1265 int y = toprow * FontHeight(screen) + screen->border; 1266 int row; 1267 int maxrow = toprow + nrows - 1; 1268 int scrollamt = screen->scroll_amt; 1269 int max = screen->max_row; 1270 unsigned gc_changes = 0; 1271#ifdef __CYGWIN__ 1272 static char first_time = 1; 1273#endif 1274 static int recurse = 0; 1275 1276 TRACE(("ScrnRefresh (%d,%d) - (%d,%d)%s {{\n", 1277 toprow, leftcol, 1278 nrows, ncols, 1279 force ? " force" : "")); 1280 1281 if (screen->cursorp.col >= leftcol 1282 && screen->cursorp.col <= (leftcol + ncols - 1) 1283 && screen->cursorp.row >= ROW2INX(screen, toprow) 1284 && screen->cursorp.row <= ROW2INX(screen, maxrow)) 1285 screen->cursor_state = OFF; 1286 1287 for (row = toprow; row <= maxrow; y += FontHeight(screen), row++) { 1288#if OPT_ISO_COLORS 1289 CellColor *fb = 0; 1290#define ColorOf(col) fb[col] 1291#endif 1292#if OPT_WIDE_CHARS 1293 int wideness = 0; 1294#endif 1295#define BLANK_CEL(cell) (chars[cell] == ' ') 1296 IChar *chars; 1297 Char *attrs; 1298 int col = leftcol; 1299 int maxcol = leftcol + ncols - 1; 1300 int hi_col = maxcol; 1301 int lastind; 1302 unsigned flags; 1303 unsigned test; 1304 CellColor fg_bg = 0; 1305 unsigned fg = 0, bg = 0; 1306 int x; 1307 GC gc; 1308 Bool hilite; 1309 1310 (void) fg; 1311 (void) bg; 1312#if !OPT_ISO_COLORS 1313 fg_bg = 0; 1314#endif 1315 1316 if (row < screen->top_marg || row > screen->bot_marg) 1317 lastind = row; 1318 else 1319 lastind = row - scrollamt; 1320 1321 TRACE2(("ScrnRefresh row=%d lastind=%d/%d\n", row, lastind, max)); 1322 if (lastind < 0 || lastind > max) 1323 continue; 1324 1325 if ((ld = getLineData(screen, ROW2INX(screen, lastind))) == 0) 1326 break; 1327 if (maxcol >= ld->lineSize) { 1328 maxcol = ld->lineSize - 1; 1329 hi_col = maxcol; 1330 } 1331 1332 chars = ld->charData; 1333 attrs = ld->attribs; 1334 1335 if_OPT_WIDE_CHARS(screen, { 1336 /* This fixes an infinite recursion bug, that leads 1337 to display anomalies. It seems to be related to 1338 problems with the selection. */ 1339 if (recurse < 3) { 1340 /* adjust to redraw all of a widechar if we just wanted 1341 to draw the right hand half */ 1342 if (leftcol > 0 && 1343 chars[leftcol] == HIDDEN_CHAR && 1344 isWide((int) chars[leftcol - 1])) { 1345 leftcol--; 1346 ncols++; 1347 col = leftcol; 1348 } 1349 } else { 1350 fprintf(stderr, "This should not happen. Why is it so?\n"); 1351 } 1352 }); 1353 1354 if (row < screen->startH.row || row > screen->endH.row || 1355 (row == screen->startH.row && maxcol < screen->startH.col) || 1356 (row == screen->endH.row && col >= screen->endH.col)) { 1357#if OPT_DEC_CHRSET 1358 /* 1359 * Temporarily change dimensions to double-sized characters so 1360 * we can reuse the recursion on this function. 1361 */ 1362 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1363 col /= 2; 1364 maxcol /= 2; 1365 } 1366#endif 1367 /* 1368 * If row does not intersect selection; don't hilite blanks. 1369 */ 1370 if (!force) { 1371 while (col <= maxcol && (attrs[col] & ~BOLD) == 0 && 1372 BLANK_CEL(col)) 1373 col++; 1374 1375 while (col <= maxcol && (attrs[maxcol] & ~BOLD) == 0 && 1376 BLANK_CEL(maxcol)) 1377 maxcol--; 1378 } 1379#if OPT_DEC_CHRSET 1380 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1381 col *= 2; 1382 maxcol *= 2; 1383 } 1384#endif 1385 hilite = False; 1386 } else { 1387 /* row intersects selection; split into pieces of single type */ 1388 if (row == screen->startH.row && col < screen->startH.col) { 1389 recurse++; 1390 ScrnRefresh(xw, row, col, 1, screen->startH.col - col, 1391 force); 1392 col = screen->startH.col; 1393 } 1394 if (row == screen->endH.row && maxcol >= screen->endH.col) { 1395 recurse++; 1396 ScrnRefresh(xw, row, screen->endH.col, 1, 1397 maxcol - screen->endH.col + 1, force); 1398 maxcol = screen->endH.col - 1; 1399 } 1400 1401 /* 1402 * If we're highlighting because the user is doing cut/paste, 1403 * trim the trailing blanks from the highlighted region so we're 1404 * showing the actual extent of the text that'll be cut. If 1405 * we're selecting a blank line, we'll highlight one column 1406 * anyway. 1407 * 1408 * We don't do this if the mouse-hilite mode is set because that 1409 * would be too confusing. 1410 * 1411 * The default if the highlightSelection resource isn't set will 1412 * highlight the whole width of the terminal, which is easy to 1413 * see, but harder to use (because trailing blanks aren't as 1414 * apparent). 1415 */ 1416 if (screen->highlight_selection 1417 && screen->send_mouse_pos != VT200_HIGHLIGHT_MOUSE) { 1418 hi_col = screen->max_col; 1419 while (hi_col > 0 && !(attrs[hi_col] & CHARDRAWN)) 1420 hi_col--; 1421 } 1422 1423 /* remaining piece should be hilited */ 1424 hilite = True; 1425 } 1426 1427 if (col > maxcol) 1428 continue; 1429 1430 /* 1431 * Go back to double-sized character dimensions if the line has 1432 * double-width characters. Note that 'hi_col' is already in the 1433 * right units. 1434 */ 1435 if_OPT_DEC_CHRSET({ 1436 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1437 col /= 2; 1438 maxcol /= 2; 1439 } 1440 }); 1441 1442 flags = attrs[col]; 1443 1444 if_OPT_WIDE_CHARS(screen, { 1445 wideness = isWide((int) chars[col]); 1446 }); 1447 1448 if_OPT_ISO_COLORS(screen, { 1449 fb = ld->color; 1450 fg_bg = ColorOf(col); 1451 fg = extract_fg(xw, fg_bg, flags); 1452 bg = extract_bg(xw, fg_bg, flags); 1453 }); 1454 1455 gc = updatedXtermGC(xw, flags, fg_bg, hilite); 1456 gc_changes |= (flags & (FG_COLOR | BG_COLOR)); 1457 1458 x = LineCursorX(screen, ld, col); 1459 lastind = col; 1460 1461 for (; col <= maxcol; col++) { 1462 if ((attrs[col] != flags) 1463 || (hilite && (col > hi_col)) 1464#if OPT_ISO_COLORS 1465 || ((flags & FG_COLOR) 1466 && (extract_fg(xw, ColorOf(col), attrs[col]) != fg)) 1467 || ((flags & BG_COLOR) 1468 && (extract_bg(xw, ColorOf(col), attrs[col]) != bg)) 1469#endif 1470#if OPT_WIDE_CHARS 1471 || (isWide((int) chars[col]) != wideness 1472 && chars[col] != HIDDEN_CHAR) 1473#endif 1474 ) { 1475 assert(col >= lastind); 1476 TRACE(("ScrnRefresh looping drawXtermText %d..%d:%s\n", 1477 lastind, col, 1478 visibleIChars((&chars[lastind]), 1479 (unsigned) (col - lastind)))); 1480 1481 test = flags; 1482 checkVeryBoldColors(test, fg); 1483 1484 x = drawXtermText(xw, test & DRAWX_MASK, gc, x, y, 1485 GetLineDblCS(ld), 1486 &chars[lastind], 1487 (unsigned) (col - lastind), 0); 1488 1489 if_OPT_WIDE_CHARS(screen, { 1490 int i; 1491 size_t off; 1492 1493 for_each_combData(off, ld) { 1494 IChar *com_off = ld->combData[off]; 1495 1496 for (i = lastind; i < col; i++) { 1497 int my_x = LineCursorX(screen, ld, i); 1498 IChar base = chars[i]; 1499 1500 if (isWide((int) base)) 1501 my_x = LineCursorX(screen, ld, i - 1); 1502 1503 if (com_off[i] != 0) 1504 drawXtermText(xw, 1505 (test & DRAWX_MASK) 1506 | NOBACKGROUND, 1507 gc, my_x, y, 1508 GetLineDblCS(ld), 1509 com_off + i, 1510 1, isWide((int) base)); 1511 } 1512 } 1513 }); 1514 1515 resetXtermGC(xw, flags, hilite); 1516 1517 lastind = col; 1518 1519 if (hilite && (col > hi_col)) 1520 hilite = False; 1521 1522 flags = attrs[col]; 1523 if_OPT_ISO_COLORS(screen, { 1524 fg_bg = ColorOf(col); 1525 fg = extract_fg(xw, fg_bg, flags); 1526 bg = extract_bg(xw, fg_bg, flags); 1527 }); 1528 if_OPT_WIDE_CHARS(screen, { 1529 wideness = isWide((int) chars[col]); 1530 }); 1531 1532 gc = updatedXtermGC(xw, flags, fg_bg, hilite); 1533 gc_changes |= (flags & (FG_COLOR | BG_COLOR)); 1534 } 1535 1536 if (chars[col] == 0) { 1537 chars[col] = ' '; 1538 } 1539 } 1540 1541 assert(col >= lastind); 1542 TRACE(("ScrnRefresh calling drawXtermText %d..%d:%s\n", 1543 lastind, col, 1544 visibleIChars(&chars[lastind], (unsigned) (col - lastind)))); 1545 1546 test = flags; 1547 checkVeryBoldColors(test, fg); 1548 1549 drawXtermText(xw, test & DRAWX_MASK, gc, x, y, 1550 GetLineDblCS(ld), 1551 &chars[lastind], 1552 (unsigned) (col - lastind), 0); 1553 1554 if_OPT_WIDE_CHARS(screen, { 1555 int i; 1556 size_t off; 1557 1558 for_each_combData(off, ld) { 1559 IChar *com_off = ld->combData[off]; 1560 1561 for (i = lastind; i < col; i++) { 1562 int my_x = LineCursorX(screen, ld, i); 1563 int base = (int) chars[i]; 1564 1565 if (isWide(base)) 1566 my_x = LineCursorX(screen, ld, i - 1); 1567 1568 if (com_off[i] != 0) 1569 drawXtermText(xw, 1570 (test & DRAWX_MASK) 1571 | NOBACKGROUND, 1572 gc, my_x, y, 1573 GetLineDblCS(ld), 1574 com_off + i, 1575 1, isWide(base)); 1576 } 1577 } 1578 }); 1579 1580 resetXtermGC(xw, flags, hilite); 1581 } 1582 1583 /* 1584 * If we're in color mode, reset the various GC's to the current 1585 * screen foreground and background so that other functions (e.g., 1586 * ClearRight) will get the correct colors. 1587 */ 1588 if_OPT_ISO_COLORS(screen, { 1589 if (gc_changes & FG_COLOR) 1590 SGR_Foreground(xw, xw->cur_foreground); 1591 if (gc_changes & BG_COLOR) 1592 SGR_Background(xw, xw->cur_background); 1593 }); 1594 1595#if defined(__CYGWIN__) && defined(TIOCSWINSZ) 1596 if (first_time == 1) { 1597 TTYSIZE_STRUCT ts; 1598 1599 first_time = 0; 1600 TTYSIZE_ROWS(ts) = nrows; 1601 TTYSIZE_COLS(ts) = ncols; 1602 ts.ws_xpixel = xw->core.width; 1603 ts.ws_ypixel = xw->core.height; 1604 SET_TTYSIZE(screen->respond, ts); 1605 } 1606#endif 1607 recurse--; 1608 1609 TRACE(("...}} ScrnRefresh\n")); 1610 return; 1611} 1612 1613/* 1614 * Call this wrapper to ScrnRefresh() when the data has changed. If the 1615 * refresh region overlaps the selection, we will release the primary selection. 1616 */ 1617void 1618ScrnUpdate(XtermWidget xw, 1619 int toprow, 1620 int leftcol, 1621 int nrows, 1622 int ncols, 1623 Bool force) /* ... leading/trailing spaces */ 1624{ 1625 TScreen *screen = &(xw->screen); 1626 1627 if (ScrnHaveSelection(screen) 1628 && (toprow <= screen->endH.row) 1629 && (toprow + nrows - 1 >= screen->startH.row)) { 1630 ScrnDisownSelection(xw); 1631 } 1632 ScrnRefresh(xw, toprow, leftcol, nrows, ncols, force); 1633} 1634 1635/* 1636 * Sets the rows first though last of the buffer of screen to spaces. 1637 * Requires first <= last; first, last are rows of screen->buf. 1638 */ 1639void 1640ClearBufRows(XtermWidget xw, 1641 int first, 1642 int last) 1643{ 1644 TScreen *screen = &(xw->screen); 1645 unsigned len = (unsigned) MaxCols(screen); 1646 int row; 1647 1648 TRACE(("ClearBufRows %d..%d\n", first, last)); 1649 for (row = first; row <= last; row++) { 1650 LineData *ld = getLineData(screen, ROW2INX(screen, row)); 1651 if_OPT_DEC_CHRSET({ 1652 /* clearing the whole row resets the doublesize characters */ 1653 SetLineDblCS(ld, CSET_SWL); 1654 }); 1655 LineClrWrapped(ld); 1656 ClearCells(xw, 0, len, row, 0); 1657 } 1658} 1659 1660/* 1661 Resizes screen: 1662 1. If new window would have fractional characters, sets window size so as to 1663 discard fractional characters and returns -1. 1664 Minimum screen size is 1 X 1. 1665 Note that this causes another ExposeWindow event. 1666 2. Enlarges screen->buf if necessary. New space is appended to the bottom 1667 and to the right 1668 3. Reduces screen->buf if necessary. Old space is removed from the bottom 1669 and from the right 1670 4. Cursor is positioned as closely to its former position as possible 1671 5. Sets screen->max_row and screen->max_col to reflect new size 1672 6. Maintains the inner border (and clears the border on the screen). 1673 7. Clears origin mode and sets scrolling region to be entire screen. 1674 8. Returns 0 1675 */ 1676int 1677ScreenResize(XtermWidget xw, 1678 int width, 1679 int height, 1680 unsigned *flags) 1681{ 1682 TScreen *screen = &(xw->screen); 1683 int code, rows, cols; 1684 int border = 2 * screen->border; 1685 int move_down_by = 0; 1686#ifdef TTYSIZE_STRUCT 1687 TTYSIZE_STRUCT ts; 1688#endif 1689 Window tw = VWindow(screen); 1690 1691 TRACE(("ScreenResize %dx%d border %d font %dx%d\n", 1692 height, width, border, 1693 FontHeight(screen), FontWidth(screen))); 1694 1695 assert(width > 0); 1696 assert(height > 0); 1697 1698 if (screen->is_running) { 1699 /* clear the right and bottom internal border because of NorthWest 1700 gravity might have left junk on the right and bottom edges */ 1701 if (width >= FullWidth(screen)) { 1702 XClearArea(screen->display, tw, 1703 FullWidth(screen), 0, /* right edge */ 1704 0, (unsigned) height, /* from top to bottom */ 1705 False); 1706 } 1707 if (height >= FullHeight(screen)) { 1708 XClearArea(screen->display, tw, 1709 0, FullHeight(screen), /* bottom */ 1710 (unsigned) width, 0, /* all across the bottom */ 1711 False); 1712 } 1713 } 1714 1715 TRACE(("...computing rows/cols: %.2f %.2f\n", 1716 (double) (height - border) / FontHeight(screen), 1717 (double) (width - border - ScrollbarWidth(screen)) / FontWidth(screen))); 1718 1719 rows = (height - border) / FontHeight(screen); 1720 cols = (width - border - ScrollbarWidth(screen)) / FontWidth(screen); 1721 if (rows < 1) 1722 rows = 1; 1723 if (cols < 1) 1724 cols = 1; 1725 1726 /* update buffers if the screen has changed size */ 1727 if (MaxRows(screen) != rows || MaxCols(screen) != cols) { 1728 int delta_rows = rows - MaxRows(screen); 1729#if OPT_TRACE 1730 int delta_cols = cols - MaxCols(screen); 1731#endif 1732 1733 TRACE(("...ScreenResize chars %dx%d delta %dx%d\n", 1734 rows, cols, delta_rows, delta_cols)); 1735 1736 if (screen->is_running) { 1737#if !OPT_FIFO_LINES 1738 int savelines = (screen->scrollWidget 1739 ? screen->savelines 1740 : 0); 1741#endif 1742 if (screen->cursor_state) 1743 HideCursor(); 1744#if OPT_SAVE_LINES 1745 /* 1746 * The non-visible buffer is simple, since we will not copy data 1747 * to/from the saved-lines. Do that first. 1748 */ 1749 if (screen->editBuf_index[!screen->whichBuf]) { 1750 (void) Reallocate(xw, 1751 &screen->editBuf_index[!screen->whichBuf], 1752 &screen->editBuf_data[!screen->whichBuf], 1753 (unsigned) rows, 1754 (unsigned) cols, 1755 (unsigned) MaxRows(screen), 1756 (unsigned) MaxCols(screen)); 1757 } 1758 1759 /* 1760 * The save-lines buffer may change width, but will not change its 1761 * height. Deal with the cases where we copy data to/from the 1762 * saved-lines buffer. 1763 */ 1764 if (GravityIsSouthWest(xw) 1765 && delta_rows 1766 && screen->saveBuf_index != 0) { 1767 1768 move_down_by = delta_rows; 1769 1770 if (delta_rows < 0) { 1771 unsigned move_up = (unsigned) (-delta_rows); 1772 ScrnBuf dst = screen->saveBuf_index; 1773 1774#if OPT_FIFO_LINES 1775 int amount = ((MaxRows(screen) - (int) move_up - 1) 1776 - screen->cur_row); 1777 1778 if (amount < 0) { 1779 /* move line-data from visible-buffer to save-buffer */ 1780 saveEditBufLines(screen, dst, -amount); 1781 move_up = -amount; 1782 move_down_by = amount; 1783 } else { 1784 move_down_by = 0; 1785 } 1786#else /* !OPT_FIFO_LINES */ 1787 int amount = screen->savelines - (int) move_up; 1788 1789 TRACE_SCRNBUF("before save", screen, dst, screen->savelines); 1790 1791 /* shift lines in save-buffer to make room */ 1792 TRACE(("...%smoving pointers in saveBuf (compare %d %d)\n", 1793 (amount > 0 1794 ? "" 1795 : "SKIP "), 1796 screen->savelines, 1797 move_up)); 1798 if (amount > 0) { 1799 SaveLineData(dst, 0, move_up); 1800 1801 MoveLineData(dst, 1802 0, 1803 move_up, 1804 (unsigned) amount); 1805 1806 TRACE(("...reuse %d lines storage in saveBuf\n", move_up)); 1807 RestoreLineData(dst, 1808 (unsigned) amount, 1809 move_up); 1810 TRACE_SCRNBUF("restoresave", screen, dst, screen->savelines); 1811 } 1812 1813 /* copy line-data from visible-buffer to save-buffer */ 1814 saveEditBufLines(screen, dst, move_up); 1815 1816 /* after data is copied, reallocate saved-lines */ 1817 (void) Reallocate(xw, 1818 &screen->saveBuf_index, 1819 &screen->saveBuf_data, 1820 (unsigned) savelines, 1821 (unsigned) cols, 1822 (unsigned) savelines, 1823 (unsigned) MaxCols(screen)); 1824 TRACE_SCRNBUF("reallocSAVE", 1825 screen, 1826 screen->saveBuf_index, 1827 savelines); 1828#endif /* OPT_FIFO_LINES */ 1829 1830 /* decrease size of visible-buffer */ 1831 (void) Reallocate(xw, 1832 &screen->editBuf_index[screen->whichBuf], 1833 &screen->editBuf_data[screen->whichBuf], 1834 (unsigned) rows, 1835 (unsigned) cols, 1836 (unsigned) MaxRows(screen), 1837 (unsigned) MaxCols(screen)); 1838 TRACE_SCRNBUF("reallocEDIT", 1839 screen, 1840 screen->editBuf_index[screen->whichBuf], 1841 rows); 1842 } else { 1843 unsigned move_down = (unsigned) delta_rows; 1844#if OPT_FIFO_LINES 1845 long unsave_fifo; 1846#else 1847 ScrnBuf src = screen->saveBuf_index; 1848#endif 1849 ScrnBuf dst; 1850 int amount; 1851 1852 if ((int) move_down > screen->savedlines) { 1853 move_down = (unsigned) screen->savedlines; 1854 } 1855 move_down_by = (int) move_down; 1856 amount = rows - (int) move_down; 1857 1858 /* increase size of visible-buffer */ 1859 (void) Reallocate(xw, 1860 &screen->editBuf_index[screen->whichBuf], 1861 &screen->editBuf_data[screen->whichBuf], 1862 (unsigned) rows, 1863 (unsigned) cols, 1864 (unsigned) MaxRows(screen), 1865 (unsigned) MaxCols(screen)); 1866 1867 dst = screen->editBuf_index[screen->whichBuf]; 1868 TRACE_SCRNBUF("reallocEDIT", screen, dst, rows); 1869 1870 TRACE(("...%smoving pointers in editBuf (compare %d %d)\n", 1871 (amount > 0 1872 ? "" 1873 : "SKIP "), 1874 rows, 1875 move_down)); 1876 if (amount > 0) { 1877 /* shift lines in visible-buffer to make room */ 1878 SaveLineData(dst, (unsigned) amount, (size_t) move_down); 1879 1880 MoveLineData(dst, 1881 move_down, 1882 0, 1883 (unsigned) amount); 1884 1885 TRACE(("...reuse %d lines storage in editBuf\n", move_down)); 1886 RestoreLineData(dst, 1887 0, 1888 move_down); 1889 1890 TRACE_SCRNBUF("shifted", screen, dst, rows); 1891 } 1892 1893 /* copy line-data from save-buffer to visible-buffer */ 1894 unsaveEditBufLines(screen, dst, move_down); 1895 TRACE_SCRNBUF("copied", screen, dst, rows); 1896 1897#if OPT_FIFO_LINES 1898 unsave_fifo = (long) move_down; 1899 if (screen->saved_fifo < (int) unsave_fifo) 1900 unsave_fifo = screen->saved_fifo; 1901 1902 /* free up storage in fifo from the copied lines */ 1903 while (unsave_fifo-- > 0) { 1904 deleteScrollback(screen, -1); 1905 screen->saved_fifo--; 1906 } 1907#else 1908 amount = (screen->savelines - (int) move_down); 1909 TRACE(("...%smoving pointers in saveBuf (compare %d %d)\n", 1910 (amount > 0 1911 ? "" 1912 : "SKIP "), 1913 rows, 1914 move_down)); 1915 if (amount > 0) { 1916 /* shift lines in save-buffer to account for copy */ 1917 src = screen->saveBuf_index; 1918 SaveLineData(src, amount, move_down); 1919 1920 MoveLineData(src, 1921 move_down, 1922 0, 1923 (unsigned) amount); 1924 1925 TRACE(("...reuse %d lines storage in saveBuf\n", move_down)); 1926 RestoreLineData(src, 1927 0, 1928 move_down); 1929 } 1930#endif 1931 1932 /* recover storage in save-buffer */ 1933 } 1934 } else { 1935#if !OPT_FIFO_LINES 1936 (void) Reallocate(xw, 1937 &screen->saveBuf_index, 1938 &screen->saveBuf_data, 1939 (unsigned) savelines, 1940 (unsigned) cols, 1941 (unsigned) savelines, 1942 (unsigned) MaxCols(screen)); 1943#endif 1944 (void) Reallocate(xw, 1945 &screen->editBuf_index[screen->whichBuf], 1946 &screen->editBuf_data[screen->whichBuf], 1947 (unsigned) rows, 1948 (unsigned) cols, 1949 (unsigned) MaxRows(screen), 1950 (unsigned) MaxCols(screen)); 1951 } 1952#else /* !OPT_SAVE_LINES */ 1953 if (screen->whichBuf 1954 && GravityIsSouthWest(xw)) 1955 /* swap buffer pointers back to make this work */ 1956 SwitchBufPtrs(screen); 1957 if (screen->editBuf_index[1]) 1958 (void) Reallocate(xw, 1959 &screen->editBuf_index[1], 1960 &screen->editBuf_data[1], 1961 (unsigned) rows, 1962 (unsigned) cols, 1963 (unsigned) MaxRows(screen), 1964 (unsigned) MaxCols(screen)); 1965 move_down_by = Reallocate(xw, 1966 &screen->saveBuf_index, 1967 &screen->saveBuf_data, 1968 (unsigned) (rows + savelines), 1969 (unsigned) cols, 1970 (unsigned) (MaxRows(screen) + savelines), 1971 (unsigned) MaxCols(screen)); 1972#endif /* OPT_SAVE_LINES */ 1973 screen->visbuf = VisBuf(screen); 1974 } 1975 1976 AdjustSavedCursor(xw, move_down_by); 1977 set_max_row(screen, screen->max_row + delta_rows); 1978 set_max_col(screen, cols - 1); 1979 1980 if (screen->is_running) { 1981 if (GravityIsSouthWest(xw)) { 1982 screen->savedlines -= move_down_by; 1983 if (screen->savedlines < 0) 1984 screen->savedlines = 0; 1985 if (screen->savedlines > screen->savelines) 1986 screen->savedlines = screen->savelines; 1987 if (screen->topline < -screen->savedlines) 1988 screen->topline = -screen->savedlines; 1989 set_cur_row(screen, screen->cur_row + move_down_by); 1990 screen->cursorp.row += move_down_by; 1991 ScrollSelection(screen, move_down_by, True); 1992 1993 if (screen->whichBuf) 1994 SwitchBufPtrs(screen); /* put the pointers back */ 1995 } 1996 } 1997 1998 /* adjust scrolling region */ 1999 set_tb_margins(screen, 0, screen->max_row); 2000 *flags &= ~ORIGIN; 2001 2002 if (screen->cur_row > screen->max_row) 2003 set_cur_row(screen, screen->max_row); 2004 if (screen->cur_col > screen->max_col) 2005 set_cur_col(screen, screen->max_col); 2006 2007 screen->fullVwin.height = height - border; 2008 screen->fullVwin.width = width - border - screen->fullVwin.sb_info.width; 2009 2010 } else if (FullHeight(screen) == height && FullWidth(screen) == width) 2011 return (0); /* nothing has changed at all */ 2012 2013 screen->fullVwin.fullheight = (Dimension) height; 2014 screen->fullVwin.fullwidth = (Dimension) width; 2015 2016 ResizeScrollBar(xw); 2017 ResizeSelection(screen, rows, cols); 2018 2019#ifndef NO_ACTIVE_ICON 2020 if (screen->iconVwin.window) { 2021 XWindowChanges changes; 2022 screen->iconVwin.width = 2023 MaxCols(screen) * screen->iconVwin.f_width; 2024 2025 screen->iconVwin.height = 2026 MaxRows(screen) * screen->iconVwin.f_height; 2027 2028 changes.width = screen->iconVwin.fullwidth = 2029 (Dimension) (screen->iconVwin.width + 2 * xw->misc.icon_border_width); 2030 changes.height = screen->iconVwin.fullheight = 2031 (Dimension) (screen->iconVwin.height + 2 * xw->misc.icon_border_width); 2032 changes.border_width = (int) xw->misc.icon_border_width; 2033 2034 TRACE(("resizing icon window %dx%d\n", changes.height, changes.width)); 2035 XConfigureWindow(XtDisplay(xw), screen->iconVwin.window, 2036 CWWidth | CWHeight | CWBorderWidth, &changes); 2037 } 2038#endif /* NO_ACTIVE_ICON */ 2039 2040#ifdef TTYSIZE_STRUCT 2041 /* Set tty's idea of window size */ 2042 TTYSIZE_ROWS(ts) = rows; 2043 TTYSIZE_COLS(ts) = cols; 2044#ifdef USE_STRUCT_WINSIZE 2045 ts.ws_xpixel = width; 2046 ts.ws_ypixel = height; 2047#endif 2048 code = SET_TTYSIZE(screen->respond, ts); 2049 TRACE(("return %d from SET_TTYSIZE %dx%d\n", code, rows, cols)); 2050 (void) code; 2051 2052#if defined(SIGWINCH) && defined(USE_STRUCT_TTYSIZE) 2053 if (screen->pid > 1) { 2054 int pgrp; 2055 2056 TRACE(("getting process-group\n")); 2057 if (ioctl(screen->respond, TIOCGPGRP, &pgrp) != -1) { 2058 TRACE(("sending SIGWINCH to process group %d\n", pgrp)); 2059 kill_process_group(pgrp, SIGWINCH); 2060 } 2061 } 2062#endif /* SIGWINCH */ 2063 2064#else 2065 TRACE(("ScreenResize cannot do anything to pty\n")); 2066#endif /* TTYSIZE_STRUCT */ 2067 return (0); 2068} 2069 2070/* 2071 * Return true if any character cell starting at [row,col], for len-cells is 2072 * nonnull. 2073 */ 2074Bool 2075non_blank_line(TScreen * screen, 2076 int row, 2077 int col, 2078 int len) 2079{ 2080 int i; 2081 Bool found = False; 2082 LineData *ld = getLineData(screen, row); 2083 2084 if (ld != 0) { 2085 for (i = col; i < len; i++) { 2086 if (ld->charData[i]) { 2087 found = True; 2088 break; 2089 } 2090 } 2091 } 2092 return found; 2093} 2094 2095/* 2096 * Rectangle parameters start from one. 2097 */ 2098#define minRectRow(screen) (getMinRow(screen) + 1) 2099#define minRectCol(screen) (getMinCol(screen) + 1) 2100#define maxRectRow(screen) (getMaxRow(screen) + 1) 2101#define maxRectCol(screen) (getMaxCol(screen) + 1) 2102 2103static int 2104limitedParseRow(XtermWidget xw, TScreen * screen, int row) 2105{ 2106 int min_row = minRectRow(screen); 2107 int max_row = maxRectRow(screen); 2108 2109 if (row < min_row) 2110 row = min_row; 2111 else if (row > max_row) 2112 row = max_row; 2113 return row; 2114} 2115 2116static int 2117limitedParseCol(XtermWidget xw, TScreen * screen, int col) 2118{ 2119 int min_col = minRectCol(screen); 2120 int max_col = maxRectCol(screen); 2121 2122 (void) xw; 2123 if (col < min_col) 2124 col = min_col; 2125 else if (col > max_col) 2126 col = max_col; 2127 return col; 2128} 2129 2130#define LimitedParse(num, func, dft) \ 2131 func(xw, screen, (nparams > num) ? params[num] : dft) 2132 2133/* 2134 * Copy the rectangle boundaries into a struct, providing default values as 2135 * needed. 2136 */ 2137void 2138xtermParseRect(XtermWidget xw, int nparams, int *params, XTermRect * target) 2139{ 2140 TScreen *screen = &(xw->screen); 2141 2142 memset(target, 0, sizeof(*target)); 2143 target->top = LimitedParse(0, limitedParseRow, minRectRow(screen)); 2144 target->left = LimitedParse(1, limitedParseCol, minRectCol(screen)); 2145 target->bottom = LimitedParse(2, limitedParseRow, maxRectRow(screen)); 2146 target->right = LimitedParse(3, limitedParseCol, maxRectCol(screen)); 2147 TRACE(("parsed rectangle %d,%d %d,%d\n", 2148 target->top, 2149 target->left, 2150 target->bottom, 2151 target->right)); 2152} 2153 2154static Bool 2155validRect(XtermWidget xw, XTermRect * target) 2156{ 2157 TScreen *screen = &(xw->screen); 2158 2159 TRACE(("comparing against screensize %dx%d\n", 2160 maxRectRow(screen), 2161 maxRectCol(screen))); 2162 return (target != 0 2163 && target->top >= minRectRow(screen) 2164 && target->left >= minRectCol(screen) 2165 && target->top <= target->bottom 2166 && target->left <= target->right 2167 && target->top <= maxRectRow(screen) 2168 && target->right <= maxRectCol(screen)); 2169} 2170 2171/* 2172 * Fills a rectangle with the given 8-bit character and video-attributes. 2173 * Colors and double-size attribute are unmodified. 2174 */ 2175void 2176ScrnFillRectangle(XtermWidget xw, 2177 XTermRect * target, 2178 int value, 2179 unsigned flags, 2180 Bool keepColors) 2181{ 2182 TScreen *screen = &(xw->screen); 2183 2184 TRACE(("filling rectangle with '%c' flags %#x\n", value, flags)); 2185 if (validRect(xw, target)) { 2186 LineData *ld; 2187 unsigned left = (unsigned) (target->left - 1); 2188 unsigned size = (unsigned) (target->right - (int) left); 2189 unsigned attrs = flags; 2190 int row, col; 2191 2192 (void) size; 2193 2194 attrs &= ATTRIBUTES; 2195 attrs |= CHARDRAWN; 2196 for (row = target->bottom - 1; row >= (target->top - 1); row--) { 2197 ld = getLineData(screen, row); 2198 2199 TRACE(("filling %d [%d..%d]\n", row, left, left + size)); 2200 2201 /* 2202 * Fill attributes, preserving "protected" flag, as well as 2203 * colors if asked. 2204 */ 2205 for (col = (int) left; col < target->right; ++col) { 2206 unsigned temp = ld->attribs[col]; 2207 2208 if (!keepColors) { 2209 temp &= ~(FG_COLOR | BG_COLOR); 2210 } 2211 temp = attrs | (temp & (FG_COLOR | BG_COLOR | PROTECTED)); 2212 temp |= CHARDRAWN; 2213 ld->attribs[col] = (Char) temp; 2214#if OPT_ISO_COLORS 2215 if (attrs & (FG_COLOR | BG_COLOR)) { 2216 if_OPT_ISO_COLORS(screen, { 2217 ld->color[col] = xtermColorPair(xw); 2218 }); 2219 } 2220#endif 2221 } 2222 2223 for (col = (int) left; col < target->right; ++col) 2224 ld->charData[col] = (CharData) value; 2225 2226 if_OPT_WIDE_CHARS(screen, { 2227 size_t off; 2228 for_each_combData(off, ld) { 2229 memset(ld->combData[off] + left, 0, size * sizeof(IChar)); 2230 } 2231 }) 2232 } 2233 ScrnUpdate(xw, 2234 target->top - 1, 2235 target->left - 1, 2236 (target->bottom - target->top) + 1, 2237 (target->right - target->left) + 1, 2238 False); 2239 } 2240} 2241 2242#if OPT_DEC_RECTOPS 2243/* 2244 * Copies the source rectangle to the target location, including video 2245 * attributes. 2246 * 2247 * This implementation ignores page numbers. 2248 * 2249 * The reference manual does not indicate if it handles overlapping copy 2250 * properly - so we make a local copy of the source rectangle first, then apply 2251 * the target from that. 2252 */ 2253void 2254ScrnCopyRectangle(XtermWidget xw, XTermRect * source, int nparam, int *params) 2255{ 2256 TScreen *screen = &(xw->screen); 2257 2258 TRACE(("copying rectangle\n")); 2259 2260 if (validRect(xw, source)) { 2261 XTermRect target; 2262 xtermParseRect(xw, 2263 ((nparam > 3) ? 2 : (nparam - 1)), 2264 params, 2265 &target); 2266 if (validRect(xw, &target)) { 2267 Cardinal high = (Cardinal) (source->bottom - source->top) + 1; 2268 Cardinal wide = (Cardinal) (source->right - source->left) + 1; 2269 Cardinal size = (high * wide); 2270 int row, col; 2271 Cardinal j, k; 2272 LineData *ld; 2273 2274 CellData *cells = newCellData(xw, size); 2275 2276 if (cells != 0) { 2277 2278 TRACE(("OK - make copy %dx%d\n", high, wide)); 2279 target.bottom = target.top + (int) (high - 1); 2280 target.right = target.left + (int) (wide - 1); 2281 2282 for (row = source->top - 1; row < source->bottom; ++row) { 2283 ld = getLineData(screen, row); 2284 j = (Cardinal) (row - (source->top - 1)); 2285 for (col = source->left - 1; col < source->right; ++col) { 2286 k = (Cardinal) (col - (source->left - 1)); 2287 saveCellData(screen, cells, 2288 (j * wide) + k, 2289 ld, col); 2290 } 2291 } 2292 for (row = target.top - 1; row < target.bottom; ++row) { 2293 ld = getLineData(screen, row); 2294 j = (Cardinal) (row - (target.top - 1)); 2295 for (col = target.left - 1; col < target.right; ++col) { 2296 k = (Cardinal) (col - (target.left - 1)); 2297 if (row >= getMinRow(screen) 2298 && row <= getMaxRow(screen) 2299 && col >= getMinCol(screen) 2300 && col <= getMaxCol(screen)) { 2301 if (j < high && k < wide) { 2302 restoreCellData(screen, cells, 2303 (j * wide) + k, 2304 ld, col); 2305 } else { 2306 /* FIXME - clear the target cell? */ 2307 } 2308 ld->attribs[col] |= CHARDRAWN; 2309 } 2310 } 2311 } 2312 free(cells); 2313 2314 ScrnUpdate(xw, 2315 (target.top - 1), 2316 (target.left - 1), 2317 (target.bottom - target.top) + 1, 2318 ((target.right - target.left) + 1), 2319 False); 2320 } 2321 } 2322 } 2323} 2324 2325/* 2326 * Modifies the video-attributes only - so selection (not a video attribute) is 2327 * unaffected. Colors and double-size flags are unaffected as well. 2328 * 2329 * FIXME: our representation for "invisible" does not work with this operation, 2330 * since the attribute byte is fully-allocated for other flags. The logic 2331 * is shown for INVISIBLE because it's harmless, and useful in case the 2332 * CHARDRAWN or PROTECTED flags are reassigned. 2333 */ 2334void 2335ScrnMarkRectangle(XtermWidget xw, 2336 XTermRect * target, 2337 Bool reverse, 2338 int nparam, 2339 int *params) 2340{ 2341 TScreen *screen = &(xw->screen); 2342 Bool exact = (screen->cur_decsace == 2); 2343 2344 TRACE(("%s %s\n", 2345 reverse ? "reversing" : "marking", 2346 (exact 2347 ? "rectangle" 2348 : "region"))); 2349 2350 if (validRect(xw, target)) { 2351 LineData *ld; 2352 int top = target->top - 1; 2353 int bottom = target->bottom - 1; 2354 int row, col; 2355 int n; 2356 2357 for (row = top; row <= bottom; ++row) { 2358 int left = ((exact || (row == top)) 2359 ? (target->left - 1) 2360 : getMinCol(screen)); 2361 int right = ((exact || (row == bottom)) 2362 ? (target->right - 1) 2363 : getMaxCol(screen)); 2364 2365 ld = getLineData(screen, row); 2366 2367 TRACE(("marking %d [%d..%d]\n", row, left, right)); 2368 for (col = left; col <= right; ++col) { 2369 unsigned flags = ld->attribs[col]; 2370 2371 for (n = 0; n < nparam; ++n) { 2372#if OPT_TRACE 2373 if (row == top && col == left) 2374 TRACE(("attr param[%d] %d\n", n + 1, params[n])); 2375#endif 2376 if (reverse) { 2377 switch (params[n]) { 2378 case 1: 2379 flags ^= BOLD; 2380 break; 2381 case 4: 2382 flags ^= UNDERLINE; 2383 break; 2384 case 5: 2385 flags ^= BLINK; 2386 break; 2387 case 7: 2388 flags ^= INVERSE; 2389 break; 2390 case 8: 2391 flags ^= INVISIBLE; 2392 break; 2393 } 2394 } else { 2395 switch (params[n]) { 2396 case 0: 2397 flags &= ~SGR_MASK; 2398 break; 2399 case 1: 2400 flags |= BOLD; 2401 break; 2402 case 4: 2403 flags |= UNDERLINE; 2404 break; 2405 case 5: 2406 flags |= BLINK; 2407 break; 2408 case 7: 2409 flags |= INVERSE; 2410 break; 2411 case 8: 2412 flags |= INVISIBLE; 2413 break; 2414 case 22: 2415 flags &= ~BOLD; 2416 break; 2417 case 24: 2418 flags &= ~UNDERLINE; 2419 break; 2420 case 25: 2421 flags &= ~BLINK; 2422 break; 2423 case 27: 2424 flags &= ~INVERSE; 2425 break; 2426 case 28: 2427 flags &= ~INVISIBLE; 2428 break; 2429 } 2430 } 2431 } 2432#if OPT_TRACE 2433 if (row == top && col == left) 2434 TRACE(("first mask-change is %#x\n", 2435 ld->attribs[col] ^ flags)); 2436#endif 2437 ld->attribs[col] = (Char) flags; 2438 } 2439 } 2440 ScrnRefresh(xw, 2441 (target->top - 1), 2442 (exact ? (target->left - 1) : getMinCol(screen)), 2443 (target->bottom - target->top) + 1, 2444 (exact 2445 ? ((target->right - target->left) + 1) 2446 : (getMaxCol(screen) - getMinCol(screen) + 1)), 2447 False); 2448 } 2449} 2450 2451/* 2452 * Resets characters to space, except where prohibited by DECSCA. Video 2453 * attributes (including color) are untouched. 2454 */ 2455void 2456ScrnWipeRectangle(XtermWidget xw, 2457 XTermRect * target) 2458{ 2459 TScreen *screen = &(xw->screen); 2460 2461 TRACE(("wiping rectangle\n")); 2462 2463 if (validRect(xw, target)) { 2464 LineData *ld; 2465 int top = target->top - 1; 2466 int bottom = target->bottom - 1; 2467 int row, col; 2468 2469 for (row = top; row <= bottom; ++row) { 2470 int left = (target->left - 1); 2471 int right = (target->right - 1); 2472 2473 TRACE(("wiping %d [%d..%d]\n", row, left, right)); 2474 2475 ld = getLineData(screen, row); 2476 for (col = left; col <= right; ++col) { 2477 if (!((screen->protected_mode == DEC_PROTECT) 2478 && (ld->attribs[col] & PROTECTED))) { 2479 ld->attribs[col] |= CHARDRAWN; 2480 ld->charData[col] = ' '; 2481 if_OPT_WIDE_CHARS(screen, { 2482 size_t off; 2483 for_each_combData(off, ld) { 2484 ld->combData[off][col] = '\0'; 2485 } 2486 }) 2487 } 2488 } 2489 } 2490 ScrnUpdate(xw, 2491 (target->top - 1), 2492 (target->left - 1), 2493 (target->bottom - target->top) + 1, 2494 ((target->right - target->left) + 1), 2495 False); 2496 } 2497} 2498#endif /* OPT_DEC_RECTOPS */ 2499