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