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