util.c revision e0a2b6df
1/* $XTermId: util.c,v 1.620 2014/01/15 02:02:14 tom Exp $ */ 2 3/* 4 * Copyright 1999-2013,2014 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/* util.c */ 56 57#include <xterm.h> 58 59#include <data.h> 60#include <error.h> 61#include <menu.h> 62#include <fontutils.h> 63#include <xstrings.h> 64 65#include <stdio.h> 66#include <ctype.h> 67#include <assert.h> 68 69#if OPT_WIDE_CHARS 70#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH) 71#include <wchar.h> 72#endif 73#include <wcwidth.h> 74#endif 75 76#include <graphics.h> 77 78static int handle_translated_exposure(XtermWidget xw, 79 int rect_x, 80 int rect_y, 81 int rect_width, 82 int rect_height); 83static void ClearLeft(XtermWidget xw); 84static void CopyWait(XtermWidget xw); 85static void horizontal_copy_area(XtermWidget xw, 86 int firstchar, 87 int nchars, 88 int amount); 89static void vertical_copy_area(XtermWidget xw, 90 int firstline, 91 int nlines, 92 int amount, 93 int left, 94 int right); 95 96#if OPT_WIDE_CHARS 97unsigned first_widechar; 98int (*my_wcwidth) (wchar_t); 99#endif 100 101#if OPT_WIDE_CHARS 102/* 103 * We will modify the 'n' cells beginning at the current position. 104 * Some of those cells may be part of multi-column characters, including 105 * carryover from the left. Find the limits of the multi-column characters 106 * that we should fill with blanks, return true if filling is needed. 107 */ 108int 109DamagedCells(TScreen *screen, unsigned n, int *klp, int *krp, int row, int col) 110{ 111 LineData *ld = getLineData(screen, row); 112 int result = False; 113 114 assert(ld); 115 if (col < (int) ld->lineSize) { 116 int nn = (int) n; 117 int kl = col; 118 int kr = col + nn; 119 120 if (kr >= (int) ld->lineSize) { 121 nn = (ld->lineSize - col - 1); 122 kr = col + nn; 123 } 124 125 if (nn > 0) { 126 assert(kl < (int) ld->lineSize); 127 if (ld->charData[kl] == HIDDEN_CHAR) { 128 while (kl > 0) { 129 if (ld->charData[--kl] != HIDDEN_CHAR) { 130 break; 131 } 132 } 133 } else { 134 kl = col + 1; 135 } 136 137 assert(kr < (int) ld->lineSize); 138 if (ld->charData[kr] == HIDDEN_CHAR) { 139 while (kr < screen->max_col) { 140 assert((kr + 1) < (int) ld->lineSize); 141 if (ld->charData[++kr] != HIDDEN_CHAR) { 142 --kr; 143 break; 144 } 145 } 146 } else { 147 kr = col - 1; 148 } 149 150 if (klp) 151 *klp = kl; 152 if (krp) 153 *krp = kr; 154 result = (kr >= kl); 155 } 156 } 157 158 return result; 159} 160 161int 162DamagedCurCells(TScreen *screen, unsigned n, int *klp, int *krp) 163{ 164 return DamagedCells(screen, n, klp, krp, screen->cur_row, screen->cur_col); 165} 166#endif /* OPT_WIDE_CHARS */ 167 168/* 169 * These routines are used for the jump scroll feature 170 */ 171void 172FlushScroll(XtermWidget xw) 173{ 174 TScreen *screen = TScreenOf(xw); 175 int i; 176 int shift = INX2ROW(screen, 0); 177 int bot = screen->max_row - shift; 178 int refreshtop; 179 int refreshheight; 180 int scrolltop; 181 int scrollheight; 182 int left = ScrnLeftMargin(xw); 183 int right = ScrnRightMargin(xw); 184 Boolean full_lines = (Boolean) ((left == 0) && (right == screen->max_col)); 185 186 if (screen->cursor_state) 187 HideCursor(); 188 189 TRACE(("FlushScroll %s-lines scroll:%d refresh %d\n", 190 full_lines ? "full" : "partial", 191 screen->scroll_amt, 192 screen->refresh_amt)); 193 194 if (screen->scroll_amt > 0) { 195 /* 196 * Lines will be scrolled "up". 197 */ 198 refreshheight = screen->refresh_amt; 199 scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1; 200 refreshtop = screen->bot_marg - refreshheight + 1 + shift; 201 i = screen->max_row - screen->scroll_amt + 1; 202 if (refreshtop > i) { 203 refreshtop = i; 204 } 205 206 /* 207 * If this is the normal (not alternate) screen, and the top margin is 208 * at the top of the screen, then we will shift full lines scrolled out 209 * of the scrolling region into the saved-lines. 210 */ 211 if (screen->scrollWidget 212 && !screen->whichBuf 213 && full_lines 214 && screen->top_marg == 0) { 215 scrolltop = 0; 216 scrollheight += shift; 217 if (scrollheight > i) 218 scrollheight = i; 219 i = screen->bot_marg - bot; 220 if (i > 0) { 221 refreshheight -= i; 222 if (refreshheight < screen->scroll_amt) { 223 refreshheight = screen->scroll_amt; 224 } 225 } 226 i = screen->savedlines; 227 if (i < screen->savelines) { 228 i += screen->scroll_amt; 229 if (i > screen->savelines) { 230 i = screen->savelines; 231 } 232 screen->savedlines = i; 233 ScrollBarDrawThumb(screen->scrollWidget); 234 } 235 } else { 236 scrolltop = screen->top_marg + shift; 237 i = bot - (screen->bot_marg - screen->refresh_amt + screen->scroll_amt); 238 if (i > 0) { 239 if (bot < screen->bot_marg) { 240 refreshheight = screen->scroll_amt + i; 241 } 242 } else { 243 scrollheight += i; 244 refreshheight = screen->scroll_amt; 245 i = screen->top_marg + screen->scroll_amt - 1 - bot; 246 if (i > 0) { 247 refreshtop += i; 248 refreshheight -= i; 249 } 250 } 251 } 252 } else { 253 /* 254 * Lines will be scrolled "down". 255 */ 256 refreshheight = -screen->refresh_amt; 257 scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1; 258 refreshtop = screen->top_marg + shift; 259 scrolltop = refreshtop + refreshheight; 260 i = screen->bot_marg - bot; 261 if (i > 0) { 262 scrollheight -= i; 263 } 264 i = screen->top_marg + refreshheight - 1 - bot; 265 if (i > 0) { 266 refreshheight -= i; 267 } 268 } 269 270 vertical_copy_area(xw, 271 scrolltop + screen->scroll_amt, 272 scrollheight, 273 screen->scroll_amt, 274 left, 275 right); 276 ScrollSelection(screen, -(screen->scroll_amt), False); 277 screen->scroll_amt = 0; 278 screen->refresh_amt = 0; 279 280 if (refreshheight > 0) { 281 ClearCurBackground(xw, 282 refreshtop, 283 left, 284 (unsigned) refreshheight, 285 (unsigned) (right + 1 - left), 286 (unsigned) FontWidth(screen)); 287 ScrnRefresh(xw, 288 refreshtop, 289 0, 290 refreshheight, 291 MaxCols(screen), 292 False); 293 } 294 return; 295} 296 297/* 298 * Returns true if there are lines off-screen due to scrolling which should 299 * include the current line. If false, the line is visible and we should 300 * paint it now rather than waiting for the line to become visible. 301 */ 302static Bool 303AddToRefresh(XtermWidget xw) 304{ 305 TScreen *screen = TScreenOf(xw); 306 int amount = screen->refresh_amt; 307 int row = screen->cur_row; 308 Bool result; 309 310 if (amount == 0) { 311 result = False; 312 } else if (amount > 0) { 313 int bottom; 314 315 if (row == (bottom = screen->bot_marg) - amount) { 316 screen->refresh_amt++; 317 result = True; 318 } else { 319 result = (row >= bottom - amount + 1 && row <= bottom); 320 } 321 } else { 322 int top; 323 324 amount = -amount; 325 if (row == (top = screen->top_marg) + amount) { 326 screen->refresh_amt--; 327 result = True; 328 } else { 329 result = (row <= top + amount - 1 && row >= top); 330 } 331 } 332 333 /* 334 * If this line is visible, and there are scrolled-off lines, flush out 335 * those which are now visible. 336 */ 337 if (!result && screen->scroll_amt) 338 FlushScroll(xw); 339 340 return result; 341} 342 343/* 344 * Returns true if the current row is in the visible area (it should be for 345 * screen operations) and incidentally flush the scrolled-in lines which 346 * have newly become visible. 347 */ 348static Bool 349AddToVisible(XtermWidget xw) 350{ 351 TScreen *screen = TScreenOf(xw); 352 Bool result = False; 353 354 if (INX2ROW(screen, screen->cur_row) <= screen->max_row) { 355 if (!AddToRefresh(xw)) { 356 result = True; 357 } 358 } 359 return result; 360} 361 362/* 363 * If we're scrolling, leave the selection intact if possible. 364 * If it will bump into one of the extremes of the saved-lines, truncate that. 365 * If the selection is not entirely contained within the margins and not 366 * entirely outside the margins, clear it. 367 */ 368static void 369adjustHiliteOnFwdScroll(XtermWidget xw, int amount, Bool all_lines) 370{ 371 TScreen *screen = TScreenOf(xw); 372 int lo_row = (all_lines 373 ? (screen->bot_marg - screen->savelines) 374 : screen->top_marg); 375 int hi_row = screen->bot_marg; 376 int left = ScrnLeftMargin(xw); 377 int right = ScrnRightMargin(xw); 378 379 TRACE2(("adjustSelection FWD %s by %d (%s)\n", 380 screen->whichBuf ? "alternate" : "normal", 381 amount, 382 all_lines ? "all" : "visible")); 383 TRACE2((" before highlite %d.%d .. %d.%d\n", 384 screen->startH.row, 385 screen->startH.col, 386 screen->endH.row, 387 screen->endH.col)); 388 TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg)); 389 TRACE2((" limits %d..%d\n", lo_row, hi_row)); 390 391 if ((left > 0 || right < screen->max_col) && 392 ((screen->startH.row >= lo_row && 393 screen->startH.row - amount <= hi_row) || 394 (screen->endH.row >= lo_row && 395 screen->endH.row - amount <= hi_row))) { 396 /* 397 * This could be improved slightly by excluding the special case where 398 * the selection is on a single line outside left/right margins. 399 */ 400 TRACE2(("deselect because selection overlaps with scrolled partial-line\n")); 401 ScrnDisownSelection(xw); 402 } else if (screen->startH.row >= lo_row 403 && screen->startH.row - amount < lo_row) { 404 /* truncate the selection because its start would move out of region */ 405 if (lo_row + amount <= screen->endH.row) { 406 TRACE2(("truncate selection by changing start %d.%d to %d.%d\n", 407 screen->startH.row, 408 screen->startH.col, 409 lo_row + amount, 410 0)); 411 screen->startH.row = lo_row + amount; 412 screen->startH.col = 0; 413 } else { 414 TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n", 415 screen->startH.row, 416 screen->startH.col, 417 screen->endH.row, 418 screen->endH.col, 419 -amount, 420 lo_row, 421 hi_row)); 422 ScrnDisownSelection(xw); 423 } 424 } else if (screen->startH.row <= hi_row && screen->endH.row > hi_row) { 425 TRACE2(("deselect because selection straddles top-margin\n")); 426 ScrnDisownSelection(xw); 427 } else if (screen->startH.row < lo_row && screen->endH.row > lo_row) { 428 TRACE2(("deselect because selection straddles bottom-margin\n")); 429 ScrnDisownSelection(xw); 430 } 431 432 TRACE2((" after highlite %d.%d .. %d.%d\n", 433 screen->startH.row, 434 screen->startH.col, 435 screen->endH.row, 436 screen->endH.col)); 437} 438 439/* 440 * This is the same as adjustHiliteOnFwdScroll(), but reversed. In this case, 441 * only the visible lines are affected. 442 */ 443static void 444adjustHiliteOnBakScroll(XtermWidget xw, int amount) 445{ 446 TScreen *screen = TScreenOf(xw); 447 int lo_row = screen->top_marg; 448 int hi_row = screen->bot_marg; 449 450 TRACE2(("adjustSelection BAK %s by %d (%s)\n", 451 screen->whichBuf ? "alternate" : "normal", 452 amount, 453 "visible")); 454 TRACE2((" before highlite %d.%d .. %d.%d\n", 455 screen->startH.row, 456 screen->startH.col, 457 screen->endH.row, 458 screen->endH.col)); 459 TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg)); 460 461 if (screen->endH.row >= hi_row 462 && screen->endH.row + amount > hi_row) { 463 /* truncate the selection because its start would move out of region */ 464 if (hi_row - amount >= screen->startH.row) { 465 TRACE2(("truncate selection by changing start %d.%d to %d.%d\n", 466 screen->startH.row, 467 screen->startH.col, 468 hi_row - amount, 469 0)); 470 screen->endH.row = hi_row - amount; 471 screen->endH.col = 0; 472 } else { 473 TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n", 474 screen->startH.row, 475 screen->startH.col, 476 screen->endH.row, 477 screen->endH.col, 478 amount, 479 lo_row, 480 hi_row)); 481 ScrnDisownSelection(xw); 482 } 483 } else if (screen->endH.row >= lo_row && screen->startH.row < lo_row) { 484 ScrnDisownSelection(xw); 485 } else if (screen->endH.row > hi_row && screen->startH.row > hi_row) { 486 ScrnDisownSelection(xw); 487 } 488 489 TRACE2((" after highlite %d.%d .. %d.%d\n", 490 screen->startH.row, 491 screen->startH.col, 492 screen->endH.row, 493 screen->endH.col)); 494} 495 496/* 497 * Move cells in LineData's on the current screen to simulate scrolling by the 498 * given amount of lines. 499 */ 500static void 501scrollInMargins(XtermWidget xw, int amount, int top) 502{ 503 TScreen *screen = TScreenOf(xw); 504 LineData *src; 505 LineData *dst; 506 int row; 507 int left = ScrnLeftMargin(xw); 508 int right = ScrnRightMargin(xw); 509 int length = right + 1 - left; 510 511 if (amount > 0) { 512 for (row = top; row <= screen->bot_marg - amount; ++row) { 513 if ((src = getLineData(screen, row + amount)) != 0 514 && (dst = getLineData(screen, row)) != 0) { 515 CopyCells(screen, src, dst, left, length); 516 } 517 } 518 while (row <= screen->bot_marg) { 519 ClearCells(xw, 0, (unsigned) length, row, left); 520 ++row; 521 } 522 } else if (amount < 0) { 523 for (row = screen->bot_marg; row >= top - amount; --row) { 524 if ((src = getLineData(screen, row + amount)) != 0 525 && (dst = getLineData(screen, row)) != 0) { 526 CopyCells(screen, src, dst, left, length); 527 } 528 } 529 while (row >= top) { 530 ClearCells(xw, 0, (unsigned) length, row, left); 531 --row; 532 } 533 } 534} 535 536/* 537 * scrolls the screen by amount lines, erases bottom, doesn't alter 538 * cursor position (i.e. cursor moves down amount relative to text). 539 * All done within the scrolling region, of course. 540 * requires: amount > 0 541 */ 542void 543xtermScroll(XtermWidget xw, int amount) 544{ 545 TScreen *screen = TScreenOf(xw); 546 int i; 547 int shift; 548 int bot; 549 int refreshtop = 0; 550 int refreshheight; 551 int scrolltop; 552 int scrollheight; 553 int left = ScrnLeftMargin(xw); 554 int right = ScrnRightMargin(xw); 555 Boolean scroll_all_lines = (Boolean) (screen->scrollWidget 556 && !screen->whichBuf 557 && screen->top_marg == 0); 558 559 TRACE(("xtermScroll count=%d\n", amount)); 560 561 screen->cursor_busy += 1; 562 screen->cursor_moved = True; 563 564 if (screen->cursor_state) 565 HideCursor(); 566 567 i = screen->bot_marg - screen->top_marg + 1; 568 if (amount > i) 569 amount = i; 570 571#if OPT_SCROLL_LOCK 572 if (screen->allowScrollLock && screen->scroll_lock) { 573 refreshheight = 0; 574 screen->scroll_amt = 0; 575 screen->refresh_amt = 0; 576 if (--(screen->topline) < -screen->savelines) { 577 screen->topline = -screen->savelines; 578 screen->scroll_dirty = True; 579 } 580 if (++(screen->savedlines) > screen->savelines) { 581 screen->savedlines = screen->savelines; 582 } 583 } else 584#endif 585 { 586 if (ScrnHaveSelection(screen)) 587 adjustHiliteOnFwdScroll(xw, amount, scroll_all_lines); 588 589 if (screen->jumpscroll) { 590 if (screen->scroll_amt > 0) { 591 if (!screen->fastscroll) { 592 if (screen->refresh_amt + amount > i) 593 FlushScroll(xw); 594 } 595 screen->scroll_amt += amount; 596 screen->refresh_amt += amount; 597 } else { 598 if (!screen->fastscroll) { 599 if (screen->scroll_amt < 0) 600 FlushScroll(xw); 601 } 602 screen->scroll_amt = amount; 603 screen->refresh_amt = amount; 604 } 605 refreshheight = 0; 606 } else { 607 ScrollSelection(screen, -(amount), False); 608 if (amount == i) { 609 ClearScreen(xw); 610 screen->cursor_busy -= 1; 611 return; 612 } 613 614 shift = INX2ROW(screen, 0); 615 bot = screen->max_row - shift; 616 scrollheight = i - amount; 617 refreshheight = amount; 618 619 if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) > 620 (i = screen->max_row - refreshheight + 1)) 621 refreshtop = i; 622 623 if (scroll_all_lines) { 624 scrolltop = 0; 625 if ((scrollheight += shift) > i) 626 scrollheight = i; 627 if ((i = screen->savedlines) < screen->savelines) { 628 if ((i += amount) > screen->savelines) 629 i = screen->savelines; 630 screen->savedlines = i; 631 ScrollBarDrawThumb(screen->scrollWidget); 632 } 633 } else { 634 scrolltop = screen->top_marg + shift; 635 if ((i = screen->bot_marg - bot) > 0) { 636 scrollheight -= i; 637 if ((i = screen->top_marg + amount - 1 - bot) >= 0) { 638 refreshtop += i; 639 refreshheight -= i; 640 } 641 } 642 } 643 644 if (screen->multiscroll && amount == 1 && 645 screen->topline == 0 && screen->top_marg == 0 && 646 screen->bot_marg == screen->max_row) { 647 if (screen->incopy < 0 && screen->scrolls == 0) 648 CopyWait(xw); 649 screen->scrolls++; 650 } 651 652 vertical_copy_area(xw, 653 scrolltop + amount, 654 scrollheight, 655 amount, 656 left, 657 right); 658 659 if (refreshheight > 0) { 660 ClearCurBackground(xw, 661 refreshtop, 662 left, 663 (unsigned) refreshheight, 664 (unsigned) (right + 1 - left), 665 (unsigned) FontWidth(screen)); 666 if (refreshheight > shift) 667 refreshheight = shift; 668 } 669 } 670 } 671 672 if (amount > 0) { 673 if (left > 0 || right < screen->max_col) { 674 scrollInMargins(xw, amount, screen->top_marg); 675 } else if (scroll_all_lines) { 676 ScrnDeleteLine(xw, 677 screen->saveBuf_index, 678 screen->bot_marg + screen->savelines, 679 0, 680 (unsigned) amount); 681 } else { 682 ScrnDeleteLine(xw, 683 screen->visbuf, 684 screen->bot_marg, 685 screen->top_marg, 686 (unsigned) amount); 687 } 688 } 689 690 scroll_displayed_graphics(amount); 691 692 if (refreshheight > 0) { 693 ScrnRefresh(xw, 694 refreshtop, 695 left, 696 refreshheight, 697 right + 1 - left, 698 False); 699 } 700 701 screen->cursor_busy -= 1; 702 return; 703} 704 705/* 706 * This is from ISO 6429, not found in any of DEC's terminals. 707 */ 708void 709xtermScrollLR(XtermWidget xw, int amount, Bool toLeft) 710{ 711 if (amount > 0) { 712 xtermColScroll(xw, amount, toLeft, 0); 713 } 714} 715 716/* 717 * Implement DECBI/DECFI (back/forward column index) 718 */ 719void 720xtermColIndex(XtermWidget xw, Bool toLeft) 721{ 722 TScreen *screen = TScreenOf(xw); 723 int margin; 724 725 if (toLeft) { 726 margin = ScrnLeftMargin(xw); 727 if (screen->cur_col > margin) { 728 CursorBack(xw, 1); 729 } else if (screen->cur_col == margin) { 730 xtermColScroll(xw, 1, False, screen->cur_col); 731 } 732 } else { 733 margin = ScrnRightMargin(xw); 734 if (screen->cur_col < margin) { 735 CursorForward(xw, 1); 736 } else if (screen->cur_col == margin) { 737 xtermColScroll(xw, 1, True, ScrnLeftMargin(xw)); 738 } 739 } 740} 741 742/* 743 * Implement DECDC/DECIC (delete/insert column) 744 */ 745void 746xtermColScroll(XtermWidget xw, int amount, Bool toLeft, int at_col) 747{ 748 TScreen *screen = TScreenOf(xw); 749 750 if (amount > 0) { 751 int min_row; 752 int max_row; 753 754 if (ScrnHaveRowMargins(screen)) { 755 min_row = screen->top_marg; 756 max_row = screen->bot_marg; 757 } else { 758 min_row = 0; 759 max_row = screen->max_row; 760 } 761 762 if (screen->cur_row >= min_row 763 && screen->cur_row <= max_row 764 && screen->cur_col >= screen->lft_marg 765 && screen->cur_col <= screen->rgt_marg) { 766 int save_row = screen->cur_row; 767 int save_col = screen->cur_col; 768 int row; 769 770 screen->cur_col = at_col; 771 if (toLeft) { 772 for (row = min_row; row <= max_row; row++) { 773 screen->cur_row = row; 774 ScrnDeleteChar(xw, (unsigned) amount); 775 } 776 } else { 777 for (row = min_row; row <= max_row; row++) { 778 screen->cur_row = row; 779 ScrnInsertChar(xw, (unsigned) amount); 780 } 781 } 782 screen->cur_row = save_row; 783 screen->cur_col = save_col; 784 xtermRepaint(xw); 785 } 786 } 787} 788 789/* 790 * Reverse scrolls the screen by amount lines, erases top, doesn't alter 791 * cursor position (i.e. cursor moves up amount relative to text). 792 * All done within the scrolling region, of course. 793 * Requires: amount > 0 794 */ 795void 796RevScroll(XtermWidget xw, int amount) 797{ 798 TScreen *screen = TScreenOf(xw); 799 int i = screen->bot_marg - screen->top_marg + 1; 800 int shift; 801 int bot; 802 int refreshtop; 803 int refreshheight; 804 int scrolltop; 805 int scrollheight; 806 int left = ScrnLeftMargin(xw); 807 int right = ScrnRightMargin(xw); 808 809 TRACE(("RevScroll count=%d\n", amount)); 810 811 screen->cursor_busy += 1; 812 screen->cursor_moved = True; 813 814 if (screen->cursor_state) 815 HideCursor(); 816 817 if (amount > i) 818 amount = i; 819 820 if (ScrnHaveSelection(screen)) 821 adjustHiliteOnBakScroll(xw, amount); 822 823 if (screen->jumpscroll) { 824 if (screen->scroll_amt < 0) { 825 if (-screen->refresh_amt + amount > i) 826 FlushScroll(xw); 827 screen->scroll_amt -= amount; 828 screen->refresh_amt -= amount; 829 } else { 830 if (screen->scroll_amt > 0) 831 FlushScroll(xw); 832 screen->scroll_amt = -amount; 833 screen->refresh_amt = -amount; 834 } 835 } else { 836 shift = INX2ROW(screen, 0); 837 bot = screen->max_row - shift; 838 refreshheight = amount; 839 scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1; 840 refreshtop = screen->top_marg + shift; 841 scrolltop = refreshtop + refreshheight; 842 if ((i = screen->bot_marg - bot) > 0) 843 scrollheight -= i; 844 if ((i = screen->top_marg + refreshheight - 1 - bot) > 0) 845 refreshheight -= i; 846 847 if (screen->multiscroll && amount == 1 && 848 screen->topline == 0 && screen->top_marg == 0 && 849 screen->bot_marg == screen->max_row) { 850 if (screen->incopy < 0 && screen->scrolls == 0) 851 CopyWait(xw); 852 screen->scrolls++; 853 } 854 855 vertical_copy_area(xw, 856 scrolltop - amount, 857 scrollheight, 858 -amount, 859 left, 860 right); 861 862 if (refreshheight > 0) { 863 ClearCurBackground(xw, 864 refreshtop, 865 left, 866 (unsigned) refreshheight, 867 (unsigned) (right + 1 - left), 868 (unsigned) FontWidth(screen)); 869 } 870 } 871 if (amount > 0) { 872 if (left > 0 || right < screen->max_col) { 873 scrollInMargins(xw, -amount, screen->top_marg); 874 } else { 875 ScrnInsertLine(xw, 876 screen->visbuf, 877 screen->bot_marg, 878 screen->top_marg, 879 (unsigned) amount); 880 } 881 } 882 screen->cursor_busy -= 1; 883 return; 884} 885 886#if OPT_ZICONBEEP 887void 888initZIconBeep(void) 889{ 890 if (resource.zIconBeep > 100 || resource.zIconBeep < -100) { 891 resource.zIconBeep = 0; /* was 100, but I prefer to defaulting off. */ 892 xtermWarning("a number between -100 and 100 is required for zIconBeep. 0 used by default\n"); 893 } 894} 895 896static void 897setZIconBeep(XtermWidget xw) 898{ 899 TScreen *screen = TScreenOf(xw); 900 901 /* Flag icon name with "***" on window output when iconified. 902 */ 903 if (resource.zIconBeep && mapstate == IsUnmapped && !screen->zIconBeep_flagged) { 904 static char *icon_name; 905 static Arg args[] = 906 { 907 {XtNiconName, (XtArgVal) & icon_name} 908 }; 909 910 icon_name = NULL; 911 XtGetValues(toplevel, args, XtNumber(args)); 912 913 if (icon_name != NULL) { 914 screen->zIconBeep_flagged = True; 915 ChangeIconName(xw, icon_name); 916 } 917 xtermBell(xw, XkbBI_Info, 0); 918 } 919 mapstate = -1; 920} 921 922/* 923 * If warning should be given then give it 924 */ 925Boolean 926showZIconBeep(XtermWidget xw, char *name) 927{ 928 Boolean code = False; 929 930 if (resource.zIconBeep && TScreenOf(xw)->zIconBeep_flagged) { 931 char *format = resource.zIconFormat; 932 char *newname = CastMallocN(char, strlen(name) + strlen(format) + 1); 933 if (!newname) { 934 xtermWarning("malloc failed in showZIconBeep\n"); 935 } else { 936 char *marker = strstr(format, "%s"); 937 char *result = newname; 938 if (marker != 0) { 939 size_t skip = (size_t) (marker - format); 940 if (skip) { 941 strncpy(result, format, skip); 942 result += skip; 943 } 944 strcpy(result, name); 945 strcat(result, marker + 2); 946 } else { 947 strcpy(result, format); 948 strcat(result, name); 949 } 950 ChangeGroup(xw, XtNiconName, newname); 951 free(newname); 952 } 953 code = True; 954 } 955 return code; 956} 957 958/* 959 * Restore the icon name, resetting the state for zIconBeep. 960 */ 961void 962resetZIconBeep(XtermWidget xw) 963{ 964 static char *icon_name; 965 static Arg args[] = 966 { 967 {XtNiconName, (XtArgVal) & icon_name} 968 }; 969 TScreen *screen = TScreenOf(xw); 970 971 if (screen->zIconBeep_flagged) { 972 screen->zIconBeep_flagged = False; 973 icon_name = NULL; 974 XtGetValues(toplevel, args, XtNumber(args)); 975 if (icon_name != NULL) { 976 char *buf = CastMallocN(char, strlen(icon_name)); 977 if (buf == NULL) { 978 screen->zIconBeep_flagged = True; 979 } else { 980 char *format = resource.zIconFormat; 981 char *marker = strstr(format, "%s"); 982 Boolean found = False; 983 984 if (marker != 0) { 985 if (marker == format 986 || !strncmp(icon_name, format, (size_t) (marker - format))) { 987 found = True; 988 strcpy(buf, icon_name + (marker - format)); 989 marker += 2; 990 if (*marker != '\0') { 991 size_t len_m = strlen(marker); 992 size_t len_b = strlen(buf); 993 if (len_m < len_b 994 && !strcmp(buf + len_b - len_m, marker)) { 995 buf[len_b - len_m] = '\0'; 996 } 997 } 998 } 999 } else if (!strncmp(icon_name, format, strlen(format))) { 1000 strcpy(buf, icon_name + strlen(format)); 1001 found = True; 1002 } 1003 if (found) 1004 ChangeIconName(xw, buf); 1005 free(buf); 1006 } 1007 } 1008 } 1009} 1010#else 1011#define setZIconBeep(xw) /* nothing */ 1012#endif /* OPT_ZICONBEEP */ 1013 1014/* 1015 * write a string str of length len onto the screen at 1016 * the current cursor position. update cursor position. 1017 */ 1018void 1019WriteText(XtermWidget xw, IChar *str, Cardinal len) 1020{ 1021 TScreen *screen = TScreenOf(xw); 1022 LineData *ld = 0; 1023 int fg; 1024 unsigned test; 1025 unsigned flags = xw->flags; 1026 CellColor fg_bg = makeColorPair(xw->cur_foreground, xw->cur_background); 1027 unsigned cells = visual_width(str, len); 1028 GC currentGC; 1029 1030 TRACE(("WriteText %d (%2d,%2d) %3d:%s\n", 1031 screen->topline, 1032 screen->cur_row, 1033 screen->cur_col, 1034 len, visibleIChars(str, len))); 1035 1036 if (cells + (unsigned) screen->cur_col > (unsigned) MaxCols(screen)) { 1037 cells = (unsigned) (MaxCols(screen) - screen->cur_col); 1038 } 1039 1040 if (ScrnHaveSelection(screen) 1041 && ScrnIsRowInSelection(screen, INX2ROW(screen, screen->cur_row))) { 1042 ScrnDisownSelection(xw); 1043 } 1044 1045 /* if we are in insert-mode, reserve space for the new cells */ 1046 if (flags & INSERT) { 1047 InsertChar(xw, cells); 1048 } 1049 1050 if (AddToVisible(xw) 1051 && ((ld = getLineData(screen, screen->cur_row))) != 0) { 1052 if (screen->cursor_state) 1053 HideCursor(); 1054 1055 /* 1056 * If we overwrite part of a multi-column character, fill the rest 1057 * of it with blanks. 1058 */ 1059 if_OPT_WIDE_CHARS(screen, { 1060 int kl; 1061 int kr; 1062 if (DamagedCurCells(screen, cells, &kl, &kr)) 1063 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1)); 1064 }); 1065 1066 if (flags & INVISIBLE) { 1067 Cardinal n; 1068 for (n = 0; n < cells; ++n) 1069 str[n] = ' '; 1070 } 1071 1072 TRACE(("WriteText calling drawXtermText (%d) (%d,%d)\n", 1073 LineCharSet(screen, ld), 1074 screen->cur_col, 1075 screen->cur_row)); 1076 1077 test = flags; 1078#if OPT_ISO_COLORS 1079 if (screen->colorAttrMode) { 1080 fg = MapToColorMode(xw->cur_foreground, screen, flags); 1081 } else { 1082 fg = xw->cur_foreground; 1083 } 1084 checkVeryBoldColors(test, fg); 1085#endif 1086 1087 /* make sure that the correct GC is current */ 1088 currentGC = updatedXtermGC(xw, flags, fg_bg, False); 1089 1090 drawXtermText(xw, test & DRAWX_MASK, currentGC, 1091 LineCursorX(screen, ld, screen->cur_col), 1092 CursorY(screen, screen->cur_row), 1093 LineCharSet(screen, ld), 1094 str, len, 0); 1095 1096 resetXtermGC(xw, flags, False); 1097 } 1098 1099 ScrnWriteText(xw, str, flags, fg_bg, len); 1100 CursorForward(xw, (int) cells); 1101 setZIconBeep(xw); 1102 return; 1103} 1104 1105/* 1106 * If cursor not in scrolling region, returns. Else, 1107 * inserts n blank lines at the cursor's position. Lines above the 1108 * bottom margin are lost. 1109 */ 1110void 1111InsertLine(XtermWidget xw, int n) 1112{ 1113 TScreen *screen = TScreenOf(xw); 1114 int i; 1115 int shift; 1116 int bot; 1117 int refreshtop; 1118 int refreshheight; 1119 int scrolltop; 1120 int scrollheight; 1121 int left = ScrnLeftMargin(xw); 1122 int right = ScrnRightMargin(xw); 1123 1124 if (!ScrnIsRowInMargins(screen, screen->cur_row) 1125 || screen->cur_col < left 1126 || screen->cur_col > right) 1127 return; 1128 1129 TRACE(("InsertLine count=%d\n", n)); 1130 1131 if (screen->cursor_state) 1132 HideCursor(); 1133 1134 if (ScrnHaveSelection(screen) 1135 && ScrnAreRowsInSelection(screen, 1136 INX2ROW(screen, screen->top_marg), 1137 INX2ROW(screen, screen->cur_row - 1)) 1138 && ScrnAreRowsInSelection(screen, 1139 INX2ROW(screen, screen->cur_row), 1140 INX2ROW(screen, screen->bot_marg))) { 1141 ScrnDisownSelection(xw); 1142 } 1143 1144 ResetWrap(screen); 1145 if (n > (i = screen->bot_marg - screen->cur_row + 1)) 1146 n = i; 1147 if (screen->jumpscroll) { 1148 if (screen->scroll_amt <= 0 && 1149 screen->cur_row <= -screen->refresh_amt) { 1150 if (-screen->refresh_amt + n > MaxRows(screen)) 1151 FlushScroll(xw); 1152 screen->scroll_amt -= n; 1153 screen->refresh_amt -= n; 1154 } else { 1155 if (screen->scroll_amt) 1156 FlushScroll(xw); 1157 } 1158 } 1159 if (!screen->scroll_amt) { 1160 shift = INX2ROW(screen, 0); 1161 bot = screen->max_row - shift; 1162 refreshheight = n; 1163 scrollheight = screen->bot_marg - screen->cur_row - refreshheight + 1; 1164 refreshtop = screen->cur_row + shift; 1165 scrolltop = refreshtop + refreshheight; 1166 if ((i = screen->bot_marg - bot) > 0) 1167 scrollheight -= i; 1168 if ((i = screen->cur_row + refreshheight - 1 - bot) > 0) 1169 refreshheight -= i; 1170 vertical_copy_area(xw, scrolltop - n, scrollheight, -n, left, right); 1171 if (refreshheight > 0) { 1172 ClearCurBackground(xw, 1173 refreshtop, 1174 left, 1175 (unsigned) refreshheight, 1176 (unsigned) (right + 1 - left), 1177 (unsigned) FontWidth(screen)); 1178 } 1179 } 1180 if (n > 0) { 1181 if (left > 0 || right < screen->max_col) { 1182 scrollInMargins(xw, -n, screen->cur_row); 1183 } else { 1184 ScrnInsertLine(xw, 1185 screen->visbuf, 1186 screen->bot_marg, 1187 screen->cur_row, 1188 (unsigned) n); 1189 } 1190 } 1191} 1192 1193/* 1194 * If cursor not in scrolling region, returns. Else, deletes n lines 1195 * at the cursor's position, lines added at bottom margin are blank. 1196 */ 1197void 1198DeleteLine(XtermWidget xw, int n) 1199{ 1200 TScreen *screen = TScreenOf(xw); 1201 int i; 1202 int shift; 1203 int bot; 1204 int refreshtop; 1205 int refreshheight; 1206 int scrolltop; 1207 int scrollheight; 1208 int left = ScrnLeftMargin(xw); 1209 int right = ScrnRightMargin(xw); 1210 Boolean scroll_all_lines = (Boolean) (screen->scrollWidget 1211 && !screen->whichBuf 1212 && screen->cur_row == 0); 1213 1214 if (!ScrnIsRowInMargins(screen, screen->cur_row) 1215 || screen->cur_col < left 1216 || screen->cur_col > right) 1217 return; 1218 1219 TRACE(("DeleteLine count=%d\n", n)); 1220 1221 if (screen->cursor_state) 1222 HideCursor(); 1223 1224 if (n > (i = screen->bot_marg - screen->cur_row + 1)) { 1225 n = i; 1226 } 1227 if (ScrnHaveSelection(screen) 1228 && ScrnAreRowsInSelection(screen, 1229 INX2ROW(screen, screen->cur_row), 1230 INX2ROW(screen, screen->cur_row + n - 1))) { 1231 ScrnDisownSelection(xw); 1232 } 1233 1234 ResetWrap(screen); 1235 if (screen->jumpscroll) { 1236 if (screen->scroll_amt >= 0 && screen->cur_row == screen->top_marg) { 1237 if (screen->refresh_amt + n > MaxRows(screen)) 1238 FlushScroll(xw); 1239 screen->scroll_amt += n; 1240 screen->refresh_amt += n; 1241 } else { 1242 if (screen->scroll_amt) 1243 FlushScroll(xw); 1244 } 1245 } 1246 1247 /* adjust screen->buf */ 1248 if (n > 0) { 1249 if (left > 0 || right < screen->max_col) { 1250 scrollInMargins(xw, n, screen->cur_row); 1251 } else if (scroll_all_lines) { 1252 ScrnDeleteLine(xw, 1253 screen->saveBuf_index, 1254 screen->bot_marg + screen->savelines, 1255 0, 1256 (unsigned) n); 1257 } else { 1258 ScrnDeleteLine(xw, 1259 screen->visbuf, 1260 screen->bot_marg, 1261 screen->cur_row, 1262 (unsigned) n); 1263 } 1264 } 1265 1266 /* repaint the screen, as needed */ 1267 if (!screen->scroll_amt) { 1268 shift = INX2ROW(screen, 0); 1269 bot = screen->max_row - shift; 1270 scrollheight = i - n; 1271 refreshheight = n; 1272 if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) > 1273 (i = screen->max_row - refreshheight + 1)) 1274 refreshtop = i; 1275 if (scroll_all_lines) { 1276 scrolltop = 0; 1277 if ((scrollheight += shift) > i) 1278 scrollheight = i; 1279 if ((i = screen->savedlines) < screen->savelines) { 1280 if ((i += n) > screen->savelines) 1281 i = screen->savelines; 1282 screen->savedlines = i; 1283 ScrollBarDrawThumb(screen->scrollWidget); 1284 } 1285 } else { 1286 scrolltop = screen->cur_row + shift; 1287 if ((i = screen->bot_marg - bot) > 0) { 1288 scrollheight -= i; 1289 if ((i = screen->cur_row + n - 1 - bot) >= 0) { 1290 refreshheight -= i; 1291 } 1292 } 1293 } 1294 vertical_copy_area(xw, scrolltop + n, scrollheight, n, left, right); 1295 if (shift > 0 && refreshheight > 0) { 1296 int rows = refreshheight; 1297 if (rows > shift) 1298 rows = shift; 1299 ScrnUpdate(xw, refreshtop, 0, rows, MaxCols(screen), True); 1300 refreshtop += shift; 1301 refreshheight -= shift; 1302 } 1303 if (refreshheight > 0) { 1304 ClearCurBackground(xw, 1305 refreshtop, 1306 left, 1307 (unsigned) refreshheight, 1308 (unsigned) (right + 1 - left), 1309 (unsigned) FontWidth(screen)); 1310 } 1311 } 1312} 1313 1314/* 1315 * Insert n blanks at the cursor's position, no wraparound 1316 */ 1317void 1318InsertChar(XtermWidget xw, unsigned n) 1319{ 1320 TScreen *screen = TScreenOf(xw); 1321 LineData *ld; 1322 unsigned limit; 1323 int row = INX2ROW(screen, screen->cur_row); 1324 int left = ScrnLeftMargin(xw); 1325 int right = ScrnRightMargin(xw); 1326 1327 if (screen->cursor_state) 1328 HideCursor(); 1329 1330 TRACE(("InsertChar count=%d\n", n)); 1331 1332 if (ScrnHaveSelection(screen) 1333 && ScrnIsRowInSelection(screen, row)) { 1334 ScrnDisownSelection(xw); 1335 } 1336 ResetWrap(screen); 1337 1338 limit = (unsigned) (right + 1 - screen->cur_col); 1339 1340 if (n > limit) 1341 n = limit; 1342 1343 if (screen->cur_col < left || screen->cur_col > right) { 1344 n = 0; 1345 } else if (AddToVisible(xw) 1346 && (ld = getLineData(screen, screen->cur_row)) != 0) { 1347 int col = right + 1 - (int) n; 1348 1349 /* 1350 * If we shift part of a multi-column character, fill the rest 1351 * of it with blanks. Do similar repair for the text which will 1352 * be shifted into the right-margin. 1353 */ 1354 if_OPT_WIDE_CHARS(screen, { 1355 int kl; 1356 int kr = screen->cur_col; 1357 if (DamagedCurCells(screen, n, &kl, (int *) 0) && kr > kl) { 1358 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1)); 1359 } 1360 kr = screen->max_col - (int) n + 1; 1361 if (DamagedCells(screen, n, &kl, (int *) 0, 1362 screen->cur_row, 1363 kr) && kr > kl) { 1364 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1)); 1365 } 1366 }); 1367 1368#if OPT_DEC_CHRSET 1369 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1370 col = MaxCols(screen) / 2 - (int) n; 1371 } 1372#endif 1373 /* 1374 * prevent InsertChar from shifting the end of a line over 1375 * if it is being appended to 1376 */ 1377 if (non_blank_line(screen, screen->cur_row, 1378 screen->cur_col, MaxCols(screen))) { 1379 horizontal_copy_area(xw, screen->cur_col, 1380 col - screen->cur_col, 1381 (int) n); 1382 } 1383 1384 ClearCurBackground(xw, 1385 INX2ROW(screen, screen->cur_row), 1386 screen->cur_col, 1387 1, 1388 n, 1389 (unsigned) LineFontWidth(screen, ld)); 1390 } 1391 if (n != 0) { 1392 /* adjust screen->buf */ 1393 ScrnInsertChar(xw, n); 1394 } 1395} 1396 1397/* 1398 * Deletes n chars at the cursor's position, no wraparound. 1399 */ 1400void 1401DeleteChar(XtermWidget xw, unsigned n) 1402{ 1403 TScreen *screen = TScreenOf(xw); 1404 LineData *ld; 1405 unsigned limit; 1406 int row = INX2ROW(screen, screen->cur_row); 1407 int left = ScrnLeftMargin(xw); 1408 int right = ScrnRightMargin(xw); 1409 1410 if (screen->cursor_state) 1411 HideCursor(); 1412 1413 TRACE(("DeleteChar count=%d\n", n)); 1414 1415 if (ScrnHaveSelection(screen) 1416 && ScrnIsRowInSelection(screen, row)) { 1417 ScrnDisownSelection(xw); 1418 } 1419 ResetWrap(screen); 1420 1421 limit = (unsigned) (right + 1 - screen->cur_col); 1422 1423 if (n > limit) 1424 n = limit; 1425 1426 if (screen->cur_col < left || screen->cur_col > right) { 1427 n = 0; 1428 } else if (AddToVisible(xw) 1429 && (ld = getLineData(screen, screen->cur_row)) != 0) { 1430 int col = right + 1 - (int) n; 1431 1432 /* 1433 * If we delete part of a multi-column character, fill the rest 1434 * of it with blanks. 1435 */ 1436 if_OPT_WIDE_CHARS(screen, { 1437 int kl; 1438 int kr; 1439 if (DamagedCurCells(screen, n, &kl, &kr)) 1440 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1)); 1441 }); 1442 1443#if OPT_DEC_CHRSET 1444 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1445 col = MaxCols(screen) / 2 - (int) n; 1446 } 1447#endif 1448 horizontal_copy_area(xw, 1449 (screen->cur_col + (int) n), 1450 col - screen->cur_col, 1451 -((int) n)); 1452 1453 ClearCurBackground(xw, 1454 INX2ROW(screen, screen->cur_row), 1455 col, 1456 1, 1457 n, 1458 (unsigned) LineFontWidth(screen, ld)); 1459 } 1460 if (n != 0) { 1461 /* adjust screen->buf */ 1462 ScrnDeleteChar(xw, n); 1463 } 1464} 1465 1466/* 1467 * Clear from cursor position to beginning of display, inclusive. 1468 */ 1469static void 1470ClearAbove(XtermWidget xw) 1471{ 1472 TScreen *screen = TScreenOf(xw); 1473 1474 if (screen->protected_mode != OFF_PROTECT) { 1475 int row; 1476 unsigned len = (unsigned) MaxCols(screen); 1477 1478 assert(screen->max_col >= 0); 1479 for (row = 0; row <= screen->max_row; row++) 1480 ClearInLine(xw, row, 0, len); 1481 } else { 1482 int top, height; 1483 1484 if (screen->cursor_state) 1485 HideCursor(); 1486 if ((top = INX2ROW(screen, 0)) <= screen->max_row) { 1487 if (screen->scroll_amt) 1488 FlushScroll(xw); 1489 if ((height = screen->cur_row + top) > screen->max_row) 1490 height = screen->max_row + 1; 1491 if ((height -= top) > 0) { 1492 chararea_clear_displayed_graphics(screen, 1493 0, 1494 top, 1495 MaxCols(screen), 1496 height); 1497 1498 ClearCurBackground(xw, 1499 top, 1500 0, 1501 (unsigned) height, 1502 (unsigned) MaxCols(screen), 1503 (unsigned) FontWidth(screen)); 1504 } 1505 } 1506 ClearBufRows(xw, 0, screen->cur_row - 1); 1507 } 1508 1509 ClearLeft(xw); 1510} 1511 1512/* 1513 * Clear from cursor position to end of display, inclusive. 1514 */ 1515static void 1516ClearBelow(XtermWidget xw) 1517{ 1518 TScreen *screen = TScreenOf(xw); 1519 1520 ClearRight(xw, -1); 1521 1522 if (screen->protected_mode != OFF_PROTECT) { 1523 int row; 1524 unsigned len = (unsigned) MaxCols(screen); 1525 1526 assert(screen->max_col >= 0); 1527 for (row = screen->cur_row + 1; row <= screen->max_row; row++) 1528 ClearInLine(xw, row, 0, len); 1529 } else { 1530 int top; 1531 1532 if ((top = INX2ROW(screen, screen->cur_row)) <= screen->max_row) { 1533 if (screen->scroll_amt) 1534 FlushScroll(xw); 1535 if (++top <= screen->max_row) { 1536 chararea_clear_displayed_graphics(screen, 1537 0, 1538 top, 1539 MaxCols(screen), 1540 (screen->max_row - top + 1)); 1541 ClearCurBackground(xw, 1542 top, 1543 0, 1544 (unsigned) (screen->max_row - top + 1), 1545 (unsigned) MaxCols(screen), 1546 (unsigned) FontWidth(screen)); 1547 } 1548 } 1549 ClearBufRows(xw, screen->cur_row + 1, screen->max_row); 1550 } 1551} 1552 1553/* 1554 * Clear the given row, for the given range of columns, returning 1 if no 1555 * protected characters were found, 0 otherwise. 1556 */ 1557static int 1558ClearInLine2(XtermWidget xw, int flags, int row, int col, unsigned len) 1559{ 1560 TScreen *screen = TScreenOf(xw); 1561 LineData *ld; 1562 int rc = 1; 1563 1564 TRACE(("ClearInLine(row=%d, col=%d, len=%d) vs %d..%d\n", 1565 row, col, len, 1566 screen->startH.row, 1567 screen->startH.col)); 1568 1569 if (ScrnHaveSelection(screen) 1570 && ScrnIsRowInSelection(screen, row)) { 1571 ScrnDisownSelection(xw); 1572 } 1573 1574 if (col + (int) len >= MaxCols(screen)) { 1575 len = (unsigned) (MaxCols(screen) - col); 1576 } 1577 1578 /* If we've marked protected text on the screen, we'll have to 1579 * check each time we do an erase. 1580 */ 1581 if (screen->protected_mode != OFF_PROTECT) { 1582 unsigned n; 1583 Char *attrs = getLineData(screen, row)->attribs + col; 1584 int saved_mode = screen->protected_mode; 1585 Bool done; 1586 1587 /* disable this branch during recursion */ 1588 screen->protected_mode = OFF_PROTECT; 1589 1590 do { 1591 done = True; 1592 for (n = 0; n < len; n++) { 1593 if (attrs[n] & PROTECTED) { 1594 rc = 0; /* found a protected segment */ 1595 if (n != 0) { 1596 ClearInLine(xw, row, col, n); 1597 } 1598 while ((n < len) 1599 && (attrs[n] & PROTECTED)) { 1600 n++; 1601 } 1602 done = False; 1603 break; 1604 } 1605 } 1606 /* setup for another segment, past the protected text */ 1607 if (!done) { 1608 attrs += n; 1609 col += (int) n; 1610 len -= n; 1611 } 1612 } while (!done); 1613 1614 screen->protected_mode = saved_mode; 1615 if ((int) len <= 0) { 1616 return 0; 1617 } 1618 } 1619 /* fall through to the final non-protected segment */ 1620 1621 if (screen->cursor_state) 1622 HideCursor(); 1623 ResetWrap(screen); 1624 1625 if (AddToVisible(xw) 1626 && (ld = getLineData(screen, row)) != 0) { 1627 1628 ClearCurBackground(xw, 1629 INX2ROW(screen, row), 1630 col, 1631 1, 1632 len, 1633 (unsigned) LineFontWidth(screen, ld)); 1634 } 1635 1636 if (len != 0) { 1637 ClearCells(xw, flags, len, row, col); 1638 } 1639 1640 return rc; 1641} 1642 1643int 1644ClearInLine(XtermWidget xw, int row, int col, unsigned len) 1645{ 1646 TScreen *screen = TScreenOf(xw); 1647 int flags = 0; 1648 1649 /* 1650 * If we're clearing to the end of the line, we won't count this as 1651 * "drawn" characters. We'll only do cut/paste on "drawn" characters, 1652 * so this has the effect of suppressing trailing blanks from a 1653 * selection. 1654 */ 1655 if (col + (int) len < MaxCols(screen)) { 1656 flags |= CHARDRAWN; 1657 } 1658 return ClearInLine2(xw, flags, row, col, len); 1659} 1660 1661/* 1662 * Clear the next n characters on the cursor's line, including the cursor's 1663 * position. 1664 */ 1665void 1666ClearRight(XtermWidget xw, int n) 1667{ 1668 TScreen *screen = TScreenOf(xw); 1669 LineData *ld; 1670 unsigned len = (unsigned) (MaxCols(screen) - screen->cur_col); 1671 1672 assert(screen->max_col >= 0); 1673 assert(screen->max_col >= screen->cur_col); 1674 1675 if (n < 0) /* the remainder of the line */ 1676 n = MaxCols(screen); 1677 if (n == 0) /* default for 'ECH' */ 1678 n = 1; 1679 1680 if (len > (unsigned) n) 1681 len = (unsigned) n; 1682 1683 ld = getLineData(screen, screen->cur_row); 1684 if (AddToVisible(xw)) { 1685 if_OPT_WIDE_CHARS(screen, { 1686 int col = screen->cur_col; 1687 int row = screen->cur_row; 1688 int kl; 1689 int kr; 1690 int xx; 1691 if (DamagedCurCells(screen, len, &kl, &kr) && kr >= kl) { 1692 xx = col; 1693 if (kl < xx) { 1694 ClearInLine2(xw, 0, row, kl, (unsigned) (xx - kl)); 1695 } 1696 xx = col + (int) len - 1; 1697 if (kr > xx) { 1698 ClearInLine2(xw, 0, row, xx + 1, (unsigned) (kr - xx)); 1699 } 1700 } 1701 }); 1702 (void) ClearInLine(xw, screen->cur_row, screen->cur_col, len); 1703 } else { 1704 ScrnClearCells(xw, screen->cur_row, screen->cur_col, len); 1705 } 1706 1707 /* with the right part cleared, we can't be wrapping */ 1708 LineClrWrapped(ld); 1709 if (screen->show_wrap_marks) { 1710 ShowWrapMarks(xw, screen->cur_row, ld); 1711 } 1712 ResetWrap(screen); 1713} 1714 1715/* 1716 * Clear first part of cursor's line, inclusive. 1717 */ 1718static void 1719ClearLeft(XtermWidget xw) 1720{ 1721 TScreen *screen = TScreenOf(xw); 1722 unsigned len = (unsigned) screen->cur_col + 1; 1723 1724 assert(screen->cur_col >= 0); 1725 if (AddToVisible(xw)) { 1726 if_OPT_WIDE_CHARS(screen, { 1727 int row = screen->cur_row; 1728 int kl; 1729 int kr; 1730 if (DamagedCurCells(screen, 1, &kl, &kr) && kr >= kl) { 1731 ClearInLine2(xw, 0, row, kl, (unsigned) (kr - kl + 1)); 1732 } 1733 }); 1734 (void) ClearInLine(xw, screen->cur_row, 0, len); 1735 } else { 1736 ScrnClearCells(xw, screen->cur_row, 0, len); 1737 } 1738} 1739 1740/* 1741 * Erase the cursor's line. 1742 */ 1743static void 1744ClearLine(XtermWidget xw) 1745{ 1746 TScreen *screen = TScreenOf(xw); 1747 unsigned len = (unsigned) MaxCols(screen); 1748 1749 assert(screen->max_col >= 0); 1750 (void) ClearInLine(xw, screen->cur_row, 0, len); 1751} 1752 1753void 1754ClearScreen(XtermWidget xw) 1755{ 1756 TScreen *screen = TScreenOf(xw); 1757 int top; 1758 1759 if (screen->cursor_state) 1760 HideCursor(); 1761 1762 ScrnDisownSelection(xw); 1763 ResetWrap(screen); 1764 if ((top = INX2ROW(screen, 0)) <= screen->max_row) { 1765 if (screen->scroll_amt) 1766 FlushScroll(xw); 1767 chararea_clear_displayed_graphics(screen, 1768 0, 1769 top, 1770 MaxCols(screen), 1771 (screen->max_row - top + 1)); 1772 ClearCurBackground(xw, 1773 top, 1774 0, 1775 (unsigned) (screen->max_row - top + 1), 1776 (unsigned) MaxCols(screen), 1777 (unsigned) FontWidth(screen)); 1778 } 1779 ClearBufRows(xw, 0, screen->max_row); 1780} 1781 1782/* 1783 * If we've written protected text DEC-style, and are issuing a non-DEC 1784 * erase, temporarily reset the protected_mode flag so that the erase will 1785 * ignore the protected flags. 1786 */ 1787void 1788do_erase_line(XtermWidget xw, int param, int mode) 1789{ 1790 TScreen *screen = TScreenOf(xw); 1791 int saved_mode = screen->protected_mode; 1792 1793 if (saved_mode == DEC_PROTECT 1794 && saved_mode != mode) { 1795 screen->protected_mode = OFF_PROTECT; 1796 } 1797 1798 switch (param) { 1799 case -1: /* DEFAULT */ 1800 case 0: 1801 ClearRight(xw, -1); 1802 break; 1803 case 1: 1804 ClearLeft(xw); 1805 break; 1806 case 2: 1807 ClearLine(xw); 1808 break; 1809 } 1810 screen->protected_mode = saved_mode; 1811} 1812 1813/* 1814 * Just like 'do_erase_line()', except that this intercepts ED controls. If we 1815 * clear the whole screen, we'll get the return-value from ClearInLine, and 1816 * find if there were any protected characters left. If not, reset the 1817 * protected mode flag in the screen data (it's slower). 1818 */ 1819void 1820do_erase_display(XtermWidget xw, int param, int mode) 1821{ 1822 TScreen *screen = TScreenOf(xw); 1823 int saved_mode = screen->protected_mode; 1824 1825 if (saved_mode == DEC_PROTECT 1826 && saved_mode != mode) 1827 screen->protected_mode = OFF_PROTECT; 1828 1829 switch (param) { 1830 case -1: /* DEFAULT */ 1831 case 0: 1832 if (screen->cur_row == 0 1833 && screen->cur_col == 0) { 1834 screen->protected_mode = saved_mode; 1835 do_erase_display(xw, 2, mode); 1836 saved_mode = screen->protected_mode; 1837 } else 1838 ClearBelow(xw); 1839 break; 1840 1841 case 1: 1842 if (screen->cur_row == screen->max_row 1843 && screen->cur_col == screen->max_col) { 1844 screen->protected_mode = saved_mode; 1845 do_erase_display(xw, 2, mode); 1846 saved_mode = screen->protected_mode; 1847 } else 1848 ClearAbove(xw); 1849 break; 1850 1851 case 2: 1852 /* 1853 * We use 'ClearScreen()' throughout the remainder of the 1854 * program for places where we don't care if the characters are 1855 * protected or not. So we modify the logic around this call 1856 * on 'ClearScreen()' to handle protected characters. 1857 */ 1858 if (screen->protected_mode != OFF_PROTECT) { 1859 int row; 1860 int rc = 1; 1861 unsigned len = (unsigned) MaxCols(screen); 1862 1863 assert(screen->max_col >= 0); 1864 for (row = 0; row <= screen->max_row; row++) 1865 rc &= ClearInLine(xw, row, 0, len); 1866 if (rc != 0) 1867 saved_mode = OFF_PROTECT; 1868 } else { 1869 ClearScreen(xw); 1870 } 1871 break; 1872 1873 case 3: 1874 /* xterm addition - erase saved lines. */ 1875 screen->savedlines = 0; 1876 ScrollBarDrawThumb(screen->scrollWidget); 1877 break; 1878 } 1879 screen->protected_mode = saved_mode; 1880} 1881 1882static Boolean 1883screen_has_data(XtermWidget xw) 1884{ 1885 TScreen *screen = TScreenOf(xw); 1886 Boolean result = False; 1887 LineData *ld; 1888 int row, col; 1889 1890 for (row = 0; row < screen->max_row; ++row) { 1891 if ((ld = getLineData(screen, row)) != 0) { 1892 for (col = 0; col < screen->max_col; ++col) { 1893 if (ld->attribs[col] & CHARDRAWN) { 1894 result = True; 1895 break; 1896 } 1897 } 1898 } 1899 if (result) 1900 break; 1901 } 1902 return result; 1903} 1904 1905/* 1906 * Like tiXtraScroll, perform a scroll up of the page contents. In this case, 1907 * it happens for the special case when erasing the whole display starting from 1908 * the upper-left corner of the screen. 1909 */ 1910void 1911do_cd_xtra_scroll(XtermWidget xw) 1912{ 1913 TScreen *screen = TScreenOf(xw); 1914 1915 if (xw->misc.cdXtraScroll 1916 && screen->cur_col == 0 1917 && screen->cur_row == 0 1918 && screen_has_data(xw)) { 1919 xtermScroll(xw, screen->max_row); 1920 } 1921} 1922 1923/* 1924 * Scroll the page up (saving it). This is called when doing terminal 1925 * initialization (ti) or exiting from that (te). 1926 */ 1927void 1928do_ti_xtra_scroll(XtermWidget xw) 1929{ 1930 TScreen *screen = TScreenOf(xw); 1931 1932 if (xw->misc.tiXtraScroll) { 1933 xtermScroll(xw, screen->max_row); 1934 } 1935} 1936 1937static void 1938CopyWait(XtermWidget xw) 1939{ 1940#if OPT_DOUBLE_BUFFER 1941 (void) xw; 1942#else /* !OPT_DOUBLE_BUFFER */ 1943 TScreen *screen = TScreenOf(xw); 1944 XEvent reply; 1945 XEvent *rep = &reply; 1946 1947 for (;;) { 1948 XWindowEvent(screen->display, VWindow(screen), 1949 ExposureMask, &reply); 1950 switch (reply.type) { 1951 case Expose: 1952 HandleExposure(xw, &reply); 1953 break; 1954 case NoExpose: 1955 case GraphicsExpose: 1956 if (screen->incopy <= 0) { 1957 screen->incopy = 1; 1958 if (screen->scrolls > 0) 1959 screen->scrolls--; 1960 } 1961 if (reply.type == GraphicsExpose) 1962 HandleExposure(xw, &reply); 1963 1964 if ((reply.type == NoExpose) || 1965 ((XExposeEvent *) rep)->count == 0) { 1966 if (screen->incopy <= 0 && screen->scrolls > 0) 1967 screen->scrolls--; 1968 if (screen->scrolls == 0) { 1969 screen->incopy = 0; 1970 return; 1971 } 1972 screen->incopy = -1; 1973 } 1974 break; 1975 } 1976 } 1977#endif /* OPT_DOUBLE_BUFFER */ 1978} 1979 1980/* 1981 * used by vertical_copy_area and and horizontal_copy_area 1982 */ 1983static void 1984copy_area(XtermWidget xw, 1985 int src_x, 1986 int src_y, 1987 unsigned width, 1988 unsigned height, 1989 int dest_x, 1990 int dest_y) 1991{ 1992 TScreen *screen = TScreenOf(xw); 1993 1994 if (width != 0 && height != 0) { 1995 /* wait for previous CopyArea to complete unless 1996 multiscroll is enabled and active */ 1997 if (screen->incopy && screen->scrolls == 0) 1998 CopyWait(xw); 1999 screen->incopy = -1; 2000 2001 /* save for translating Expose events */ 2002 screen->copy_src_x = src_x; 2003 screen->copy_src_y = src_y; 2004 screen->copy_width = width; 2005 screen->copy_height = height; 2006 screen->copy_dest_x = dest_x; 2007 screen->copy_dest_y = dest_y; 2008 2009 XCopyArea(screen->display, 2010 VDrawable(screen), VDrawable(screen), 2011 NormalGC(xw, screen), 2012 src_x, src_y, width, height, dest_x, dest_y); 2013 } 2014} 2015 2016/* 2017 * use when inserting or deleting characters on the current line 2018 */ 2019static void 2020horizontal_copy_area(XtermWidget xw, 2021 int firstchar, /* char pos on screen to start copying at */ 2022 int nchars, 2023 int amount) /* number of characters to move right */ 2024{ 2025 TScreen *screen = TScreenOf(xw); 2026 LineData *ld; 2027 2028 if ((ld = getLineData(screen, screen->cur_row)) != 0) { 2029 int src_x = LineCursorX(screen, ld, firstchar); 2030 int src_y = CursorY(screen, screen->cur_row); 2031 2032 copy_area(xw, src_x, src_y, 2033 (unsigned) (nchars * LineFontWidth(screen, ld)), 2034 (unsigned) FontHeight(screen), 2035 src_x + amount * LineFontWidth(screen, ld), src_y); 2036 } 2037} 2038 2039/* 2040 * use when inserting or deleting lines from the screen 2041 */ 2042static void 2043vertical_copy_area(XtermWidget xw, 2044 int firstline, /* line on screen to start copying at */ 2045 int nlines, 2046 int amount, /* number of lines to move up (neg=down) */ 2047 int left, 2048 int right) 2049{ 2050 TScreen *screen = TScreenOf(xw); 2051 2052 TRACE(("vertical_copy_area - firstline=%d nlines=%d left=%d right=%d amount=%d\n", 2053 firstline, nlines, left, right, amount)); 2054 2055 if (nlines > 0) { 2056 int src_x = CursorX(screen, left); 2057 int src_y = firstline * FontHeight(screen) + screen->border; 2058 unsigned int w = (unsigned) ((right + 1 - left) * FontWidth(screen)); 2059 unsigned int h = (unsigned) (nlines * FontHeight(screen)); 2060 int dst_x = src_x; 2061 int dst_y = src_y - amount * FontHeight(screen); 2062 2063 copy_area(xw, src_x, src_y, w, h, dst_x, dst_y); 2064 2065 if (screen->show_wrap_marks) { 2066 LineData *ld; 2067 int row; 2068 for (row = firstline; row < firstline + nlines; ++row) { 2069 if ((ld = getLineData(screen, row)) != 0) { 2070 ShowWrapMarks(xw, row, ld); 2071 } 2072 } 2073 } 2074 } 2075} 2076 2077/* 2078 * use when scrolling the entire screen 2079 */ 2080void 2081scrolling_copy_area(XtermWidget xw, 2082 int firstline, /* line on screen to start copying at */ 2083 int nlines, 2084 int amount) /* number of lines to move up (neg=down) */ 2085{ 2086 2087 if (nlines > 0) { 2088 vertical_copy_area(xw, firstline, nlines, amount, 0, TScreenOf(xw)->max_col); 2089 } 2090} 2091 2092/* 2093 * Handler for Expose events on the VT widget. 2094 * Returns 1 iff the area where the cursor was got refreshed. 2095 */ 2096int 2097HandleExposure(XtermWidget xw, XEvent * event) 2098{ 2099 TScreen *screen = TScreenOf(xw); 2100 XExposeEvent *reply = (XExposeEvent *) event; 2101 2102#ifndef NO_ACTIVE_ICON 2103 if (reply->window == screen->iconVwin.window) { 2104 WhichVWin(screen) = &screen->iconVwin; 2105 TRACE(("HandleExposure - icon\n")); 2106 } else { 2107 WhichVWin(screen) = &screen->fullVwin; 2108 TRACE(("HandleExposure - normal\n")); 2109 } 2110 TRACE((" event %d,%d %dx%d\n", 2111 reply->y, 2112 reply->x, 2113 reply->height, 2114 reply->width)); 2115#endif /* NO_ACTIVE_ICON */ 2116 2117 /* if not doing CopyArea or if this is a GraphicsExpose, don't translate */ 2118 if (!screen->incopy || event->type != Expose) 2119 return handle_translated_exposure(xw, reply->x, reply->y, 2120 reply->width, 2121 reply->height); 2122 else { 2123 /* compute intersection of area being copied with 2124 area being exposed. */ 2125 int both_x1 = Max(screen->copy_src_x, reply->x); 2126 int both_y1 = Max(screen->copy_src_y, reply->y); 2127 int both_x2 = Min(screen->copy_src_x + (int) screen->copy_width, 2128 (reply->x + (int) reply->width)); 2129 int both_y2 = Min(screen->copy_src_y + (int) screen->copy_height, 2130 (reply->y + (int) reply->height)); 2131 int value = 0; 2132 2133 /* was anything copied affected? */ 2134 if (both_x2 > both_x1 && both_y2 > both_y1) { 2135 /* do the copied area */ 2136 value = handle_translated_exposure 2137 (xw, reply->x + screen->copy_dest_x - screen->copy_src_x, 2138 reply->y + screen->copy_dest_y - screen->copy_src_y, 2139 reply->width, reply->height); 2140 } 2141 /* was anything not copied affected? */ 2142 if (reply->x < both_x1 || reply->y < both_y1 2143 || reply->x + reply->width > both_x2 2144 || reply->y + reply->height > both_y2) 2145 value = handle_translated_exposure(xw, reply->x, reply->y, 2146 reply->width, reply->height); 2147 2148 return value; 2149 } 2150} 2151 2152static void 2153set_background(XtermWidget xw, int color GCC_UNUSED) 2154{ 2155 TScreen *screen = TScreenOf(xw); 2156 Pixel c = getXtermBackground(xw, xw->flags, color); 2157 2158 TRACE(("set_background(%d) %#lx\n", color, c)); 2159 XSetWindowBackground(screen->display, VShellWindow(xw), c); 2160 XSetWindowBackground(screen->display, VWindow(screen), c); 2161} 2162 2163/* 2164 * Called by the ExposeHandler to do the actual repaint after the coordinates 2165 * have been translated to allow for any CopyArea in progress. 2166 * The rectangle passed in is pixel coordinates. 2167 */ 2168static int 2169handle_translated_exposure(XtermWidget xw, 2170 int rect_x, 2171 int rect_y, 2172 int rect_width, 2173 int rect_height) 2174{ 2175 TScreen *screen = TScreenOf(xw); 2176 int toprow, leftcol, nrows, ncols; 2177 int x0, x1; 2178 int y0, y1; 2179 int result = 0; 2180 2181 TRACE(("handle_translated_exposure at %d,%d size %dx%d\n", 2182 rect_y, rect_x, rect_height, rect_width)); 2183 2184 x0 = (rect_x - OriginX(screen)); 2185 x1 = (x0 + rect_width); 2186 2187 y0 = (rect_y - OriginY(screen)); 2188 y1 = (y0 + rect_height); 2189 2190 if ((x0 < 0 || 2191 y0 < 0 || 2192 x1 > Width(screen) || 2193 y1 > Height(screen))) { 2194 set_background(xw, -1); 2195#if OPT_DOUBLE_BUFFER 2196 XFillRectangle(screen->display, VDrawable(screen), 2197 ReverseGC(xw, screen), 2198 rect_x, 2199 rect_y, 2200 (unsigned) rect_width, 2201 (unsigned) rect_height); 2202#else 2203 XClearArea(screen->display, VWindow(screen), 2204 rect_x, 2205 rect_y, 2206 (unsigned) rect_width, 2207 (unsigned) rect_height, False); 2208#endif 2209 } 2210 toprow = y0 / FontHeight(screen); 2211 if (toprow < 0) 2212 toprow = 0; 2213 2214 leftcol = x0 / FontWidth(screen); 2215 if (leftcol < 0) 2216 leftcol = 0; 2217 2218 nrows = (y1 - 1) / FontHeight(screen) - toprow + 1; 2219 ncols = (x1 - 1) / FontWidth(screen) - leftcol + 1; 2220 toprow -= screen->scrolls; 2221 if (toprow < 0) { 2222 nrows += toprow; 2223 toprow = 0; 2224 } 2225 if (toprow + nrows > MaxRows(screen)) 2226 nrows = MaxRows(screen) - toprow; 2227 if (leftcol + ncols > MaxCols(screen)) 2228 ncols = MaxCols(screen) - leftcol; 2229 2230 if (nrows > 0 && ncols > 0) { 2231 ScrnRefresh(xw, toprow, leftcol, nrows, ncols, True); 2232 first_map_occurred(); 2233 if (screen->cur_row >= toprow && 2234 screen->cur_row < toprow + nrows && 2235 screen->cur_col >= leftcol && 2236 screen->cur_col < leftcol + ncols) { 2237 result = 1; 2238 } 2239 2240 } 2241 TRACE(("...handle_translated_exposure %d\n", result)); 2242 return (result); 2243} 2244 2245/***====================================================================***/ 2246 2247void 2248GetColors(XtermWidget xw, ScrnColors * pColors) 2249{ 2250 TScreen *screen = TScreenOf(xw); 2251 int n; 2252 2253 pColors->which = 0; 2254 for (n = 0; n < NCOLORS; ++n) { 2255 SET_COLOR_VALUE(pColors, n, T_COLOR(screen, n)); 2256 } 2257} 2258 2259void 2260ChangeColors(XtermWidget xw, ScrnColors * pNew) 2261{ 2262 Bool repaint = False; 2263 TScreen *screen = TScreenOf(xw); 2264 VTwin *win = WhichVWin(screen); 2265 2266 TRACE(("ChangeColors\n")); 2267 2268 if (COLOR_DEFINED(pNew, TEXT_CURSOR)) { 2269 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_CURSOR); 2270 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR))); 2271 /* no repaint needed */ 2272 } else if ((T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) && 2273 (COLOR_DEFINED(pNew, TEXT_FG))) { 2274 if (T_COLOR(screen, TEXT_CURSOR) != COLOR_VALUE(pNew, TEXT_FG)) { 2275 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_FG); 2276 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR))); 2277 if (screen->Vshow) 2278 repaint = True; 2279 } 2280 } 2281 2282 if (COLOR_DEFINED(pNew, TEXT_FG)) { 2283 Pixel fg = COLOR_VALUE(pNew, TEXT_FG); 2284 T_COLOR(screen, TEXT_FG) = fg; 2285 TRACE(("... TEXT_FG: %#lx\n", T_COLOR(screen, TEXT_FG))); 2286 if (screen->Vshow) { 2287 setCgsFore(xw, win, gcNorm, fg); 2288 setCgsBack(xw, win, gcNormReverse, fg); 2289 setCgsFore(xw, win, gcBold, fg); 2290 setCgsBack(xw, win, gcBoldReverse, fg); 2291 repaint = True; 2292 } 2293 } 2294 2295 if (COLOR_DEFINED(pNew, TEXT_BG)) { 2296 Pixel bg = COLOR_VALUE(pNew, TEXT_BG); 2297 T_COLOR(screen, TEXT_BG) = bg; 2298 TRACE(("... TEXT_BG: %#lx\n", T_COLOR(screen, TEXT_BG))); 2299 if (screen->Vshow) { 2300 setCgsBack(xw, win, gcNorm, bg); 2301 setCgsFore(xw, win, gcNormReverse, bg); 2302 setCgsBack(xw, win, gcBold, bg); 2303 setCgsFore(xw, win, gcBoldReverse, bg); 2304 set_background(xw, -1); 2305 repaint = True; 2306 } 2307 } 2308#if OPT_HIGHLIGHT_COLOR 2309 if (COLOR_DEFINED(pNew, HIGHLIGHT_BG)) { 2310 if (T_COLOR(screen, HIGHLIGHT_BG) != COLOR_VALUE(pNew, HIGHLIGHT_BG)) { 2311 T_COLOR(screen, HIGHLIGHT_BG) = COLOR_VALUE(pNew, HIGHLIGHT_BG); 2312 TRACE(("... HIGHLIGHT_BG: %#lx\n", T_COLOR(screen, HIGHLIGHT_BG))); 2313 if (screen->Vshow) 2314 repaint = True; 2315 } 2316 } 2317 if (COLOR_DEFINED(pNew, HIGHLIGHT_FG)) { 2318 if (T_COLOR(screen, HIGHLIGHT_FG) != COLOR_VALUE(pNew, HIGHLIGHT_FG)) { 2319 T_COLOR(screen, HIGHLIGHT_FG) = COLOR_VALUE(pNew, HIGHLIGHT_FG); 2320 TRACE(("... HIGHLIGHT_FG: %#lx\n", T_COLOR(screen, HIGHLIGHT_FG))); 2321 if (screen->Vshow) 2322 repaint = True; 2323 } 2324 } 2325#endif 2326 2327 if (COLOR_DEFINED(pNew, MOUSE_FG) || (COLOR_DEFINED(pNew, MOUSE_BG))) { 2328 if (COLOR_DEFINED(pNew, MOUSE_FG)) { 2329 T_COLOR(screen, MOUSE_FG) = COLOR_VALUE(pNew, MOUSE_FG); 2330 TRACE(("... MOUSE_FG: %#lx\n", T_COLOR(screen, MOUSE_FG))); 2331 } 2332 if (COLOR_DEFINED(pNew, MOUSE_BG)) { 2333 T_COLOR(screen, MOUSE_BG) = COLOR_VALUE(pNew, MOUSE_BG); 2334 TRACE(("... MOUSE_BG: %#lx\n", T_COLOR(screen, MOUSE_BG))); 2335 } 2336 2337 if (screen->Vshow) { 2338 recolor_cursor(screen, 2339 screen->pointer_cursor, 2340 T_COLOR(screen, MOUSE_FG), 2341 T_COLOR(screen, MOUSE_BG)); 2342 XDefineCursor(screen->display, VWindow(screen), 2343 screen->pointer_cursor); 2344 } 2345#if OPT_TEK4014 2346 if (TEK4014_SHOWN(xw)) { 2347 TekScreen *tekscr = TekScreenOf(tekWidget); 2348 Window tekwin = TWindow(tekscr); 2349 if (tekwin) { 2350 recolor_cursor(screen, 2351 tekscr->arrow, 2352 T_COLOR(screen, MOUSE_FG), 2353 T_COLOR(screen, MOUSE_BG)); 2354 XDefineCursor(screen->display, tekwin, tekscr->arrow); 2355 } 2356 } 2357#endif 2358 /* no repaint needed */ 2359 } 2360 2361 if (COLOR_DEFINED(pNew, TEXT_FG) || 2362 COLOR_DEFINED(pNew, TEXT_BG) || 2363 COLOR_DEFINED(pNew, TEXT_CURSOR)) { 2364 if (set_cursor_gcs(xw) && screen->Vshow) { 2365 repaint = True; 2366 } 2367 } 2368#if OPT_TEK4014 2369 if (COLOR_DEFINED(pNew, TEK_FG) || 2370 COLOR_DEFINED(pNew, TEK_BG)) { 2371 ChangeTekColors(tekWidget, screen, pNew); 2372 if (TEK4014_SHOWN(xw)) { 2373 TekRepaint(tekWidget); 2374 } 2375 } else if (COLOR_DEFINED(pNew, TEK_CURSOR)) { 2376 ChangeTekColors(tekWidget, screen, pNew); 2377 } 2378#endif 2379 if (repaint) 2380 xtermRepaint(xw); 2381} 2382 2383void 2384xtermClear(XtermWidget xw) 2385{ 2386 TScreen *screen = TScreenOf(xw); 2387 2388 TRACE(("xtermClear\n")); 2389#if OPT_DOUBLE_BUFFER 2390 XFillRectangle(screen->display, VDrawable(screen), 2391 ReverseGC(xw, screen), 2392 0, 0, 2393 FullWidth(screen), FullHeight(screen)); 2394#else 2395 XClearWindow(screen->display, VWindow(screen)); 2396#endif 2397} 2398 2399void 2400xtermRepaint(XtermWidget xw) 2401{ 2402 TScreen *screen = TScreenOf(xw); 2403 2404 TRACE(("xtermRepaint\n")); 2405 xtermClear(xw); 2406 ScrnRefresh(xw, 0, 0, MaxRows(screen), MaxCols(screen), True); 2407} 2408 2409/***====================================================================***/ 2410 2411Boolean 2412isDefaultForeground(const char *name) 2413{ 2414 return (Boolean) !x_strcasecmp(name, XtDefaultForeground); 2415} 2416 2417Boolean 2418isDefaultBackground(const char *name) 2419{ 2420 return (Boolean) !x_strcasecmp(name, XtDefaultBackground); 2421} 2422 2423#if OPT_WIDE_CHARS 2424/* 2425 * Check for Unicode BIDI control characters, which may be miscategorized via 2426 * wcwidth() and iswprint() as zero-width printable characters. 2427 */ 2428Boolean 2429isWideControl(unsigned ch) 2430{ 2431 Boolean result; 2432 2433 switch (ch) { 2434 case 0x200E: 2435 case 0x200F: 2436 case 0x202A: 2437 case 0x202B: 2438 case 0x202C: 2439 case 0x202D: 2440 case 0x202E: 2441 result = True; 2442 break; 2443 default: 2444 result = False; 2445 break; 2446 } 2447 return result; 2448} 2449#endif 2450 2451/***====================================================================***/ 2452 2453typedef struct { 2454 Pixel fg; 2455 Pixel bg; 2456} ToSwap; 2457 2458#if OPT_HIGHLIGHT_COLOR 2459#define hc_param ,Bool hilite_color 2460#define hc_value ,screen->hilite_color 2461#else 2462#define hc_param /* nothing */ 2463#define hc_value /* nothing */ 2464#endif 2465 2466/* 2467 * Use this to swap the foreground/background color values in the resource 2468 * data, and to build up a list of the pairs which must be swapped in the 2469 * GC cache. 2470 */ 2471static void 2472swapLocally(ToSwap * list, int *count, ColorRes * fg, ColorRes * bg hc_param) 2473{ 2474 ColorRes tmp; 2475 int n; 2476 Boolean found = False; 2477 2478#if OPT_COLOR_RES 2479 Pixel fg_color = fg->value; 2480 Pixel bg_color = bg->value; 2481#else 2482 Pixel fg_color = *fg; 2483 Pixel bg_color = *bg; 2484#endif 2485 2486#if OPT_HIGHLIGHT_COLOR 2487 if ((fg_color != bg_color) || !hilite_color) 2488#endif 2489 { 2490 EXCHANGE(*fg, *bg, tmp); 2491 for (n = 0; n < *count; ++n) { 2492 if ((list[n].fg == fg_color && list[n].bg == bg_color) 2493 || (list[n].fg == bg_color && list[n].bg == fg_color)) { 2494 found = True; 2495 break; 2496 } 2497 } 2498 if (!found) { 2499 list[*count].fg = fg_color; 2500 list[*count].bg = bg_color; 2501 *count = *count + 1; 2502 TRACE(("swapLocally fg %#lx, bg %#lx ->%d\n", 2503 fg_color, bg_color, *count)); 2504 } 2505 } 2506} 2507 2508static void 2509reallySwapColors(XtermWidget xw, ToSwap * list, int count) 2510{ 2511 int j, k; 2512 2513 TRACE(("reallySwapColors\n")); 2514 for (j = 0; j < count; ++j) { 2515 for_each_text_gc(k) { 2516 redoCgs(xw, list[j].fg, list[j].bg, (CgsEnum) k); 2517 } 2518 } 2519} 2520 2521static void 2522swapVTwinGCs(XtermWidget xw, VTwin * win) 2523{ 2524 swapCgs(xw, win, gcNorm, gcNormReverse); 2525 swapCgs(xw, win, gcBold, gcBoldReverse); 2526} 2527 2528void 2529ReverseVideo(XtermWidget xw) 2530{ 2531 TScreen *screen = TScreenOf(xw); 2532 ToSwap listToSwap[5]; 2533 int numToSwap = 0; 2534 2535 TRACE(("ReverseVideo\n")); 2536 2537 /* 2538 * Swap SGR foreground and background colors. By convention, these are 2539 * the colors assigned to "black" (SGR #0) and "white" (SGR #7). Also, 2540 * SGR #8 and SGR #15 are the bold (or bright) versions of SGR #0 and 2541 * #7, respectively. 2542 * 2543 * We don't swap colors that happen to match the screen's foreground 2544 * and background because that tends to produce bizarre effects. 2545 */ 2546#define swapAnyColor(name,a,b) swapLocally(listToSwap, &numToSwap, &(screen->name[a]), &(screen->name[b]) hc_value) 2547#define swapAColor(a,b) swapAnyColor(Acolors, a, b) 2548 if_OPT_ISO_COLORS(screen, { 2549 swapAColor(0, 7); 2550 swapAColor(8, 15); 2551 }); 2552 2553 if (T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) 2554 T_COLOR(screen, TEXT_CURSOR) = T_COLOR(screen, TEXT_BG); 2555 2556#define swapTColor(a,b) swapAnyColor(Tcolors, a, b) 2557 swapTColor(TEXT_FG, TEXT_BG); 2558 swapTColor(MOUSE_FG, MOUSE_BG); 2559 2560 reallySwapColors(xw, listToSwap, numToSwap); 2561 2562 swapVTwinGCs(xw, &(screen->fullVwin)); 2563#ifndef NO_ACTIVE_ICON 2564 swapVTwinGCs(xw, &(screen->iconVwin)); 2565#endif /* NO_ACTIVE_ICON */ 2566 2567 xw->misc.re_verse = (Boolean) !xw->misc.re_verse; 2568 2569 if (XtIsRealized((Widget) xw)) { 2570 xtermDisplayCursor(xw); 2571 } 2572#if OPT_TEK4014 2573 if (TEK4014_SHOWN(xw)) { 2574 TekScreen *tekscr = TekScreenOf(tekWidget); 2575 Window tekwin = TWindow(tekscr); 2576 recolor_cursor(screen, 2577 tekscr->arrow, 2578 T_COLOR(screen, MOUSE_FG), 2579 T_COLOR(screen, MOUSE_BG)); 2580 XDefineCursor(screen->display, tekwin, tekscr->arrow); 2581 } 2582#endif 2583 2584 if (screen->scrollWidget) 2585 ScrollBarReverseVideo(screen->scrollWidget); 2586 2587 if (XtIsRealized((Widget) xw)) { 2588 set_background(xw, -1); 2589 } 2590#if OPT_TEK4014 2591 TekReverseVideo(tekWidget); 2592#endif 2593 if (XtIsRealized((Widget) xw)) { 2594 xtermRepaint(xw); 2595 } 2596#if OPT_TEK4014 2597 if (TEK4014_SHOWN(xw)) { 2598 TekRepaint(tekWidget); 2599 } 2600#endif 2601 ReverseOldColors(); 2602 set_cursor_gcs(xw); 2603 update_reversevideo(); 2604 TRACE(("...ReverseVideo\n")); 2605} 2606 2607void 2608recolor_cursor(TScreen *screen, 2609 Cursor cursor, /* X cursor ID to set */ 2610 unsigned long fg, /* pixel indexes to look up */ 2611 unsigned long bg) /* pixel indexes to look up */ 2612{ 2613 Display *dpy = screen->display; 2614 XColor colordefs[2]; /* 0 is foreground, 1 is background */ 2615 2616 colordefs[0].pixel = fg; 2617 colordefs[1].pixel = bg; 2618 XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), 2619 colordefs, 2); 2620 XRecolorCursor(dpy, cursor, colordefs, colordefs + 1); 2621 cleanup_colored_cursor(); 2622 return; 2623} 2624 2625#if OPT_RENDERFONT 2626static XftColor * 2627getXftColor(XtermWidget xw, Pixel pixel) 2628{ 2629#define CACHE_SIZE 4 2630 static struct { 2631 XftColor color; 2632 int use; 2633 } cache[CACHE_SIZE]; 2634 static int use; 2635 int i; 2636 int oldest, oldestuse; 2637 XColor color; 2638 2639 oldestuse = 0x7fffffff; 2640 oldest = 0; 2641 for (i = 0; i < CACHE_SIZE; i++) { 2642 if (cache[i].use) { 2643 if (cache[i].color.pixel == pixel) { 2644 cache[i].use = ++use; 2645 return &cache[i].color; 2646 } 2647 } 2648 if (cache[i].use < oldestuse) { 2649 oldestuse = cache[i].use; 2650 oldest = i; 2651 } 2652 } 2653 i = oldest; 2654 color.pixel = pixel; 2655 XQueryColor(TScreenOf(xw)->display, xw->core.colormap, &color); 2656 cache[i].color.color.red = color.red; 2657 cache[i].color.color.green = color.green; 2658 cache[i].color.color.blue = color.blue; 2659 cache[i].color.color.alpha = 0xffff; 2660 cache[i].color.pixel = pixel; 2661 cache[i].use = ++use; 2662 return &cache[i].color; 2663} 2664 2665/* 2666 * The cell-width is related to, but not the same as the wide-character width. 2667 * We will only get useful values from wcwidth() for codes above 255. 2668 * Otherwise, interpret according to internal data. 2669 */ 2670#if OPT_RENDERWIDE 2671 2672#if OPT_C1_PRINT 2673#define XtermCellWidth(xw, ch) \ 2674 (((ch) == 0 || (ch) == 127) \ 2675 ? 0 \ 2676 : (((ch) < 256) \ 2677 ? (((ch) >= 128 && (ch) < 160) \ 2678 ? (TScreenOf(xw)->c1_printable ? 1 : 0) \ 2679 : 1) \ 2680 : my_wcwidth(ch))) 2681#else 2682#define XtermCellWidth(xw, ch) \ 2683 (((ch) == 0 || (ch) == 127) \ 2684 ? 0 \ 2685 : (((ch) < 256) \ 2686 ? 1 \ 2687 : my_wcwidth(ch))) 2688#endif 2689 2690#endif /* OPT_RENDERWIDE */ 2691 2692#define XFT_FONT(name) screen->name.font 2693 2694#if OPT_ISO_COLORS 2695#define UseBoldFont(screen) (!(screen)->colorBDMode || ((screen)->veryBoldColors & BOLD)) 2696#else 2697#define UseBoldFont(screen) 1 2698#endif 2699 2700#if OPT_RENDERWIDE 2701static XftFont * 2702getWideXftFont(XtermWidget xw, 2703 unsigned flags) 2704{ 2705 TScreen *screen = TScreenOf(xw); 2706 int fontnum = screen->menu_font_number; 2707 XftFont *wfont; 2708 2709#if OPT_ISO_COLORS 2710 if ((flags & UNDERLINE) 2711 && !screen->colorULMode 2712 && screen->italicULMode 2713 && XFT_FONT(renderWideItal[fontnum])) { 2714 wfont = XFT_FONT(renderWideItal[fontnum]); 2715 } else 2716#endif 2717 if ((flags & BOLDATTR(screen)) 2718 && UseBoldFont(screen) 2719 && XFT_FONT(renderWideBold[fontnum])) { 2720 wfont = XFT_FONT(renderWideBold[fontnum]); 2721 } else { 2722 wfont = XFT_FONT(renderWideNorm[fontnum]); 2723 } 2724 return wfont; 2725} 2726#endif /* OPT_RENDERWIDE */ 2727 2728static XftFont * 2729getNormXftFont(XtermWidget xw, 2730 unsigned flags, 2731 Bool *did_ul) 2732{ 2733 TScreen *screen = TScreenOf(xw); 2734 int fontnum = screen->menu_font_number; 2735 XftFont *font; 2736 2737#if OPT_ISO_COLORS 2738 if ((flags & UNDERLINE) 2739 && !screen->colorULMode 2740 && screen->italicULMode 2741 && XFT_FONT(renderFontItal[fontnum])) { 2742 font = XFT_FONT(renderFontItal[fontnum]); 2743 *did_ul = True; 2744 } else 2745#endif 2746 if ((flags & BOLDATTR(screen)) 2747 && UseBoldFont(screen) 2748 && XFT_FONT(renderFontBold[fontnum])) { 2749 font = XFT_FONT(renderFontBold[fontnum]); 2750 } else { 2751 font = XFT_FONT(renderFontNorm[fontnum]); 2752 } 2753 return font; 2754} 2755 2756#if OPT_RENDERWIDE 2757#define pickXftFont(width, nf, wf) ((width == 2 && wf != 0) ? wf : nf) 2758#else 2759#define pickXftFont(width, nf, wf) (nf) 2760#endif 2761 2762/* 2763 * fontconfig/Xft combination prior to 2.2 has a problem with 2764 * CJK truetype 'double-width' (bi-width/monospace) fonts leading 2765 * to the 's p a c e d o u t' rendering. Consequently, we can't 2766 * rely on XftDrawString8/16 when one of those fonts is used. 2767 * Instead, we need to roll out our own using XftDrawCharSpec. 2768 * A patch in the same spirit (but in a rather different form) 2769 * was applied to gnome vte and gtk2 port of vim. 2770 * See http://bugzilla.mozilla.org/show_bug.cgi?id=196312 2771 */ 2772static int 2773xtermXftDrawString(XtermWidget xw, 2774 unsigned flags GCC_UNUSED, 2775 XftColor * color, 2776 XftFont * font, 2777 int x, 2778 int y, 2779 IChar *text, 2780 Cardinal len, 2781 Bool really) 2782{ 2783 TScreen *screen = TScreenOf(xw); 2784 int ncells = 0; 2785 2786 if (len != 0) { 2787#if OPT_RENDERWIDE 2788 XftCharSpec *sbuf; 2789 XftFont *wfont = getWideXftFont(xw, flags); 2790 Cardinal src, dst; 2791 XftFont *lastFont = 0; 2792 XftFont *currFont = 0; 2793 Cardinal start = 0; 2794 int charWidth; 2795 int fwidth = FontWidth(screen); 2796 2797 BumpTypedBuffer(XftCharSpec, len); 2798 sbuf = BfBuf(XftCharSpec); 2799 2800 for (src = dst = 0; src < len; src++) { 2801 FcChar32 wc = *text++; 2802 2803 charWidth = XtermCellWidth(xw, (wchar_t) wc); 2804 if (charWidth < 0) 2805 continue; 2806 2807 sbuf[dst].ucs4 = wc; 2808 sbuf[dst].x = (short) (x + fwidth * ncells); 2809 sbuf[dst].y = (short) (y); 2810 2811 currFont = pickXftFont(charWidth, font, wfont); 2812 ncells += charWidth; 2813 2814 if (lastFont != currFont) { 2815 if ((lastFont != 0) && really) { 2816 XftDrawCharSpec(screen->renderDraw, 2817 color, 2818 lastFont, 2819 sbuf + start, 2820 (int) (dst - start)); 2821 } 2822 start = dst; 2823 lastFont = currFont; 2824 } 2825 ++dst; 2826 } 2827 if ((dst != start) && really) { 2828 XftDrawCharSpec(screen->renderDraw, 2829 color, 2830 lastFont, 2831 sbuf + start, 2832 (int) (dst - start)); 2833 } 2834#else /* !OPT_RENDERWIDE */ 2835 if (really) { 2836 XftChar8 *buffer; 2837 int dst; 2838 2839 BumpTypedBuffer(XftChar8, len); 2840 buffer = BfBuf(XftChar8); 2841 2842 for (dst = 0; dst < (int) len; ++dst) 2843 buffer[dst] = CharOf(text[dst]); 2844 2845 XftDrawString8(screen->renderDraw, 2846 color, 2847 font, 2848 x, y, buffer, (int) len); 2849 } 2850 ncells = (int) len; 2851#endif 2852 } 2853 return ncells; 2854} 2855#define xtermXftWidth(xw, flags, color, font, x, y, chars, len) \ 2856 xtermXftDrawString(xw, flags, color, font, x, y, chars, len, False) 2857#endif /* OPT_RENDERFONT */ 2858 2859#if OPT_WIDE_CHARS 2860/* 2861 * Map characters commonly "fixed" by groff back to their ASCII equivalents. 2862 * Also map other useful equivalents. 2863 */ 2864unsigned 2865AsciiEquivs(unsigned ch) 2866{ 2867 switch (ch) { 2868 case 0x2010: /* groff "-" */ 2869 case 0x2011: 2870 case 0x2012: 2871 case 0x2013: 2872 case 0x2014: 2873 case 0x2015: 2874 case 0x2212: /* groff "\-" */ 2875 ch = '-'; 2876 break; 2877 case 0x2018: /* groff "`" */ 2878 ch = '`'; 2879 break; 2880 case 0x2019: /* groff ' */ 2881 ch = '\''; 2882 break; 2883 case 0x201C: /* groff lq */ 2884 case 0x201D: /* groff rq */ 2885 ch = '"'; 2886 break; 2887 case 0x2329: /* groff ".URL" */ 2888 ch = '<'; 2889 break; 2890 case 0x232a: /* groff ".URL" */ 2891 ch = '>'; 2892 break; 2893 default: 2894 if (ch >= 0xff01 && ch <= 0xff5e) { 2895 /* "Fullwidth" codes (actually double-width) */ 2896 ch -= 0xff00; 2897 ch += ANSI_SPA; 2898 break; 2899 } 2900 } 2901 return ch; 2902} 2903 2904/* 2905 * Actually this should be called "groff_workaround()" - for the places where 2906 * groff stomps on compatibility. Still, if enough people get used to it, 2907 * this might someday become a quasi-standard. 2908 */ 2909#if OPT_BOX_CHARS 2910static int 2911ucs_workaround(XtermWidget xw, 2912 unsigned ch, 2913 unsigned flags, 2914 GC gc, 2915 int x, 2916 int y, 2917 int chrset, 2918 int on_wide) 2919{ 2920 TScreen *screen = TScreenOf(xw); 2921 int fixed = False; 2922 2923 if (screen->wide_chars && screen->utf8_mode && ch > 256) { 2924 IChar eqv = (IChar) AsciiEquivs(ch); 2925 2926 if (eqv != (IChar) ch) { 2927 int width = my_wcwidth((wchar_t) ch); 2928 2929 do { 2930 drawXtermText(xw, 2931 flags, 2932 gc, 2933 x, 2934 y, 2935 chrset, 2936 &eqv, 2937 1, 2938 on_wide); 2939 x += FontWidth(screen); 2940 eqv = '?'; 2941 } while (width-- > 1); 2942 2943 fixed = True; 2944 } else if (ch == HIDDEN_CHAR) { 2945 fixed = True; 2946 } 2947 } 2948 return fixed; 2949} 2950#endif /* OPT_BOX_CHARS */ 2951#endif /* OPT_WIDE_CHARS */ 2952 2953/* 2954 * Use this when the characters will not fill the cell area properly. Fill the 2955 * area where we'll write the characters, otherwise we'll get gaps between 2956 * them, e.g., in the original background color. 2957 * 2958 * The cursor is a special case, because the XFillRectangle call only uses the 2959 * foreground, while we've set the cursor color in the background. So we need 2960 * a special GC for that. 2961 */ 2962static void 2963xtermFillCells(XtermWidget xw, 2964 unsigned flags, 2965 GC gc, 2966 int x, 2967 int y, 2968 Cardinal len) 2969{ 2970 TScreen *screen = TScreenOf(xw); 2971 VTwin *currentWin = WhichVWin(screen); 2972 2973 if (!(flags & NOBACKGROUND)) { 2974 CgsEnum srcId = getCgsId(xw, currentWin, gc); 2975 CgsEnum dstId = gcMAX; 2976 Pixel fg = getCgsFore(xw, currentWin, gc); 2977 Pixel bg = getCgsBack(xw, currentWin, gc); 2978 2979 switch (srcId) { 2980 case gcVTcursNormal: 2981 case gcVTcursReverse: 2982 dstId = gcVTcursOutline; 2983 break; 2984 case gcVTcursFilled: 2985 case gcVTcursOutline: 2986 /* FIXME */ 2987 break; 2988 case gcNorm: 2989 dstId = gcNormReverse; 2990 break; 2991 case gcNormReverse: 2992 dstId = gcNorm; 2993 break; 2994 case gcBold: 2995 dstId = gcBoldReverse; 2996 break; 2997 case gcBoldReverse: 2998 dstId = gcBold; 2999 break; 3000#if OPT_BOX_CHARS 3001 case gcLine: 3002 case gcDots: 3003 /* FIXME */ 3004 break; 3005#endif 3006#if OPT_DEC_CHRSET 3007 case gcCNorm: 3008 case gcCBold: 3009 /* FIXME */ 3010 break; 3011#endif 3012#if OPT_WIDE_CHARS 3013 case gcWide: 3014 dstId = gcWideReverse; 3015 break; 3016 case gcWBold: 3017 dstId = gcBoldReverse; 3018 break; 3019 case gcWideReverse: 3020 case gcWBoldReverse: 3021 /* FIXME */ 3022 break; 3023#endif 3024#if OPT_TEK4014 3025 case gcTKcurs: 3026 /* FIXME */ 3027 break; 3028#endif 3029 case gcMAX: 3030 break; 3031 } 3032 3033 if (dstId != gcMAX) { 3034 setCgsFore(xw, currentWin, dstId, bg); 3035 setCgsBack(xw, currentWin, dstId, fg); 3036 3037 XFillRectangle(screen->display, VDrawable(screen), 3038 getCgsGC(xw, currentWin, dstId), 3039 x, y, 3040 len * (Cardinal) FontWidth(screen), 3041 (unsigned) FontHeight(screen)); 3042 } 3043 } 3044} 3045 3046#if OPT_TRACE 3047static void 3048xtermSetClipRectangles(Display *dpy, 3049 GC gc, 3050 int x, 3051 int y, 3052 XRectangle * rp, 3053 Cardinal nr, 3054 int order) 3055{ 3056#if 0 3057 TScreen *screen = TScreenOf(term); 3058 Drawable draw = VDrawable(screen); 3059 3060 XSetClipMask(dpy, gc, None); 3061 XDrawRectangle(screen->display, draw, gc, 3062 x + rp->x - 1, 3063 y + rp->y - 1, 3064 rp->width, 3065 rp->height); 3066#endif 3067 3068 XSetClipRectangles(dpy, gc, 3069 x, y, rp, (int) nr, order); 3070 TRACE(("clipping @(%3d,%3d) (%3d,%3d)..(%3d,%3d)\n", 3071 y, x, 3072 rp->y, rp->x, rp->height, rp->width)); 3073} 3074 3075#else 3076#define xtermSetClipRectangles(dpy, gc, x, y, rp, nr, order) \ 3077 XSetClipRectangles(dpy, gc, x, y, rp, (int) nr, order) 3078#endif 3079 3080#if OPT_CLIP_BOLD 3081/* 3082 * This special case is a couple of percent slower, but avoids a lot of pixel 3083 * trash in rxcurses' hanoi.cmd demo (e.g., 10x20 font). 3084 */ 3085#define beginClipping(screen,gc,pwidth,plength) \ 3086 if (screen->use_clipping && (pwidth > 2)) { \ 3087 XRectangle clip; \ 3088 int clip_x = x; \ 3089 int clip_y = y - FontHeight(screen) + FontDescent(screen); \ 3090 clip.x = 0; \ 3091 clip.y = 0; \ 3092 clip.height = (unsigned short) FontHeight(screen); \ 3093 clip.width = (unsigned short) (pwidth * plength); \ 3094 xtermSetClipRectangles(screen->display, gc, \ 3095 clip_x, clip_y, \ 3096 &clip, 1, Unsorted); \ 3097 } 3098#define endClipping(screen,gc) \ 3099 XSetClipMask(screen->display, gc, None) 3100#else 3101#define beginClipping(screen,gc,pwidth,plength) /* nothing */ 3102#define endClipping(screen,gc) /* nothing */ 3103#endif /* OPT_CLIP_BOLD */ 3104 3105#if OPT_CLIP_BOLD && OPT_RENDERFONT && defined(HAVE_XFTDRAWSETCLIP) && defined(HAVE_XFTDRAWSETCLIPRECTANGLES) 3106#define beginXftClipping(screen,px,py,plength) \ 3107 if (screen->use_clipping && (FontWidth(screen) > 2)) { \ 3108 XRectangle clip; \ 3109 double adds = (screen->scale_height - 1.0) * FontHeight(screen); \ 3110 int height = dimRound(adds + FontHeight(screen)); \ 3111 int descnt = dimRound(adds / 2.0) + FontDescent(screen); \ 3112 int clip_x = px; \ 3113 int clip_y = py - height + descnt; \ 3114 clip.x = 0; \ 3115 clip.y = 0; \ 3116 clip.height = (unsigned short) height; \ 3117 clip.width = (unsigned short) (FontWidth(screen) * plength); \ 3118 XftDrawSetClipRectangles (screen->renderDraw, \ 3119 clip_x, clip_y, \ 3120 &clip, 1); \ 3121 } 3122#define endXftClipping(screen) \ 3123 XftDrawSetClip (screen->renderDraw, 0) 3124#else 3125#define beginXftClipping(screen,px,py,plength) /* nothing */ 3126#define endXftClipping(screen) /* nothing */ 3127#endif /* OPT_CLIP_BOLD */ 3128 3129#if OPT_RENDERFONT 3130static int 3131drawClippedXftString(XtermWidget xw, 3132 unsigned flags, 3133 XftFont * font, 3134 XftColor * fg_color, 3135 int x, 3136 int y, 3137 IChar *text, 3138 Cardinal len) 3139{ 3140 int ncells = xtermXftWidth(xw, flags, 3141 fg_color, 3142 font, x, y, 3143 text, 3144 len); 3145 TScreen *screen = TScreenOf(xw); 3146 3147 beginXftClipping(screen, x, y, ncells); 3148 xtermXftDrawString(xw, flags, 3149 fg_color, 3150 font, x, y, 3151 text, 3152 len, 3153 True); 3154 endXftClipping(screen); 3155 return ncells; 3156} 3157#endif 3158 3159#ifndef NO_ACTIVE_ICON 3160#define WhichVFontData(screen,name) \ 3161 (IsIcon(screen) ? &((screen)->fnt_icon) \ 3162 : &((screen)->name)) 3163#else 3164#define WhichVFontData(screen,name) \ 3165 (&((screen)->name)) 3166#endif 3167 3168/* 3169 * Draws text with the specified combination of bold/underline. The return 3170 * value is the updated x position. 3171 */ 3172int 3173drawXtermText(XtermWidget xw, 3174 unsigned flags, 3175 GC gc, 3176 int start_x, 3177 int start_y, 3178 int chrset, 3179 IChar *text, 3180 Cardinal len, 3181 int on_wide) 3182{ 3183 int x = start_x, y = start_y; 3184 TScreen *screen = TScreenOf(xw); 3185 Cardinal real_length = len; 3186 Cardinal underline_len = 0; 3187 /* Intended width of the font to draw (as opposed to the actual width of 3188 the X font, and the width of the default font) */ 3189 int font_width = ((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide; 3190 Bool did_ul = False; 3191 XTermFonts *curFont; 3192 3193#if OPT_WIDE_CHARS 3194 if (text == 0) 3195 return 0; 3196#endif 3197#if OPT_DEC_CHRSET 3198 if (CSET_DOUBLE(chrset)) { 3199 /* We could try drawing double-size characters in the icon, but 3200 * given that the icon font is usually nil or nil2, there 3201 * doesn't seem to be much point. 3202 */ 3203 int inx = 0; 3204 GC gc2 = ((!IsIcon(screen) && screen->font_doublesize) 3205 ? xterm_DoubleGC(xw, (unsigned) chrset, flags, gc, &inx) 3206 : 0); 3207 3208 TRACE(("DRAWTEXT%c[%4d,%4d] (%d)%3d:%s\n", 3209 screen->cursor_state == OFF ? ' ' : '*', 3210 y, x, chrset, len, 3211 visibleIChars(text, len))); 3212 3213 if (gc2 != 0) { /* draw actual double-sized characters */ 3214 XFontStruct *fs = screen->double_fonts[inx].fs; 3215 3216#if OPT_RENDERFONT 3217 if (!UsingRenderFont(xw)) 3218#endif 3219 { 3220 XRectangle rect, *rp = ▭ 3221 Cardinal nr = 1; 3222 3223 font_width *= 2; 3224 flags |= DOUBLEWFONT; 3225 3226 rect.x = 0; 3227 rect.y = 0; 3228 rect.width = (unsigned short) ((int) len * font_width); 3229 rect.height = (unsigned short) (FontHeight(screen)); 3230 3231 TRACE(("drawing %s\n", visibleDblChrset((unsigned) chrset))); 3232 switch (chrset) { 3233 case CSET_DHL_TOP: 3234 rect.y = (short) -(fs->ascent / 2); 3235 y -= rect.y; 3236 flags |= DOUBLEHFONT; 3237 break; 3238 case CSET_DHL_BOT: 3239 rect.y = (short) (rect.height - (fs->ascent / 2)); 3240 y -= rect.y; 3241 flags |= DOUBLEHFONT; 3242 break; 3243 default: 3244 nr = 0; 3245 break; 3246 } 3247 3248 if (nr) { 3249 xtermSetClipRectangles(screen->display, gc2, 3250 x, y, rp, nr, YXBanded); 3251 } else { 3252 XSetClipMask(screen->display, gc2, None); 3253 } 3254 } 3255 3256 /* Call ourselves recursively with the new gc */ 3257 3258 /* 3259 * If we're trying to use proportional font, or if the 3260 * font server didn't give us what we asked for wrt 3261 * width, position each character independently. 3262 */ 3263 if (screen->fnt_prop 3264 || (fs->min_bounds.width != fs->max_bounds.width) 3265 || (fs->min_bounds.width != 2 * FontWidth(screen))) { 3266 /* It is hard to fall-through to the main 3267 branch: in a lot of places the check 3268 for the cached font info is for 3269 normal/bold fonts only. */ 3270 while (len--) { 3271 x = drawXtermText(xw, flags, gc2, 3272 x, y, 0, 3273 text++, 3274 1, on_wide); 3275 x += FontWidth(screen); 3276 } 3277 } else { 3278 x = drawXtermText(xw, flags, gc2, 3279 x, y, 0, 3280 text, 3281 len, on_wide); 3282 x += (int) len *FontWidth(screen); 3283 } 3284 3285 TRACE(("drawtext [%4d,%4d]\n", y, x)); 3286 } else { /* simulate double-sized characters */ 3287 unsigned need = 2 * len; 3288 IChar *temp = TypeMallocN(IChar, need); 3289 unsigned n = 0; 3290 3291 while (len--) { 3292 temp[n++] = *text++; 3293 temp[n++] = ' '; 3294 } 3295 x = drawXtermText(xw, 3296 flags, 3297 gc, 3298 x, y, 3299 0, 3300 temp, 3301 n, 3302 on_wide); 3303 free(temp); 3304 } 3305 return x; 3306 } 3307#endif 3308#if OPT_RENDERFONT 3309 if (UsingRenderFont(xw)) { 3310 VTwin *currentWin = WhichVWin(screen); 3311 Display *dpy = screen->display; 3312 XftFont *font, *font0; 3313 XGCValues values; 3314 int ncells; 3315#if OPT_RENDERWIDE 3316 XftFont *wfont, *wfont0; 3317#endif 3318 if (!screen->renderDraw) { 3319 int scr; 3320 Drawable draw = VDrawable(screen); 3321 Visual *visual; 3322 3323 scr = DefaultScreen(dpy); 3324 visual = DefaultVisual(dpy, scr); 3325 screen->renderDraw = XftDrawCreate(dpy, draw, visual, 3326 DefaultColormap(dpy, scr)); 3327 } 3328#define IS_BOLD (flags & BOLDATTR(screen)) 3329#define NOT_BOLD (flags & ~BOLDATTR(screen)) 3330 font = getNormXftFont(xw, flags, &did_ul); 3331 font0 = IS_BOLD ? getNormXftFont(xw, NOT_BOLD, &did_ul) : font; 3332#if OPT_RENDERWIDE 3333 wfont = getWideXftFont(xw, flags); 3334 wfont0 = IS_BOLD ? getWideXftFont(xw, NOT_BOLD) : wfont; 3335#endif 3336 values.foreground = getCgsFore(xw, currentWin, gc); 3337 values.background = getCgsBack(xw, currentWin, gc); 3338 3339 if (!(flags & NOBACKGROUND)) { 3340 XftColor *bg_color = getXftColor(xw, values.background); 3341 ncells = xtermXftWidth(xw, flags, 3342 bg_color, 3343 font, x, y, 3344 text, 3345 len); 3346 XftDrawRect(screen->renderDraw, 3347 bg_color, 3348 x, y, 3349 (unsigned) (ncells * FontWidth(screen)), 3350 (unsigned) FontHeight(screen)); 3351 } 3352 3353 y += font->ascent; 3354#if OPT_BOX_CHARS 3355 { 3356 /* adding code to substitute simulated line-drawing characters */ 3357 int last, first = 0; 3358 Dimension old_wide, old_high = 0; 3359 int curX = x; 3360 3361 for (last = 0; last < (int) len; last++) { 3362 Boolean replace = False; 3363 Boolean missing = False; 3364 unsigned ch = (unsigned) text[last]; 3365 int filler = 0; 3366 int nc; 3367#if OPT_WIDE_CHARS 3368 int needed = my_wcwidth((wchar_t) ch); 3369 XftFont *currFont = pickXftFont(needed, font, wfont); 3370 3371 if (xtermIsDecGraphic(ch)) { 3372 /* 3373 * Xft generally does not have the line-drawing characters 3374 * in cells 1-31. Assume this (we cannot inspect the 3375 * picture easily...), and attempt to fill in from real 3376 * line-drawing character in the font at the Unicode 3377 * position. Failing that, use our own box-characters. 3378 */ 3379 if (screen->force_box_chars 3380 || xtermXftMissing(xw, currFont, dec2ucs(ch))) { 3381 missing = 1; 3382 } else { 3383 ch = dec2ucs(ch); 3384 replace = True; 3385 } 3386 } else if (ch >= 256) { 3387 /* 3388 * If we're reading UTF-8 from the client, we may have a 3389 * line-drawing character. Translate it back to our 3390 * box-code if Xft tells us that the glyph is missing. 3391 */ 3392 if_OPT_WIDE_CHARS(screen, { 3393 unsigned part = ucs2dec(ch); 3394 if (xtermIsDecGraphic(part)) { 3395 if (screen->force_box_chars 3396 || xtermXftMissing(xw, currFont, ch)) { 3397 ch = part; 3398 missing = True; 3399 } 3400 } else if (xtermXftMissing(xw, currFont, ch)) { 3401 XftFont *test = pickXftFont(needed, font0, wfont0); 3402 if (!xtermXftMissing(xw, test, ch)) { 3403 currFont = test; 3404 replace = True; 3405 filler = needed - 1; 3406 } else if ((part = AsciiEquivs(ch)) != ch) { 3407 filler = needed - 1; 3408 ch = part; 3409 replace = True; 3410 } 3411 } 3412 }); 3413 } 3414#else 3415 XftFont *currFont = font; 3416 if (xtermIsDecGraphic(ch)) { 3417 /* 3418 * Xft generally does not have the line-drawing characters 3419 * in cells 1-31. Check for this, and attempt to fill in 3420 * from real line-drawing character in the font at the 3421 * Unicode position. Failing that, use our own 3422 * box-characters. 3423 */ 3424 if (xtermXftMissing(xw, currFont, ch)) { 3425 missing = 1; 3426 } 3427 } 3428#endif 3429 3430 /* 3431 * If we now have one of our box-codes, draw it directly. 3432 */ 3433 if (missing || replace) { 3434 /* line drawing character time */ 3435 if (last > first) { 3436 nc = drawClippedXftString(xw, 3437 flags, 3438 currFont, 3439 getXftColor(xw, values.foreground), 3440 curX, 3441 y, 3442 text + first, 3443 (Cardinal) (last - first)); 3444 curX += nc * FontWidth(screen); 3445 underline_len += (Cardinal) nc; 3446 } 3447 if (missing) { 3448 old_wide = screen->fnt_wide; 3449 old_high = screen->fnt_high; 3450 screen->fnt_wide = (Dimension) FontWidth(screen); 3451 screen->fnt_high = (Dimension) FontHeight(screen); 3452 xtermDrawBoxChar(xw, ch, flags, gc, 3453 curX, y - FontAscent(screen), 1); 3454 curX += FontWidth(screen); 3455 underline_len += 1; 3456 screen->fnt_wide = old_wide; 3457 screen->fnt_high = old_high; 3458 } else { 3459 IChar ch2 = (IChar) ch; 3460 nc = drawClippedXftString(xw, 3461 flags, 3462 currFont, 3463 getXftColor(xw, values.foreground), 3464 curX, 3465 y, 3466 &ch2, 3467 1); 3468 curX += nc * FontWidth(screen); 3469 underline_len += (Cardinal) nc; 3470 if (filler) { 3471 ch2 = ' '; 3472 nc = drawClippedXftString(xw, 3473 flags, 3474 currFont, 3475 getXftColor(xw, values.foreground), 3476 curX, 3477 y, 3478 &ch2, 3479 1); 3480 curX += nc * FontWidth(screen); 3481 underline_len += (Cardinal) nc; 3482 } 3483 } 3484 first = last + 1; 3485 } 3486 } 3487 if (last > first) { 3488 underline_len += (Cardinal) 3489 drawClippedXftString(xw, 3490 flags, 3491 font, 3492 getXftColor(xw, values.foreground), 3493 curX, 3494 y, 3495 text + first, 3496 (Cardinal) (last - first)); 3497 } 3498 } 3499#else 3500 { 3501 underline_len += (Cardinal) 3502 drawClippedXftString(xw, 3503 flags, 3504 font, 3505 getXftColor(xw, values.foreground), 3506 x, 3507 y, 3508 text, 3509 len); 3510 } 3511#endif /* OPT_BOX_CHARS */ 3512 3513 if ((flags & UNDERLINE) && screen->underline && !did_ul) { 3514 if (FontDescent(screen) > 1) 3515 y++; 3516 XDrawLine(screen->display, VDrawable(screen), gc, 3517 x, y, 3518 x + (int) underline_len * FontWidth(screen) - 1, 3519 y); 3520 } 3521 3522 x += (int) len *FontWidth(screen); 3523 3524 return x; 3525 } 3526#endif /* OPT_RENDERFONT */ 3527 curFont = ((flags & BOLDATTR(screen)) 3528 ? WhichVFontData(screen, fnts[fBold]) 3529 : WhichVFontData(screen, fnts[fNorm])); 3530 /* 3531 * If we're asked to display a proportional font, do this with a fixed 3532 * pitch. Yes, it's ugly. But we cannot distinguish the use of xterm 3533 * as a dumb terminal vs its use as in fullscreen programs such as vi. 3534 * Hint: do not try to use a proportional font in the icon. 3535 */ 3536 if (!IsIcon(screen) && !(flags & CHARBYCHAR) && screen->fnt_prop) { 3537 int adj, width; 3538 3539 while (len--) { 3540 int cells = WideCells(*text); 3541#if OPT_BOX_CHARS 3542#if OPT_WIDE_CHARS 3543 if (*text == HIDDEN_CHAR) { 3544 ++text; 3545 continue; 3546 } else 3547#endif 3548 if (IsXtermMissingChar(screen, *text, curFont)) { 3549 adj = 0; 3550 } else 3551#endif 3552 { 3553 if_WIDE_OR_NARROW(screen, { 3554 XChar2b temp[1]; 3555 temp[0].byte2 = LO_BYTE(*text); 3556 temp[0].byte1 = HI_BYTE(*text); 3557 width = XTextWidth16(curFont->fs, temp, 1); 3558 } 3559 , { 3560 char temp[1]; 3561 temp[0] = (char) LO_BYTE(*text); 3562 width = XTextWidth(curFont->fs, temp, 1); 3563 }); 3564 adj = (FontWidth(screen) - width) / 2; 3565 if (adj < 0) 3566 adj = 0; 3567 } 3568 xtermFillCells(xw, flags, gc, x, y, (Cardinal) cells); 3569 x = drawXtermText(xw, 3570 flags | NOBACKGROUND | CHARBYCHAR, 3571 gc, x + adj, y, chrset, 3572 text++, 1, on_wide) - adj; 3573 } 3574 3575 return x; 3576 } 3577#if OPT_BOX_CHARS 3578 /* 3579 * Draw some substitutions, if needed. The font may not include the 3580 * line-drawing set, or it may be incomplete (in which case we'll draw an 3581 * empty space via xtermDrawBoxChar), or we may be told to force our 3582 * line-drawing. 3583 * 3584 * The empty space is a special case which can be overridden with the 3585 * showMissingGlyphs resource to produce an outline. Not all fonts in 3586 * "modern" (sic) X provide an empty space; some use a thick outline or 3587 * something like the replacement character. If you would rather not see 3588 * that, you can set assumeAllChars. 3589 */ 3590 if (!IsIcon(screen) 3591 && !(flags & NOTRANSLATION) 3592 && (!screen->fnt_boxes 3593 || (FontIsIncomplete(curFont) && !screen->assume_all_chars) 3594 || screen->force_box_chars)) { 3595 /* Fill in missing box-characters. 3596 Find regions without missing characters, and draw 3597 them calling ourselves recursively. Draw missing 3598 characters via xtermDrawBoxChar(). */ 3599 int last, first = 0; 3600 Bool drewBoxes = False; 3601 3602 for (last = 0; last < (int) len; last++) { 3603 unsigned ch = (unsigned) text[last]; 3604 Bool isMissing; 3605 int ch_width; 3606#if OPT_WIDE_CHARS 3607 3608 if (ch == HIDDEN_CHAR) { 3609 if (last > first) { 3610 x = drawXtermText(xw, flags | NOTRANSLATION, gc, 3611 x, y, 3612 chrset, text + first, 3613 (unsigned) (last - first), on_wide); 3614 } 3615 first = last + 1; 3616 drewBoxes = True; 3617 continue; 3618 } 3619 ch_width = my_wcwidth((wchar_t) ch); 3620 isMissing = 3621 IsXtermMissingChar(screen, ch, 3622 ((on_wide || ch_width > 1) 3623 && okFont(NormalWFont(screen))) 3624 ? WhichVFontData(screen, fnts[fWide]) 3625 : curFont); 3626#else 3627 isMissing = IsXtermMissingChar(screen, ch, curFont); 3628 ch_width = 1; 3629#endif 3630 /* 3631 * If the character is not missing, but we're in wide-character 3632 * mode and the character happens to be a wide-character that 3633 * corresponds to the line-drawing set, allow the forceBoxChars 3634 * resource (or menu entry) to force it to display using our 3635 * tables. 3636 */ 3637 if_OPT_WIDE_CHARS(screen, { 3638 if (!isMissing 3639 && TScreenOf(xw)->force_box_chars) { 3640 if (ch > 255 3641 && ucs2dec(ch) < 32) { 3642 ch = ucs2dec(ch); 3643 isMissing = True; 3644 } else if (ch < 32) { 3645 isMissing = True; 3646 } 3647 } 3648 }); 3649 3650 if (isMissing) { 3651 if (last > first) { 3652 x = drawXtermText(xw, flags | NOTRANSLATION, gc, 3653 x, y, 3654 chrset, text + first, 3655 (unsigned) (last - first), on_wide); 3656 } 3657#if OPT_WIDE_CHARS 3658 /* 3659 * One way or another, we will draw at least one cell. 3660 */ 3661 if (ch_width <= 0) 3662 ch_width = 1; 3663 if (!ucs_workaround(xw, ch, flags, gc, x, y, chrset, on_wide)) { 3664 xtermDrawBoxChar(xw, ch, flags, gc, x, y, ch_width); 3665 } 3666#else 3667 xtermDrawBoxChar(xw, ch, flags, gc, x, y, ch_width); 3668#endif 3669 x += (ch_width * FontWidth(screen)); 3670 first = last + 1; 3671 drewBoxes = True; 3672 } 3673 } 3674 if (last <= first) { 3675 return x; 3676 } 3677 text += first; 3678 len = (Cardinal) (last - first); 3679 flags |= NOTRANSLATION; 3680 if (drewBoxes) { 3681 return drawXtermText(xw, 3682 flags, 3683 gc, 3684 x, 3685 y, 3686 chrset, 3687 text, 3688 len, 3689 on_wide); 3690 } 3691 } 3692#endif /* OPT_BOX_CHARS */ 3693 /* 3694 * Behave as if the font has (maybe Unicode-replacements for) drawing 3695 * characters in the range 1-31 (either we were not asked to ignore them, 3696 * or the caller made sure that there is none). 3697 */ 3698 TRACE(("drawtext%c[%4d,%4d] (%d) %d:%s\n", 3699 screen->cursor_state == OFF ? ' ' : '*', 3700 y, x, chrset, len, 3701 visibleIChars(text, len))); 3702 if (screen->scale_height != 1.0) { 3703 xtermFillCells(xw, flags, gc, x, y, (Cardinal) len); 3704 } 3705 y += FontAscent(screen); 3706 3707#if OPT_WIDE_CHARS 3708 3709 if (screen->wide_chars || screen->unicode_font) { 3710 XChar2b *buffer; 3711 Bool needWide = False; 3712 int ascent_adjust = 0; 3713 int src, dst; 3714 Bool useBoldFont; 3715 3716 BumpTypedBuffer(XChar2b, len); 3717 buffer = BfBuf(XChar2b); 3718 3719 for (src = dst = 0; src < (int) len; src++) { 3720 IChar ch = text[src]; 3721 3722 if (ch == HIDDEN_CHAR) 3723 continue; 3724 3725 if (!needWide 3726 && !IsIcon(screen) 3727 && ((on_wide || my_wcwidth((wchar_t) ch) > 1) 3728 && okFont(NormalWFont(screen)))) { 3729 needWide = True; 3730 } 3731 3732 /* 3733 * bitmap-fonts are limited to 16-bits. 3734 */ 3735#if OPT_WIDER_ICHAR 3736 if (ch > 0xffff) { 3737 ch = UCS_REPL; 3738 } 3739#endif 3740 buffer[dst].byte2 = LO_BYTE(ch); 3741 buffer[dst].byte1 = HI_BYTE(ch); 3742#if OPT_MINI_LUIT 3743#define UCS2SBUF(value) buffer[dst].byte2 = LO_BYTE(value);\ 3744 buffer[dst].byte1 = HI_BYTE(value) 3745 3746#define Map2Sbuf(from,to) (text[src] == from) { UCS2SBUF(to); } 3747 3748 if (screen->latin9_mode && !screen->utf8_mode && text[src] < 256) { 3749 3750 /* see http://www.cs.tut.fi/~jkorpela/latin9.html */ 3751 /* *INDENT-OFF* */ 3752 if Map2Sbuf(0xa4, 0x20ac) 3753 else if Map2Sbuf(0xa6, 0x0160) 3754 else if Map2Sbuf(0xa8, 0x0161) 3755 else if Map2Sbuf(0xb4, 0x017d) 3756 else if Map2Sbuf(0xb8, 0x017e) 3757 else if Map2Sbuf(0xbc, 0x0152) 3758 else if Map2Sbuf(0xbd, 0x0153) 3759 else if Map2Sbuf(0xbe, 0x0178) 3760 /* *INDENT-ON* */ 3761 3762 } 3763 if (screen->unicode_font 3764 && (text[src] == ANSI_DEL || 3765 text[src] < ANSI_SPA)) { 3766 unsigned ni = dec2ucs((unsigned) ((text[src] == ANSI_DEL) 3767 ? 0 3768 : text[src])); 3769 UCS2SBUF(ni); 3770 } 3771#endif /* OPT_MINI_LUIT */ 3772 ++dst; 3773 } 3774 3775 /* 3776 * Check for special case where the bold font lacks glyphs found in the 3777 * normal font, and drop down to normal fonts with overstriking to help 3778 * show the actual characters. 3779 */ 3780 useBoldFont = ((flags & BOLDATTR(screen)) != 0); 3781 if (useBoldFont) { 3782 XTermFonts *norm = 0; 3783 XTermFonts *bold = 0; 3784 Bool noBold, noNorm; 3785 3786 if (needWide && okFont(BoldWFont(screen))) { 3787 norm = WhichVFontData(screen, fnts[fWide]); 3788 bold = WhichVFontData(screen, fnts[fWBold]); 3789 } else if (okFont(BoldFont(screen))) { 3790 norm = WhichVFontData(screen, fnts[fNorm]); 3791 bold = WhichVFontData(screen, fnts[fBold]); 3792 } else { 3793 useBoldFont = False; 3794 } 3795 3796 if (useBoldFont && FontIsIncomplete(bold)) { 3797 for (src = 0; src < (int) len; src++) { 3798 IChar ch = text[src]; 3799 3800 if (ch == HIDDEN_CHAR) 3801 continue; 3802 3803 noBold = IsXtermMissingChar(screen, ch, bold); 3804 if (noBold) { 3805 noNorm = IsXtermMissingChar(screen, ch, norm); 3806 if (!noNorm) { 3807 useBoldFont = False; 3808 break; 3809 } 3810 } 3811 } 3812 } 3813 } 3814 3815 /* FIXME This is probably wrong. But it works. */ 3816 underline_len = len; 3817 3818 /* Set the drawing font */ 3819 if (!(flags & (DOUBLEHFONT | DOUBLEWFONT))) { 3820 VTwin *currentWin = WhichVWin(screen); 3821 VTFontEnum fntId; 3822 CgsEnum cgsId; 3823 Pixel fg = getCgsFore(xw, currentWin, gc); 3824 Pixel bg = getCgsBack(xw, currentWin, gc); 3825 3826 if (needWide 3827 && useBoldFont 3828 && okFont(BoldWFont(screen))) { 3829 fntId = fWBold; 3830 cgsId = gcWBold; 3831 } else if (needWide) { 3832 fntId = fWide; 3833 cgsId = gcWide; 3834 } else if (useBoldFont) { 3835 fntId = fBold; 3836 cgsId = gcBold; 3837 } else { 3838 fntId = fNorm; 3839 cgsId = gcNorm; 3840 } 3841 3842 setCgsFore(xw, currentWin, cgsId, fg); 3843 setCgsBack(xw, currentWin, cgsId, bg); 3844 gc = getCgsGC(xw, currentWin, cgsId); 3845 3846 if (fntId != fNorm) { 3847 XFontStruct *thisFp = WhichVFont(screen, fnts[fntId].fs); 3848 ascent_adjust = (thisFp->ascent 3849 - NormalFont(screen)->ascent); 3850 if (thisFp->max_bounds.width == 3851 NormalFont(screen)->max_bounds.width * 2) { 3852 underline_len = real_length = (Cardinal) (dst * 2); 3853 } else if (cgsId == gcWide || cgsId == gcWBold) { 3854 underline_len = real_length = (Cardinal) (dst * 2); 3855 xtermFillCells(xw, 3856 flags, 3857 gc, 3858 x, 3859 y - thisFp->ascent, 3860 real_length); 3861 } 3862 } 3863 } 3864 3865 if (flags & NOBACKGROUND) { 3866 XDrawString16(screen->display, 3867 VDrawable(screen), gc, 3868 x, y + ascent_adjust, 3869 buffer, dst); 3870 } else { 3871 XDrawImageString16(screen->display, 3872 VDrawable(screen), gc, 3873 x, y + ascent_adjust, 3874 buffer, dst); 3875 } 3876 3877 if ((flags & BOLDATTR(screen)) && (screen->enbolden || !useBoldFont)) { 3878 beginClipping(screen, gc, (Cardinal) font_width, len); 3879 XDrawString16(screen->display, VDrawable(screen), gc, 3880 x + 1, 3881 y + ascent_adjust, 3882 buffer, dst); 3883 endClipping(screen, gc); 3884 } 3885 3886 } else 3887#endif /* OPT_WIDE_CHARS */ 3888 { 3889 int length = (int) len; /* X should have used unsigned */ 3890#if OPT_WIDE_CHARS 3891 char *buffer; 3892 int dst; 3893 3894 BumpTypedBuffer(char, len); 3895 buffer = BfBuf(char); 3896 3897 for (dst = 0; dst < length; ++dst) 3898 buffer[dst] = (char) LO_BYTE(text[dst]); 3899#else 3900 char *buffer = (char *) text; 3901#endif 3902 3903 if (flags & NOBACKGROUND) { 3904 XDrawString(screen->display, VDrawable(screen), gc, 3905 x, y, buffer, length); 3906 } else { 3907 XDrawImageString(screen->display, VDrawable(screen), gc, 3908 x, y, buffer, length); 3909 } 3910 underline_len = (Cardinal) length; 3911 if ((flags & BOLDATTR(screen)) && screen->enbolden) { 3912 beginClipping(screen, gc, font_width, length); 3913 XDrawString(screen->display, VDrawable(screen), gc, 3914 x + 1, y, buffer, length); 3915 endClipping(screen, gc); 3916 } 3917 } 3918 3919 if ((flags & UNDERLINE) && screen->underline && !did_ul) { 3920 if (FontDescent(screen) > 1) 3921 y++; 3922 XDrawLine(screen->display, VDrawable(screen), gc, 3923 x, y, (x + (int) underline_len * font_width - 1), y); 3924 } 3925 3926 x += (int) real_length *FontWidth(screen); 3927 return x; 3928} 3929 3930#if OPT_WIDE_CHARS 3931/* 3932 * Allocate buffer - workaround for wide-character interfaces. 3933 */ 3934void 3935allocXtermChars(ScrnPtr * buffer, Cardinal length) 3936{ 3937 if (*buffer == 0) { 3938 *buffer = (ScrnPtr) XtMalloc(length); 3939 } else { 3940 *buffer = (ScrnPtr) XtRealloc((char *) *buffer, length); 3941 } 3942} 3943#endif 3944 3945/* set up size hints for window manager; min 1 char by 1 char */ 3946void 3947xtermSizeHints(XtermWidget xw, int scrollbarWidth) 3948{ 3949 TScreen *screen = TScreenOf(xw); 3950 3951 TRACE(("xtermSizeHints\n")); 3952 TRACE((" border %d\n", xw->core.border_width)); 3953 TRACE((" scrollbar %d\n", scrollbarWidth)); 3954 3955 xw->hints.base_width = 2 * screen->border + scrollbarWidth; 3956 xw->hints.base_height = 2 * screen->border; 3957 3958#if OPT_TOOLBAR 3959 TRACE((" toolbar %d\n", ToolbarHeight(xw))); 3960 3961 xw->hints.base_height += ToolbarHeight(xw); 3962 xw->hints.base_height += BorderWidth(xw) * 2; 3963 xw->hints.base_width += BorderWidth(xw) * 2; 3964#endif 3965 3966 xw->hints.width_inc = FontWidth(screen); 3967 xw->hints.height_inc = FontHeight(screen); 3968 xw->hints.min_width = xw->hints.base_width + xw->hints.width_inc; 3969 xw->hints.min_height = xw->hints.base_height + xw->hints.height_inc; 3970 3971 xw->hints.width = MaxCols(screen) * FontWidth(screen) + xw->hints.min_width; 3972 xw->hints.height = MaxRows(screen) * FontHeight(screen) + xw->hints.min_height; 3973 3974 xw->hints.flags |= (PSize | PBaseSize | PMinSize | PResizeInc); 3975 3976 TRACE_HINTS(&(xw->hints)); 3977} 3978 3979void 3980getXtermSizeHints(XtermWidget xw) 3981{ 3982 TScreen *screen = TScreenOf(xw); 3983 long supp; 3984 3985 if (!XGetWMNormalHints(screen->display, VShellWindow(xw), 3986 &xw->hints, &supp)) 3987 memset(&xw->hints, 0, sizeof(xw->hints)); 3988 TRACE_HINTS(&(xw->hints)); 3989} 3990 3991/* 3992 * Returns a GC, selected according to the font (reverse/bold/normal) that is 3993 * required for the current position (implied). The GC is updated with the 3994 * current screen foreground and background colors. 3995 */ 3996GC 3997updatedXtermGC(XtermWidget xw, unsigned flags, unsigned fg_bg, Bool hilite) 3998{ 3999 TScreen *screen = TScreenOf(xw); 4000 VTwin *win = WhichVWin(screen); 4001 CgsEnum cgsId = gcMAX; 4002 unsigned my_fg = extract_fg(xw, fg_bg, flags); 4003 unsigned my_bg = extract_bg(xw, fg_bg, flags); 4004 Pixel fg_pix = getXtermForeground(xw, flags, my_fg); 4005 Pixel bg_pix = getXtermBackground(xw, flags, my_bg); 4006 Pixel xx_pix; 4007#if OPT_HIGHLIGHT_COLOR 4008 Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG); 4009 Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG); 4010 Boolean always = screen->hilite_color; 4011 Boolean use_selbg = (Boolean) (always || 4012 isNotForeground(xw, fg_pix, bg_pix, selbg_pix)); 4013 Boolean use_selfg = (Boolean) (always && 4014 isNotBackground(xw, fg_pix, bg_pix, selfg_pix)); 4015#endif 4016 4017 (void) fg_bg; 4018 (void) my_bg; 4019 (void) my_fg; 4020 4021 /* 4022 * Discard video attributes overridden by colorXXXMode's. 4023 */ 4024 checkVeryBoldColors(flags, my_fg); 4025 4026 if (ReverseOrHilite(screen, flags, hilite)) { 4027 if (flags & BOLDATTR(screen)) { 4028 cgsId = gcBoldReverse; 4029 } else { 4030 cgsId = gcNormReverse; 4031 } 4032 4033#if OPT_HIGHLIGHT_COLOR 4034 if (!screen->hilite_color) { 4035 if (selbg_pix != T_COLOR(screen, TEXT_FG) 4036 && selbg_pix != fg_pix 4037 && selbg_pix != bg_pix 4038 && selbg_pix != xw->dft_foreground) { 4039 bg_pix = fg_pix; 4040 fg_pix = selbg_pix; 4041 } 4042 } 4043#endif 4044 EXCHANGE(fg_pix, bg_pix, xx_pix); 4045#if OPT_HIGHLIGHT_COLOR 4046 if (screen->hilite_color) { 4047 if (screen->hilite_reverse) { 4048 if (use_selbg) { 4049 if (use_selfg) 4050 bg_pix = fg_pix; 4051 else 4052 fg_pix = bg_pix; 4053 } 4054 if (use_selbg) 4055 bg_pix = selbg_pix; 4056 if (use_selfg) 4057 fg_pix = selfg_pix; 4058 } 4059 } 4060#endif 4061 } else { 4062 if (flags & BOLDATTR(screen)) { 4063 cgsId = gcBold; 4064 } else { 4065 cgsId = gcNorm; 4066 } 4067 } 4068#if OPT_HIGHLIGHT_COLOR 4069 if (!screen->hilite_color || !screen->hilite_reverse) { 4070 if (hilite && !screen->hilite_reverse) { 4071 if (use_selbg) 4072 bg_pix = selbg_pix; 4073 if (use_selfg) 4074 fg_pix = selfg_pix; 4075 } 4076 } 4077#endif 4078 4079#if OPT_BLINK_TEXT 4080 if ((screen->blink_state == ON) && (!screen->blink_as_bold) && (flags & BLINK)) { 4081 fg_pix = bg_pix; 4082 } 4083#endif 4084 4085 setCgsFore(xw, win, cgsId, fg_pix); 4086 setCgsBack(xw, win, cgsId, bg_pix); 4087 return getCgsGC(xw, win, cgsId); 4088} 4089 4090/* 4091 * Resets the foreground/background of the GC returned by 'updatedXtermGC()' 4092 * to the values that would be set in SGR_Foreground and SGR_Background. This 4093 * duplicates some logic, but only modifies 1/4 as many GC's. 4094 */ 4095void 4096resetXtermGC(XtermWidget xw, unsigned flags, Bool hilite) 4097{ 4098 TScreen *screen = TScreenOf(xw); 4099 VTwin *win = WhichVWin(screen); 4100 CgsEnum cgsId = gcMAX; 4101 Pixel fg_pix = getXtermForeground(xw, flags, xw->cur_foreground); 4102 Pixel bg_pix = getXtermBackground(xw, flags, xw->cur_background); 4103 4104 checkVeryBoldColors(flags, xw->cur_foreground); 4105 4106 if (ReverseOrHilite(screen, flags, hilite)) { 4107 if (flags & BOLDATTR(screen)) { 4108 cgsId = gcBoldReverse; 4109 } else { 4110 cgsId = gcNormReverse; 4111 } 4112 4113 setCgsFore(xw, win, cgsId, bg_pix); 4114 setCgsBack(xw, win, cgsId, fg_pix); 4115 4116 } else { 4117 if (flags & BOLDATTR(screen)) { 4118 cgsId = gcBold; 4119 } else { 4120 cgsId = gcNorm; 4121 } 4122 4123 setCgsFore(xw, win, cgsId, fg_pix); 4124 setCgsBack(xw, win, cgsId, bg_pix); 4125 } 4126} 4127 4128#if OPT_ISO_COLORS 4129/* 4130 * Extract the foreground-color index from a color pair. 4131 * If we've got BOLD or UNDERLINE color-mode active, those will be used. 4132 */ 4133unsigned 4134extract_fg(XtermWidget xw, unsigned color, unsigned flags) 4135{ 4136 unsigned fg = ExtractForeground(color); 4137 4138 if (TScreenOf(xw)->colorAttrMode 4139 || (fg == ExtractBackground(color))) { 4140 fg = MapToColorMode(fg, TScreenOf(xw), flags); 4141 } 4142 return fg; 4143} 4144 4145/* 4146 * Extract the background-color index from a color pair. 4147 * If we've got INVERSE color-mode active, that will be used. 4148 */ 4149unsigned 4150extract_bg(XtermWidget xw, unsigned color, unsigned flags) 4151{ 4152 unsigned bg = ExtractBackground(color); 4153 4154 if (TScreenOf(xw)->colorAttrMode 4155 || (bg == ExtractForeground(color))) { 4156 if (TScreenOf(xw)->colorRVMode && (flags & INVERSE)) 4157 bg = COLOR_RV; 4158 } 4159 return bg; 4160} 4161 4162/* 4163 * Combine the current foreground and background into a single 8-bit number. 4164 * Note that we're storing the SGR foreground, since cur_foreground may be set 4165 * to COLOR_UL, COLOR_BD or COLOR_BL, which would make the code larger than 8 4166 * bits. 4167 * 4168 * This assumes that fg/bg are equal when we override with one of the special 4169 * attribute colors. 4170 */ 4171CellColor 4172makeColorPair(int fg, int bg) 4173{ 4174 unsigned my_bg = (bg >= 0) && (bg < NUM_ANSI_COLORS) ? (unsigned) bg : 0; 4175 unsigned my_fg = (fg >= 0) && (fg < NUM_ANSI_COLORS) ? (unsigned) fg : my_bg; 4176 4177 return (CellColor) (my_fg | (my_bg << COLOR_BITS)); 4178} 4179 4180/* 4181 * Using the "current" SGR background, clear a rectangle. 4182 */ 4183void 4184ClearCurBackground(XtermWidget xw, 4185 int top, 4186 int left, 4187 unsigned height, 4188 unsigned width, 4189 unsigned fw) 4190{ 4191 TScreen *screen = TScreenOf(xw); 4192 4193 TRACE(("ClearCurBackground %d,%d %dx%d with %d\n", 4194 top, left, height, width, xw->cur_background)); 4195 4196 assert((int) width > 0); 4197 assert((left + (int) width) <= screen->max_col + 1); 4198 assert((int) height <= screen->max_row + 1); 4199 4200 if (VWindow(screen)) { 4201 set_background(xw, xw->cur_background); 4202 4203#if OPT_DOUBLE_BUFFER 4204 XFillRectangle(screen->display, VDrawable(screen), 4205 ReverseGC(xw, screen), 4206 CursorX2(screen, left, fw), 4207 CursorY(screen, top), 4208 (width * fw), 4209 (height * (unsigned) FontHeight(screen))); 4210#else 4211 XClearArea(screen->display, VWindow(screen), 4212 CursorX2(screen, left, fw), 4213 CursorY2(screen, top), 4214 (width * fw), 4215 (height * (unsigned) FontHeight(screen)), 4216 False); 4217#endif 4218 4219 set_background(xw, -1); 4220 } 4221} 4222#endif /* OPT_ISO_COLORS */ 4223 4224/* 4225 * Returns a single base character for the given cell. 4226 */ 4227unsigned 4228getXtermCell(TScreen *screen, int row, int col) 4229{ 4230 LineData *ld = getLineData(screen, row); 4231 4232 return ((ld && (col < (int) ld->lineSize)) 4233 ? ld->charData[col] 4234 : (unsigned) ' '); 4235} 4236 4237/* 4238 * Sets a single base character for the given cell. 4239 */ 4240void 4241putXtermCell(TScreen *screen, int row, int col, int ch) 4242{ 4243 LineData *ld = getLineData(screen, row); 4244 4245 if (ld && (col < (int) ld->lineSize)) { 4246 ld->charData[col] = (CharData) ch; 4247 if_OPT_WIDE_CHARS(screen, { 4248 size_t off; 4249 for_each_combData(off, ld) { 4250 ld->combData[off][col] = 0; 4251 } 4252 }); 4253 } 4254} 4255 4256#if OPT_WIDE_CHARS 4257/* 4258 * Add a combining character for the given cell 4259 */ 4260void 4261addXtermCombining(TScreen *screen, int row, int col, unsigned ch) 4262{ 4263 if (ch != 0) { 4264 LineData *ld = getLineData(screen, row); 4265 size_t off; 4266 4267 TRACE(("addXtermCombining %d,%d %#x (%d)\n", 4268 row, col, ch, my_wcwidth((wchar_t) ch))); 4269 4270 for_each_combData(off, ld) { 4271 if (!ld->combData[off][col]) { 4272 ld->combData[off][col] = (CharData) ch; 4273 break; 4274 } 4275 } 4276 } 4277} 4278 4279unsigned 4280getXtermCombining(TScreen *screen, int row, int col, int off) 4281{ 4282 LineData *ld = getLineData(screen, row); 4283 return ld->combData[off][col]; 4284} 4285#endif 4286 4287void 4288update_keyboard_type(void) 4289{ 4290 update_delete_del(); 4291 update_tcap_fkeys(); 4292 update_old_fkeys(); 4293 update_hp_fkeys(); 4294 update_sco_fkeys(); 4295 update_sun_fkeys(); 4296 update_sun_kbd(); 4297} 4298 4299void 4300set_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set) 4301{ 4302 xtermKeyboardType save = xw->keyboard.type; 4303 4304 TRACE(("set_keyboard_type(%s, %s) currently %s\n", 4305 visibleKeyboardType(type), 4306 BtoS(set), 4307 visibleKeyboardType(xw->keyboard.type))); 4308 if (set) { 4309 xw->keyboard.type = type; 4310 } else { 4311 xw->keyboard.type = keyboardIsDefault; 4312 } 4313 4314 if (save != xw->keyboard.type) { 4315 update_keyboard_type(); 4316 } 4317} 4318 4319void 4320toggle_keyboard_type(XtermWidget xw, xtermKeyboardType type) 4321{ 4322 xtermKeyboardType save = xw->keyboard.type; 4323 4324 TRACE(("toggle_keyboard_type(%s) currently %s\n", 4325 visibleKeyboardType(type), 4326 visibleKeyboardType(xw->keyboard.type))); 4327 if (xw->keyboard.type == type) { 4328 xw->keyboard.type = keyboardIsDefault; 4329 } else { 4330 xw->keyboard.type = type; 4331 } 4332 4333 if (save != xw->keyboard.type) { 4334 update_keyboard_type(); 4335 } 4336} 4337 4338void 4339init_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set) 4340{ 4341 static Bool wasSet = False; 4342 4343 TRACE(("init_keyboard_type(%s, %s) currently %s\n", 4344 visibleKeyboardType(type), 4345 BtoS(set), 4346 visibleKeyboardType(xw->keyboard.type))); 4347 if (set) { 4348 if (wasSet) { 4349 xtermWarning("Conflicting keyboard type option (%u/%u)\n", 4350 xw->keyboard.type, type); 4351 } 4352 xw->keyboard.type = type; 4353 wasSet = True; 4354 update_keyboard_type(); 4355 } 4356} 4357 4358/* 4359 * If the keyboardType resource is set, use that, overriding the individual 4360 * boolean resources for different keyboard types. 4361 */ 4362void 4363decode_keyboard_type(XtermWidget xw, XTERM_RESOURCE * rp) 4364{ 4365#define DATA(n, t, f) { n, t, XtOffsetOf(XTERM_RESOURCE, f) } 4366#define FLAG(n) *(Boolean *)(((char *)rp) + table[n].offset) 4367 static struct { 4368 const char *name; 4369 xtermKeyboardType type; 4370 unsigned offset; 4371 } table[] = { 4372#if OPT_HP_FUNC_KEYS 4373 DATA(NAME_HP_KT, keyboardIsHP, hpFunctionKeys), 4374#endif 4375#if OPT_SCO_FUNC_KEYS 4376 DATA(NAME_SCO_KT, keyboardIsSCO, scoFunctionKeys), 4377#endif 4378#if OPT_SUN_FUNC_KEYS 4379 DATA(NAME_SUN_KT, keyboardIsSun, sunFunctionKeys), 4380#endif 4381#if OPT_SUNPC_KBD 4382 DATA(NAME_VT220_KT, keyboardIsVT220, sunKeyboard), 4383#endif 4384#if OPT_TCAP_FKEYS 4385 DATA(NAME_TCAP_KT, keyboardIsTermcap, termcapKeys), 4386#endif 4387 }; 4388 Cardinal n; 4389 4390 TRACE(("decode_keyboard_type(%s)\n", rp->keyboardType)); 4391 if (!x_strcasecmp(rp->keyboardType, "unknown")) { 4392 /* 4393 * Let the individual resources comprise the keyboard-type. 4394 */ 4395 for (n = 0; n < XtNumber(table); ++n) 4396 init_keyboard_type(xw, table[n].type, FLAG(n)); 4397 } else if (!x_strcasecmp(rp->keyboardType, "default")) { 4398 /* 4399 * Set the keyboard-type to the Sun/PC type, allowing modified 4400 * function keys, etc. 4401 */ 4402 for (n = 0; n < XtNumber(table); ++n) 4403 init_keyboard_type(xw, table[n].type, False); 4404 } else { 4405 Bool found = False; 4406 4407 /* 4408 * Choose an individual keyboard type. 4409 */ 4410 for (n = 0; n < XtNumber(table); ++n) { 4411 if (!x_strcasecmp(rp->keyboardType, table[n].name + 1)) { 4412 FLAG(n) = True; 4413 found = True; 4414 } else { 4415 FLAG(n) = False; 4416 } 4417 init_keyboard_type(xw, table[n].type, FLAG(n)); 4418 } 4419 if (!found) { 4420 xtermWarning("KeyboardType resource \"%s\" not found\n", 4421 rp->keyboardType); 4422 } 4423 } 4424#undef DATA 4425#undef FLAG 4426} 4427 4428#if OPT_WIDE_CHARS 4429#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH) 4430/* 4431 * If xterm is running in a UTF-8 locale, it is still possible to encounter 4432 * old runtime configurations which yield incomplete or inaccurate data. 4433 */ 4434static Bool 4435systemWcwidthOk(int samplesize, int samplepass) 4436{ 4437 wchar_t n; 4438 int oops = 0; 4439 4440 for (n = 21; n <= 25; ++n) { 4441 wchar_t code = (wchar_t) dec2ucs((unsigned) n); 4442 int system_code = wcwidth(code); 4443 int intern_code = mk_wcwidth(code); 4444 4445 /* 4446 * Solaris 10 wcwidth() returns "2" for all of the line-drawing (page 4447 * 0x2500) and most of the geometric shapes (a few are excluded, just 4448 * to make it more difficult to use). Do a sanity check to avoid using 4449 * it. 4450 */ 4451 if ((system_code < 0 && intern_code >= 1) 4452 || (system_code >= 0 && intern_code != system_code)) { 4453 TRACE(("systemWcwidthOk: broken system line-drawing wcwidth\n")); 4454 oops += (samplepass + 1); 4455 break; 4456 } 4457 } 4458 4459 for (n = 0; n < (wchar_t) samplesize; ++n) { 4460 int system_code = wcwidth(n); 4461 int intern_code = mk_wcwidth(n); 4462 4463 /* 4464 * Since mk_wcwidth() is designed to check for nonspacing characters, 4465 * and has rough range-checks for double-width characters, it will 4466 * generally not detect cases where a code has not been assigned. 4467 * 4468 * Some experimentation with GNU libc suggests that up to 1/4 of the 4469 * codes would differ, simply because the runtime library would have a 4470 * table listing the unassigned codes, and return -1 for those. If 4471 * mk_wcwidth() has no information about a code, it returns 1. On the 4472 * other hand, if the runtime returns a positive number, the two should 4473 * agree. 4474 * 4475 * The "up to" is measured for 4k, 8k, 16k of data. With only 1k, the 4476 * number of differences was only 77. However, that is only one 4477 * system, and this is only a sanity check to avoid using broken 4478 * libraries. 4479 */ 4480 if ((system_code < 0 && intern_code >= 1) 4481 || (system_code >= 0 && intern_code != system_code)) { 4482 ++oops; 4483 } 4484 } 4485 TRACE(("systemWcwidthOk: %d/%d mismatches, allowed %d\n", 4486 oops, samplesize, samplepass)); 4487 return (oops <= samplepass); 4488} 4489#endif /* HAVE_WCWIDTH */ 4490 4491void 4492decode_wcwidth(XtermWidget xw) 4493{ 4494 int mode = ((xw->misc.cjk_width ? 2 : 0) 4495 + (xw->misc.mk_width ? 1 : 0) 4496 + 1); 4497 4498 switch (mode) { 4499 default: 4500#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH) 4501 if (xtermEnvUTF8() && 4502 systemWcwidthOk(xw->misc.mk_samplesize, xw->misc.mk_samplepass)) { 4503 my_wcwidth = wcwidth; 4504 TRACE(("using system wcwidth() function\n")); 4505 break; 4506 } 4507 /* FALLTHRU */ 4508#endif 4509 case 2: 4510 my_wcwidth = &mk_wcwidth; 4511 TRACE(("using MK wcwidth() function\n")); 4512 break; 4513 case 3: 4514 case 4: 4515 my_wcwidth = &mk_wcwidth_cjk; 4516 TRACE(("using MK-CJK wcwidth() function\n")); 4517 break; 4518 } 4519 4520 for (first_widechar = 128; first_widechar < 4500; ++first_widechar) { 4521 if (my_wcwidth((int) first_widechar) > 1) { 4522 TRACE(("first_widechar %#x\n", first_widechar)); 4523 break; 4524 } 4525 } 4526} 4527#endif 4528 4529/* 4530 * Extend a (normally) boolean resource value by checking for additional values 4531 * which will be mapped into true/false. 4532 */ 4533int 4534extendedBoolean(const char *value, FlagList * table, Cardinal limit) 4535{ 4536 int result = -1; 4537 long check; 4538 char *next; 4539 Cardinal n; 4540 4541 if ((x_strcasecmp(value, "true") == 0) 4542 || (x_strcasecmp(value, "yes") == 0) 4543 || (x_strcasecmp(value, "on") == 0)) { 4544 result = True; 4545 } else if ((x_strcasecmp(value, "false") == 0) 4546 || (x_strcasecmp(value, "no") == 0) 4547 || (x_strcasecmp(value, "off") == 0)) { 4548 result = False; 4549 } else if ((check = strtol(value, &next, 0)) >= 0 && *next == '\0') { 4550 if (check >= (long) limit) 4551 check = True; 4552 result = (int) check; 4553 } else { 4554 for (n = 0; n < limit; ++n) { 4555 if (x_strcasecmp(value, table[n].name) == 0) { 4556 result = table[n].code; 4557 break; 4558 } 4559 } 4560 } 4561 4562 if (result < 0) { 4563 xtermWarning("Unrecognized keyword: %s\n", value); 4564 result = False; 4565 } 4566 4567 TRACE(("extendedBoolean(%s) = %d\n", value, result)); 4568 return result; 4569} 4570 4571/* 4572 * Something like round() from math library, but round() is less widely-used 4573 * than xterm. Also, there are no negative numbers to complicate this. 4574 */ 4575int 4576dimRound(double value) 4577{ 4578 int result = (int) value; 4579 if (result < value) 4580 ++result; 4581 return result; 4582} 4583