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