screen.c revision d522f475
1/* $XTermId: screen.c,v 1.241 2008/04/20 21:07:10 tom Exp $ */ 2 3/* 4 * Copyright 1999-2007,2008 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 getMinRow(screen) ((xw->flags & ORIGIN) ? (screen)->top_marg : 0) 73#define getMaxRow(screen) ((xw->flags & ORIGIN) ? (screen)->bot_marg : (screen)->max_row) 74#define getMinCol(screen) 0 75#define getMaxCol(screen) ((screen)->max_col) 76 77/* 78 * Allocates memory for a 2-dimensional array of chars and returns a pointer 79 * thereto. Each line is formed from a set of char arrays, with an index 80 * (i.e., the ScrnBuf type). The first pointer in the index is reserved for 81 * per-line flags, and does not point to data. 82 * 83 * After the per-line flags, we have a series of pointers to char arrays: The 84 * first one is the actual character array, the second one is the attributes, 85 * the third is the foreground and background colors, and the fourth denotes 86 * the character set. 87 * 88 * We store it all as pointers, because of alignment considerations, together 89 * with the intention of being able to change the total number of pointers per 90 * row according to whether the user wants color or not. 91 */ 92ScrnBuf 93Allocate(int nrow, int ncol, Char ** addr) 94{ 95 ScrnBuf base; 96 Char *tmp; 97 int i, j, k; 98 size_t entries = MAX_PTRS * nrow; 99 size_t length = BUF_PTRS * nrow * ncol; 100 101 if ((base = TypeCallocN(ScrnPtr, entries)) == 0) 102 SysError(ERROR_SCALLOC); 103 104 if ((tmp = TypeCallocN(Char, length)) == 0) 105 SysError(ERROR_SCALLOC2); 106 107 *addr = tmp; 108 for (i = k = 0; i < nrow; i++) { 109 base[k] = 0; /* per-line flags */ 110 k += BUF_HEAD; 111 for (j = BUF_HEAD; j < MAX_PTRS; j++) { 112 base[k++] = tmp; 113 tmp += ncol; 114 } 115 } 116 117 return (base); 118} 119 120/* 121 * This is called when the screen is resized. 122 * Returns the number of lines the text was moved down (neg for up). 123 * (Return value only necessary with SouthWestGravity.) 124 */ 125static int 126Reallocate(XtermWidget xw, 127 ScrnBuf * sbuf, 128 Char ** sbufaddr, 129 int nrow, 130 int ncol, 131 int oldrow, 132 int oldcol) 133{ 134 ScrnBuf base; 135 Char *tmp; 136 int i, j, k, minrows; 137 size_t mincols; 138 Char *oldbuf; 139 int move_down = 0, move_up = 0; 140 size_t entries = MAX_PTRS * nrow; 141 size_t length = BUF_PTRS * nrow * ncol; 142 143 if (sbuf == NULL || *sbuf == NULL) { 144 return 0; 145 } 146 147 oldbuf = *sbufaddr; 148 149 /* 150 * Special case if oldcol == ncol - straight forward realloc and 151 * update of the additional lines in sbuf 152 * 153 * FIXME: this is a good idea, but doesn't seem to be implemented. 154 * -gildea 155 */ 156 157 /* 158 * realloc sbuf, the pointers to all the lines. 159 * If the screen shrinks, remove lines off the top of the buffer 160 * if resizeGravity resource says to do so. 161 */ 162 if (nrow < oldrow 163 && xw->misc.resizeGravity == SouthWestGravity) { 164 /* Remove lines off the top of the buffer if necessary. */ 165 move_up = (oldrow - nrow) 166 - (xw->screen.max_row - xw->screen.cur_row); 167 if (move_up < 0) 168 move_up = 0; 169 /* Overlapping memmove here! */ 170 memmove(*sbuf, *sbuf + (move_up * MAX_PTRS), 171 MAX_PTRS * (oldrow - move_up) * sizeof((*sbuf)[0])); 172 } 173 *sbuf = TypeRealloc(ScrnPtr, entries, *sbuf); 174 if (*sbuf == 0) 175 SysError(ERROR_RESIZE); 176 base = *sbuf; 177 178 /* 179 * create the new buffer space and copy old buffer contents there 180 * line by line. 181 */ 182 if ((tmp = TypeCallocN(Char, length)) == 0) 183 SysError(ERROR_SREALLOC); 184 *sbufaddr = tmp; 185 minrows = (oldrow < nrow) ? oldrow : nrow; 186 mincols = (oldcol < ncol) ? oldcol : ncol; 187 if (nrow > oldrow 188 && xw->misc.resizeGravity == SouthWestGravity) { 189 /* move data down to bottom of expanded screen */ 190 move_down = Min(nrow - oldrow, xw->screen.savedlines); 191 tmp += (ncol * move_down * BUF_PTRS); 192 } 193 194 for (i = k = 0; i < minrows; i++) { 195 k += BUF_HEAD; 196 for (j = BUF_HEAD; j < MAX_PTRS; j++) { 197 memcpy(tmp, base[k++], mincols); 198 tmp += ncol; 199 } 200 } 201 202 /* 203 * update the pointers in sbuf 204 */ 205 for (i = k = 0, tmp = *sbufaddr; i < nrow; i++) { 206 for (j = 0; j < BUF_HEAD; j++) 207 base[k++] = 0; 208 for (j = BUF_HEAD; j < MAX_PTRS; j++) { 209 base[k++] = tmp; 210 tmp += ncol; 211 } 212 } 213 214 /* Now free the old buffer */ 215 free(oldbuf); 216 217 return move_down ? move_down : -move_up; /* convert to rows */ 218} 219 220#if OPT_WIDE_CHARS 221#if 0 222static void 223dump_screen(const char *tag, 224 XtermWidget xw, 225 ScrnBuf sbuf, 226 Char * sbufaddr, 227 unsigned nrow, 228 unsigned ncol) 229{ 230 unsigned y, x; 231 232 TRACE(("DUMP %s, ptrs %d\n", tag, xw->num_ptrs)); 233 TRACE((" sbuf %p\n", sbuf)); 234 TRACE((" sbufaddr %p\n", sbufaddr)); 235 TRACE((" nrow %d\n", nrow)); 236 TRACE((" ncol %d\n", ncol)); 237 238 for (y = 0; y < nrow; ++y) { 239 ScrnPtr ptr = BUF_CHARS(sbuf, y); 240 TRACE(("%3d:%p:", y, ptr)); 241 for (x = 0; x < ncol; ++x) { 242 Char c = ptr[x]; 243 if (c == 0) 244 c = '~'; 245 TRACE(("%c", c)); 246 } 247 TRACE(("\n")); 248 } 249} 250#else 251#define dump_screen(tag, xw, sbuf, sbufaddr, nrow, ncol) /* nothing */ 252#endif 253 254/* 255 * This function reallocates memory if changing the number of Buf offsets. 256 * The code is based on Reallocate(). 257 */ 258static void 259ReallocateBufOffsets(XtermWidget xw, 260 ScrnBuf * sbuf, 261 Char ** sbufaddr, 262 unsigned nrow, 263 unsigned ncol, 264 size_t new_max_offsets) 265{ 266 unsigned i; 267 int j, k; 268 ScrnBuf base; 269 Char *oldbuf, *tmp; 270 size_t entries, length; 271 /* 272 * As there are 2 buffers (allbuf, altbuf), we cannot change num_ptrs in 273 * this function. However MAX_PTRS and BUF_PTRS depend on num_ptrs so 274 * change it now and restore the value when done. 275 */ 276 int old_max_ptrs = MAX_PTRS; 277 278 assert(nrow != 0); 279 assert(ncol != 0); 280 assert(new_max_offsets != 0); 281 282 dump_screen("before", xw, *sbuf, *sbufaddr, nrow, ncol); 283 284 xw->num_ptrs = new_max_offsets; 285 286 entries = MAX_PTRS * nrow; 287 length = BUF_PTRS * nrow * ncol; 288 oldbuf = *sbufaddr; 289 290 *sbuf = TypeRealloc(ScrnPtr, entries, *sbuf); 291 if (*sbuf == 0) 292 SysError(ERROR_RESIZE); 293 base = *sbuf; 294 295 if ((tmp = TypeCallocN(Char, length)) == 0) 296 SysError(ERROR_SREALLOC); 297 *sbufaddr = tmp; 298 299 for (i = k = 0; i < nrow; i++) { 300 k += BUF_HEAD; 301 for (j = BUF_HEAD; j < old_max_ptrs; j++) { 302 memcpy(tmp, base[k++], ncol); 303 tmp += ncol; 304 } 305 tmp += ncol * (new_max_offsets - old_max_ptrs); 306 } 307 308 /* 309 * update the pointers in sbuf 310 */ 311 for (i = k = 0, tmp = *sbufaddr; i < nrow; i++) { 312 for (j = 0; j < BUF_HEAD; j++) 313 base[k++] = 0; 314 for (j = BUF_HEAD; j < MAX_PTRS; j++) { 315 base[k++] = tmp; 316 tmp += ncol; 317 } 318 } 319 320 /* Now free the old buffer and restore num_ptrs */ 321 free(oldbuf); 322 dump_screen("after", xw, *sbuf, *sbufaddr, nrow, ncol); 323 324 xw->num_ptrs = old_max_ptrs; 325} 326 327/* 328 * This function dynamically adds support for wide-characters. 329 */ 330void 331ChangeToWide(XtermWidget xw) 332{ 333 TScreen *screen = &(xw->screen); 334 unsigned new_bufoffset = OFF_FINAL + (screen->max_combining * 2); 335 int savelines = screen->scrollWidget ? screen->savelines : 0; 336 337 if (screen->wide_chars) 338 return; 339 340 TRACE(("ChangeToWide\n")); 341 if (xtermLoadWideFonts(xw, True)) { 342 if (savelines < 0) 343 savelines = 0; 344 345 /* 346 * If we're displaying the alternate screen, switch the pointers back 347 * temporarily so ReallocateBufOffsets() will operate on the proper 348 * data in altbuf. 349 */ 350 if (screen->alternate) 351 SwitchBufPtrs(screen); 352 353 ReallocateBufOffsets(xw, 354 &screen->allbuf, &screen->sbuf_address, 355 (unsigned) (MaxRows(screen) + savelines), 356 (unsigned) MaxCols(screen), 357 new_bufoffset); 358 if (screen->altbuf) { 359 ReallocateBufOffsets(xw, 360 &screen->altbuf, &screen->abuf_address, 361 (unsigned) MaxRows(screen), 362 (unsigned) MaxCols(screen), 363 new_bufoffset); 364 } 365 366 screen->wide_chars = True; 367 xw->num_ptrs = new_bufoffset; 368 screen->visbuf = &screen->allbuf[MAX_PTRS * savelines]; 369 370 /* 371 * Switch the pointers back before we start painting on the screen. 372 */ 373 if (screen->alternate) 374 SwitchBufPtrs(screen); 375 376 update_font_utf8_mode(); 377 SetVTFont(xw, screen->menu_font_number, True, NULL); 378 } 379 TRACE(("...ChangeToWide\n")); 380} 381#endif 382 383/* 384 * Clear cells, no side-effects. 385 */ 386void 387ClearCells(XtermWidget xw, int flags, unsigned len, int row, int col) 388{ 389 if (len != 0) { 390 TScreen *screen = &(xw->screen); 391 flags |= TERM_COLOR_FLAGS(xw); 392 393 memset(SCRN_BUF_CHARS(screen, row) + col, ' ', len); 394 memset(SCRN_BUF_ATTRS(screen, row) + col, flags, len); 395 396 if_OPT_EXT_COLORS(screen, { 397 memset(SCRN_BUF_FGRND(screen, row) + col, 398 xw->sgr_foreground, len); 399 memset(SCRN_BUF_BGRND(screen, row) + col, 400 xw->cur_background, len); 401 }); 402 if_OPT_ISO_TRADITIONAL_COLORS(screen, { 403 memset(SCRN_BUF_COLOR(screen, row) + col, 404 (int) xtermColorPair(xw), len); 405 }); 406 if_OPT_DEC_CHRSET({ 407 memset(SCRN_BUF_CSETS(screen, row) + col, 408 curXtermChrSet(xw, row), len); 409 }); 410 if_OPT_WIDE_CHARS(screen, { 411 int off; 412 for (off = OFF_WIDEC; off < MAX_PTRS; ++off) { 413 memset(SCREEN_PTR(screen, row, off) + col, 0, len); 414 } 415 }); 416 } 417} 418 419/* 420 * Clear data in the screen-structure (no I/O). 421 * Check for wide-character damage as well, clearing the damaged cells. 422 */ 423void 424ScrnClearCells(XtermWidget xw, int row, int col, unsigned len) 425{ 426#if OPT_WIDE_CHARS 427 TScreen *screen = &(xw->screen); 428#endif 429 int flags = 0; 430 431 if_OPT_WIDE_CHARS(screen, { 432 int kl; 433 int kr; 434 if (DamagedCells(screen, len, &kl, &kr, INX2ROW(screen, row), col) 435 && kr >= kl) { 436 ClearCells(xw, flags, (unsigned) (kr - kl + 1), row, kl); 437 } 438 }); 439 ClearCells(xw, flags, len, row, col); 440} 441 442/* 443 * Disown the selection and repaint the area that is highlighted so it is no 444 * longer highlighted. 445 */ 446void 447ScrnDisownSelection(XtermWidget xw) 448{ 449 if (ScrnHaveSelection(&(xw->screen))) { 450 if (xw->screen.keepSelection) { 451 UnhiliteSelection(xw); 452 } else { 453 DisownSelection(xw); 454 } 455 } 456} 457 458/* 459 * Writes str into buf at screen's current row and column. Characters are set 460 * to match flags. 461 */ 462void 463ScrnWriteText(XtermWidget xw, 464 PAIRED_CHARS(Char * str, Char * str2), 465 unsigned flags, 466 unsigned cur_fg_bg, 467 unsigned length) 468{ 469 TScreen *screen = &(xw->screen); 470#if OPT_ISO_COLORS 471#if OPT_EXT_COLORS 472 Char *fbf = 0; 473 Char *fbb = 0; 474#else 475 Char *fb = 0; 476#endif 477#endif 478#if OPT_DEC_CHRSET 479 Char *cb = 0; 480#endif 481 Char *attrs; 482 int avail = MaxCols(screen) - screen->cur_col; 483 Char *chars; 484#if OPT_WIDE_CHARS 485 Char starcol1, starcol2; 486#endif 487 unsigned real_width = visual_width(PAIRED_CHARS(str, str2), length); 488 489 (void) cur_fg_bg; 490 491 if (avail <= 0) 492 return; 493 if (length > (unsigned) avail) 494 length = avail; 495 if (length == 0 || real_width == 0) 496 return; 497 498 chars = SCRN_BUF_CHARS(screen, screen->cur_row) + screen->cur_col; 499 attrs = SCRN_BUF_ATTRS(screen, screen->cur_row) + screen->cur_col; 500 501 if_OPT_EXT_COLORS(screen, { 502 fbf = SCRN_BUF_FGRND(screen, screen->cur_row) + screen->cur_col; 503 fbb = SCRN_BUF_BGRND(screen, screen->cur_row) + screen->cur_col; 504 }); 505 if_OPT_ISO_TRADITIONAL_COLORS(screen, { 506 fb = SCRN_BUF_COLOR(screen, screen->cur_row) + screen->cur_col; 507 }); 508 if_OPT_DEC_CHRSET({ 509 cb = SCRN_BUF_CSETS(screen, screen->cur_row) + screen->cur_col; 510 }); 511 512#if OPT_WIDE_CHARS 513 starcol1 = *chars; 514 starcol2 = chars[length - 1]; 515#endif 516 517 /* write blanks if we're writing invisible text */ 518 if (flags & INVISIBLE) { 519 memset(chars, ' ', length); 520 } else { 521 memcpy(chars, str, length); /* This can stand for the present. If it 522 is wrong, we will scribble over it */ 523 } 524 525#if OPT_BLINK_TEXT 526 if ((flags & BLINK) && !(screen->blink_as_bold)) { 527 ScrnSetBlinked(screen, screen->cur_row); 528 } 529#endif 530 531#define ERROR_1 0x20 532#define ERROR_2 0x00 533 if_OPT_WIDE_CHARS(screen, { 534 535 Char *char2; 536 537 if (real_width != length) { 538 Char *char1 = chars; 539 char2 = SCRN_BUF_WIDEC(screen, screen->cur_row); 540 char2 += screen->cur_col; 541 if (screen->cur_col && starcol1 == HIDDEN_LO && *char2 == HIDDEN_HI 542 && iswide(PACK_PAIR(char1, char2, -1))) { 543 char1[-1] = ERROR_1; 544 char2[-1] = ERROR_2; 545 } 546 /* if we are overwriting the right hand half of a 547 wide character, make the other half vanish */ 548 while (length) { 549 int ch = PACK_PAIR(str, str2, 0); 550 551 *char1 = *str; 552 char1++; 553 str++; 554 555 if (str2) { 556 *char2 = *str2; 557 str2++; 558 } else 559 *char2 = 0; 560 char2++; 561 length--; 562 563 if (iswide(ch)) { 564 *char1 = HIDDEN_LO; 565 *char2 = HIDDEN_HI; 566 char1++; 567 char2++; 568 } 569 } 570 571 if (*char1 == HIDDEN_LO 572 && *char2 == HIDDEN_HI 573 && char1[-1] == HIDDEN_LO 574 && char2[-1] == HIDDEN_HI) { 575 *char1 = ERROR_1; 576 *char2 = ERROR_2; 577 } 578 /* if we are overwriting the left hand half of a 579 wide character, make the other half vanish */ 580 } else { 581 582 if ((char2 = SCRN_BUF_WIDEC(screen, screen->cur_row)) != 0) { 583 char2 += screen->cur_col; 584 if (screen->cur_col && starcol1 == HIDDEN_LO && *char2 == HIDDEN_HI 585 && iswide(PACK_PAIR(chars, char2, -1))) { 586 chars[-1] = ERROR_1; 587 char2[-1] = ERROR_2; 588 } 589 /* if we are overwriting the right hand half of a 590 wide character, make the other half vanish */ 591 if (chars[length] == HIDDEN_LO && char2[length] == HIDDEN_HI && 592 iswide(PACK_PAIR(chars, char2, length - 1))) { 593 chars[length] = ERROR_1; 594 char2[length] = ERROR_2; 595 } 596 /* if we are overwriting the left hand half of a 597 wide character, make the other half vanish */ 598 if ((flags & INVISIBLE) || (str2 == 0)) 599 memset(char2, 0, length); 600 else 601 memcpy(char2, str2, length); 602 } 603 } 604 }); 605 606 flags &= ATTRIBUTES; 607 flags |= CHARDRAWN; 608 memset(attrs, (Char) flags, real_width); 609 610 if_OPT_WIDE_CHARS(screen, { 611 int off; 612 for (off = OFF_FINAL; off < MAX_PTRS; ++off) { 613 memset(SCREEN_PTR(screen, 614 screen->cur_row, 615 off) + screen->cur_col, 616 0, real_width); 617 } 618 }); 619 if_OPT_EXT_COLORS(screen, { 620 memset(fbf, (int) ExtractForeground(cur_fg_bg), real_width); 621 memset(fbb, (int) ExtractBackground(cur_fg_bg), real_width); 622 }); 623 if_OPT_ISO_TRADITIONAL_COLORS(screen, { 624 memset(fb, (int) cur_fg_bg, real_width); 625 }); 626 if_OPT_DEC_CHRSET({ 627 memset(cb, curXtermChrSet(xw, screen->cur_row), real_width); 628 }); 629 630 if_OPT_WIDE_CHARS(screen, { 631 screen->last_written_col = screen->cur_col + real_width - 1; 632 screen->last_written_row = screen->cur_row; 633 }); 634 635 if_OPT_XMC_GLITCH(screen, { 636 Resolve_XMC(xw); 637 }); 638} 639 640/* 641 * Saves pointers to the n lines beginning at sb + where, and clears the lines 642 */ 643static void 644ScrnClearLines(XtermWidget xw, ScrnBuf sb, int where, unsigned n, unsigned size) 645{ 646 TScreen *screen = &(xw->screen); 647 int i, j; 648 size_t len = ScrnPointers(screen, n); 649 int last = (n * MAX_PTRS); 650 651 TRACE(("ScrnClearLines(where %d, n %d, size %d)\n", where, n, size)); 652 653 assert(n != 0); 654 assert(size != 0); 655 656 /* save n lines at where */ 657 memcpy((char *) screen->save_ptr, 658 (char *) &sb[MAX_PTRS * where], 659 len); 660 661 /* clear contents of old rows */ 662 if (TERM_COLOR_FLAGS(xw)) { 663 int flags = TERM_COLOR_FLAGS(xw); 664 for (i = 0; i < last; i += MAX_PTRS) { 665 for (j = 0; j < MAX_PTRS; j++) { 666 if (j < BUF_HEAD) 667 screen->save_ptr[i + j] = 0; 668 else if (j == OFF_ATTRS) 669 memset(screen->save_ptr[i + j], flags, size); 670#if OPT_ISO_COLORS 671#if OPT_EXT_COLORS 672 else if (j == OFF_FGRND) 673 memset(screen->save_ptr[i + j], xw->sgr_foreground, size); 674 else if (j == OFF_BGRND) 675 memset(screen->save_ptr[i + j], xw->cur_background, size); 676#else 677 else if (j == OFF_COLOR) 678 memset(screen->save_ptr[i + j], (int) 679 xtermColorPair(xw), size); 680#endif 681#endif 682 else 683 bzero(screen->save_ptr[i + j], size); 684 } 685 } 686 } else { 687 for (i = 0; i < last; i += MAX_PTRS) { 688 for (j = 0; j < BUF_HEAD; j++) 689 screen->save_ptr[i + j] = 0; 690 for (j = BUF_HEAD; j < MAX_PTRS; j++) 691 bzero(screen->save_ptr[i + j], size); 692 } 693 } 694} 695 696size_t 697ScrnPointers(TScreen * screen, size_t len) 698{ 699 len *= MAX_PTRS; 700 701 if (len > screen->save_len) { 702 if (screen->save_len) 703 screen->save_ptr = TypeRealloc(ScrnPtr, len, screen->save_ptr); 704 else 705 screen->save_ptr = TypeMallocN(ScrnPtr, len); 706 screen->save_len = len; 707 if (screen->save_ptr == 0) 708 SysError(ERROR_SAVE_PTR); 709 } 710 return len * sizeof(ScrnPtr); 711} 712 713/* 714 * Inserts n blank lines at sb + where, treating last as a bottom margin. 715 * size is the size of each entry in sb. 716 */ 717void 718ScrnInsertLine(XtermWidget xw, ScrnBuf sb, int last, int where, 719 unsigned n, unsigned size) 720{ 721 TScreen *screen = &(xw->screen); 722 size_t len = ScrnPointers(screen, n); 723 724 assert(where >= 0); 725 assert(last >= (int) n); 726 assert(last >= where); 727 728 assert(n != 0); 729 assert(size != 0); 730 assert(MAX_PTRS > 0); 731 732 /* save n lines at bottom */ 733 ScrnClearLines(xw, sb, (last -= n - 1), n, size); 734 735 /* 736 * WARNING, overlapping copy operation. Move down lines (pointers). 737 * 738 * +----|---------|--------+ 739 * 740 * is copied in the array to: 741 * 742 * +--------|---------|----+ 743 */ 744 assert(last >= where); 745 memmove((char *) &sb[MAX_PTRS * (where + n)], 746 (char *) &sb[MAX_PTRS * where], 747 MAX_PTRS * sizeof(char *) * (last - where)); 748 749 /* reuse storage for new lines at where */ 750 memcpy((char *) &sb[MAX_PTRS * where], 751 (char *) screen->save_ptr, 752 len); 753} 754 755/* 756 * Deletes n lines at sb + where, treating last as a bottom margin. 757 * size is the size of each entry in sb. 758 */ 759void 760ScrnDeleteLine(XtermWidget xw, ScrnBuf sb, int last, int where, 761 unsigned n, unsigned size) 762{ 763 TScreen *screen = &(xw->screen); 764 765 assert(where >= 0); 766 assert(last >= where + (int) n - 1); 767 768 assert(n != 0); 769 assert(size != 0); 770 assert(MAX_PTRS > 0); 771 772 ScrnClearLines(xw, sb, where, n, size); 773 774 /* move up lines */ 775 memmove((char *) &sb[MAX_PTRS * where], 776 (char *) &sb[MAX_PTRS * (where + n)], 777 MAX_PTRS * sizeof(char *) * ((last -= n - 1) - where)); 778 779 /* reuse storage for new bottom lines */ 780 memcpy((char *) &sb[MAX_PTRS * last], 781 (char *) screen->save_ptr, 782 MAX_PTRS * sizeof(char *) * n); 783} 784 785/* 786 * Inserts n blanks in screen at current row, col. Size is the size of each 787 * row. 788 */ 789void 790ScrnInsertChar(XtermWidget xw, unsigned n) 791{ 792#define Target (data + col + n) 793#define Source (data + col) 794 795 TScreen *screen = &(xw->screen); 796 ScrnBuf sb = screen->visbuf; 797 int last = MaxCols(screen); 798 int row = screen->cur_row; 799 int col = screen->cur_col; 800 Char *data; 801 size_t nbytes; 802 803 if (last <= (int) (col + n)) { 804 if (last <= col) 805 return; 806 n = last - col; 807 } 808 nbytes = (last - (col + n)); 809 810 assert(screen->cur_col >= 0); 811 assert(screen->cur_row >= 0); 812 assert(n > 0); 813 assert(last > (int) n); 814 815 if_OPT_WIDE_CHARS(screen, { 816 int xx = INX2ROW(screen, screen->cur_row); 817 int kl; 818 int kr = screen->cur_col; 819 if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) { 820 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl); 821 } 822 kr = screen->max_col - n + 1; 823 if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) { 824 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl); 825 } 826 }); 827 828 data = BUF_CHARS(sb, row); 829 memmove(Target, Source, nbytes); 830 831 data = BUF_ATTRS(sb, row); 832 memmove(Target, Source, nbytes); 833 834 if_OPT_EXT_COLORS(screen, { 835 data = BUF_FGRND(sb, row); 836 memmove(Target, Source, nbytes); 837 data = BUF_BGRND(sb, row); 838 memmove(Target, Source, nbytes); 839 }); 840 if_OPT_ISO_TRADITIONAL_COLORS(screen, { 841 data = BUF_COLOR(sb, row); 842 memmove(Target, Source, nbytes); 843 }); 844 if_OPT_DEC_CHRSET({ 845 data = BUF_CSETS(sb, row); 846 memmove(Target, Source, nbytes); 847 }); 848 if_OPT_WIDE_CHARS(screen, { 849 int off; 850 for (off = OFF_WIDEC; off < MAX_PTRS; ++off) { 851 data = BUFFER_PTR(sb, row, off); 852 memmove(Target, Source, nbytes); 853 } 854 }); 855 ClearCells(xw, CHARDRAWN, n, row, col); 856 857#undef Source 858#undef Target 859} 860 861/* 862 * Deletes n characters at current row, col. 863 */ 864void 865ScrnDeleteChar(XtermWidget xw, unsigned n) 866{ 867#define Target (data + col) 868#define Source (data + col + n) 869 870 TScreen *screen = &(xw->screen); 871 ScrnBuf sb = screen->visbuf; 872 int last = MaxCols(screen); 873 int row = screen->cur_row; 874 int col = screen->cur_col; 875 Char *data; 876 size_t nbytes; 877 878 if (last <= (int) (col + n)) { 879 if (last <= col) 880 return; 881 n = last - col; 882 } 883 nbytes = (last - (col + n)); 884 885 assert(screen->cur_col >= 0); 886 assert(screen->cur_row >= 0); 887 assert(n > 0); 888 assert(last > (int) n); 889 890 if_OPT_WIDE_CHARS(screen, { 891 int kl; 892 int kr; 893 if (DamagedCells(screen, n, &kl, &kr, 894 INX2ROW(screen, screen->cur_row), 895 screen->cur_col)) 896 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl); 897 }); 898 899 data = BUF_CHARS(sb, row); 900 memmove(Target, Source, nbytes); 901 902 data = BUF_ATTRS(sb, row); 903 memmove(Target, Source, nbytes); 904 905 if_OPT_EXT_COLORS(screen, { 906 data = BUF_FGRND(sb, row); 907 memmove(Target, Source, nbytes); 908 data = BUF_BGRND(sb, row); 909 memmove(Target, Source, nbytes); 910 }); 911 if_OPT_ISO_TRADITIONAL_COLORS(screen, { 912 data = BUF_COLOR(sb, row); 913 memmove(Target, Source, nbytes); 914 }); 915 if_OPT_DEC_CHRSET({ 916 data = BUF_CSETS(sb, row); 917 memmove(Target, Source, nbytes); 918 }); 919 if_OPT_WIDE_CHARS(screen, { 920 int off; 921 for (off = OFF_WIDEC; off < MAX_PTRS; ++off) { 922 data = BUFFER_PTR(sb, row, off); 923 memmove(Target, Source, nbytes); 924 } 925 }); 926 ClearCells(xw, 0, n, row, (int) (last - n)); 927 ScrnClrWrapped(screen, row); 928 929#undef Source 930#undef Target 931} 932 933/* 934 * Repaints the area enclosed by the parameters. 935 * Requires: (toprow, leftcol), (toprow + nrows, leftcol + ncols) are 936 * coordinates of characters in screen; 937 * nrows and ncols positive. 938 * all dimensions are based on single-characters. 939 */ 940void 941ScrnRefresh(XtermWidget xw, 942 int toprow, 943 int leftcol, 944 int nrows, 945 int ncols, 946 Bool force) /* ... leading/trailing spaces */ 947{ 948 TScreen *screen = &(xw->screen); 949 int y = toprow * FontHeight(screen) + screen->border; 950 int row; 951 int maxrow = toprow + nrows - 1; 952 int scrollamt = screen->scroll_amt; 953 int max = screen->max_row; 954 int gc_changes = 0; 955#ifdef __CYGWIN__ 956 static char first_time = 1; 957#endif 958 static int recurse = 0; 959 960 TRACE(("ScrnRefresh (%d,%d) - (%d,%d)%s\n", 961 toprow, leftcol, 962 nrows, ncols, 963 force ? " force" : "")); 964 965 if (screen->cursorp.col >= leftcol 966 && screen->cursorp.col <= (leftcol + ncols - 1) 967 && screen->cursorp.row >= ROW2INX(screen, toprow) 968 && screen->cursorp.row <= ROW2INX(screen, maxrow)) 969 screen->cursor_state = OFF; 970 971 for (row = toprow; row <= maxrow; y += FontHeight(screen), row++) { 972#if OPT_ISO_COLORS 973#if OPT_EXT_COLORS 974 Char *fbf = 0; 975 Char *fbb = 0; 976#define ColorOf(col) (unsigned) ((fbf[col] << 8) | fbb[col]) 977#else 978 Char *fb = 0; 979#define ColorOf(col) (unsigned) (fb[col]) 980#endif 981#endif 982#if OPT_DEC_CHRSET 983 Char *cb = 0; 984#endif 985#if OPT_WIDE_CHARS 986 int wideness = 0; 987 Char *widec = 0; 988#define WIDEC_PTR(cell) widec ? &widec[cell] : 0 989#define BLANK_CEL(cell) ((chars[cell] == ' ') && (widec == 0 || widec[cell] == 0)) 990#else 991#define BLANK_CEL(cell) (chars[cell] == ' ') 992#endif 993 Char cs = 0; 994 Char *chars; 995 Char *attrs; 996 int col = leftcol; 997 int maxcol = leftcol + ncols - 1; 998 int hi_col = maxcol; 999 int lastind; 1000 unsigned flags; 1001 unsigned test; 1002 unsigned fg_bg = 0, fg = 0, bg = 0; 1003 int x; 1004 GC gc; 1005 Bool hilite; 1006 1007 (void) fg; 1008 (void) bg; 1009 1010 if (row < screen->top_marg || row > screen->bot_marg) 1011 lastind = row; 1012 else 1013 lastind = row - scrollamt; 1014 1015 TRACE(("ScrnRefresh row=%d lastind=%d/%d\n", row, lastind, max)); 1016 if (lastind < 0 || lastind > max) 1017 continue; 1018 1019 chars = SCRN_BUF_CHARS(screen, ROW2INX(screen, lastind)); 1020 attrs = SCRN_BUF_ATTRS(screen, ROW2INX(screen, lastind)); 1021 1022 if_OPT_DEC_CHRSET({ 1023 cb = SCRN_BUF_CSETS(screen, ROW2INX(screen, lastind)); 1024 }); 1025 1026 if_OPT_WIDE_CHARS(screen, { 1027 widec = SCRN_BUF_WIDEC(screen, ROW2INX(screen, lastind)); 1028 }); 1029 1030 if_OPT_WIDE_CHARS(screen, { 1031 /* This fixes an infinite recursion bug, that leads 1032 to display anomalies. It seems to be related to 1033 problems with the selection. */ 1034 if (recurse < 3) { 1035 /* adjust to redraw all of a widechar if we just wanted 1036 to draw the right hand half */ 1037 if (leftcol > 0 && 1038 (PACK_PAIR(chars, widec, leftcol)) == HIDDEN_CHAR && 1039 iswide(PACK_PAIR(chars, widec, leftcol - 1))) { 1040 leftcol--; 1041 ncols++; 1042 col = leftcol; 1043 } 1044 } else { 1045 fprintf(stderr, "This should not happen. Why is it so?\n"); 1046 } 1047 }); 1048 1049 if (row < screen->startH.row || row > screen->endH.row || 1050 (row == screen->startH.row && maxcol < screen->startH.col) || 1051 (row == screen->endH.row && col >= screen->endH.col)) { 1052#if OPT_DEC_CHRSET 1053 /* 1054 * Temporarily change dimensions to double-sized characters so 1055 * we can reuse the recursion on this function. 1056 */ 1057 if (CSET_DOUBLE(*cb)) { 1058 col /= 2; 1059 maxcol /= 2; 1060 } 1061#endif 1062 /* 1063 * If row does not intersect selection; don't hilite blanks. 1064 */ 1065 if (!force) { 1066 while (col <= maxcol && (attrs[col] & ~BOLD) == 0 && 1067 BLANK_CEL(col)) 1068 col++; 1069 1070 while (col <= maxcol && (attrs[maxcol] & ~BOLD) == 0 && 1071 BLANK_CEL(maxcol)) 1072 maxcol--; 1073 } 1074#if OPT_DEC_CHRSET 1075 if (CSET_DOUBLE(*cb)) { 1076 col *= 2; 1077 maxcol *= 2; 1078 } 1079#endif 1080 hilite = False; 1081 } else { 1082 /* row intersects selection; split into pieces of single type */ 1083 if (row == screen->startH.row && col < screen->startH.col) { 1084 recurse++; 1085 ScrnRefresh(xw, row, col, 1, screen->startH.col - col, 1086 force); 1087 col = screen->startH.col; 1088 } 1089 if (row == screen->endH.row && maxcol >= screen->endH.col) { 1090 recurse++; 1091 ScrnRefresh(xw, row, screen->endH.col, 1, 1092 maxcol - screen->endH.col + 1, force); 1093 maxcol = screen->endH.col - 1; 1094 } 1095 1096 /* 1097 * If we're highlighting because the user is doing cut/paste, 1098 * trim the trailing blanks from the highlighted region so we're 1099 * showing the actual extent of the text that'll be cut. If 1100 * we're selecting a blank line, we'll highlight one column 1101 * anyway. 1102 * 1103 * We don't do this if the mouse-hilite mode is set because that 1104 * would be too confusing. 1105 * 1106 * The default if the highlightSelection resource isn't set will 1107 * highlight the whole width of the terminal, which is easy to 1108 * see, but harder to use (because trailing blanks aren't as 1109 * apparent). 1110 */ 1111 if (screen->highlight_selection 1112 && screen->send_mouse_pos != VT200_HIGHLIGHT_MOUSE) { 1113 hi_col = screen->max_col; 1114 while (hi_col > 0 && !(attrs[hi_col] & CHARDRAWN)) 1115 hi_col--; 1116 } 1117 1118 /* remaining piece should be hilited */ 1119 hilite = True; 1120 } 1121 1122 if (col > maxcol) 1123 continue; 1124 1125 /* 1126 * Go back to double-sized character dimensions if the line has 1127 * double-width characters. Note that 'hi_col' is already in the 1128 * right units. 1129 */ 1130 if_OPT_DEC_CHRSET({ 1131 if (CSET_DOUBLE(*cb)) { 1132 col /= 2; 1133 maxcol /= 2; 1134 } 1135 cs = cb[col]; 1136 }); 1137 1138 flags = attrs[col]; 1139#if OPT_WIDE_CHARS 1140 if (widec) 1141 wideness = iswide(PACK_PAIR(chars, widec, col)); 1142 else 1143 wideness = 0; 1144#endif 1145 if_OPT_EXT_COLORS(screen, { 1146 fbf = SCRN_BUF_FGRND(screen, ROW2INX(screen, lastind)); 1147 fbb = SCRN_BUF_BGRND(screen, ROW2INX(screen, lastind)); 1148 fg_bg = ColorOf(col); 1149 /* this combines them, then splits them again. but 1150 extract_fg does more, so seems reasonable */ 1151 fg = extract_fg(xw, fg_bg, flags); 1152 bg = extract_bg(xw, fg_bg, flags); 1153 }); 1154 if_OPT_ISO_TRADITIONAL_COLORS(screen, { 1155 fb = SCRN_BUF_COLOR(screen, ROW2INX(screen, lastind)); 1156 fg_bg = ColorOf(col); 1157 fg = extract_fg(xw, fg_bg, flags); 1158 bg = extract_bg(xw, fg_bg, flags); 1159 }); 1160 1161 gc = updatedXtermGC(xw, flags, fg_bg, hilite); 1162 gc_changes |= (flags & (FG_COLOR | BG_COLOR)); 1163 1164 x = CurCursorX(screen, ROW2INX(screen, row), col); 1165 lastind = col; 1166 1167 for (; col <= maxcol; col++) { 1168 if ((attrs[col] != flags) 1169 || (hilite && (col > hi_col)) 1170#if OPT_ISO_COLORS 1171 || ((flags & FG_COLOR) 1172 && (extract_fg(xw, ColorOf(col), attrs[col]) != fg)) 1173 || ((flags & BG_COLOR) 1174 && (extract_bg(xw, ColorOf(col), attrs[col]) != bg)) 1175#endif 1176#if OPT_WIDE_CHARS 1177 || (widec 1178 && ((iswide(PACK_PAIR(chars, widec, col))) != wideness) 1179 && !((PACK_PAIR(chars, widec, col)) == HIDDEN_CHAR)) 1180#endif 1181#if OPT_DEC_CHRSET 1182 || (cb[col] != cs) 1183#endif 1184 ) { 1185 assert(col >= lastind); 1186 TRACE(("ScrnRefresh looping drawXtermText %d..%d:%s\n", 1187 lastind, col, 1188 visibleChars(PAIRED_CHARS(&chars[lastind], 1189 WIDEC_PTR(lastind)), 1190 (unsigned) (col - lastind)))); 1191 1192 test = flags; 1193 checkVeryBoldColors(test, fg); 1194 1195 x = drawXtermText(xw, test & DRAWX_MASK, gc, x, y, 1196 cs, 1197 PAIRED_CHARS(&chars[lastind], WIDEC_PTR(lastind)), 1198 (unsigned) (col - lastind), 0); 1199 1200 if_OPT_WIDE_CHARS(screen, { 1201 int i; 1202 int off; 1203 for (off = OFF_FINAL; off < MAX_PTRS; off += 2) { 1204 Char *com_lo = BUFFER_PTR(screen->visbuf, 1205 ROW2INX(screen, row), 1206 off + 0); 1207 Char *com_hi = BUFFER_PTR(screen->visbuf, 1208 ROW2INX(screen, row), 1209 off + 1); 1210 for (i = lastind; i < col; i++) { 1211 int my_x = CurCursorX(screen, 1212 ROW2INX(screen, row), 1213 i); 1214 int base = PACK_PAIR(chars, widec, i); 1215 int combo = PACK_PAIR(com_lo, com_hi, i); 1216 1217 if (iswide(base)) 1218 my_x = CurCursorX(screen, 1219 ROW2INX(screen, row), 1220 i - 1); 1221 1222 if (combo != 0) 1223 drawXtermText(xw, 1224 (test & DRAWX_MASK) 1225 | NOBACKGROUND, 1226 gc, my_x, y, cs, 1227 PAIRED_CHARS(com_lo + i, 1228 com_hi + i), 1229 1, iswide(base)); 1230 } 1231 } 1232 }); 1233 1234 resetXtermGC(xw, flags, hilite); 1235 1236 lastind = col; 1237 1238 if (hilite && (col > hi_col)) 1239 hilite = False; 1240 1241 flags = attrs[col]; 1242 if_OPT_EXT_COLORS(screen, { 1243 fg_bg = ColorOf(col); 1244 fg = extract_fg(xw, fg_bg, flags); 1245 bg = extract_bg(xw, fg_bg, flags); 1246 }); 1247 if_OPT_ISO_TRADITIONAL_COLORS(screen, { 1248 fg_bg = ColorOf(col); 1249 fg = extract_fg(xw, fg_bg, flags); 1250 bg = extract_bg(xw, fg_bg, flags); 1251 }); 1252 if_OPT_DEC_CHRSET({ 1253 cs = cb[col]; 1254 }); 1255#if OPT_WIDE_CHARS 1256 if (widec) 1257 wideness = iswide(PACK_PAIR(chars, widec, col)); 1258#endif 1259 1260 gc = updatedXtermGC(xw, flags, fg_bg, hilite); 1261 gc_changes |= (flags & (FG_COLOR | BG_COLOR)); 1262 } 1263 1264 if (chars[col] == 0) { 1265#if OPT_WIDE_CHARS 1266 if (widec == 0 || widec[col] == 0) 1267#endif 1268 chars[col] = ' '; 1269 } 1270 } 1271 1272 assert(col >= lastind); 1273 TRACE(("ScrnRefresh calling drawXtermText %d..%d:%s\n", 1274 lastind, col, 1275 visibleChars(PAIRED_CHARS(&chars[lastind], WIDEC_PTR(lastind)), 1276 (unsigned) (col - lastind)))); 1277 1278 test = flags; 1279 checkVeryBoldColors(test, fg); 1280 1281 drawXtermText(xw, test & DRAWX_MASK, gc, x, y, 1282 cs, 1283 PAIRED_CHARS(&chars[lastind], WIDEC_PTR(lastind)), 1284 (unsigned) (col - lastind), 0); 1285 1286 if_OPT_WIDE_CHARS(screen, { 1287 int i; 1288 int off; 1289 for (off = OFF_FINAL; off < MAX_PTRS; off += 2) { 1290 Char *com_lo = BUFFER_PTR(screen->visbuf, 1291 ROW2INX(screen, row), 1292 off + 0); 1293 Char *com_hi = BUFFER_PTR(screen->visbuf, 1294 ROW2INX(screen, row), 1295 off + 1); 1296 for (i = lastind; i < col; i++) { 1297 int my_x = CurCursorX(screen, 1298 ROW2INX(screen, row), 1299 i); 1300 int base = PACK_PAIR(chars, widec, i); 1301 int combo = PACK_PAIR(com_lo, com_hi, i); 1302 1303 if (iswide(base)) 1304 my_x = CurCursorX(screen, 1305 ROW2INX(screen, row), 1306 i - 1); 1307 1308 if (combo != 0) 1309 drawXtermText(xw, 1310 (test & DRAWX_MASK) 1311 | NOBACKGROUND, 1312 gc, my_x, y, cs, 1313 PAIRED_CHARS(com_lo + i, 1314 com_hi + i), 1315 1, iswide(base)); 1316 } 1317 } 1318 }); 1319 1320 resetXtermGC(xw, flags, hilite); 1321 } 1322 1323 /* 1324 * If we're in color mode, reset the various GC's to the current 1325 * screen foreground and background so that other functions (e.g., 1326 * ClearRight) will get the correct colors. 1327 */ 1328 if_OPT_ISO_COLORS(screen, { 1329 if (gc_changes & FG_COLOR) 1330 SGR_Foreground(xw, xw->cur_foreground); 1331 if (gc_changes & BG_COLOR) 1332 SGR_Background(xw, xw->cur_background); 1333 }); 1334 1335#if defined(__CYGWIN__) && defined(TIOCSWINSZ) 1336 if (first_time == 1) { 1337 TTYSIZE_STRUCT ts; 1338 1339 first_time = 0; 1340 TTYSIZE_ROWS(ts) = nrows; 1341 TTYSIZE_COLS(ts) = ncols; 1342 ts.ws_xpixel = xw->core.width; 1343 ts.ws_ypixel = xw->core.height; 1344 SET_TTYSIZE(screen->respond, ts); 1345 } 1346#endif 1347 recurse--; 1348} 1349 1350/* 1351 * Call this wrapper to ScrnRefresh() when the data has changed. If the 1352 * refresh region overlaps the selection, we will release the primary selection. 1353 */ 1354void 1355ScrnUpdate(XtermWidget xw, 1356 int toprow, 1357 int leftcol, 1358 int nrows, 1359 int ncols, 1360 Bool force) /* ... leading/trailing spaces */ 1361{ 1362 TScreen *screen = &(xw->screen); 1363 1364 if (ScrnHaveSelection(screen) 1365 && (toprow <= screen->endH.row) 1366 && (toprow + nrows - 1 >= screen->startH.row)) { 1367 ScrnDisownSelection(xw); 1368 } 1369 ScrnRefresh(xw, toprow, leftcol, nrows, ncols, force); 1370} 1371 1372/* 1373 * Sets the rows first though last of the buffer of screen to spaces. 1374 * Requires first <= last; first, last are rows of screen->buf. 1375 */ 1376void 1377ClearBufRows(XtermWidget xw, 1378 int first, 1379 int last) 1380{ 1381 TScreen *screen = &(xw->screen); 1382 unsigned len = MaxCols(screen); 1383 int row; 1384 1385 TRACE(("ClearBufRows %d..%d\n", first, last)); 1386 for (row = first; row <= last; row++) { 1387 if_OPT_DEC_CHRSET({ 1388 /* clearing the whole row resets the doublesize characters */ 1389 SCRN_ROW_CSET(screen, row) = CSET_SWL; 1390 }); 1391 ScrnClrWrapped(screen, row); 1392 ClearCells(xw, 0, len, row, 0); 1393 } 1394} 1395 1396/* 1397 Resizes screen: 1398 1. If new window would have fractional characters, sets window size so as to 1399 discard fractional characters and returns -1. 1400 Minimum screen size is 1 X 1. 1401 Note that this causes another ExposeWindow event. 1402 2. Enlarges screen->buf if necessary. New space is appended to the bottom 1403 and to the right 1404 3. Reduces screen->buf if necessary. Old space is removed from the bottom 1405 and from the right 1406 4. Cursor is positioned as closely to its former position as possible 1407 5. Sets screen->max_row and screen->max_col to reflect new size 1408 6. Maintains the inner border (and clears the border on the screen). 1409 7. Clears origin mode and sets scrolling region to be entire screen. 1410 8. Returns 0 1411 */ 1412int 1413ScreenResize(XtermWidget xw, 1414 int width, 1415 int height, 1416 unsigned *flags) 1417{ 1418 TScreen *screen = &(xw->screen); 1419 int code, rows, cols; 1420 int border = 2 * screen->border; 1421 int move_down_by = 0; 1422#ifdef TTYSIZE_STRUCT 1423 TTYSIZE_STRUCT ts; 1424#endif 1425 Window tw = VWindow(screen); 1426 1427 TRACE(("ScreenResize %dx%d border %d font %dx%d\n", 1428 height, width, border, 1429 FontHeight(screen), FontWidth(screen))); 1430 1431 assert(width > 0); 1432 assert(height > 0); 1433 1434 if (screen->is_running) { 1435 /* clear the right and bottom internal border because of NorthWest 1436 gravity might have left junk on the right and bottom edges */ 1437 if (width >= FullWidth(screen)) { 1438 XClearArea(screen->display, tw, 1439 FullWidth(screen), 0, /* right edge */ 1440 0, (unsigned) height, /* from top to bottom */ 1441 False); 1442 } 1443 if (height >= FullHeight(screen)) { 1444 XClearArea(screen->display, tw, 1445 0, FullHeight(screen), /* bottom */ 1446 (unsigned) width, 0, /* all across the bottom */ 1447 False); 1448 } 1449 } 1450 1451 TRACE(("...computing rows/cols: %.2f %.2f\n", 1452 (double) (height - border) / FontHeight(screen), 1453 (double) (width - border - ScrollbarWidth(screen)) / FontWidth(screen))); 1454 1455 rows = (height - border) / FontHeight(screen); 1456 cols = (width - border - ScrollbarWidth(screen)) / FontWidth(screen); 1457 if (rows < 1) 1458 rows = 1; 1459 if (cols < 1) 1460 cols = 1; 1461 1462 /* update buffers if the screen has changed size */ 1463 if (MaxRows(screen) != rows || MaxCols(screen) != cols) { 1464 int savelines = (screen->scrollWidget 1465 ? screen->savelines 1466 : 0); 1467 int delta_rows = rows - MaxRows(screen); 1468 1469 TRACE(("...ScreenResize chars %dx%d\n", rows, cols)); 1470 1471 if (screen->is_running) { 1472 if (screen->cursor_state) 1473 HideCursor(); 1474 if (screen->alternate 1475 && xw->misc.resizeGravity == SouthWestGravity) 1476 /* swap buffer pointers back to make this work */ 1477 SwitchBufPtrs(screen); 1478 if (screen->altbuf) 1479 (void) Reallocate(xw, 1480 &screen->altbuf, 1481 &screen->abuf_address, 1482 rows, 1483 cols, 1484 MaxRows(screen), 1485 MaxCols(screen)); 1486 move_down_by = Reallocate(xw, 1487 &screen->allbuf, 1488 &screen->sbuf_address, 1489 rows + savelines, cols, 1490 MaxRows(screen) + savelines, 1491 MaxCols(screen)); 1492 screen->visbuf = &screen->allbuf[MAX_PTRS * savelines]; 1493 } 1494 1495 AdjustSavedCursor(xw, move_down_by); 1496 set_max_row(screen, screen->max_row + delta_rows); 1497 set_max_col(screen, cols - 1); 1498 1499 if (screen->is_running) { 1500 if (xw->misc.resizeGravity == SouthWestGravity) { 1501 screen->savedlines -= move_down_by; 1502 if (screen->savedlines < 0) 1503 screen->savedlines = 0; 1504 if (screen->savedlines > screen->savelines) 1505 screen->savedlines = screen->savelines; 1506 if (screen->topline < -screen->savedlines) 1507 screen->topline = -screen->savedlines; 1508 set_cur_row(screen, screen->cur_row + move_down_by); 1509 screen->cursorp.row += move_down_by; 1510 ScrollSelection(screen, move_down_by, True); 1511 1512 if (screen->alternate) 1513 SwitchBufPtrs(screen); /* put the pointers back */ 1514 } 1515 } 1516 1517 /* adjust scrolling region */ 1518 set_tb_margins(screen, 0, screen->max_row); 1519 *flags &= ~ORIGIN; 1520 1521 if (screen->cur_row > screen->max_row) 1522 set_cur_row(screen, screen->max_row); 1523 if (screen->cur_col > screen->max_col) 1524 set_cur_col(screen, screen->max_col); 1525 1526 screen->fullVwin.height = height - border; 1527 screen->fullVwin.width = width - border - screen->fullVwin.sb_info.width; 1528 1529 } else if (FullHeight(screen) == height && FullWidth(screen) == width) 1530 return (0); /* nothing has changed at all */ 1531 1532 screen->fullVwin.fullheight = height; 1533 screen->fullVwin.fullwidth = width; 1534 1535 ResizeScrollBar(xw); 1536 ResizeSelection(screen, rows, cols); 1537 1538#ifndef NO_ACTIVE_ICON 1539 if (screen->iconVwin.window) { 1540 XWindowChanges changes; 1541 screen->iconVwin.width = 1542 MaxCols(screen) * screen->iconVwin.f_width; 1543 1544 screen->iconVwin.height = 1545 MaxRows(screen) * screen->iconVwin.f_height; 1546 1547 changes.width = screen->iconVwin.fullwidth = 1548 screen->iconVwin.width + 2 * xw->misc.icon_border_width; 1549 changes.height = screen->iconVwin.fullheight = 1550 screen->iconVwin.height + 2 * xw->misc.icon_border_width; 1551 changes.border_width = xw->misc.icon_border_width; 1552 1553 TRACE(("resizing icon window %dx%d\n", changes.height, changes.width)); 1554 XConfigureWindow(XtDisplay(xw), screen->iconVwin.window, 1555 CWWidth | CWHeight | CWBorderWidth, &changes); 1556 } 1557#endif /* NO_ACTIVE_ICON */ 1558 1559#ifdef TTYSIZE_STRUCT 1560 /* Set tty's idea of window size */ 1561 TTYSIZE_ROWS(ts) = rows; 1562 TTYSIZE_COLS(ts) = cols; 1563#ifdef USE_STRUCT_WINSIZE 1564 ts.ws_xpixel = width; 1565 ts.ws_ypixel = height; 1566#endif 1567 code = SET_TTYSIZE(screen->respond, ts); 1568 TRACE(("return %d from SET_TTYSIZE %dx%d\n", code, rows, cols)); 1569 (void) code; 1570 1571#if defined(SIGWINCH) && defined(USE_STRUCT_TTYSIZE) 1572 if (screen->pid > 1) { 1573 int pgrp; 1574 1575 TRACE(("getting process-group\n")); 1576 if (ioctl(screen->respond, TIOCGPGRP, &pgrp) != -1) { 1577 TRACE(("sending SIGWINCH to process group %d\n", pgrp)); 1578 kill_process_group(pgrp, SIGWINCH); 1579 } 1580 } 1581#endif /* SIGWINCH */ 1582 1583#else 1584 TRACE(("ScreenResize cannot do anything to pty\n")); 1585#endif /* TTYSIZE_STRUCT */ 1586 return (0); 1587} 1588 1589/* 1590 * Return true if any character cell starting at [row,col], for len-cells is 1591 * nonnull. 1592 */ 1593Bool 1594non_blank_line(TScreen * screen, 1595 int row, 1596 int col, 1597 int len) 1598{ 1599 ScrnBuf sb = screen->visbuf; 1600 int i; 1601 Char *ptr = BUF_CHARS(sb, row); 1602 1603 for (i = col; i < len; i++) { 1604 if (ptr[i]) 1605 return True; 1606 } 1607 1608 if_OPT_WIDE_CHARS(screen, { 1609 if ((ptr = BUF_WIDEC(sb, row)) != 0) { 1610 for (i = col; i < len; i++) { 1611 if (ptr[i]) 1612 return True; 1613 } 1614 } 1615 }); 1616 1617 return False; 1618} 1619 1620/* 1621 * Rectangle parameters start from one. 1622 */ 1623#define minRectRow(screen) (getMinRow(screen) + 1) 1624#define minRectCol(screen) (getMinCol(screen) + 1) 1625#define maxRectRow(screen) (getMaxRow(screen) + 1) 1626#define maxRectCol(screen) (getMaxCol(screen) + 1) 1627 1628static int 1629limitedParseRow(XtermWidget xw, TScreen * screen, int row) 1630{ 1631 int min_row = minRectRow(screen); 1632 int max_row = maxRectRow(screen); 1633 1634 if (row < min_row) 1635 row = min_row; 1636 else if (row > max_row) 1637 row = max_row; 1638 return row; 1639} 1640 1641static int 1642limitedParseCol(XtermWidget xw, TScreen * screen, int col) 1643{ 1644 int min_col = minRectCol(screen); 1645 int max_col = maxRectCol(screen); 1646 1647 (void) xw; 1648 if (col < min_col) 1649 col = min_col; 1650 else if (col > max_col) 1651 col = max_col; 1652 return col; 1653} 1654 1655#define LimitedParse(num, func, dft) \ 1656 func(xw, screen, (nparams > num) ? params[num] : dft) 1657 1658/* 1659 * Copy the rectangle boundaries into a struct, providing default values as 1660 * needed. 1661 */ 1662void 1663xtermParseRect(XtermWidget xw, int nparams, int *params, XTermRect * target) 1664{ 1665 TScreen *screen = &(xw->screen); 1666 1667 memset(target, 0, sizeof(*target)); 1668 target->top = LimitedParse(0, limitedParseRow, minRectRow(screen)); 1669 target->left = LimitedParse(1, limitedParseCol, minRectCol(screen)); 1670 target->bottom = LimitedParse(2, limitedParseRow, maxRectRow(screen)); 1671 target->right = LimitedParse(3, limitedParseCol, maxRectCol(screen)); 1672 TRACE(("parsed rectangle %d,%d %d,%d\n", 1673 target->top, 1674 target->left, 1675 target->bottom, 1676 target->right)); 1677} 1678 1679static Bool 1680validRect(XtermWidget xw, XTermRect * target) 1681{ 1682 TScreen *screen = &(xw->screen); 1683 1684 TRACE(("comparing against screensize %dx%d\n", 1685 maxRectRow(screen), 1686 maxRectCol(screen))); 1687 return (target != 0 1688 && target->top >= minRectRow(screen) 1689 && target->left >= minRectCol(screen) 1690 && target->top <= target->bottom 1691 && target->left <= target->right 1692 && target->top <= maxRectRow(screen) 1693 && target->right <= maxRectCol(screen)); 1694} 1695 1696/* 1697 * Fills a rectangle with the given 8-bit character and video-attributes. 1698 * Colors and double-size attribute are unmodified. 1699 */ 1700void 1701ScrnFillRectangle(XtermWidget xw, 1702 XTermRect * target, 1703 int value, 1704 unsigned flags, 1705 Bool keepColors) 1706{ 1707 TScreen *screen = &(xw->screen); 1708 1709 TRACE(("filling rectangle with '%c' flags %#x\n", value, flags)); 1710 if (validRect(xw, target)) { 1711 unsigned left = target->left - 1; 1712 unsigned size = target->right - left; 1713 Char attrs = flags; 1714 int row, col; 1715 1716 attrs &= ATTRIBUTES; 1717 attrs |= CHARDRAWN; 1718 for (row = target->bottom - 1; row >= (target->top - 1); row--) { 1719 TRACE(("filling %d [%d..%d]\n", row, left, left + size)); 1720 1721 /* 1722 * Fill attributes, preserving "protected" flag, as well as 1723 * colors if asked. 1724 */ 1725 for (col = left; col < target->right; ++col) { 1726 Char temp = SCRN_BUF_ATTRS(screen, row)[col]; 1727 if (!keepColors) { 1728 temp &= ~(FG_COLOR | BG_COLOR); 1729 } 1730 temp = attrs | (temp & (FG_COLOR | BG_COLOR | PROTECTED)); 1731 temp |= CHARDRAWN; 1732 SCRN_BUF_ATTRS(screen, row)[col] = temp; 1733#if OPT_ISO_COLORS 1734 if (attrs & (FG_COLOR | BG_COLOR)) { 1735 if_OPT_EXT_COLORS(screen, { 1736 SCRN_BUF_FGRND(screen, row)[col] = xw->sgr_foreground; 1737 SCRN_BUF_BGRND(screen, row)[col] = xw->cur_background; 1738 }); 1739 if_OPT_ISO_TRADITIONAL_COLORS(screen, { 1740 SCRN_BUF_COLOR(screen, row)[col] = xtermColorPair(xw); 1741 }); 1742 } 1743#endif 1744 } 1745 1746 memset(SCRN_BUF_CHARS(screen, row) + left, (Char) value, size); 1747 if_OPT_WIDE_CHARS(screen, { 1748 int off; 1749 for (off = OFF_WIDEC; off < MAX_PTRS; ++off) { 1750 memset(SCREEN_PTR(screen, row, off) + left, 0, size); 1751 } 1752 }) 1753 } 1754 ScrnUpdate(xw, 1755 target->top - 1, 1756 target->left - 1, 1757 (target->bottom - target->top) + 1, 1758 (target->right - target->left) + 1, 1759 False); 1760 } 1761} 1762 1763#if OPT_DEC_RECTOPS 1764/* 1765 * Copies the source rectangle to the target location, including video 1766 * attributes. 1767 * 1768 * This implementation ignores page numbers. 1769 * 1770 * The reference manual does not indicate if it handles overlapping copy 1771 * properly - so we make a local copy of the source rectangle first, then apply 1772 * the target from that. 1773 */ 1774void 1775ScrnCopyRectangle(XtermWidget xw, XTermRect * source, int nparam, int *params) 1776{ 1777 TScreen *screen = &(xw->screen); 1778 1779 TRACE(("copying rectangle\n")); 1780 1781 if (validRect(xw, source)) { 1782 XTermRect target; 1783 xtermParseRect(xw, 1784 ((nparam > 3) ? 2 : (nparam - 1)), 1785 params, 1786 &target); 1787 if (validRect(xw, &target)) { 1788 unsigned high = (source->bottom - source->top) + 1; 1789 unsigned wide = (source->right - source->left) + 1; 1790 unsigned size = (high * wide * MAX_PTRS); 1791 int row, col, n, j; 1792 1793 Char *cells = TypeMallocN(Char, size); 1794 1795 if (cells == 0) 1796 return; 1797 1798 TRACE(("OK - make copy %dx%d\n", high, wide)); 1799 target.bottom = target.top + (high - 1); 1800 target.right = target.left + (wide - 1); 1801 1802 for (row = source->top - 1; row < source->bottom; ++row) { 1803 for (col = source->left - 1; col < source->right; ++col) { 1804 n = (((1 + row - source->top) * wide) 1805 + (1 + col - source->left)) * MAX_PTRS; 1806 for (j = OFF_ATTRS; j < MAX_PTRS; ++j) 1807 cells[n + j] = SCREEN_PTR(screen, row, j)[col]; 1808 } 1809 } 1810 for (row = target.top - 1; row < target.bottom; ++row) { 1811 for (col = target.left - 1; col < target.right; ++col) { 1812 if (row >= getMinRow(screen) 1813 && row <= getMaxRow(screen) 1814 && col >= getMinCol(screen) 1815 && col <= getMaxCol(screen)) { 1816 n = (((1 + row - target.top) * wide) 1817 + (1 + col - target.left)) * MAX_PTRS; 1818 for (j = OFF_ATTRS; j < MAX_PTRS; ++j) 1819 SCREEN_PTR(screen, row, j)[col] = cells[n + j]; 1820 SCRN_BUF_ATTRS(screen, row)[col] |= CHARDRAWN; 1821 } 1822 } 1823 } 1824 free(cells); 1825 1826 ScrnUpdate(xw, 1827 (target.top - 1), 1828 (target.left - 1), 1829 (target.bottom - target.top) + 1, 1830 ((target.right - target.left) + 1), 1831 False); 1832 } 1833 } 1834} 1835 1836/* 1837 * Modifies the video-attributes only - so selection (not a video attribute) is 1838 * unaffected. Colors and double-size flags are unaffected as well. 1839 * 1840 * FIXME: our representation for "invisible" does not work with this operation, 1841 * since the attribute byte is fully-allocated for other flags. The logic 1842 * is shown for INVISIBLE because it's harmless, and useful in case the 1843 * CHARDRAWN or PROTECTED flags are reassigned. 1844 */ 1845void 1846ScrnMarkRectangle(XtermWidget xw, 1847 XTermRect * target, 1848 Bool reverse, 1849 int nparam, 1850 int *params) 1851{ 1852 TScreen *screen = &(xw->screen); 1853 Bool exact = (screen->cur_decsace == 2); 1854 1855 TRACE(("%s %s\n", 1856 reverse ? "reversing" : "marking", 1857 (exact 1858 ? "rectangle" 1859 : "region"))); 1860 1861 if (validRect(xw, target)) { 1862 int top = target->top - 1; 1863 int bottom = target->bottom - 1; 1864 int row, col; 1865 int n; 1866 1867 for (row = top; row <= bottom; ++row) { 1868 int left = ((exact || (row == top)) 1869 ? (target->left - 1) 1870 : getMinCol(screen)); 1871 int right = ((exact || (row == bottom)) 1872 ? (target->right - 1) 1873 : getMaxCol(screen)); 1874 1875 TRACE(("marking %d [%d..%d]\n", row, left, right)); 1876 for (col = left; col <= right; ++col) { 1877 unsigned flags = SCRN_BUF_ATTRS(screen, row)[col]; 1878 1879 for (n = 0; n < nparam; ++n) { 1880#if OPT_TRACE 1881 if (row == top && col == left) 1882 TRACE(("attr param[%d] %d\n", n + 1, params[n])); 1883#endif 1884 if (reverse) { 1885 switch (params[n]) { 1886 case 1: 1887 flags ^= BOLD; 1888 break; 1889 case 4: 1890 flags ^= UNDERLINE; 1891 break; 1892 case 5: 1893 flags ^= BLINK; 1894 break; 1895 case 7: 1896 flags ^= INVERSE; 1897 break; 1898 case 8: 1899 flags ^= INVISIBLE; 1900 break; 1901 } 1902 } else { 1903 switch (params[n]) { 1904 case 0: 1905 flags &= ~SGR_MASK; 1906 break; 1907 case 1: 1908 flags |= BOLD; 1909 break; 1910 case 4: 1911 flags |= UNDERLINE; 1912 break; 1913 case 5: 1914 flags |= BLINK; 1915 break; 1916 case 7: 1917 flags |= INVERSE; 1918 break; 1919 case 8: 1920 flags |= INVISIBLE; 1921 break; 1922 case 22: 1923 flags &= ~BOLD; 1924 break; 1925 case 24: 1926 flags &= ~UNDERLINE; 1927 break; 1928 case 25: 1929 flags &= ~BLINK; 1930 break; 1931 case 27: 1932 flags &= ~INVERSE; 1933 break; 1934 case 28: 1935 flags &= ~INVISIBLE; 1936 break; 1937 } 1938 } 1939 } 1940#if OPT_TRACE 1941 if (row == top && col == left) 1942 TRACE(("first mask-change is %#x\n", 1943 SCRN_BUF_ATTRS(screen, row)[col] ^ flags)); 1944#endif 1945 SCRN_BUF_ATTRS(screen, row)[col] = flags; 1946 } 1947 } 1948 ScrnRefresh(xw, 1949 (target->top - 1), 1950 (exact ? (target->left - 1) : getMinCol(screen)), 1951 (target->bottom - target->top) + 1, 1952 (exact 1953 ? ((target->right - target->left) + 1) 1954 : (getMaxCol(screen) - getMinCol(screen) + 1)), 1955 False); 1956 } 1957} 1958 1959/* 1960 * Resets characters to space, except where prohibited by DECSCA. Video 1961 * attributes (including color) are untouched. 1962 */ 1963void 1964ScrnWipeRectangle(XtermWidget xw, 1965 XTermRect * target) 1966{ 1967 TScreen *screen = &(xw->screen); 1968 1969 TRACE(("wiping rectangle\n")); 1970 1971 if (validRect(xw, target)) { 1972 int top = target->top - 1; 1973 int bottom = target->bottom - 1; 1974 int row, col; 1975 1976 for (row = top; row <= bottom; ++row) { 1977 int left = (target->left - 1); 1978 int right = (target->right - 1); 1979 1980 TRACE(("wiping %d [%d..%d]\n", row, left, right)); 1981 for (col = left; col <= right; ++col) { 1982 if (!((screen->protected_mode == DEC_PROTECT) 1983 && (SCRN_BUF_ATTRS(screen, row)[col] & PROTECTED))) { 1984 SCRN_BUF_ATTRS(screen, row)[col] |= CHARDRAWN; 1985 SCRN_BUF_CHARS(screen, row)[col] = ' '; 1986 if_OPT_WIDE_CHARS(screen, { 1987 int off; 1988 for (off = OFF_WIDEC; off < MAX_PTRS; ++off) { 1989 memset(SCREEN_PTR(screen, row, off) + col, 0, 1); 1990 } 1991 }) 1992 } 1993 } 1994 } 1995 ScrnUpdate(xw, 1996 (target->top - 1), 1997 (target->left - 1), 1998 (target->bottom - target->top) + 1, 1999 ((target->right - target->left) + 1), 2000 False); 2001 } 2002} 2003#endif /* OPT_DEC_RECTOPS */ 2004