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