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