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