screen.c revision 492d43a5
1/* $XTermId: screen.c,v 1.426 2010/10/11 00:46:05 tom Exp $ */ 2 3/* 4 * Copyright 1999-2009,2010 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, (unsigned) (dst)), \ 83 scrnHeadAddr(screen, base, (unsigned) (src)), \ 84 (size_t) scrnHeadSize(screen, (unsigned) (len))) 85 86#define SaveLineData(base, src, len) \ 87 (void) ScrnPointers(screen, len); \ 88 memcpy (screen->save_ptr, \ 89 scrnHeadAddr(screen, base, src), \ 90 (size_t) scrnHeadSize(screen, (unsigned) (len))) 91 92#define RestoreLineData(base, dst, len) \ 93 memcpy (scrnHeadAddr(screen, base, dst), \ 94 screen->save_ptr, \ 95 (size_t) scrnHeadSize(screen, (unsigned) (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 (unsigned) 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 | (unsigned) 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 += (unsigned) 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((size_t) nrow, (size_t) size); 269 if (result == 0) 270 SysError(ERROR_SCALLOC); 271 272 TRACE(("allocScrnHead %d -> %d -> %p..%p\n", nrow, nrow * size, 273 (void *) 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 * (unsigned) 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 %ux%u -> %lu -> %p..%p\n", 324 nrow, ncol, (unsigned long) 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, (void *) 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{ 426 TScreen *screen = TScreenOf(xw); 427 ScrnBuf oldBufHead; 428 ScrnBuf newBufHead; 429 Char *newBufData; 430 unsigned minrows; 431 Char *oldBufData; 432 int move_down = 0, move_up = 0; 433 434 if (sbuf == NULL || *sbuf == NULL) { 435 return 0; 436 } 437 438 oldBufData = *sbufaddr; 439 440 TRACE(("Reallocate %dx%d -> %dx%d\n", oldrow, MaxCols(screen), nrow, ncol)); 441 442 /* 443 * realloc sbuf, the pointers to all the lines. 444 * If the screen shrinks, remove lines off the top of the buffer 445 * if resizeGravity resource says to do so. 446 */ 447 TRACE(("Check move_up, nrow %d vs oldrow %d (resizeGravity %s)\n", 448 nrow, oldrow, 449 BtoS(GravityIsSouthWest(xw)))); 450 if (GravityIsSouthWest(xw)) { 451 if (nrow < oldrow) { 452 /* Remove lines off the top of the buffer if necessary. */ 453 move_up = (int) (oldrow - nrow) 454 - (TScreenOf(xw)->max_row - TScreenOf(xw)->cur_row); 455 if (move_up < 0) 456 move_up = 0; 457 /* Overlapping move here! */ 458 TRACE(("move_up %d\n", move_up)); 459 if (move_up) { 460 ScrnBuf dst = *sbuf; 461 unsigned len = (unsigned) ((int) oldrow - move_up); 462 463 TRACE_SCRNBUF("before move_up", screen, dst, oldrow); 464 SaveLineData(dst, 0, (size_t) move_up); 465 MoveLineData(dst, 0, (size_t) move_up, len); 466 RestoreLineData(dst, len, (size_t) move_up); 467 TRACE_SCRNBUF("after move_up", screen, dst, oldrow); 468 } 469 } 470 } 471 oldBufHead = *sbuf; 472 *sbuf = allocScrnHead(screen, (unsigned) nrow); 473 newBufHead = *sbuf; 474 475 /* 476 * Create the new buffer space and copy old buffer contents there, line by 477 * line. 478 */ 479 newBufData = allocScrnData(screen, nrow, ncol); 480 *sbufaddr = newBufData; 481 482 minrows = (oldrow < nrow) ? oldrow : nrow; 483 if (GravityIsSouthWest(xw)) { 484 if (nrow > oldrow) { 485 /* move data down to bottom of expanded screen */ 486 move_down = Min((int) (nrow - oldrow), TScreenOf(xw)->savedlines); 487 } 488 } 489 490 setupLineData(screen, newBufHead, *sbufaddr, nrow, ncol); 491 extractScrnData(screen, newBufHead, oldBufHead, minrows, 492#if OPT_SAVE_LINES 493 0 494#else 495 (unsigned) move_down 496#endif 497 ); 498 free(oldBufHead); 499 500 /* Now free the old data */ 501 free(oldBufData); 502 503 TRACE(("...Reallocate %dx%d ->%p\n", nrow, ncol, (void *) newBufHead)); 504 return move_down ? move_down : -move_up; /* convert to rows */ 505} 506 507#if OPT_WIDE_CHARS 508/* 509 * This function reallocates memory if changing the number of Buf offsets. 510 * The code is based on Reallocate(). 511 */ 512static void 513ReallocateBufOffsets(XtermWidget xw, 514 ScrnBuf * sbuf, 515 Char ** sbufaddr, 516 unsigned nrow, 517 unsigned ncol) 518{ 519 TScreen *screen = TScreenOf(xw); 520 unsigned i; 521 ScrnBuf newBufHead; 522 Char *oldBufData; 523 ScrnBuf oldBufHead; 524 525 unsigned old_jump = scrnHeadSize(screen, 1); 526 unsigned new_jump; 527 unsigned new_ptrs = 1 + (unsigned) (screen->max_combining); 528 unsigned dstCols = ncol; 529 unsigned srcCols = ncol; 530 LineData *dstPtrs; 531 LineData *srcPtrs; 532 Char *nextPtr; 533 534 assert(nrow != 0); 535 assert(ncol != 0); 536 537 oldBufData = *sbufaddr; 538 oldBufHead = *sbuf; 539 540 /* 541 * Allocate a new LineData array, retain the old one until we've copied 542 * the data that it points to, as well as non-pointer data, e.g., bufHead. 543 * 544 * Turn on wide-chars temporarily when constructing pointers, since that is 545 * used to decide whether to address the combData[] array, which affects 546 * the length of the LineData structure. 547 */ 548 screen->wide_chars = True; 549 550 new_jump = scrnHeadSize(screen, 1); 551 newBufHead = allocScrnHead(screen, nrow); 552 *sbufaddr = allocScrnData(screen, nrow, ncol); 553 setupLineData(screen, newBufHead, *sbufaddr, nrow, ncol); 554 555 screen->wide_chars = False; 556 557 nextPtr = *sbufaddr; 558 559 srcPtrs = (LineData *) oldBufHead; 560 dstPtrs = (LineData *) newBufHead; 561 for (i = 0; i < nrow; i++) { 562 dstPtrs->bufHead = srcPtrs->bufHead; 563 ExtractScrnData(attribs); 564#if OPT_ISO_COLORS 565 ExtractScrnData(color); 566#endif 567 ExtractScrnData(charData); 568 569 nextPtr += ncol * new_ptrs; 570 srcPtrs = LineDataAddr(srcPtrs, old_jump); 571 dstPtrs = LineDataAddr(dstPtrs, new_jump); 572 } 573 574 /* Now free the old data */ 575 free(oldBufData); 576 free(oldBufHead); 577 578 *sbuf = newBufHead; 579 580 TRACE(("ReallocateBufOffsets %dx%d ->%p\n", nrow, ncol, *sbufaddr)); 581} 582 583/* 584 * This function dynamically adds support for wide-characters. 585 */ 586void 587ChangeToWide(XtermWidget xw) 588{ 589 TScreen *screen = TScreenOf(xw); 590 591 if (screen->wide_chars) 592 return; 593 594 TRACE(("ChangeToWide\n")); 595 if (xtermLoadWideFonts(xw, True)) { 596 int whichBuf = screen->whichBuf; 597 598#if !OPT_FIFO_LINES || !OPT_SAVE_LINES 599 int savelines = screen->scrollWidget ? screen->savelines : 0; 600 601 if (savelines < 0) 602 savelines = 0; 603#endif 604 605 /* 606 * If we're displaying the alternate screen, switch the pointers back 607 * temporarily so ReallocateBufOffsets() will operate on the proper 608 * data in the alternate buffer. 609 */ 610 if (screen->whichBuf) 611 SwitchBufPtrs(screen, 0); 612 613#if OPT_SAVE_LINES 614#if !OPT_FIFO_LINES 615 ReallocateBufOffsets(xw, 616 &screen->saveBuf_index, 617 &screen->saveBuf_data, 618 (unsigned) savelines, 619 (unsigned) MaxCols(screen)); 620#endif 621 if (screen->editBuf_index[0]) { 622 ReallocateBufOffsets(xw, 623 &screen->editBuf_index[0], 624 &screen->editBuf_data[0], 625 (unsigned) MaxRows(screen), 626 (unsigned) MaxCols(screen)); 627 } 628#else 629 ReallocateBufOffsets(xw, 630 &screen->saveBuf_index, 631 &screen->saveBuf_data, 632 (unsigned) (MaxRows(screen) + savelines), 633 (unsigned) MaxCols(screen)); 634#endif 635 if (screen->editBuf_index[1]) { 636 ReallocateBufOffsets(xw, 637 &screen->editBuf_index[1], 638 &screen->editBuf_data[1], 639 (unsigned) MaxRows(screen), 640 (unsigned) MaxCols(screen)); 641 } 642 643 screen->wide_chars = True; 644 screen->visbuf = VisBuf(screen); 645 646 /* 647 * Switch the pointers back before we start painting on the screen. 648 */ 649 if (whichBuf) 650 SwitchBufPtrs(screen, whichBuf); 651 652 update_font_utf8_mode(); 653 SetVTFont(xw, screen->menu_font_number, True, NULL); 654 } 655 TRACE(("...ChangeToWide\n")); 656} 657#endif 658 659/* 660 * Clear cells, no side-effects. 661 */ 662void 663ClearCells(XtermWidget xw, int flags, unsigned len, int row, int col) 664{ 665 if (len != 0) { 666 TScreen *screen = TScreenOf(xw); 667 LineData *ld; 668 unsigned n; 669 670 ld = getLineData(screen, row); 671 672 flags = (int) ((unsigned) flags | TERM_COLOR_FLAGS(xw)); 673 674 for (n = 0; n < len; ++n) 675 ld->charData[(unsigned) col + n] = (CharData) ' '; 676 677 memset(ld->attribs + col, flags, (size_t) len); 678 679 if_OPT_ISO_COLORS(screen, { 680 CellColor p = xtermColorPair(xw); 681 for (n = 0; n < len; ++n) { 682 ld->color[(unsigned) col + n] = p; 683 } 684 }); 685 if_OPT_WIDE_CHARS(screen, { 686 size_t off; 687 for_each_combData(off, ld) { 688 memset(ld->combData[off] + col, 0, (size_t) len * sizeof(CharData)); 689 } 690 }); 691 } 692} 693 694/* 695 * Clear data in the screen-structure (no I/O). 696 * Check for wide-character damage as well, clearing the damaged cells. 697 */ 698void 699ScrnClearCells(XtermWidget xw, int row, int col, unsigned len) 700{ 701#if OPT_WIDE_CHARS 702 TScreen *screen = TScreenOf(xw); 703#endif 704 int flags = 0; 705 706 if_OPT_WIDE_CHARS(screen, { 707 int kl; 708 int kr; 709 710 if (DamagedCells(screen, len, &kl, &kr, row, col) 711 && kr >= kl) { 712 ClearCells(xw, flags, (unsigned) (kr - kl + 1), row, kl); 713 } 714 }); 715 ClearCells(xw, flags, len, row, col); 716} 717 718/* 719 * Disown the selection and repaint the area that is highlighted so it is no 720 * longer highlighted. 721 */ 722void 723ScrnDisownSelection(XtermWidget xw) 724{ 725 if (ScrnHaveSelection(TScreenOf(xw))) { 726 if (TScreenOf(xw)->keepSelection) { 727 UnhiliteSelection(xw); 728 } else { 729 DisownSelection(xw); 730 } 731 } 732} 733 734/* 735 * Writes str into buf at screen's current row and column. Characters are set 736 * to match flags. 737 */ 738void 739ScrnWriteText(XtermWidget xw, 740 IChar * str, 741 unsigned flags, 742 unsigned cur_fg_bg, 743 unsigned length) 744{ 745 TScreen *screen = TScreenOf(xw); 746 LineData *ld; 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 (real_width + (unsigned) screen->cur_col > (unsigned) MaxCols(screen)) { 759 real_width = (unsigned) (MaxCols(screen) - screen->cur_col); 760 } 761 762 if (avail <= 0) 763 return; 764 if (length > (unsigned) avail) 765 length = (unsigned) avail; 766 if (length == 0 || real_width == 0) 767 return; 768 769 ld = getLineData(screen, screen->cur_row); 770 771 chars = ld->charData + screen->cur_col; 772 attrs = ld->attribs + screen->cur_col; 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, (size_t) 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(CharData)); 845 } 846 }); 847 if_OPT_ISO_COLORS(screen, { 848 unsigned j; 849 for (j = 0; j < real_width; ++j) 850 ld->color[screen->cur_col + (int) j] = (CellColor) 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 = TScreenOf(xw); 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(CharData)); 901 if (TERM_COLOR_FLAGS(xw)) { 902 memset(work->attribs, (int) flags, (size_t) 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_t) 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(CharData)); 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, (unsigned) 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 = TScreenOf(xw); 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 = TScreenOf(xw); 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 = TScreenOf(xw); 1140 int last = MaxCols(screen); 1141 int row = screen->cur_row; 1142 int col = screen->cur_col; 1143 int j; 1144 LineData *ld; 1145 1146 if (last <= (col + (int) n)) { 1147 if (last <= col) 1148 return; 1149 n = (unsigned) (last - col); 1150 } 1151 1152 assert(screen->cur_col >= 0); 1153 assert(screen->cur_row >= 0); 1154 assert(n > 0); 1155 assert(last > (int) n); 1156 1157 if_OPT_WIDE_CHARS(screen, { 1158 int xx = screen->cur_row; 1159 int kl; 1160 int kr = screen->cur_col; 1161 if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) { 1162 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl); 1163 } 1164 kr = screen->max_col - (int) n + 1; 1165 if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) { 1166 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl); 1167 } 1168 }); 1169 1170 if ((ld = getLineData(screen, row)) != 0) { 1171 MemMove(ld->charData); 1172 MemMove(ld->attribs); 1173 1174 if_OPT_ISO_COLORS(screen, { 1175 MemMove(ld->color); 1176 }); 1177 if_OPT_WIDE_CHARS(screen, { 1178 size_t off; 1179 for_each_combData(off, ld) { 1180 MemMove(ld->combData[off]); 1181 } 1182 }); 1183 } 1184 ClearCells(xw, CHARDRAWN, n, row, col); 1185 1186#undef MemMove 1187} 1188 1189/* 1190 * Deletes n characters at current row, col. 1191 */ 1192void 1193ScrnDeleteChar(XtermWidget xw, unsigned n) 1194{ 1195#define MemMove(data) \ 1196 for (j = col; j < last - (int) n; ++j) \ 1197 data[j] = data[j + (int) n] 1198 1199 TScreen *screen = TScreenOf(xw); 1200 int last = MaxCols(screen); 1201 int row = screen->cur_row; 1202 int col = screen->cur_col; 1203 int j; 1204 LineData *ld; 1205 1206 if (last <= (col + (int) n)) { 1207 if (last <= col) 1208 return; 1209 n = (unsigned) (last - col); 1210 } 1211 1212 assert(screen->cur_col >= 0); 1213 assert(screen->cur_row >= 0); 1214 assert(n > 0); 1215 assert(last > (int) n); 1216 1217 if_OPT_WIDE_CHARS(screen, { 1218 int kl; 1219 int kr; 1220 if (DamagedCells(screen, n, &kl, &kr, 1221 screen->cur_row, 1222 screen->cur_col)) 1223 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl); 1224 }); 1225 1226 if ((ld = getLineData(screen, row)) != 0) { 1227 MemMove(ld->charData); 1228 MemMove(ld->attribs); 1229 1230 if_OPT_ISO_COLORS(screen, { 1231 MemMove(ld->color); 1232 }); 1233 if_OPT_WIDE_CHARS(screen, { 1234 size_t off; 1235 for_each_combData(off, ld) { 1236 MemMove(ld->combData[off]); 1237 } 1238 }); 1239 LineClrWrapped(ld); 1240 if (screen->show_wrap_marks) { 1241 ShowWrapMarks(xw, row, ld); 1242 } 1243 } 1244 ClearCells(xw, 0, n, row, (last - (int) n)); 1245 1246#undef MemMove 1247} 1248 1249/* 1250 * This is useful for debugging both xterm and applications that may manipulate 1251 * its line-wrapping state. 1252 */ 1253void 1254ShowWrapMarks(XtermWidget xw, int row, LineData * ld) 1255{ 1256 TScreen *screen = TScreenOf(xw); 1257 Boolean set = LineTstWrapped(ld); 1258 CgsEnum cgsId = set ? gcVTcursFilled : gcVTcursReverse; 1259 VTwin *currentWin = WhichVWin(screen); 1260 int y = row * FontHeight(screen) + screen->border; 1261 int x = LineCursorX(screen, ld, screen->max_col + 1); 1262 1263 TRACE2(("ShowWrapMarks %d:%s\n", row, BtoS(set))); 1264 1265 XFillRectangle(screen->display, VWindow(screen), 1266 getCgsGC(xw, currentWin, cgsId), 1267 x, y, 1268 (unsigned) screen->border, 1269 (unsigned) FontHeight(screen)); 1270} 1271 1272/* 1273 * Repaints the area enclosed by the parameters. 1274 * Requires: (toprow, leftcol), (toprow + nrows, leftcol + ncols) are 1275 * coordinates of characters in screen; 1276 * nrows and ncols positive. 1277 * all dimensions are based on single-characters. 1278 */ 1279void 1280ScrnRefresh(XtermWidget xw, 1281 int toprow, 1282 int leftcol, 1283 int nrows, 1284 int ncols, 1285 Bool force) /* ... leading/trailing spaces */ 1286{ 1287 TScreen *screen = TScreenOf(xw); 1288 LineData *ld; 1289 int y = toprow * FontHeight(screen) + screen->border; 1290 int row; 1291 int maxrow = toprow + nrows - 1; 1292 int scrollamt = screen->scroll_amt; 1293 unsigned gc_changes = 0; 1294#ifdef __CYGWIN__ 1295 static char first_time = 1; 1296#endif 1297 static int recurse = 0; 1298 1299 TRACE(("ScrnRefresh top %d (%d,%d) - (%d,%d)%s {{\n", 1300 screen->topline, toprow, leftcol, 1301 nrows, ncols, 1302 force ? " force" : "")); 1303 1304 if (screen->cursorp.col >= leftcol 1305 && screen->cursorp.col <= (leftcol + ncols - 1) 1306 && screen->cursorp.row >= ROW2INX(screen, toprow) 1307 && screen->cursorp.row <= ROW2INX(screen, maxrow)) 1308 screen->cursor_state = OFF; 1309 1310 for (row = toprow; row <= maxrow; y += FontHeight(screen), row++) { 1311#if OPT_ISO_COLORS 1312 CellColor *fb = 0; 1313#define ColorOf(col) (CellColor) (fb ? fb[col] : 0) 1314#endif 1315#if OPT_WIDE_CHARS 1316 int wideness = 0; 1317#endif 1318#define BLANK_CEL(cell) (chars[cell] == ' ') 1319 IChar *chars; 1320 Char *attrs; 1321 int col = leftcol; 1322 int maxcol = leftcol + ncols - 1; 1323 int hi_col = maxcol; 1324 int lastind; 1325 unsigned flags; 1326 unsigned test; 1327 CellColor fg_bg = 0; 1328 unsigned fg = 0, bg = 0; 1329 int x; 1330 GC gc; 1331 Bool hilite; 1332 1333 (void) fg; 1334 (void) bg; 1335#if !OPT_ISO_COLORS 1336 fg_bg = 0; 1337#endif 1338 1339 if (row < screen->top_marg || row > screen->bot_marg) 1340 lastind = row; 1341 else 1342 lastind = row - scrollamt; 1343 1344 if (lastind < 0 || lastind > screen->max_row) 1345 continue; 1346 1347 TRACE2(("ScrnRefresh row=%d lastind=%d ->%d\n", 1348 row, lastind, ROW2INX(screen, lastind))); 1349 1350 if ((ld = getLineData(screen, ROW2INX(screen, lastind))) == 0 1351 || ld->charData == 0 1352 || ld->attribs == 0) { 1353 break; 1354 } 1355 1356 if (screen->show_wrap_marks) { 1357 ShowWrapMarks(xw, lastind, ld); 1358 } 1359 1360 if (maxcol >= (int) ld->lineSize) { 1361 maxcol = ld->lineSize - 1; 1362 hi_col = maxcol; 1363 } 1364 1365 chars = ld->charData; 1366 attrs = ld->attribs; 1367 1368 if_OPT_WIDE_CHARS(screen, { 1369 /* This fixes an infinite recursion bug, that leads 1370 to display anomalies. It seems to be related to 1371 problems with the selection. */ 1372 if (recurse < 3) { 1373 /* adjust to redraw all of a widechar if we just wanted 1374 to draw the right hand half */ 1375 if (leftcol > 0 && 1376 chars[leftcol] == HIDDEN_CHAR && 1377 isWide((int) chars[leftcol - 1])) { 1378 leftcol--; 1379 ncols++; 1380 col = leftcol; 1381 } 1382 } else { 1383 fprintf(stderr, "This should not happen. Why is it so?\n"); 1384 } 1385 }); 1386 1387 if (row < screen->startH.row || row > screen->endH.row || 1388 (row == screen->startH.row && maxcol < screen->startH.col) || 1389 (row == screen->endH.row && col >= screen->endH.col)) { 1390#if OPT_DEC_CHRSET 1391 /* 1392 * Temporarily change dimensions to double-sized characters so 1393 * we can reuse the recursion on this function. 1394 */ 1395 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1396 col /= 2; 1397 maxcol /= 2; 1398 } 1399#endif 1400 /* 1401 * If row does not intersect selection; don't hilite blanks. 1402 */ 1403 if (!force) { 1404 while (col <= maxcol && (attrs[col] & ~BOLD) == 0 && 1405 BLANK_CEL(col)) 1406 col++; 1407 1408 while (col <= maxcol && (attrs[maxcol] & ~BOLD) == 0 && 1409 BLANK_CEL(maxcol)) 1410 maxcol--; 1411 } 1412#if OPT_DEC_CHRSET 1413 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1414 col *= 2; 1415 maxcol *= 2; 1416 } 1417#endif 1418 hilite = False; 1419 } else { 1420 /* row intersects selection; split into pieces of single type */ 1421 if (row == screen->startH.row && col < screen->startH.col) { 1422 recurse++; 1423 ScrnRefresh(xw, row, col, 1, screen->startH.col - col, 1424 force); 1425 col = screen->startH.col; 1426 } 1427 if (row == screen->endH.row && maxcol >= screen->endH.col) { 1428 recurse++; 1429 ScrnRefresh(xw, row, screen->endH.col, 1, 1430 maxcol - screen->endH.col + 1, force); 1431 maxcol = screen->endH.col - 1; 1432 } 1433 1434 /* 1435 * If we're highlighting because the user is doing cut/paste, 1436 * trim the trailing blanks from the highlighted region so we're 1437 * showing the actual extent of the text that'll be cut. If 1438 * we're selecting a blank line, we'll highlight one column 1439 * anyway. 1440 * 1441 * We don't do this if the mouse-hilite mode is set because that 1442 * would be too confusing. 1443 * 1444 * The default if the highlightSelection resource isn't set will 1445 * highlight the whole width of the terminal, which is easy to 1446 * see, but harder to use (because trailing blanks aren't as 1447 * apparent). 1448 */ 1449 if (screen->highlight_selection 1450 && screen->send_mouse_pos != VT200_HIGHLIGHT_MOUSE) { 1451 hi_col = screen->max_col; 1452 while (hi_col > 0 && !(attrs[hi_col] & CHARDRAWN)) 1453 hi_col--; 1454 } 1455 1456 /* remaining piece should be hilited */ 1457 hilite = True; 1458 } 1459 1460 if (col > maxcol) 1461 continue; 1462 1463 /* 1464 * Go back to double-sized character dimensions if the line has 1465 * double-width characters. Note that 'hi_col' is already in the 1466 * right units. 1467 */ 1468 if_OPT_DEC_CHRSET({ 1469 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1470 col /= 2; 1471 maxcol /= 2; 1472 } 1473 }); 1474 1475 flags = attrs[col]; 1476 1477 if_OPT_WIDE_CHARS(screen, { 1478 wideness = isWide((int) chars[col]); 1479 }); 1480 1481 if_OPT_ISO_COLORS(screen, { 1482 fb = ld->color; 1483 fg_bg = ColorOf(col); 1484 fg = extract_fg(xw, fg_bg, flags); 1485 bg = extract_bg(xw, fg_bg, flags); 1486 }); 1487 1488 gc = updatedXtermGC(xw, flags, fg_bg, hilite); 1489 gc_changes |= (flags & (FG_COLOR | BG_COLOR)); 1490 1491 x = LineCursorX(screen, ld, col); 1492 lastind = col; 1493 1494 for (; col <= maxcol; col++) { 1495 if ((attrs[col] != flags) 1496 || (hilite && (col > hi_col)) 1497#if OPT_ISO_COLORS 1498 || ((flags & FG_COLOR) 1499 && (extract_fg(xw, ColorOf(col), attrs[col]) != fg)) 1500 || ((flags & BG_COLOR) 1501 && (extract_bg(xw, ColorOf(col), attrs[col]) != bg)) 1502#endif 1503#if OPT_WIDE_CHARS 1504 || (isWide((int) chars[col]) != wideness 1505 && chars[col] != HIDDEN_CHAR) 1506#endif 1507 ) { 1508 assert(col >= lastind); 1509 TRACE(("ScrnRefresh looping drawXtermText %d..%d:%s\n", 1510 lastind, col, 1511 visibleIChars((&chars[lastind]), 1512 (unsigned) (col - lastind)))); 1513 1514 test = flags; 1515 checkVeryBoldColors(test, fg); 1516 1517 x = drawXtermText(xw, test & DRAWX_MASK, gc, x, y, 1518 GetLineDblCS(ld), 1519 &chars[lastind], 1520 (unsigned) (col - lastind), 0); 1521 1522 if_OPT_WIDE_CHARS(screen, { 1523 int i; 1524 size_t off; 1525 1526 for_each_combData(off, ld) { 1527 IChar *com_off = ld->combData[off]; 1528 1529 for (i = lastind; i < col; i++) { 1530 int my_x = LineCursorX(screen, ld, i); 1531 IChar base = chars[i]; 1532 1533 if (isWide((int) base)) 1534 my_x = LineCursorX(screen, ld, i - 1); 1535 1536 if (com_off[i] != 0) 1537 drawXtermText(xw, 1538 (test & DRAWX_MASK) 1539 | NOBACKGROUND, 1540 gc, my_x, y, 1541 GetLineDblCS(ld), 1542 com_off + i, 1543 1, isWide((int) base)); 1544 } 1545 } 1546 }); 1547 1548 resetXtermGC(xw, flags, hilite); 1549 1550 lastind = col; 1551 1552 if (hilite && (col > hi_col)) 1553 hilite = False; 1554 1555 flags = attrs[col]; 1556 if_OPT_ISO_COLORS(screen, { 1557 fg_bg = ColorOf(col); 1558 fg = extract_fg(xw, fg_bg, flags); 1559 bg = extract_bg(xw, fg_bg, flags); 1560 }); 1561 if_OPT_WIDE_CHARS(screen, { 1562 wideness = isWide((int) chars[col]); 1563 }); 1564 1565 gc = updatedXtermGC(xw, flags, fg_bg, hilite); 1566 gc_changes |= (flags & (FG_COLOR | BG_COLOR)); 1567 } 1568 1569 if (chars[col] == 0) { 1570 chars[col] = ' '; 1571 } 1572 } 1573 1574 assert(col >= lastind); 1575 TRACE(("ScrnRefresh calling drawXtermText %d..%d:%s\n", 1576 lastind, col, 1577 visibleIChars(&chars[lastind], (unsigned) (col - lastind)))); 1578 1579 test = flags; 1580 checkVeryBoldColors(test, fg); 1581 1582 drawXtermText(xw, test & DRAWX_MASK, gc, x, y, 1583 GetLineDblCS(ld), 1584 &chars[lastind], 1585 (unsigned) (col - lastind), 0); 1586 1587 if_OPT_WIDE_CHARS(screen, { 1588 int i; 1589 size_t off; 1590 1591 for_each_combData(off, ld) { 1592 IChar *com_off = ld->combData[off]; 1593 1594 for (i = lastind; i < col; i++) { 1595 int my_x = LineCursorX(screen, ld, i); 1596 int base = (int) chars[i]; 1597 1598 if (isWide(base)) 1599 my_x = LineCursorX(screen, ld, i - 1); 1600 1601 if (com_off[i] != 0) 1602 drawXtermText(xw, 1603 (test & DRAWX_MASK) 1604 | NOBACKGROUND, 1605 gc, my_x, y, 1606 GetLineDblCS(ld), 1607 com_off + i, 1608 1, isWide(base)); 1609 } 1610 } 1611 }); 1612 1613 resetXtermGC(xw, flags, hilite); 1614 } 1615 1616 /* 1617 * If we're in color mode, reset the various GC's to the current 1618 * screen foreground and background so that other functions (e.g., 1619 * ClearRight) will get the correct colors. 1620 */ 1621 if_OPT_ISO_COLORS(screen, { 1622 if (gc_changes & FG_COLOR) 1623 SGR_Foreground(xw, xw->cur_foreground); 1624 if (gc_changes & BG_COLOR) 1625 SGR_Background(xw, xw->cur_background); 1626 }); 1627 1628#if defined(__CYGWIN__) && defined(TIOCSWINSZ) 1629 if (first_time == 1) { 1630 TTYSIZE_STRUCT ts; 1631 1632 first_time = 0; 1633 TTYSIZE_ROWS(ts) = nrows; 1634 TTYSIZE_COLS(ts) = ncols; 1635 ts.ws_xpixel = xw->core.width; 1636 ts.ws_ypixel = xw->core.height; 1637 SET_TTYSIZE(screen->respond, ts); 1638 } 1639#endif 1640 recurse--; 1641 1642 TRACE(("...}} ScrnRefresh\n")); 1643 return; 1644} 1645 1646/* 1647 * Call this wrapper to ScrnRefresh() when the data has changed. If the 1648 * refresh region overlaps the selection, we will release the primary selection. 1649 */ 1650void 1651ScrnUpdate(XtermWidget xw, 1652 int toprow, 1653 int leftcol, 1654 int nrows, 1655 int ncols, 1656 Bool force) /* ... leading/trailing spaces */ 1657{ 1658 TScreen *screen = TScreenOf(xw); 1659 1660 if (ScrnHaveSelection(screen) 1661 && (toprow <= screen->endH.row) 1662 && (toprow + nrows - 1 >= screen->startH.row)) { 1663 ScrnDisownSelection(xw); 1664 } 1665 ScrnRefresh(xw, toprow, leftcol, nrows, ncols, force); 1666} 1667 1668/* 1669 * Sets the rows first though last of the buffer of screen to spaces. 1670 * Requires first <= last; first, last are rows of screen->buf. 1671 */ 1672void 1673ClearBufRows(XtermWidget xw, 1674 int first, 1675 int last) 1676{ 1677 TScreen *screen = TScreenOf(xw); 1678 unsigned len = (unsigned) MaxCols(screen); 1679 int row; 1680 1681 TRACE(("ClearBufRows %d..%d\n", first, last)); 1682 for (row = first; row <= last; row++) { 1683 LineData *ld = getLineData(screen, row); 1684 if (ld != 0) { 1685 if_OPT_DEC_CHRSET({ 1686 /* clearing the whole row resets the doublesize characters */ 1687 SetLineDblCS(ld, CSET_SWL); 1688 }); 1689 LineClrWrapped(ld); 1690 if (screen->show_wrap_marks) { 1691 ShowWrapMarks(xw, row, ld); 1692 } 1693 ClearCells(xw, 0, len, row, 0); 1694 } 1695 } 1696} 1697 1698/* 1699 Resizes screen: 1700 1. If new window would have fractional characters, sets window size so as to 1701 discard fractional characters and returns -1. 1702 Minimum screen size is 1 X 1. 1703 Note that this causes another ExposeWindow event. 1704 2. Enlarges screen->buf if necessary. New space is appended to the bottom 1705 and to the right 1706 3. Reduces screen->buf if necessary. Old space is removed from the bottom 1707 and from the right 1708 4. Cursor is positioned as closely to its former position as possible 1709 5. Sets screen->max_row and screen->max_col to reflect new size 1710 6. Maintains the inner border (and clears the border on the screen). 1711 7. Clears origin mode and sets scrolling region to be entire screen. 1712 8. Returns 0 1713 */ 1714int 1715ScreenResize(XtermWidget xw, 1716 int width, 1717 int height, 1718 unsigned *flags) 1719{ 1720 TScreen *screen = TScreenOf(xw); 1721 int code, rows, cols; 1722 int border = 2 * screen->border; 1723 int move_down_by = 0; 1724#ifdef TTYSIZE_STRUCT 1725 TTYSIZE_STRUCT ts; 1726#endif 1727 Window tw = VWindow(screen); 1728 1729 TRACE(("ScreenResize %dx%d border %d font %dx%d\n", 1730 height, width, border, 1731 FontHeight(screen), FontWidth(screen))); 1732 1733 assert(width > 0); 1734 assert(height > 0); 1735 1736 if (screen->is_running) { 1737 /* clear the right and bottom internal border because of NorthWest 1738 gravity might have left junk on the right and bottom edges */ 1739 if (width >= (int) FullWidth(screen)) { 1740 XClearArea(screen->display, tw, 1741 FullWidth(screen), 0, /* right edge */ 1742 0, (unsigned) height, /* from top to bottom */ 1743 False); 1744 } 1745 if (height >= (int) FullHeight(screen)) { 1746 XClearArea(screen->display, tw, 1747 0, FullHeight(screen), /* bottom */ 1748 (unsigned) width, 0, /* all across the bottom */ 1749 False); 1750 } 1751 } 1752 1753 TRACE(("...computing rows/cols: %.2f %.2f\n", 1754 (double) (height - border) / FontHeight(screen), 1755 (double) (width - border - ScrollbarWidth(screen)) / FontWidth(screen))); 1756 1757 rows = (height - border) / FontHeight(screen); 1758 cols = (width - border - ScrollbarWidth(screen)) / FontWidth(screen); 1759 if (rows < 1) 1760 rows = 1; 1761 if (cols < 1) 1762 cols = 1; 1763 1764 /* update buffers if the screen has changed size */ 1765 if (MaxRows(screen) != rows || MaxCols(screen) != cols) { 1766 int whichBuf = 0; 1767 int delta_rows = rows - MaxRows(screen); 1768#if OPT_TRACE 1769 int delta_cols = cols - MaxCols(screen); 1770#endif 1771 1772 TRACE(("...ScreenResize chars %dx%d delta %dx%d\n", 1773 rows, cols, delta_rows, delta_cols)); 1774 1775 if (screen->is_running) { 1776#if !OPT_FIFO_LINES 1777 int savelines = (screen->scrollWidget 1778 ? screen->savelines 1779 : 0); 1780#endif 1781 if (screen->cursor_state) 1782 HideCursor(); 1783#if OPT_SAVE_LINES 1784 /* 1785 * The non-visible buffer is simple, since we will not copy data 1786 * to/from the saved-lines. Do that first. 1787 */ 1788 if (screen->editBuf_index[!screen->whichBuf]) { 1789 (void) Reallocate(xw, 1790 &screen->editBuf_index[!screen->whichBuf], 1791 &screen->editBuf_data[!screen->whichBuf], 1792 (unsigned) rows, 1793 (unsigned) cols, 1794 (unsigned) MaxRows(screen)); 1795 } 1796 1797 /* 1798 * The save-lines buffer may change width, but will not change its 1799 * height. Deal with the cases where we copy data to/from the 1800 * saved-lines buffer. 1801 */ 1802 if (GravityIsSouthWest(xw) 1803 && delta_rows 1804 && screen->saveBuf_index != 0) { 1805 1806 if (delta_rows < 0) { 1807 unsigned move_up = (unsigned) (-delta_rows); 1808 ScrnBuf dst = screen->saveBuf_index; 1809 1810#if OPT_FIFO_LINES 1811 int amount = ((MaxRows(screen) - (int) move_up - 1) 1812 - screen->cur_row); 1813 1814 if (amount < 0) { 1815 /* move line-data from visible-buffer to save-buffer */ 1816 saveEditBufLines(screen, dst, (unsigned) -amount); 1817 move_down_by = amount; 1818 } else { 1819 move_down_by = 0; 1820 } 1821#else /* !OPT_FIFO_LINES */ 1822 int amount = screen->savelines - (int) move_up; 1823 1824 TRACE_SCRNBUF("before save", screen, dst, screen->savelines); 1825 1826 /* shift lines in save-buffer to make room */ 1827 TRACE(("...%smoving pointers in saveBuf (compare %d %d)\n", 1828 (amount > 0 1829 ? "" 1830 : "SKIP "), 1831 screen->savelines, 1832 move_up)); 1833 if (amount > 0) { 1834 SaveLineData(dst, 0, move_up); 1835 1836 MoveLineData(dst, 1837 0, 1838 move_up, 1839 (unsigned) amount); 1840 1841 TRACE(("...reuse %d lines storage in saveBuf\n", move_up)); 1842 RestoreLineData(dst, 1843 (unsigned) amount, 1844 move_up); 1845 TRACE_SCRNBUF("restoresave", screen, dst, screen->savelines); 1846 } 1847 1848 /* copy line-data from visible-buffer to save-buffer */ 1849 saveEditBufLines(screen, dst, move_up); 1850 1851 /* after data is copied, reallocate saved-lines */ 1852 (void) Reallocate(xw, 1853 &screen->saveBuf_index, 1854 &screen->saveBuf_data, 1855 (unsigned) savelines, 1856 (unsigned) cols, 1857 (unsigned) savelines); 1858 TRACE_SCRNBUF("reallocSAVE", 1859 screen, 1860 screen->saveBuf_index, 1861 savelines); 1862#endif /* OPT_FIFO_LINES */ 1863 1864 /* decrease size of visible-buffer */ 1865 (void) Reallocate(xw, 1866 &screen->editBuf_index[screen->whichBuf], 1867 &screen->editBuf_data[screen->whichBuf], 1868 (unsigned) rows, 1869 (unsigned) cols, 1870 (unsigned) MaxRows(screen)); 1871 TRACE_SCRNBUF("reallocEDIT", 1872 screen, 1873 screen->editBuf_index[screen->whichBuf], 1874 rows); 1875 } else { 1876 unsigned move_down = (unsigned) delta_rows; 1877#if OPT_FIFO_LINES 1878 long unsave_fifo; 1879#else 1880 ScrnBuf src = screen->saveBuf_index; 1881#endif 1882 ScrnBuf dst; 1883 int amount; 1884 1885 if ((int) move_down > screen->savedlines) { 1886 move_down = (unsigned) screen->savedlines; 1887 } 1888 move_down_by = (int) move_down; 1889 amount = rows - (int) move_down; 1890 1891 /* increase size of visible-buffer */ 1892 (void) Reallocate(xw, 1893 &screen->editBuf_index[screen->whichBuf], 1894 &screen->editBuf_data[screen->whichBuf], 1895 (unsigned) rows, 1896 (unsigned) cols, 1897 (unsigned) MaxRows(screen)); 1898 1899 dst = screen->editBuf_index[screen->whichBuf]; 1900 TRACE_SCRNBUF("reallocEDIT", screen, dst, rows); 1901 1902 TRACE(("...%smoving pointers in editBuf (compare %d %d)\n", 1903 (amount > 0 1904 ? "" 1905 : "SKIP "), 1906 rows, 1907 move_down)); 1908 if (amount > 0) { 1909 /* shift lines in visible-buffer to make room */ 1910 SaveLineData(dst, (unsigned) amount, (size_t) move_down); 1911 1912 MoveLineData(dst, 1913 move_down, 1914 0, 1915 (unsigned) amount); 1916 1917 TRACE(("...reuse %d lines storage in editBuf\n", move_down)); 1918 RestoreLineData(dst, 1919 0, 1920 move_down); 1921 1922 TRACE_SCRNBUF("shifted", screen, dst, rows); 1923 } 1924 1925 /* copy line-data from save-buffer to visible-buffer */ 1926 unsaveEditBufLines(screen, dst, move_down); 1927 TRACE_SCRNBUF("copied", screen, dst, rows); 1928 1929#if OPT_FIFO_LINES 1930 unsave_fifo = (long) move_down; 1931 if (screen->saved_fifo < (int) unsave_fifo) 1932 unsave_fifo = screen->saved_fifo; 1933 1934 /* free up storage in fifo from the copied lines */ 1935 while (unsave_fifo-- > 0) { 1936 deleteScrollback(screen, -1); 1937 screen->saved_fifo--; 1938 } 1939#else 1940 amount = (screen->savelines - (int) move_down); 1941 TRACE(("...%smoving pointers in saveBuf (compare %d %d)\n", 1942 (amount > 0 1943 ? "" 1944 : "SKIP "), 1945 rows, 1946 move_down)); 1947 if (amount > 0) { 1948 /* shift lines in save-buffer to account for copy */ 1949 src = screen->saveBuf_index; 1950 SaveLineData(src, amount, move_down); 1951 1952 MoveLineData(src, 1953 move_down, 1954 0, 1955 (unsigned) amount); 1956 1957 TRACE(("...reuse %d lines storage in saveBuf\n", move_down)); 1958 RestoreLineData(src, 1959 0, 1960 move_down); 1961 } 1962#endif 1963 1964 /* recover storage in save-buffer */ 1965 } 1966 } else { 1967#if !OPT_FIFO_LINES 1968 (void) Reallocate(xw, 1969 &screen->saveBuf_index, 1970 &screen->saveBuf_data, 1971 (unsigned) savelines, 1972 (unsigned) cols, 1973 (unsigned) savelines); 1974#endif 1975 (void) Reallocate(xw, 1976 &screen->editBuf_index[screen->whichBuf], 1977 &screen->editBuf_data[screen->whichBuf], 1978 (unsigned) rows, 1979 (unsigned) cols, 1980 (unsigned) MaxRows(screen)); 1981 } 1982#else /* !OPT_SAVE_LINES */ 1983 if (screen->whichBuf 1984 && GravityIsSouthWest(xw)) { 1985 /* swap buffer pointers back to make this work */ 1986 whichBuf = screen->whichBuf; 1987 SwitchBufPtrs(screen, 0); 1988 } else { 1989 whichBuf = 0; 1990 } 1991 if (screen->editBuf_index[1]) 1992 (void) Reallocate(xw, 1993 &screen->editBuf_index[1], 1994 &screen->editBuf_data[1], 1995 (unsigned) rows, 1996 (unsigned) cols, 1997 (unsigned) MaxRows(screen)); 1998 move_down_by = Reallocate(xw, 1999 &screen->saveBuf_index, 2000 &screen->saveBuf_data, 2001 (unsigned) (rows + savelines), 2002 (unsigned) cols, 2003 (unsigned) (MaxRows(screen) + savelines)); 2004#endif /* OPT_SAVE_LINES */ 2005 screen->visbuf = VisBuf(screen); 2006 } 2007 2008 AdjustSavedCursor(xw, move_down_by); 2009 set_max_row(screen, screen->max_row + delta_rows); 2010 set_max_col(screen, cols - 1); 2011 2012 if (screen->is_running) { 2013 if (GravityIsSouthWest(xw)) { 2014 screen->savedlines -= move_down_by; 2015 if (screen->savedlines < 0) 2016 screen->savedlines = 0; 2017 if (screen->savedlines > screen->savelines) 2018 screen->savedlines = screen->savelines; 2019 if (screen->topline < -screen->savedlines) 2020 screen->topline = -screen->savedlines; 2021 set_cur_row(screen, screen->cur_row + move_down_by); 2022 screen->cursorp.row += move_down_by; 2023 ScrollSelection(screen, move_down_by, True); 2024 2025 if (whichBuf) 2026 SwitchBufPtrs(screen, whichBuf); /* put the pointers back */ 2027 } 2028 } 2029 2030 /* adjust scrolling region */ 2031 set_tb_margins(screen, 0, screen->max_row); 2032 UIntClr(*flags, ORIGIN); 2033 2034 if (screen->cur_row > screen->max_row) 2035 set_cur_row(screen, screen->max_row); 2036 if (screen->cur_col > screen->max_col) 2037 set_cur_col(screen, screen->max_col); 2038 2039 screen->fullVwin.height = height - border; 2040 screen->fullVwin.width = width - border - screen->fullVwin.sb_info.width; 2041 2042 } else if (FullHeight(screen) == height && FullWidth(screen) == width) 2043 return (0); /* nothing has changed at all */ 2044 2045 screen->fullVwin.fullheight = (Dimension) height; 2046 screen->fullVwin.fullwidth = (Dimension) width; 2047 2048 ResizeScrollBar(xw); 2049 ResizeSelection(screen, rows, cols); 2050 2051#ifndef NO_ACTIVE_ICON 2052 if (screen->iconVwin.window) { 2053 XWindowChanges changes; 2054 screen->iconVwin.width = 2055 MaxCols(screen) * screen->iconVwin.f_width; 2056 2057 screen->iconVwin.height = 2058 MaxRows(screen) * screen->iconVwin.f_height; 2059 2060 changes.width = screen->iconVwin.fullwidth = 2061 (Dimension) ((unsigned) screen->iconVwin.width 2062 + 2 * xw->misc.icon_border_width); 2063 2064 changes.height = screen->iconVwin.fullheight = 2065 (Dimension) ((unsigned) screen->iconVwin.height 2066 + 2 * xw->misc.icon_border_width); 2067 2068 changes.border_width = (int) xw->misc.icon_border_width; 2069 2070 TRACE(("resizing icon window %dx%d\n", changes.height, changes.width)); 2071 XConfigureWindow(XtDisplay(xw), screen->iconVwin.window, 2072 CWWidth | CWHeight | CWBorderWidth, &changes); 2073 } 2074#endif /* NO_ACTIVE_ICON */ 2075 2076#ifdef TTYSIZE_STRUCT 2077 /* Set tty's idea of window size */ 2078 TTYSIZE_ROWS(ts) = (ttySize_t) rows; 2079 TTYSIZE_COLS(ts) = (ttySize_t) cols; 2080#ifdef USE_STRUCT_WINSIZE 2081 ts.ws_xpixel = (ttySize_t) width; 2082 ts.ws_ypixel = (ttySize_t) height; 2083#endif 2084 code = SET_TTYSIZE(screen->respond, ts); 2085 TRACE(("return %d from SET_TTYSIZE %dx%d\n", code, rows, cols)); 2086 (void) code; 2087 2088#if defined(SIGWINCH) && defined(USE_STRUCT_TTYSIZE) 2089 if (screen->pid > 1) { 2090 int pgrp; 2091 2092 TRACE(("getting process-group\n")); 2093 if (ioctl(screen->respond, TIOCGPGRP, &pgrp) != -1) { 2094 TRACE(("sending SIGWINCH to process group %d\n", pgrp)); 2095 kill_process_group(pgrp, SIGWINCH); 2096 } 2097 } 2098#endif /* SIGWINCH */ 2099 2100#else 2101 TRACE(("ScreenResize cannot do anything to pty\n")); 2102#endif /* TTYSIZE_STRUCT */ 2103 return (0); 2104} 2105 2106/* 2107 * Return true if any character cell starting at [row,col], for len-cells is 2108 * nonnull. 2109 */ 2110Bool 2111non_blank_line(TScreen * screen, 2112 int row, 2113 int col, 2114 int len) 2115{ 2116 int i; 2117 Bool found = False; 2118 LineData *ld = getLineData(screen, row); 2119 2120 if (ld != 0) { 2121 for (i = col; i < len; i++) { 2122 if (ld->charData[i]) { 2123 found = True; 2124 break; 2125 } 2126 } 2127 } 2128 return found; 2129} 2130 2131/* 2132 * Rectangle parameters start from one. 2133 */ 2134#define minRectRow(screen) (getMinRow(screen) + 1) 2135#define minRectCol(screen) (getMinCol(screen) + 1) 2136#define maxRectRow(screen) (getMaxRow(screen) + 1) 2137#define maxRectCol(screen) (getMaxCol(screen) + 1) 2138 2139static int 2140limitedParseRow(XtermWidget xw, TScreen * screen, int row) 2141{ 2142 int min_row = minRectRow(screen); 2143 int max_row = maxRectRow(screen); 2144 2145 if (row < min_row) 2146 row = min_row; 2147 else if (row > max_row) 2148 row = max_row; 2149 return row; 2150} 2151 2152static int 2153limitedParseCol(XtermWidget xw, TScreen * screen, int col) 2154{ 2155 int min_col = minRectCol(screen); 2156 int max_col = maxRectCol(screen); 2157 2158 (void) xw; 2159 if (col < min_col) 2160 col = min_col; 2161 else if (col > max_col) 2162 col = max_col; 2163 return col; 2164} 2165 2166#define LimitedParse(num, func, dft) \ 2167 func(xw, screen, (nparams > num) ? params[num] : dft) 2168 2169/* 2170 * Copy the rectangle boundaries into a struct, providing default values as 2171 * needed. 2172 */ 2173void 2174xtermParseRect(XtermWidget xw, int nparams, int *params, XTermRect * target) 2175{ 2176 TScreen *screen = TScreenOf(xw); 2177 2178 memset(target, 0, sizeof(*target)); 2179 target->top = LimitedParse(0, limitedParseRow, minRectRow(screen)); 2180 target->left = LimitedParse(1, limitedParseCol, minRectCol(screen)); 2181 target->bottom = LimitedParse(2, limitedParseRow, maxRectRow(screen)); 2182 target->right = LimitedParse(3, limitedParseCol, maxRectCol(screen)); 2183 TRACE(("parsed rectangle %d,%d %d,%d\n", 2184 target->top, 2185 target->left, 2186 target->bottom, 2187 target->right)); 2188} 2189 2190static Bool 2191validRect(XtermWidget xw, XTermRect * target) 2192{ 2193 TScreen *screen = TScreenOf(xw); 2194 2195 TRACE(("comparing against screensize %dx%d\n", 2196 maxRectRow(screen), 2197 maxRectCol(screen))); 2198 return (target != 0 2199 && target->top >= minRectRow(screen) 2200 && target->left >= minRectCol(screen) 2201 && target->top <= target->bottom 2202 && target->left <= target->right 2203 && target->top <= maxRectRow(screen) 2204 && target->right <= maxRectCol(screen)); 2205} 2206 2207/* 2208 * Fills a rectangle with the given 8-bit character and video-attributes. 2209 * Colors and double-size attribute are unmodified. 2210 */ 2211void 2212ScrnFillRectangle(XtermWidget xw, 2213 XTermRect * target, 2214 int value, 2215 unsigned flags, 2216 Bool keepColors) 2217{ 2218 TScreen *screen = TScreenOf(xw); 2219 2220 TRACE(("filling rectangle with '%c' flags %#x\n", value, flags)); 2221 if (validRect(xw, target)) { 2222 LineData *ld; 2223 unsigned left = (unsigned) (target->left - 1); 2224 unsigned size = (unsigned) (target->right - (int) left); 2225 unsigned attrs = flags; 2226 int row, col; 2227 2228 (void) size; 2229 2230 attrs &= ATTRIBUTES; 2231 attrs |= CHARDRAWN; 2232 for (row = target->bottom - 1; row >= (target->top - 1); row--) { 2233 ld = getLineData(screen, row); 2234 2235 TRACE(("filling %d [%d..%d]\n", row, left, left + size)); 2236 2237 /* 2238 * Fill attributes, preserving "protected" flag, as well as 2239 * colors if asked. 2240 */ 2241 for (col = (int) left; col < target->right; ++col) { 2242 unsigned temp = ld->attribs[col]; 2243 2244 if (!keepColors) { 2245 UIntClr(temp, (FG_COLOR | BG_COLOR)); 2246 } 2247 temp = attrs | (temp & (FG_COLOR | BG_COLOR | PROTECTED)); 2248 temp |= CHARDRAWN; 2249 ld->attribs[col] = (Char) temp; 2250#if OPT_ISO_COLORS 2251 if (attrs & (FG_COLOR | BG_COLOR)) { 2252 if_OPT_ISO_COLORS(screen, { 2253 ld->color[col] = xtermColorPair(xw); 2254 }); 2255 } 2256#endif 2257 } 2258 2259 for (col = (int) left; col < target->right; ++col) 2260 ld->charData[col] = (CharData) value; 2261 2262 if_OPT_WIDE_CHARS(screen, { 2263 size_t off; 2264 for_each_combData(off, ld) { 2265 memset(ld->combData[off] + left, 0, size * sizeof(CharData)); 2266 } 2267 }) 2268 } 2269 ScrnUpdate(xw, 2270 target->top - 1, 2271 target->left - 1, 2272 (target->bottom - target->top) + 1, 2273 (target->right - target->left) + 1, 2274 False); 2275 } 2276} 2277 2278#if OPT_DEC_RECTOPS 2279/* 2280 * Copies the source rectangle to the target location, including video 2281 * attributes. 2282 * 2283 * This implementation ignores page numbers. 2284 * 2285 * The reference manual does not indicate if it handles overlapping copy 2286 * properly - so we make a local copy of the source rectangle first, then apply 2287 * the target from that. 2288 */ 2289void 2290ScrnCopyRectangle(XtermWidget xw, XTermRect * source, int nparam, int *params) 2291{ 2292 TScreen *screen = TScreenOf(xw); 2293 2294 TRACE(("copying rectangle\n")); 2295 2296 if (validRect(xw, source)) { 2297 XTermRect target; 2298 xtermParseRect(xw, 2299 ((nparam > 3) ? 2 : (nparam - 1)), 2300 params, 2301 &target); 2302 if (validRect(xw, &target)) { 2303 Cardinal high = (Cardinal) (source->bottom - source->top) + 1; 2304 Cardinal wide = (Cardinal) (source->right - source->left) + 1; 2305 Cardinal size = (high * wide); 2306 int row, col; 2307 Cardinal j, k; 2308 LineData *ld; 2309 2310 CellData *cells = newCellData(xw, size); 2311 2312 if (cells != 0) { 2313 2314 TRACE(("OK - make copy %dx%d\n", high, wide)); 2315 target.bottom = target.top + (int) (high - 1); 2316 target.right = target.left + (int) (wide - 1); 2317 2318 for (row = source->top - 1; row < source->bottom; ++row) { 2319 ld = getLineData(screen, row); 2320 j = (Cardinal) (row - (source->top - 1)); 2321 for (col = source->left - 1; col < source->right; ++col) { 2322 k = (Cardinal) (col - (source->left - 1)); 2323 saveCellData(screen, cells, 2324 (j * wide) + k, 2325 ld, col); 2326 } 2327 } 2328 for (row = target.top - 1; row < target.bottom; ++row) { 2329 ld = getLineData(screen, row); 2330 j = (Cardinal) (row - (target.top - 1)); 2331 for (col = target.left - 1; col < target.right; ++col) { 2332 k = (Cardinal) (col - (target.left - 1)); 2333 if (row >= getMinRow(screen) 2334 && row <= getMaxRow(screen) 2335 && col >= getMinCol(screen) 2336 && col <= getMaxCol(screen)) { 2337 if (j < high && k < wide) { 2338 restoreCellData(screen, cells, 2339 (j * wide) + k, 2340 ld, col); 2341 } else { 2342 /* FIXME - clear the target cell? */ 2343 } 2344 ld->attribs[col] |= CHARDRAWN; 2345 } 2346 } 2347 } 2348 free(cells); 2349 2350 ScrnUpdate(xw, 2351 (target.top - 1), 2352 (target.left - 1), 2353 (target.bottom - target.top) + 1, 2354 ((target.right - target.left) + 1), 2355 False); 2356 } 2357 } 2358 } 2359} 2360 2361/* 2362 * Modifies the video-attributes only - so selection (not a video attribute) is 2363 * unaffected. Colors and double-size flags are unaffected as well. 2364 * 2365 * FIXME: our representation for "invisible" does not work with this operation, 2366 * since the attribute byte is fully-allocated for other flags. The logic 2367 * is shown for INVISIBLE because it's harmless, and useful in case the 2368 * CHARDRAWN or PROTECTED flags are reassigned. 2369 */ 2370void 2371ScrnMarkRectangle(XtermWidget xw, 2372 XTermRect * target, 2373 Bool reverse, 2374 int nparam, 2375 int *params) 2376{ 2377 TScreen *screen = TScreenOf(xw); 2378 Bool exact = (screen->cur_decsace == 2); 2379 2380 TRACE(("%s %s\n", 2381 reverse ? "reversing" : "marking", 2382 (exact 2383 ? "rectangle" 2384 : "region"))); 2385 2386 if (validRect(xw, target)) { 2387 LineData *ld; 2388 int top = target->top - 1; 2389 int bottom = target->bottom - 1; 2390 int row, col; 2391 int n; 2392 2393 for (row = top; row <= bottom; ++row) { 2394 int left = ((exact || (row == top)) 2395 ? (target->left - 1) 2396 : getMinCol(screen)); 2397 int right = ((exact || (row == bottom)) 2398 ? (target->right - 1) 2399 : getMaxCol(screen)); 2400 2401 ld = getLineData(screen, row); 2402 2403 TRACE(("marking %d [%d..%d]\n", row, left, right)); 2404 for (col = left; col <= right; ++col) { 2405 unsigned flags = ld->attribs[col]; 2406 2407 for (n = 0; n < nparam; ++n) { 2408#if OPT_TRACE 2409 if (row == top && col == left) 2410 TRACE(("attr param[%d] %d\n", n + 1, params[n])); 2411#endif 2412 if (reverse) { 2413 switch (params[n]) { 2414 case 1: 2415 flags ^= BOLD; 2416 break; 2417 case 4: 2418 flags ^= UNDERLINE; 2419 break; 2420 case 5: 2421 flags ^= BLINK; 2422 break; 2423 case 7: 2424 flags ^= INVERSE; 2425 break; 2426 case 8: 2427 flags ^= INVISIBLE; 2428 break; 2429 } 2430 } else { 2431 switch (params[n]) { 2432 case 0: 2433 UIntClr(flags, SGR_MASK); 2434 break; 2435 case 1: 2436 flags |= BOLD; 2437 break; 2438 case 4: 2439 flags |= UNDERLINE; 2440 break; 2441 case 5: 2442 flags |= BLINK; 2443 break; 2444 case 7: 2445 flags |= INVERSE; 2446 break; 2447 case 8: 2448 flags |= INVISIBLE; 2449 break; 2450 case 22: 2451 UIntClr(flags, BOLD); 2452 break; 2453 case 24: 2454 UIntClr(flags, UNDERLINE); 2455 break; 2456 case 25: 2457 UIntClr(flags, BLINK); 2458 break; 2459 case 27: 2460 UIntClr(flags, INVERSE); 2461 break; 2462 case 28: 2463 UIntClr(flags, INVISIBLE); 2464 break; 2465 } 2466 } 2467 } 2468#if OPT_TRACE 2469 if (row == top && col == left) 2470 TRACE(("first mask-change is %#x\n", 2471 ld->attribs[col] ^ flags)); 2472#endif 2473 ld->attribs[col] = (Char) flags; 2474 } 2475 } 2476 ScrnRefresh(xw, 2477 (target->top - 1), 2478 (exact ? (target->left - 1) : getMinCol(screen)), 2479 (target->bottom - target->top) + 1, 2480 (exact 2481 ? ((target->right - target->left) + 1) 2482 : (getMaxCol(screen) - getMinCol(screen) + 1)), 2483 False); 2484 } 2485} 2486 2487/* 2488 * Resets characters to space, except where prohibited by DECSCA. Video 2489 * attributes (including color) are untouched. 2490 */ 2491void 2492ScrnWipeRectangle(XtermWidget xw, 2493 XTermRect * target) 2494{ 2495 TScreen *screen = TScreenOf(xw); 2496 2497 TRACE(("wiping rectangle\n")); 2498 2499 if (validRect(xw, target)) { 2500 LineData *ld; 2501 int top = target->top - 1; 2502 int bottom = target->bottom - 1; 2503 int row, col; 2504 2505 for (row = top; row <= bottom; ++row) { 2506 int left = (target->left - 1); 2507 int right = (target->right - 1); 2508 2509 TRACE(("wiping %d [%d..%d]\n", row, left, right)); 2510 2511 ld = getLineData(screen, row); 2512 for (col = left; col <= right; ++col) { 2513 if (!((screen->protected_mode == DEC_PROTECT) 2514 && (ld->attribs[col] & PROTECTED))) { 2515 ld->attribs[col] |= CHARDRAWN; 2516 ld->charData[col] = ' '; 2517 if_OPT_WIDE_CHARS(screen, { 2518 size_t off; 2519 for_each_combData(off, ld) { 2520 ld->combData[off][col] = '\0'; 2521 } 2522 }) 2523 } 2524 } 2525 } 2526 ScrnUpdate(xw, 2527 (target->top - 1), 2528 (target->left - 1), 2529 (target->bottom - target->top) + 1, 2530 ((target->right - target->left) + 1), 2531 False); 2532 } 2533} 2534#endif /* OPT_DEC_RECTOPS */ 2535