screen.c revision 5307cd1a
1/* $XTermId: screen.c,v 1.627 2022/10/23 22:57:40 tom Exp $ */ 2 3/* 4 * Copyright 1999-2022,2023 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(xw, 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(xw, 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 (void) recurse; 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((size_t) 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((size_t) 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 /* 1989 * The dimensions passed to this function include the status-line. 1990 * Discount that here (to obtain the actual rows/columns), and save 1991 * the contents of the status-line, to repaint it after resizing. 1992 */ 1993 TRACE(("...StatusShown %d/%d\n", IsStatusShown(screen), screen->status_shown)); 1994 if (IsStatusShown(screen)) { 1995 int oldRow = MaxRows(screen); 1996 int newRow = rows - StatusLineRows; 1997 LineData *oldLD; 1998 TRACE(("...status line is currently on row %d(%d-%d) vs %d\n", 1999 oldRow, 2000 MaxRows(screen), 2001 (screen->status_shown ? 0 : StatusLineRows), 2002 rows)); 2003 oldLD = getLineData(screen, oldRow); 2004 TRACE(("...copying:%s\n", 2005 visibleIChars(oldLD->charData, 2006 oldLD->lineSize))); 2007 TRACE(("...will move status-line from row %d to %d\n", 2008 oldRow, 2009 newRow)); 2010 savedStatus = allocLineData(screen, oldLD); 2011 copyLineData(savedStatus, oldLD); 2012 TRACE(("...copied::%s\n", 2013 visibleIChars(savedStatus->charData, 2014 savedStatus->lineSize))); 2015 TRACE(("...discount a row for status-line\n")); 2016 rows = newRow; 2017 height -= FontHeight(screen) * StatusLineRows; 2018 } 2019#endif 2020 2021 if (screen->is_running) { 2022 /* clear the right and bottom internal border because of NorthWest 2023 gravity might have left junk on the right and bottom edges */ 2024 if (width >= (int) FullWidth(screen)) { 2025 xtermClear2(xw, 2026 FullWidth(screen), 0, /* right edge */ 2027 0, (unsigned) height); /* from top to bottom */ 2028 } 2029 if (height >= (int) FullHeight(screen)) { 2030 xtermClear2(xw, 2031 0, FullHeight(screen), /* bottom */ 2032 (unsigned) width, 0); /* all across the bottom */ 2033 } 2034 } 2035 2036 /* update buffers if the screen has changed size */ 2037 if (forced) { 2038 ; 2039 } else if (MaxRows(screen) != rows || MaxCols(screen) != cols) { 2040 int delta_rows = rows - MaxRows(screen); 2041#if OPT_TRACE 2042 int delta_cols = cols - MaxCols(screen); 2043#endif 2044 2045 TRACE(("...ScreenResize chars %dx%d delta %dx%d\n", 2046 rows, cols, delta_rows, delta_cols)); 2047 2048 if (screen->is_running) { 2049 if (screen->cursor_state) 2050 HideCursor(xw); 2051 2052 /* 2053 * The non-visible buffer is simple, since we will not copy data 2054 * to/from the saved-lines. Do that first. 2055 */ 2056 if (screen->editBuf_index[!screen->whichBuf]) { 2057 (void) Reallocate(xw, 2058 &screen->editBuf_index[!screen->whichBuf], 2059 &screen->editBuf_data[!screen->whichBuf], 2060 (unsigned) rows, 2061 (unsigned) cols, 2062 (unsigned) MaxRows(screen)); 2063 } 2064 2065 /* 2066 * The save-lines buffer may change width, but will not change its 2067 * height. Deal with the cases where we copy data to/from the 2068 * saved-lines buffer. 2069 */ 2070 if (GravityIsSouthWest(xw) 2071 && delta_rows 2072 && screen->saveBuf_index != 0) { 2073 2074 if (delta_rows < 0) { 2075 unsigned move_up = (unsigned) (-delta_rows); 2076 int amount = ((MaxRows(screen) - (int) move_up - 1) 2077 - screen->cur_row); 2078 2079 if (amount < 0) { 2080 /* move line-data from visible-buffer to save-buffer */ 2081 saveEditBufLines(screen, (unsigned) -amount); 2082 move_down_by = amount; 2083 } else { 2084 move_down_by = 0; 2085 } 2086 2087 /* decrease size of visible-buffer */ 2088 (void) Reallocate(xw, 2089 &screen->editBuf_index[screen->whichBuf], 2090 &screen->editBuf_data[screen->whichBuf], 2091 (unsigned) rows, 2092 (unsigned) cols, 2093 (unsigned) MaxRows(screen)); 2094 TRACE_SCRNBUF("reallocEDIT", 2095 screen, 2096 screen->editBuf_index[screen->whichBuf], 2097 rows); 2098 } else { 2099 unsigned move_down = (unsigned) delta_rows; 2100 long unsave_fifo; 2101 ScrnBuf dst; 2102 int amount; 2103 2104 if ((int) move_down > screen->savedlines) { 2105 move_down = (unsigned) screen->savedlines; 2106 } 2107 move_down_by = (int) move_down; 2108 amount = rows - (int) move_down; 2109 2110 /* increase size of visible-buffer */ 2111 (void) Reallocate(xw, 2112 &screen->editBuf_index[screen->whichBuf], 2113 &screen->editBuf_data[screen->whichBuf], 2114 (unsigned) rows, 2115 (unsigned) cols, 2116 (unsigned) MaxRows(screen)); 2117 2118 dst = screen->editBuf_index[screen->whichBuf]; 2119 TRACE_SCRNBUF("reallocEDIT", screen, dst, rows); 2120 2121 TRACE(("...%smoving pointers in editBuf (compare %d %d)\n", 2122 (amount > 0 2123 ? "" 2124 : "SKIP "), 2125 rows, 2126 move_down)); 2127 if (amount > 0) { 2128 /* shift lines in visible-buffer to make room */ 2129 SaveLineData(dst, (unsigned) amount, (size_t) move_down); 2130 2131 MoveLineData(dst, 2132 move_down, 2133 0, 2134 (unsigned) amount); 2135 2136 TRACE(("...reuse %d lines storage in editBuf\n", move_down)); 2137 RestoreLineData(dst, 2138 0, 2139 move_down); 2140 2141 TRACE_SCRNBUF("shifted", screen, dst, rows); 2142 } 2143 2144 /* copy line-data from save-buffer to visible-buffer */ 2145 unsaveEditBufLines(screen, dst, move_down); 2146 TRACE_SCRNBUF("copied", screen, dst, rows); 2147 2148 unsave_fifo = (long) move_down; 2149 if (screen->saved_fifo < (int) unsave_fifo) 2150 unsave_fifo = screen->saved_fifo; 2151 2152 /* free up storage in fifo from the copied lines */ 2153 while (unsave_fifo-- > 0) { 2154 deleteScrollback(screen); 2155 } 2156 2157 /* recover storage in save-buffer */ 2158 } 2159 } else { 2160 (void) Reallocate(xw, 2161 &screen->editBuf_index[screen->whichBuf], 2162 &screen->editBuf_data[screen->whichBuf], 2163 (unsigned) rows, 2164 (unsigned) cols, 2165 (unsigned) MaxRows(screen)); 2166 } 2167 2168 screen->visbuf = VisBuf(screen); 2169 } 2170 2171 AdjustSavedCursor(xw, move_down_by); 2172 set_max_row(screen, screen->max_row + delta_rows); 2173 set_max_col(screen, cols - 1); 2174 2175 if (screen->is_running) { 2176 if (GravityIsSouthWest(xw)) { 2177 screen->savedlines -= move_down_by; 2178 if (screen->savedlines < 0) 2179 screen->savedlines = 0; 2180 if (screen->savedlines > screen->savelines) 2181 screen->savedlines = screen->savelines; 2182 if (screen->topline < -screen->savedlines) 2183 screen->topline = -screen->savedlines; 2184 set_cur_row(screen, screen->cur_row + move_down_by); 2185 screen->cursorp.row += move_down_by; 2186 ScrollSelection(screen, move_down_by, True); 2187 } 2188 } 2189 2190 /* adjust scrolling region */ 2191 resetMargins(xw); 2192 UIntClr(*flags, ORIGIN); 2193 2194 if (screen->cur_row > screen->max_row) 2195 set_cur_row(screen, screen->max_row); 2196 if (screen->cur_col > screen->max_col) 2197 set_cur_col(screen, screen->max_col); 2198 2199 screen->fullVwin.height = height - border; 2200 screen->fullVwin.width = width - border - screen->fullVwin.sb_info.width; 2201 2202 scroll_displayed_graphics(xw, -move_down_by); 2203 } else if (FullHeight(screen) == height && FullWidth(screen) == width) { 2204#if OPT_STATUS_LINE 2205 if (savedStatus != NULL) { 2206 TRACE(("...status line is currently saved!\n")); 2207 freeLineData(screen, savedStatus); 2208 } 2209#endif 2210 return; /* nothing has changed at all */ 2211 } 2212 2213 screen->fullVwin.fullheight = (Dimension) height; 2214 screen->fullVwin.fullwidth = (Dimension) width; 2215 2216 ResizeScrollBar(xw); 2217 ResizeSelection(screen, rows, cols); 2218 2219#ifndef NO_ACTIVE_ICON 2220 if (screen->iconVwin.window) { 2221 XWindowChanges changes; 2222 screen->iconVwin.width = 2223 MaxCols(screen) * screen->iconVwin.f_width; 2224 2225 screen->iconVwin.height = 2226 MaxRows(screen) * screen->iconVwin.f_height; 2227 2228 changes.width = screen->iconVwin.fullwidth = 2229 (Dimension) ((unsigned) screen->iconVwin.width 2230 + 2 * xw->misc.icon_border_width); 2231 2232 changes.height = screen->iconVwin.fullheight = 2233 (Dimension) ((unsigned) screen->iconVwin.height 2234 + 2 * xw->misc.icon_border_width); 2235 2236 changes.border_width = (int) xw->misc.icon_border_width; 2237 2238 TRACE(("resizing icon window %dx%d\n", changes.height, changes.width)); 2239 XConfigureWindow(XtDisplay(xw), screen->iconVwin.window, 2240 CWWidth | CWHeight | CWBorderWidth, &changes); 2241 } 2242#endif /* NO_ACTIVE_ICON */ 2243 2244#if OPT_STATUS_LINE 2245 if (savedStatus != NULL) { 2246 int newRow = LastRowNumber(screen); 2247 LineData *newLD = getLineData(screen, newRow); 2248 TRACE(("...status line is currently on row %d\n", 2249 LastRowNumber(screen))); 2250 copyLineData(newLD, savedStatus); 2251 TRACE(("...copied::%s\n", 2252 visibleIChars(newLD->charData, 2253 newLD->lineSize))); 2254 freeLineData(screen, savedStatus); 2255 } 2256#endif 2257 2258#ifdef TTYSIZE_STRUCT 2259 if (update_winsize(screen, rows, cols, height, width) == 0) { 2260#if defined(SIGWINCH) && defined(TIOCGPGRP) 2261 if (screen->pid > 1) { 2262 int pgrp; 2263 2264 TRACE(("getting process-group\n")); 2265 if (ioctl(screen->respond, TIOCGPGRP, &pgrp) != -1) { 2266 TRACE(("sending SIGWINCH to process group %d\n", pgrp)); 2267 kill_process_group(pgrp, SIGWINCH); 2268 } 2269 } 2270#endif /* SIGWINCH */ 2271 } 2272#else 2273 TRACE(("ScreenResize cannot do anything to pty\n")); 2274#endif /* TTYSIZE_STRUCT */ 2275 return; 2276} 2277 2278/* 2279 * Return true if any character cell starting at [row,col], for len-cells is 2280 * nonnull. 2281 */ 2282Bool 2283non_blank_line(TScreen *screen, 2284 int row, 2285 int col, 2286 int len) 2287{ 2288 int i; 2289 Bool found = False; 2290 LineData *ld = getLineData(screen, row); 2291 2292 if (ld != 0) { 2293 for (i = col; i < len; i++) { 2294 if (ld->charData[i]) { 2295 found = True; 2296 break; 2297 } 2298 } 2299 } 2300 return found; 2301} 2302 2303/* 2304 * Limit/map rectangle parameters. 2305 */ 2306#define minRectRow(screen) (getMinRow(screen) + 1) 2307#define minRectCol(screen) (getMinCol(screen) + 1) 2308#define maxRectRow(screen) (getMaxRow(screen) + 1) 2309#define maxRectCol(screen) (getMaxCol(screen) + 1) 2310 2311static int 2312limitedParseRow(XtermWidget xw, int row, int err) 2313{ 2314 TScreen *screen = TScreenOf(xw); 2315 int min_row = minRectRow(screen); 2316 int max_row = maxRectRow(screen) + err; 2317 2318 if (xw->flags & ORIGIN) 2319 row += screen->top_marg; 2320 2321 if (row < min_row) 2322 row = min_row; 2323 else if (row > max_row) 2324 row = max_row; 2325 2326 return row; 2327} 2328 2329static int 2330limitedParseCol(XtermWidget xw, int col, int err) 2331{ 2332 TScreen *screen = TScreenOf(xw); 2333 int min_col = minRectCol(screen); 2334 int max_col = maxRectCol(screen) + err; 2335 2336 if (xw->flags & ORIGIN) 2337 col += screen->lft_marg; 2338 2339 if (col < min_col) 2340 col = min_col; 2341 else if (col > max_col) 2342 col = max_col; 2343 2344 return col; 2345} 2346 2347#define LimitedParse(num, func, dft, err) \ 2348 func(xw, (nparams > num && params[num] > 0) ? params[num] : dft, err) 2349 2350/* 2351 * Copy the rectangle boundaries into a struct, providing default values as 2352 * needed. 2353 */ 2354void 2355xtermParseRect(XtermWidget xw, int nparams, int *params, XTermRect *target) 2356{ 2357 TScreen *screen = TScreenOf(xw); 2358 2359 memset(target, 0, sizeof(*target)); 2360 target->top = LimitedParse(0, limitedParseRow, minRectRow(screen), 1); 2361 target->left = LimitedParse(1, limitedParseCol, minRectCol(screen), 1); 2362 target->bottom = LimitedParse(2, limitedParseRow, maxRectRow(screen), 0); 2363 target->right = LimitedParse(3, limitedParseCol, maxRectCol(screen), 0); 2364 TRACE(("parsed %d params for rectangle %d,%d %d,%d default %d,%d %d,%d\n", 2365 nparams, 2366 target->top, 2367 target->left, 2368 target->bottom, 2369 target->right, 2370 minRectRow(screen), 2371 minRectCol(screen), 2372 maxRectRow(screen), 2373 maxRectCol(screen))); 2374} 2375 2376static Bool 2377validRect(XtermWidget xw, XTermRect *target) 2378{ 2379 TScreen *screen = TScreenOf(xw); 2380 Bool result = (target != 0 2381 && target->top >= minRectRow(screen) 2382 && target->left >= minRectCol(screen) 2383 && target->top <= target->bottom 2384 && target->left <= target->right 2385 && target->top <= maxRectRow(screen) 2386 && target->right <= maxRectCol(screen)); 2387 2388 TRACE(("comparing against screensize %dx%d, is%s valid\n", 2389 maxRectRow(screen), 2390 maxRectCol(screen), 2391 result ? "" : " NOT")); 2392 return result; 2393} 2394 2395/* 2396 * Fills a rectangle with the given 8-bit character and video-attributes. 2397 * Colors and double-size attribute are unmodified. 2398 */ 2399void 2400ScrnFillRectangle(XtermWidget xw, 2401 XTermRect *target, 2402 int value, 2403 unsigned flags, 2404 Bool keepColors) 2405{ 2406 IChar actual = (IChar) value; 2407 TScreen *screen = TScreenOf(xw); 2408 2409 TRACE(("filling rectangle with '%s' flags %#x\n", 2410 visibleIChars(&actual, 1), flags)); 2411 if (validRect(xw, target)) { 2412 LineData *ld; 2413 int top = (target->top - 1); 2414 int left = (target->left - 1); 2415 int right = (target->right - 1); 2416 int bottom = (target->bottom - 1); 2417 int numcols = (right - left) + 1; 2418 int numrows = (bottom - top) + 1; 2419 unsigned attrs = flags; 2420 int row, col; 2421 int b_left = 0; 2422 int b_right = 0; 2423 2424 (void) numcols; 2425 2426 attrs &= ATTRIBUTES; 2427 attrs |= CHARDRAWN; 2428 for (row = bottom; row >= top; row--) { 2429 ld = getLineData(screen, row); 2430 2431 TRACE(("filling %d [%d..%d]\n", row, left, left + numcols)); 2432 2433 if_OPT_WIDE_CHARS(screen, { 2434 if (left > 0) { 2435 if (ld->charData[left] == HIDDEN_CHAR) { 2436 b_left = 1; 2437 Clear1Cell(ld, left - 1); 2438 Clear1Cell(ld, left); 2439 } 2440 } 2441 if (right + 1 < (int) ld->lineSize) { 2442 if (ld->charData[right + 1] == HIDDEN_CHAR) { 2443 b_right = 1; 2444 Clear1Cell(ld, right); 2445 Clear1Cell(ld, right + 1); 2446 } 2447 } 2448 }); 2449 2450 /* 2451 * Fill attributes, preserving colors. 2452 */ 2453 for (col = left; col <= right; ++col) { 2454 unsigned temp = ld->attribs[col]; 2455 2456 if (!keepColors) { 2457 UIntClr(temp, (FG_COLOR | BG_COLOR)); 2458 } 2459 temp = attrs | (temp & (FG_COLOR | BG_COLOR)) | CHARDRAWN; 2460 ld->attribs[col] = (IAttr) temp; 2461 if_OPT_ISO_COLORS(screen, { 2462 if (attrs & (FG_COLOR | BG_COLOR)) { 2463 ld->color[col] = xtermColorPair(xw); 2464 } 2465 }); 2466 } 2467 2468 for (col = left; col <= right; ++col) 2469 ld->charData[col] = actual; 2470 2471 if_OPT_WIDE_CHARS(screen, { 2472 size_t off; 2473 for_each_combData(off, ld) { 2474 memset(ld->combData[off] + left, 2475 0, 2476 (size_t) numcols * sizeof(CharData)); 2477 } 2478 }) 2479 } 2480 chararea_clear_displayed_graphics(screen, 2481 left, 2482 top, 2483 numcols, numrows); 2484 ScrnUpdate(xw, 2485 top, 2486 left - b_left, 2487 numrows, 2488 numcols + b_left + b_right, 2489 False); 2490 } 2491} 2492 2493#if OPT_DEC_RECTOPS 2494/* 2495 * Copies the source rectangle to the target location, including video 2496 * attributes. 2497 * 2498 * This implementation ignores page numbers. 2499 * 2500 * The reference manual does not indicate if it handles overlapping copy 2501 * properly - so we make a local copy of the source rectangle first, then apply 2502 * the target from that. 2503 */ 2504void 2505ScrnCopyRectangle(XtermWidget xw, XTermRect *source, int nparam, int *params) 2506{ 2507 TScreen *screen = TScreenOf(xw); 2508 2509 TRACE(("copying rectangle\n")); 2510 2511 if (nparam > 4) 2512 nparam = 4; 2513 2514 if (validRect(xw, source)) { 2515 XTermRect target; 2516 xtermParseRect(xw, 2517 ((nparam > 2) ? 2 : nparam), 2518 params, 2519 &target); 2520 if (validRect(xw, &target)) { 2521 Cardinal high = (Cardinal) (source->bottom - source->top) + 1; 2522 Cardinal wide = (Cardinal) (source->right - source->left) + 1; 2523 Cardinal size = (high * wide); 2524 int row, col; 2525 Cardinal j, k; 2526 LineData *ld; 2527 int b_left = 0; 2528 int b_right = 0; 2529 2530 CellData *cells = newCellData(xw, size); 2531 2532 if (cells != 0) { 2533 2534 TRACE(("OK - make copy %dx%d\n", high, wide)); 2535 target.bottom = target.top + (int) (high - 1); 2536 target.right = target.left + (int) (wide - 1); 2537 2538 for (row = source->top - 1; row < source->bottom; ++row) { 2539 ld = getLineData(screen, row); 2540 if (ld == 0) 2541 continue; 2542 j = (Cardinal) (row - (source->top - 1)); 2543 TRACE2(("ROW %d\n", row + 1)); 2544 for (col = source->left - 1; col < source->right; ++col) { 2545 k = (Cardinal) (col - (source->left - 1)); 2546 saveCellData(screen, cells, 2547 (j * wide) + k, 2548 ld, source, col); 2549 } 2550 } 2551 for (row = target.top - 1; row < target.bottom; ++row) { 2552 ld = getLineData(screen, row); 2553 if (ld == 0) 2554 continue; 2555 j = (Cardinal) (row - (target.top - 1)); 2556 TRACE2(("ROW %d\n", row + 1)); 2557 for (col = target.left - 1; col < target.right; ++col) { 2558 k = (Cardinal) (col - (target.left - 1)); 2559 if (row >= getMinRow(screen) 2560 && row <= getMaxRow(screen) 2561 && col >= getMinCol(screen) 2562 && col <= getMaxCol(screen) 2563 && (j < high) 2564 && (k < wide)) { 2565 if_OPT_WIDE_CHARS(screen, { 2566 if (ld->charData[col] == HIDDEN_CHAR 2567 && (col + 1) == target.left) { 2568 b_left = 1; 2569 Clear1Cell(ld, col - 1); 2570 } 2571 if ((col + 1) == target.right 2572 && ld->charData[col] == HIDDEN_CHAR) { 2573 b_right = 1; 2574 } 2575 }); 2576 restoreCellData(screen, cells, 2577 (j * wide) + k, 2578 ld, &target, col); 2579 } 2580 ld->attribs[col] |= CHARDRAWN; 2581 } 2582#if OPT_BLINK_TEXT 2583 if (LineHasBlinking(screen, ld)) { 2584 LineSetBlinked(ld); 2585 } else { 2586 LineClrBlinked(ld); 2587 } 2588#endif 2589 } 2590 free(cells); 2591 2592 ScrnUpdate(xw, 2593 (target.top - 1), 2594 (target.left - (1 + b_left)), 2595 (target.bottom - target.top) + 1, 2596 ((target.right - target.left) + (1 + b_left + b_right)), 2597 False); 2598 } 2599 } 2600 } 2601} 2602 2603/* 2604 * Modifies the video-attributes only - so selection (not a video attribute) is 2605 * unaffected. Colors and double-size flags are unaffected as well. 2606 * 2607 * FIXME: our representation for "invisible" does not work with this operation, 2608 * since the attribute byte is fully-allocated for other flags. The logic 2609 * is shown for INVISIBLE because it's harmless, and useful in case the 2610 * CHARDRAWN or PROTECTED flags are reassigned. 2611 */ 2612void 2613ScrnMarkRectangle(XtermWidget xw, 2614 XTermRect *target, 2615 Bool reverse, 2616 int nparam, 2617 int *params) 2618{ 2619 TScreen *screen = TScreenOf(xw); 2620 Bool exact = (screen->cur_decsace == 2); 2621 2622 TRACE(("%s %s\n", 2623 reverse ? "reversing" : "marking", 2624 (exact 2625 ? "rectangle" 2626 : "region"))); 2627 2628 if (validRect(xw, target)) { 2629 LineData *ld; 2630 int top = target->top - 1; 2631 int bottom = target->bottom - 1; 2632 int row, col; 2633 int n; 2634 2635 for (row = top; row <= bottom; ++row) { 2636 int left = ((exact || (row == top)) 2637 ? (target->left - 1) 2638 : getMinCol(screen)); 2639 int right = ((exact || (row == bottom)) 2640 ? (target->right - 1) 2641 : getMaxCol(screen)); 2642 2643 ld = getLineData(screen, row); 2644 2645 TRACE(("marking %d [%d..%d]\n", row, left, right)); 2646 for (col = left; col <= right; ++col) { 2647 unsigned flags = ld->attribs[col]; 2648 2649 for (n = 0; n < nparam; ++n) { 2650#if OPT_TRACE 2651 if (row == top && col == left) 2652 TRACE(("attr param[%d] %d\n", n + 1, params[n])); 2653#endif 2654 if (reverse) { 2655 switch (params[n]) { 2656 case 1: 2657 flags ^= BOLD; 2658 break; 2659 case 4: 2660 flags ^= UNDERLINE; 2661 break; 2662 case 5: 2663 flags ^= BLINK; 2664 break; 2665 case 7: 2666 flags ^= INVERSE; 2667 break; 2668 case 8: 2669 flags ^= INVISIBLE; 2670 break; 2671 } 2672 } else { 2673 switch (params[n]) { 2674 case 0: 2675 UIntClr(flags, SGR_MASK); 2676 break; 2677 case 1: 2678 flags |= BOLD; 2679 break; 2680 case 4: 2681 flags |= UNDERLINE; 2682 break; 2683 case 5: 2684 flags |= BLINK; 2685 break; 2686 case 7: 2687 flags |= INVERSE; 2688 break; 2689 case 8: 2690 flags |= INVISIBLE; 2691 break; 2692 case 22: 2693 UIntClr(flags, BOLD); 2694 break; 2695 case 24: 2696 UIntClr(flags, UNDERLINE); 2697 break; 2698 case 25: 2699 UIntClr(flags, BLINK); 2700 break; 2701 case 27: 2702 UIntClr(flags, INVERSE); 2703 break; 2704 case 28: 2705 UIntClr(flags, INVISIBLE); 2706 break; 2707 } 2708 } 2709 } 2710#if OPT_TRACE 2711 if (row == top && col == left) 2712 TRACE(("first mask-change is %#x\n", 2713 ld->attribs[col] ^ flags)); 2714#endif 2715 ld->attribs[col] = (IAttr) flags; 2716 } 2717 } 2718 ScrnRefresh(xw, 2719 (target->top - 1), 2720 (exact ? (target->left - 1) : getMinCol(screen)), 2721 (target->bottom - target->top) + 1, 2722 (exact 2723 ? ((target->right - target->left) + 1) 2724 : (getMaxCol(screen) - getMinCol(screen) + 1)), 2725 True); 2726 } 2727} 2728 2729/* 2730 * Resets characters to space, except where prohibited by DECSCA. Video 2731 * attributes (including color) are untouched. 2732 */ 2733void 2734ScrnWipeRectangle(XtermWidget xw, 2735 XTermRect *target) 2736{ 2737 TScreen *screen = TScreenOf(xw); 2738 2739 TRACE(("wiping rectangle\n")); 2740 2741#define IsProtected(ld, col) \ 2742 ((screen->protected_mode == DEC_PROTECT) \ 2743 && (ld->attribs[col] & PROTECTED)) 2744 2745 if (validRect(xw, target)) { 2746 LineData *ld; 2747 int top = target->top - 1; 2748 int left = target->left - 1; 2749 int right = target->right - 1; 2750 int bottom = target->bottom - 1; 2751 int numcols = (right - left) + 1; 2752 int numrows = (bottom - top) + 1; 2753 int row, col; 2754 int b_left = 0; 2755 int b_right = 0; 2756 2757 for (row = top; row <= bottom; ++row) { 2758 TRACE(("wiping %d [%d..%d]\n", row, left, right)); 2759 2760 ld = getLineData(screen, row); 2761 2762 if_OPT_WIDE_CHARS(screen, { 2763 if (left > 0 && !IsProtected(ld, left)) { 2764 if (ld->charData[left] == HIDDEN_CHAR) { 2765 b_left = 1; 2766 Clear1Cell(ld, left - 1); 2767 Clear1Cell(ld, left); 2768 } 2769 } 2770 if (right + 1 < (int) ld->lineSize && !IsProtected(ld, right)) { 2771 if (ld->charData[right + 1] == HIDDEN_CHAR) { 2772 b_right = 1; 2773 Clear1Cell(ld, right); 2774 Clear1Cell(ld, right + 1); 2775 } 2776 } 2777 }); 2778 2779 for (col = left; col <= right; ++col) { 2780 if (!IsProtected(ld, col)) { 2781 ld->attribs[col] |= CHARDRAWN; 2782 Clear1Cell(ld, col); 2783 } 2784 } 2785 } 2786 chararea_clear_displayed_graphics(screen, 2787 left, 2788 top, 2789 numcols, numrows); 2790 ScrnUpdate(xw, 2791 top, 2792 left - b_left, 2793 numrows, 2794 numcols + b_left + b_right, 2795 False); 2796 } 2797} 2798 2799/* 2800 * Compute a checksum, ignoring the page number (since we have only one page). 2801 */ 2802void 2803xtermCheckRect(XtermWidget xw, 2804 int nparam, 2805 int *params, 2806 int *result) 2807{ 2808 TScreen *screen = TScreenOf(xw); 2809 XTermRect target; 2810 LineData *ld; 2811 int total = 0; 2812 int trimmed = 0; 2813 int mode = screen->checksum_ext; 2814 2815 TRACE(("xtermCheckRect: %s%s%s%s%s%s%s\n", 2816 (mode == csDEC) ? "DEC" : "checksumExtension", 2817 (mode & csPOSITIVE) ? " !negative" : "", 2818 (mode & csATTRIBS) ? " !attribs" : "", 2819 (mode & csNOTRIM) ? " !trimmed" : "", 2820 (mode & csDRAWN) ? " !drawn" : "", 2821 (mode & csBYTE) ? " !byte" : "", 2822 (mode & cs8TH) ? " !7bit" : "")); 2823 2824 if (nparam > 2) { 2825 nparam -= 2; 2826 params += 2; 2827 } 2828 xtermParseRect(xw, nparam, params, &target); 2829 if (validRect(xw, &target)) { 2830 int top = target.top - 1; 2831 int bottom = target.bottom - 1; 2832 int row, col; 2833 Boolean first = True; 2834 int embedded = 0; 2835 DECNRCM_codes my_GR = screen->gsets[(int) screen->curgr]; 2836 2837 for (row = top; row <= bottom; ++row) { 2838 int left = (target.left - 1); 2839 int right = (target.right - 1); 2840 2841 ld = getLineData(screen, row); 2842 if (ld == 0) 2843 continue; 2844 for (col = left; col <= right && col < (int) ld->lineSize; ++col) { 2845 int ch = ((ld->attribs[col] & CHARDRAWN) 2846 ? (int) ld->charData[col] 2847 : ' '); 2848 if (!(mode & csBYTE)) { 2849 unsigned c2 = (unsigned) ch; 2850 if (c2 > 0x7f && my_GR != nrc_ASCII) { 2851 c2 = xtermCharSetIn(xw, c2, my_GR); 2852 if (!(mode & cs8TH) && (c2 < 0x80)) 2853 c2 |= 0x80; 2854 } 2855 ch = (c2 & 0xff); 2856 } 2857 if (!(mode & csATTRIBS)) { 2858 if (ld->attribs[col] & UNDERLINE) 2859 ch += 0x10; 2860 if (ld->attribs[col] & INVERSE) 2861 ch += 0x20; 2862 if (ld->attribs[col] & BLINK) 2863 ch += 0x40; 2864 if (ld->attribs[col] & BOLD) 2865 ch += 0x80; 2866 } 2867 if (first || (ch != ' ') || (ld->attribs[col] & DRAWX_MASK)) { 2868 trimmed += ch + embedded; 2869 embedded = 0; 2870 } else if (ch == ' ') { 2871 if ((mode & csNOTRIM)) 2872 embedded += ch; 2873 } 2874 if ((ld->attribs[col] & CHARDRAWN)) { 2875 total += ch; 2876 if_OPT_WIDE_CHARS(screen, { 2877 /* FIXME - not counted if trimming blanks */ 2878 if (!(mode & csBYTE)) { 2879 size_t off; 2880 for_each_combData(off, ld) { 2881 total += (int) ld->combData[off][col]; 2882 } 2883 } 2884 }) 2885 } else if (!(mode & csDRAWN)) { 2886 total += ch; 2887 } 2888 first = ((mode & csNOTRIM) != 0) ? True : False; 2889 } 2890 if (!(mode & csNOTRIM)) { 2891 embedded = 0; 2892 first = False; 2893 } 2894 } 2895 } 2896 if (!(mode & csNOTRIM)) 2897 total = trimmed; 2898 if (!(mode & csPOSITIVE)) 2899 total = -total; 2900 *result = total; 2901} 2902#endif /* OPT_DEC_RECTOPS */ 2903 2904#if OPT_MAXIMIZE 2905 2906static _Xconst char * 2907ewmhProperty(int mode) 2908{ 2909 _Xconst char *result; 2910 switch (mode) { 2911 default: 2912 result = 0; 2913 break; 2914 case 1: 2915 result = "_NET_WM_STATE_FULLSCREEN"; 2916 break; 2917 case 2: 2918 result = "_NET_WM_STATE_MAXIMIZED_VERT"; 2919 break; 2920 case 3: 2921 result = "_NET_WM_STATE_MAXIMIZED_HORZ"; 2922 break; 2923 } 2924 return result; 2925} 2926 2927static void 2928set_resize_increments(XtermWidget xw) 2929{ 2930 TScreen *screen = TScreenOf(xw); 2931 int min_width = (2 * screen->border) + screen->fullVwin.sb_info.width; 2932 int min_height = (2 * screen->border); 2933 XSizeHints sizehints; 2934 2935 TRACE(("set_resize_increments\n")); 2936 memset(&sizehints, 0, sizeof(XSizeHints)); 2937 sizehints.width_inc = FontWidth(screen); 2938 sizehints.height_inc = FontHeight(screen); 2939 sizehints.flags = PResizeInc; 2940 TRACE_HINTS(&sizehints); 2941 XSetWMNormalHints(screen->display, VShellWindow(xw), &sizehints); 2942 2943 TRACE(("setting values for widget %p:\n", (void *) SHELL_OF(xw))); 2944 TRACE((" base width %d\n", min_width)); 2945 TRACE((" base height %d\n", min_width)); 2946 TRACE((" min width %d\n", min_width + FontWidth(screen))); 2947 TRACE((" min height %d\n", min_width + FontHeight(screen))); 2948 TRACE((" width inc %d\n", FontWidth(screen))); 2949 TRACE((" height inc %d\n", FontHeight(screen))); 2950 2951 XtVaSetValues(SHELL_OF(xw), 2952 XtNbaseWidth, min_width, 2953 XtNbaseHeight, min_height, 2954 XtNminWidth, min_width + FontWidth(screen), 2955 XtNminHeight, min_height + FontHeight(screen), 2956 XtNwidthInc, FontWidth(screen), 2957 XtNheightInc, FontHeight(screen), 2958 (XtPointer) 0); 2959 2960 XFlush(XtDisplay(xw)); 2961} 2962 2963static void 2964unset_resize_increments(XtermWidget xw) 2965{ 2966 TScreen *screen = TScreenOf(xw); 2967 XSizeHints sizehints; 2968 2969 TRACE(("unset_resize_increments\n")); 2970 memset(&sizehints, 0, sizeof(XSizeHints)); 2971 sizehints.width_inc = 1; 2972 sizehints.height_inc = 1; 2973 sizehints.flags = PResizeInc; 2974 TRACE_HINTS(&sizehints); 2975 XSetWMNormalHints(screen->display, VShellWindow(xw), &sizehints); 2976 2977 XtVaSetValues(SHELL_OF(xw), 2978 XtNwidthInc, 1, 2979 XtNheightInc, 1, 2980 (XtPointer) 0); 2981 2982 XFlush(XtDisplay(xw)); 2983} 2984 2985static void 2986set_ewmh_hint(Display *dpy, Window window, int operation, _Xconst char *prop) 2987{ 2988 XEvent e; 2989 Atom atom_fullscreen = XInternAtom(dpy, prop, False); 2990 Atom atom_state = XInternAtom(dpy, "_NET_WM_STATE", False); 2991 2992#if OPT_TRACE 2993 const char *what = "?"; 2994 switch (operation) { 2995 case _NET_WM_STATE_ADD: 2996 what = "adding"; 2997 break; 2998 case _NET_WM_STATE_REMOVE: 2999 what = "removing"; 3000 break; 3001 } 3002 TRACE(("set_ewmh_hint %s %s\n", what, prop)); 3003#endif 3004 3005 memset(&e, 0, sizeof(e)); 3006 e.xclient.type = ClientMessage; 3007 e.xclient.message_type = atom_state; 3008 e.xclient.display = dpy; 3009 e.xclient.window = window; 3010 e.xclient.format = 32; 3011 e.xclient.data.l[0] = operation; 3012 e.xclient.data.l[1] = (long) atom_fullscreen; 3013 3014 XSendEvent(dpy, DefaultRootWindow(dpy), False, 3015 SubstructureRedirectMask, &e); 3016} 3017 3018/* 3019 * Check if the given property is supported on the root window. 3020 * 3021 * The XGetWindowProperty function returns a list of Atom's which corresponds 3022 * to the output of xprop. The actual list (ignore the manpage, which refers 3023 * to an array of 32-bit values) is constructed by _XRead32, which uses long 3024 * as a datatype. 3025 * 3026 * Alternatively, we could check _NET_WM_ALLOWED_ACTIONS on the application's 3027 * window. 3028 */ 3029static Boolean 3030probe_netwm(Display *dpy, _Xconst char *propname) 3031{ 3032 Atom atom_fullscreen = XInternAtom(dpy, propname, False); 3033 Atom atom_supported = XInternAtom(dpy, "_NET_SUPPORTED", False); 3034 Atom actual_type; 3035 int actual_format; 3036 long long_offset = 0; 3037 long long_length = 128; /* number of items to ask for at a time */ 3038 unsigned int i; 3039 unsigned long nitems, bytes_after; 3040 unsigned char *args; 3041 long *ldata; 3042 Boolean has_capability = False; 3043 Boolean rc; 3044 3045 while (!has_capability) { 3046 rc = xtermGetWinProp(dpy, 3047 DefaultRootWindow(dpy), 3048 atom_supported, 3049 long_offset, 3050 long_length, 3051 AnyPropertyType, /* req_type */ 3052 &actual_type, /* actual_type_return */ 3053 &actual_format, /* actual_format_return */ 3054 &nitems, /* nitems_return */ 3055 &bytes_after, /* bytes_after_return */ 3056 &args /* prop_return */ 3057 ); 3058 if (!rc 3059 || actual_type != XA_ATOM) { 3060 break; 3061 } 3062 ldata = (long *) (void *) args; 3063 for (i = 0; i < nitems; i++) { 3064#if OPT_TRACE > 1 3065 char *name; 3066 if ((name = XGetAtomName(dpy, ldata[i])) != 0) { 3067 TRACE(("atom[%d] = %s\n", i, name)); 3068 XFree(name); 3069 } else { 3070 TRACE(("atom[%d] = ?\n", i)); 3071 } 3072#endif 3073 if ((Atom) ldata[i] == atom_fullscreen) { 3074 has_capability = True; 3075 break; 3076 } 3077 } 3078 XFree(ldata); 3079 3080 if (!has_capability) { 3081 if (bytes_after != 0) { 3082 long remaining = (long) (bytes_after / sizeof(long)); 3083 if (long_length > remaining) 3084 long_length = remaining; 3085 long_offset += (long) nitems; 3086 } else { 3087 break; 3088 } 3089 } 3090 } 3091 3092 TRACE(("probe_netwm(%s) ->%d\n", propname, has_capability)); 3093 return has_capability; 3094} 3095 3096/* 3097 * Alter fullscreen mode for the xterm widget, if the window manager supports 3098 * that feature. 3099 */ 3100void 3101FullScreen(XtermWidget xw, int new_ewmh_mode) 3102{ 3103 TScreen *screen = TScreenOf(xw); 3104 Display *dpy = screen->display; 3105 int old_ewmh_mode; 3106 _Xconst char *oldprop; 3107 _Xconst char *newprop; 3108 3109 int which = 0; 3110 Window window; 3111 3112#if OPT_TEK4014 3113 if (TEK4014_ACTIVE(xw)) { 3114 which = 1; 3115 window = TShellWindow; 3116 } else 3117#endif 3118 window = VShellWindow(xw); 3119 3120 old_ewmh_mode = xw->work.ewmh[which].mode; 3121 oldprop = ewmhProperty(old_ewmh_mode); 3122 newprop = ewmhProperty(new_ewmh_mode); 3123 3124 TRACE(("FullScreen %d:%s -> %d:%s\n", 3125 old_ewmh_mode, NonNull(oldprop), 3126 new_ewmh_mode, NonNull(newprop))); 3127 3128 if (new_ewmh_mode == old_ewmh_mode) { 3129 TRACE(("...unchanged\n")); 3130 return; 3131 } else if (new_ewmh_mode < 0 || new_ewmh_mode > MAX_EWMH_MODE) { 3132 TRACE(("BUG: FullScreen %d\n", new_ewmh_mode)); 3133 return; 3134 } else if (new_ewmh_mode == 0) { 3135 xw->work.ewmh[which].checked[new_ewmh_mode] = True; 3136 xw->work.ewmh[which].allowed[new_ewmh_mode] = True; 3137 } else if (resource.fullscreen == esNever) { 3138 xw->work.ewmh[which].checked[new_ewmh_mode] = True; 3139 xw->work.ewmh[which].allowed[new_ewmh_mode] = False; 3140 } else if (!xw->work.ewmh[which].checked[new_ewmh_mode]) { 3141 xw->work.ewmh[which].checked[new_ewmh_mode] = True; 3142 xw->work.ewmh[which].allowed[new_ewmh_mode] = probe_netwm(dpy, newprop); 3143 } 3144 3145 if (xw->work.ewmh[which].allowed[new_ewmh_mode]) { 3146 TRACE(("...new EWMH mode is allowed\n")); 3147 if (new_ewmh_mode && !xw->work.ewmh[which].mode) { 3148 unset_resize_increments(xw); 3149 set_ewmh_hint(dpy, window, _NET_WM_STATE_ADD, newprop); 3150 } else if (xw->work.ewmh[which].mode && !new_ewmh_mode) { 3151 if (!xw->misc.resizeByPixel) { 3152 set_resize_increments(xw); 3153 } 3154 set_ewmh_hint(dpy, window, _NET_WM_STATE_REMOVE, oldprop); 3155 } else { 3156 set_ewmh_hint(dpy, window, _NET_WM_STATE_REMOVE, oldprop); 3157 set_ewmh_hint(dpy, window, _NET_WM_STATE_ADD, newprop); 3158 } 3159 xw->work.ewmh[which].mode = new_ewmh_mode; 3160 update_fullscreen(); 3161 } else { 3162 Bell(xw, XkbBI_MinorError, 100); 3163 } 3164} 3165#endif /* OPT_MAXIMIZE */ 3166