util.c revision 20d2c4d2
1/* $XTermId: util.c,v 1.538 2010/06/15 08:17:36 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 screen->do_wrap = False; 1347} 1348 1349/* 1350 * Clear first part of cursor's line, inclusive. 1351 */ 1352static void 1353ClearLeft(XtermWidget xw) 1354{ 1355 TScreen *screen = TScreenOf(xw); 1356 unsigned len = (unsigned) screen->cur_col + 1; 1357 1358 assert(screen->cur_col >= 0); 1359 if (AddToVisible(xw)) { 1360 if_OPT_WIDE_CHARS(screen, { 1361 int row = screen->cur_row; 1362 int kl; 1363 int kr; 1364 if (DamagedCurCells(screen, 1, &kl, &kr) && kr >= kl) { 1365 ClearInLine2(xw, 0, row, kl, (unsigned) (kr - kl + 1)); 1366 } 1367 }); 1368 (void) ClearInLine(xw, screen->cur_row, 0, len); 1369 } else { 1370 ScrnClearCells(xw, screen->cur_row, 0, len); 1371 } 1372} 1373 1374/* 1375 * Erase the cursor's line. 1376 */ 1377static void 1378ClearLine(XtermWidget xw) 1379{ 1380 TScreen *screen = TScreenOf(xw); 1381 unsigned len = (unsigned) MaxCols(screen); 1382 1383 assert(screen->max_col >= 0); 1384 (void) ClearInLine(xw, screen->cur_row, 0, len); 1385} 1386 1387void 1388ClearScreen(XtermWidget xw) 1389{ 1390 TScreen *screen = TScreenOf(xw); 1391 int top; 1392 1393 if (screen->cursor_state) 1394 HideCursor(); 1395 1396 ScrnDisownSelection(xw); 1397 screen->do_wrap = False; 1398 if ((top = INX2ROW(screen, 0)) <= screen->max_row) { 1399 if (screen->scroll_amt) 1400 FlushScroll(xw); 1401 ClearCurBackground(xw, 1402 top * FontHeight(screen) + screen->border, 1403 OriginX(screen), 1404 (unsigned) ((screen->max_row - top + 1) 1405 * FontHeight(screen)), 1406 (unsigned) Width(screen)); 1407 } 1408 ClearBufRows(xw, 0, screen->max_row); 1409} 1410 1411/* 1412 * If we've written protected text DEC-style, and are issuing a non-DEC 1413 * erase, temporarily reset the protected_mode flag so that the erase will 1414 * ignore the protected flags. 1415 */ 1416void 1417do_erase_line(XtermWidget xw, int param, int mode) 1418{ 1419 TScreen *screen = TScreenOf(xw); 1420 int saved_mode = screen->protected_mode; 1421 1422 if (saved_mode == DEC_PROTECT 1423 && saved_mode != mode) { 1424 screen->protected_mode = OFF_PROTECT; 1425 } 1426 1427 switch (param) { 1428 case -1: /* DEFAULT */ 1429 case 0: 1430 ClearRight(xw, -1); 1431 break; 1432 case 1: 1433 ClearLeft(xw); 1434 break; 1435 case 2: 1436 ClearLine(xw); 1437 break; 1438 } 1439 screen->protected_mode = saved_mode; 1440} 1441 1442/* 1443 * Just like 'do_erase_line()', except that this intercepts ED controls. If we 1444 * clear the whole screen, we'll get the return-value from ClearInLine, and 1445 * find if there were any protected characters left. If not, reset the 1446 * protected mode flag in the screen data (it's slower). 1447 */ 1448void 1449do_erase_display(XtermWidget xw, int param, int mode) 1450{ 1451 TScreen *screen = TScreenOf(xw); 1452 int saved_mode = screen->protected_mode; 1453 1454 if (saved_mode == DEC_PROTECT 1455 && saved_mode != mode) 1456 screen->protected_mode = OFF_PROTECT; 1457 1458 switch (param) { 1459 case -1: /* DEFAULT */ 1460 case 0: 1461 if (screen->cur_row == 0 1462 && screen->cur_col == 0) { 1463 screen->protected_mode = saved_mode; 1464 do_erase_display(xw, 2, mode); 1465 saved_mode = screen->protected_mode; 1466 } else 1467 ClearBelow(xw); 1468 break; 1469 1470 case 1: 1471 if (screen->cur_row == screen->max_row 1472 && screen->cur_col == screen->max_col) { 1473 screen->protected_mode = saved_mode; 1474 do_erase_display(xw, 2, mode); 1475 saved_mode = screen->protected_mode; 1476 } else 1477 ClearAbove(xw); 1478 break; 1479 1480 case 2: 1481 /* 1482 * We use 'ClearScreen()' throughout the remainder of the 1483 * program for places where we don't care if the characters are 1484 * protected or not. So we modify the logic around this call 1485 * on 'ClearScreen()' to handle protected characters. 1486 */ 1487 if (screen->protected_mode != OFF_PROTECT) { 1488 int row; 1489 int rc = 1; 1490 unsigned len = (unsigned) MaxCols(screen); 1491 1492 assert(screen->max_col >= 0); 1493 for (row = 0; row <= screen->max_row; row++) 1494 rc &= ClearInLine(xw, row, 0, len); 1495 if (rc != 0) 1496 saved_mode = OFF_PROTECT; 1497 } else { 1498 ClearScreen(xw); 1499 } 1500 break; 1501 1502 case 3: 1503 /* xterm addition - erase saved lines. */ 1504 screen->savedlines = 0; 1505 ScrollBarDrawThumb(screen->scrollWidget); 1506 break; 1507 } 1508 screen->protected_mode = saved_mode; 1509} 1510 1511static void 1512CopyWait(XtermWidget xw) 1513{ 1514 TScreen *screen = TScreenOf(xw); 1515 XEvent reply; 1516 XEvent *rep = &reply; 1517 1518 while (1) { 1519 XWindowEvent(screen->display, VWindow(screen), 1520 ExposureMask, &reply); 1521 switch (reply.type) { 1522 case Expose: 1523 HandleExposure(xw, &reply); 1524 break; 1525 case NoExpose: 1526 case GraphicsExpose: 1527 if (screen->incopy <= 0) { 1528 screen->incopy = 1; 1529 if (screen->scrolls > 0) 1530 screen->scrolls--; 1531 } 1532 if (reply.type == GraphicsExpose) 1533 HandleExposure(xw, &reply); 1534 1535 if ((reply.type == NoExpose) || 1536 ((XExposeEvent *) rep)->count == 0) { 1537 if (screen->incopy <= 0 && screen->scrolls > 0) 1538 screen->scrolls--; 1539 if (screen->scrolls == 0) { 1540 screen->incopy = 0; 1541 return; 1542 } 1543 screen->incopy = -1; 1544 } 1545 break; 1546 } 1547 } 1548} 1549 1550/* 1551 * used by vertical_copy_area and and horizontal_copy_area 1552 */ 1553static void 1554copy_area(XtermWidget xw, 1555 int src_x, 1556 int src_y, 1557 unsigned width, 1558 unsigned height, 1559 int dest_x, 1560 int dest_y) 1561{ 1562 TScreen *screen = TScreenOf(xw); 1563 1564 if (width != 0 && height != 0) { 1565 /* wait for previous CopyArea to complete unless 1566 multiscroll is enabled and active */ 1567 if (screen->incopy && screen->scrolls == 0) 1568 CopyWait(xw); 1569 screen->incopy = -1; 1570 1571 /* save for translating Expose events */ 1572 screen->copy_src_x = src_x; 1573 screen->copy_src_y = src_y; 1574 screen->copy_width = width; 1575 screen->copy_height = height; 1576 screen->copy_dest_x = dest_x; 1577 screen->copy_dest_y = dest_y; 1578 1579 XCopyArea(screen->display, 1580 VWindow(screen), VWindow(screen), 1581 NormalGC(xw, screen), 1582 src_x, src_y, width, height, dest_x, dest_y); 1583 } 1584} 1585 1586/* 1587 * use when inserting or deleting characters on the current line 1588 */ 1589static void 1590horizontal_copy_area(XtermWidget xw, 1591 int firstchar, /* char pos on screen to start copying at */ 1592 int nchars, 1593 int amount) /* number of characters to move right */ 1594{ 1595 TScreen *screen = TScreenOf(xw); 1596 LineData *ld; 1597 1598 if ((ld = getLineData(screen, screen->cur_row)) != 0) { 1599 int src_x = LineCursorX(screen, ld, firstchar); 1600 int src_y = CursorY(screen, screen->cur_row); 1601 1602 copy_area(xw, src_x, src_y, 1603 (unsigned) (nchars * LineFontWidth(screen, ld)), 1604 (unsigned) FontHeight(screen), 1605 src_x + amount * LineFontWidth(screen, ld), src_y); 1606 } 1607} 1608 1609/* 1610 * use when inserting or deleting lines from the screen 1611 */ 1612static void 1613vertical_copy_area(XtermWidget xw, 1614 int firstline, /* line on screen to start copying at */ 1615 int nlines, 1616 int amount) /* number of lines to move up (neg=down) */ 1617{ 1618 TScreen *screen = TScreenOf(xw); 1619 1620 if (nlines > 0) { 1621 int src_x = OriginX(screen); 1622 int src_y = firstline * FontHeight(screen) + screen->border; 1623 1624 copy_area(xw, src_x, src_y, 1625 (unsigned) Width(screen), 1626 (unsigned) (nlines * FontHeight(screen)), 1627 src_x, src_y - amount * FontHeight(screen)); 1628 } 1629} 1630 1631/* 1632 * use when scrolling the entire screen 1633 */ 1634void 1635scrolling_copy_area(XtermWidget xw, 1636 int firstline, /* line on screen to start copying at */ 1637 int nlines, 1638 int amount) /* number of lines to move up (neg=down) */ 1639{ 1640 1641 if (nlines > 0) { 1642 vertical_copy_area(xw, firstline, nlines, amount); 1643 } 1644} 1645 1646/* 1647 * Handler for Expose events on the VT widget. 1648 * Returns 1 iff the area where the cursor was got refreshed. 1649 */ 1650int 1651HandleExposure(XtermWidget xw, XEvent * event) 1652{ 1653 TScreen *screen = TScreenOf(xw); 1654 XExposeEvent *reply = (XExposeEvent *) event; 1655 1656#ifndef NO_ACTIVE_ICON 1657 if (reply->window == screen->iconVwin.window) { 1658 WhichVWin(screen) = &screen->iconVwin; 1659 TRACE(("HandleExposure - icon")); 1660 } else { 1661 WhichVWin(screen) = &screen->fullVwin; 1662 TRACE(("HandleExposure - normal")); 1663 } 1664 TRACE((" event %d,%d %dx%d\n", 1665 reply->y, 1666 reply->x, 1667 reply->height, 1668 reply->width)); 1669#endif /* NO_ACTIVE_ICON */ 1670 1671 /* if not doing CopyArea or if this is a GraphicsExpose, don't translate */ 1672 if (!screen->incopy || event->type != Expose) 1673 return handle_translated_exposure(xw, reply->x, reply->y, 1674 reply->width, 1675 reply->height); 1676 else { 1677 /* compute intersection of area being copied with 1678 area being exposed. */ 1679 int both_x1 = Max(screen->copy_src_x, reply->x); 1680 int both_y1 = Max(screen->copy_src_y, reply->y); 1681 int both_x2 = Min(screen->copy_src_x + (int) screen->copy_width, 1682 (reply->x + (int) reply->width)); 1683 int both_y2 = Min(screen->copy_src_y + (int) screen->copy_height, 1684 (reply->y + (int) reply->height)); 1685 int value = 0; 1686 1687 /* was anything copied affected? */ 1688 if (both_x2 > both_x1 && both_y2 > both_y1) { 1689 /* do the copied area */ 1690 value = handle_translated_exposure 1691 (xw, reply->x + screen->copy_dest_x - screen->copy_src_x, 1692 reply->y + screen->copy_dest_y - screen->copy_src_y, 1693 reply->width, reply->height); 1694 } 1695 /* was anything not copied affected? */ 1696 if (reply->x < both_x1 || reply->y < both_y1 1697 || reply->x + reply->width > both_x2 1698 || reply->y + reply->height > both_y2) 1699 value = handle_translated_exposure(xw, reply->x, reply->y, 1700 reply->width, reply->height); 1701 1702 return value; 1703 } 1704} 1705 1706static void 1707set_background(XtermWidget xw, int color GCC_UNUSED) 1708{ 1709 TScreen *screen = TScreenOf(xw); 1710 Pixel c = getXtermBackground(xw, xw->flags, color); 1711 1712 TRACE(("set_background(%d) %#lx\n", color, c)); 1713 XSetWindowBackground(screen->display, VShellWindow, c); 1714 XSetWindowBackground(screen->display, VWindow(screen), c); 1715} 1716 1717/* 1718 * Called by the ExposeHandler to do the actual repaint after the coordinates 1719 * have been translated to allow for any CopyArea in progress. 1720 * The rectangle passed in is pixel coordinates. 1721 */ 1722static int 1723handle_translated_exposure(XtermWidget xw, 1724 int rect_x, 1725 int rect_y, 1726 int rect_width, 1727 int rect_height) 1728{ 1729 TScreen *screen = TScreenOf(xw); 1730 int toprow, leftcol, nrows, ncols; 1731 int x0, x1; 1732 int y0, y1; 1733 int result = 0; 1734 1735 TRACE(("handle_translated_exposure at %d,%d size %dx%d\n", 1736 rect_y, rect_x, rect_height, rect_width)); 1737 1738 x0 = (rect_x - OriginX(screen)); 1739 x1 = (x0 + rect_width); 1740 1741 y0 = (rect_y - OriginY(screen)); 1742 y1 = (y0 + rect_height); 1743 1744 if ((x0 < 0 || 1745 y0 < 0 || 1746 x1 > Width(screen) || 1747 y1 > Height(screen))) { 1748 set_background(xw, -1); 1749 XClearArea(screen->display, VWindow(screen), 1750 rect_x, 1751 rect_y, 1752 (unsigned) rect_width, 1753 (unsigned) rect_height, False); 1754 } 1755 toprow = y0 / FontHeight(screen); 1756 if (toprow < 0) 1757 toprow = 0; 1758 1759 leftcol = x0 / FontWidth(screen); 1760 if (leftcol < 0) 1761 leftcol = 0; 1762 1763 nrows = (y1 - 1) / FontHeight(screen) - toprow + 1; 1764 ncols = (x1 - 1) / FontWidth(screen) - leftcol + 1; 1765 toprow -= screen->scrolls; 1766 if (toprow < 0) { 1767 nrows += toprow; 1768 toprow = 0; 1769 } 1770 if (toprow + nrows > MaxRows(screen)) 1771 nrows = MaxRows(screen) - toprow; 1772 if (leftcol + ncols > MaxCols(screen)) 1773 ncols = MaxCols(screen) - leftcol; 1774 1775 if (nrows > 0 && ncols > 0) { 1776 ScrnRefresh(xw, toprow, leftcol, nrows, ncols, True); 1777 first_map_occurred(); 1778 if (screen->cur_row >= toprow && 1779 screen->cur_row < toprow + nrows && 1780 screen->cur_col >= leftcol && 1781 screen->cur_col < leftcol + ncols) { 1782 result = 1; 1783 } 1784 1785 } 1786 TRACE(("...handle_translated_exposure %d\n", result)); 1787 return (result); 1788} 1789 1790/***====================================================================***/ 1791 1792void 1793GetColors(XtermWidget xw, ScrnColors * pColors) 1794{ 1795 TScreen *screen = TScreenOf(xw); 1796 int n; 1797 1798 pColors->which = 0; 1799 for (n = 0; n < NCOLORS; ++n) { 1800 SET_COLOR_VALUE(pColors, n, T_COLOR(screen, n)); 1801 } 1802} 1803 1804void 1805ChangeColors(XtermWidget xw, ScrnColors * pNew) 1806{ 1807 Bool repaint = False; 1808 TScreen *screen = TScreenOf(xw); 1809 VTwin *win = WhichVWin(screen); 1810 1811 TRACE(("ChangeColors\n")); 1812 1813 if (COLOR_DEFINED(pNew, TEXT_CURSOR)) { 1814 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_CURSOR); 1815 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR))); 1816 /* no repaint needed */ 1817 } else if ((T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) && 1818 (COLOR_DEFINED(pNew, TEXT_FG))) { 1819 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_FG); 1820 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR))); 1821 repaint = screen->Vshow; 1822 } 1823 1824 if (COLOR_DEFINED(pNew, TEXT_FG)) { 1825 Pixel fg = COLOR_VALUE(pNew, TEXT_FG); 1826 T_COLOR(screen, TEXT_FG) = fg; 1827 TRACE(("... TEXT_FG: %#lx\n", T_COLOR(screen, TEXT_FG))); 1828 if (screen->Vshow) { 1829 setCgsFore(xw, win, gcNorm, fg); 1830 setCgsBack(xw, win, gcNormReverse, fg); 1831 setCgsFore(xw, win, gcBold, fg); 1832 setCgsBack(xw, win, gcBoldReverse, fg); 1833 repaint = True; 1834 } 1835 } 1836 1837 if (COLOR_DEFINED(pNew, TEXT_BG)) { 1838 Pixel bg = COLOR_VALUE(pNew, TEXT_BG); 1839 T_COLOR(screen, TEXT_BG) = bg; 1840 TRACE(("... TEXT_BG: %#lx\n", T_COLOR(screen, TEXT_BG))); 1841 if (screen->Vshow) { 1842 setCgsBack(xw, win, gcNorm, bg); 1843 setCgsFore(xw, win, gcNormReverse, bg); 1844 setCgsBack(xw, win, gcBold, bg); 1845 setCgsFore(xw, win, gcBoldReverse, bg); 1846 set_background(xw, -1); 1847 repaint = True; 1848 } 1849 } 1850#if OPT_HIGHLIGHT_COLOR 1851 if (COLOR_DEFINED(pNew, HIGHLIGHT_BG)) { 1852 T_COLOR(screen, HIGHLIGHT_BG) = COLOR_VALUE(pNew, HIGHLIGHT_BG); 1853 TRACE(("... HIGHLIGHT_BG: %#lx\n", T_COLOR(screen, HIGHLIGHT_BG))); 1854 repaint = screen->Vshow; 1855 } 1856 if (COLOR_DEFINED(pNew, HIGHLIGHT_FG)) { 1857 T_COLOR(screen, HIGHLIGHT_FG) = COLOR_VALUE(pNew, HIGHLIGHT_FG); 1858 TRACE(("... HIGHLIGHT_FG: %#lx\n", T_COLOR(screen, HIGHLIGHT_FG))); 1859 repaint = screen->Vshow; 1860 } 1861#endif 1862 1863 if (COLOR_DEFINED(pNew, MOUSE_FG) || (COLOR_DEFINED(pNew, MOUSE_BG))) { 1864 if (COLOR_DEFINED(pNew, MOUSE_FG)) { 1865 T_COLOR(screen, MOUSE_FG) = COLOR_VALUE(pNew, MOUSE_FG); 1866 TRACE(("... MOUSE_FG: %#lx\n", T_COLOR(screen, MOUSE_FG))); 1867 } 1868 if (COLOR_DEFINED(pNew, MOUSE_BG)) { 1869 T_COLOR(screen, MOUSE_BG) = COLOR_VALUE(pNew, MOUSE_BG); 1870 TRACE(("... MOUSE_BG: %#lx\n", T_COLOR(screen, MOUSE_BG))); 1871 } 1872 1873 if (screen->Vshow) { 1874 recolor_cursor(screen, 1875 screen->pointer_cursor, 1876 T_COLOR(screen, MOUSE_FG), 1877 T_COLOR(screen, MOUSE_BG)); 1878 XDefineCursor(screen->display, VWindow(screen), 1879 screen->pointer_cursor); 1880 } 1881#if OPT_TEK4014 1882 if (TEK4014_SHOWN(xw)) { 1883 TekScreen *tekscr = TekScreenOf(tekWidget); 1884 Window tekwin = TWindow(tekscr); 1885 if (tekwin) { 1886 recolor_cursor(screen, 1887 tekscr->arrow, 1888 T_COLOR(screen, MOUSE_FG), 1889 T_COLOR(screen, MOUSE_BG)); 1890 XDefineCursor(screen->display, tekwin, tekscr->arrow); 1891 } 1892 } 1893#endif 1894 /* no repaint needed */ 1895 } 1896 1897 if (COLOR_DEFINED(pNew, TEXT_FG) || 1898 COLOR_DEFINED(pNew, TEXT_BG) || 1899 COLOR_DEFINED(pNew, TEXT_CURSOR)) { 1900 set_cursor_gcs(xw); 1901 } 1902#if OPT_TEK4014 1903 if (COLOR_DEFINED(pNew, TEK_FG) || 1904 COLOR_DEFINED(pNew, TEK_BG)) { 1905 ChangeTekColors(tekWidget, screen, pNew); 1906 if (TEK4014_SHOWN(xw)) { 1907 TekRepaint(tekWidget); 1908 } 1909 } else if (COLOR_DEFINED(pNew, TEK_CURSOR)) { 1910 ChangeTekColors(tekWidget, screen, pNew); 1911 } 1912#endif 1913 if (repaint) 1914 xtermRepaint(xw); 1915} 1916 1917void 1918xtermClear(XtermWidget xw) 1919{ 1920 TScreen *screen = TScreenOf(xw); 1921 1922 TRACE(("xtermClear\n")); 1923 XClearWindow(screen->display, VWindow(screen)); 1924} 1925 1926void 1927xtermRepaint(XtermWidget xw) 1928{ 1929 TScreen *screen = TScreenOf(xw); 1930 1931 TRACE(("xtermRepaint\n")); 1932 xtermClear(xw); 1933 ScrnRefresh(xw, 0, 0, MaxRows(screen), MaxCols(screen), True); 1934} 1935 1936/***====================================================================***/ 1937 1938Boolean 1939isDefaultForeground(const char *name) 1940{ 1941 return (Boolean) ! x_strcasecmp(name, XtDefaultForeground); 1942} 1943 1944Boolean 1945isDefaultBackground(const char *name) 1946{ 1947 return (Boolean) ! x_strcasecmp(name, XtDefaultBackground); 1948} 1949 1950#if OPT_WIDE_CHARS 1951/* 1952 * Check for Unicode BIDI control characters, which may be miscategorized via 1953 * wcwidth() and iswprint() as zero-width printable characters. 1954 */ 1955Boolean 1956isWideControl(unsigned ch) 1957{ 1958 Boolean result; 1959 1960 switch (ch) { 1961 case 0x200E: 1962 case 0x200F: 1963 case 0x202A: 1964 case 0x202B: 1965 case 0x202C: 1966 case 0x202D: 1967 case 0x202E: 1968 result = True; 1969 break; 1970 default: 1971 result = False; 1972 break; 1973 } 1974 return result; 1975} 1976#endif 1977 1978/***====================================================================***/ 1979 1980typedef struct { 1981 Pixel fg; 1982 Pixel bg; 1983} ToSwap; 1984 1985#if OPT_HIGHLIGHT_COLOR 1986#define hc_param ,Bool hilite_color 1987#define hc_value ,screen->hilite_color 1988#else 1989#define hc_param /* nothing */ 1990#define hc_value /* nothing */ 1991#endif 1992 1993/* 1994 * Use this to swap the foreground/background color values in the resource 1995 * data, and to build up a list of the pairs which must be swapped in the 1996 * GC cache. 1997 */ 1998static void 1999swapLocally(ToSwap * list, int *count, ColorRes * fg, ColorRes * bg hc_param) 2000{ 2001 ColorRes tmp; 2002 int n; 2003 Boolean found = False; 2004 2005#if OPT_COLOR_RES 2006 Pixel fg_color = fg->value; 2007 Pixel bg_color = bg->value; 2008#else 2009 Pixel fg_color = *fg; 2010 Pixel bg_color = *bg; 2011#endif 2012 2013#if OPT_HIGHLIGHT_COLOR 2014 if ((fg_color != bg_color) || !hilite_color) 2015#endif 2016 { 2017 EXCHANGE(*fg, *bg, tmp); 2018 for (n = 0; n < *count; ++n) { 2019 if ((list[n].fg == fg_color && list[n].bg == bg_color) 2020 || (list[n].fg == bg_color && list[n].bg == fg_color)) { 2021 found = True; 2022 break; 2023 } 2024 } 2025 if (!found) { 2026 list[*count].fg = fg_color; 2027 list[*count].bg = bg_color; 2028 *count = *count + 1; 2029 TRACE(("swapLocally fg %#lx, bg %#lx ->%d\n", 2030 fg_color, bg_color, *count)); 2031 } 2032 } 2033} 2034 2035static void 2036reallySwapColors(XtermWidget xw, ToSwap * list, int count) 2037{ 2038 int j, k; 2039 2040 TRACE(("reallySwapColors\n")); 2041 for (j = 0; j < count; ++j) { 2042 for_each_text_gc(k) { 2043 redoCgs(xw, list[j].fg, list[j].bg, (CgsEnum) k); 2044 } 2045 } 2046} 2047 2048static void 2049swapVTwinGCs(XtermWidget xw, VTwin * win) 2050{ 2051 swapCgs(xw, win, gcNorm, gcNormReverse); 2052 swapCgs(xw, win, gcBold, gcBoldReverse); 2053} 2054 2055void 2056ReverseVideo(XtermWidget xw) 2057{ 2058 TScreen *screen = TScreenOf(xw); 2059 ToSwap listToSwap[5]; 2060 int numToSwap = 0; 2061 2062 TRACE(("ReverseVideo\n")); 2063 2064 /* 2065 * Swap SGR foreground and background colors. By convention, these are 2066 * the colors assigned to "black" (SGR #0) and "white" (SGR #7). Also, 2067 * SGR #8 and SGR #15 are the bold (or bright) versions of SGR #0 and 2068 * #7, respectively. 2069 * 2070 * We don't swap colors that happen to match the screen's foreground 2071 * and background because that tends to produce bizarre effects. 2072 */ 2073#define swapAnyColor(name,a,b) swapLocally(listToSwap, &numToSwap, &(screen->name[a]), &(screen->name[b]) hc_value) 2074#define swapAColor(a,b) swapAnyColor(Acolors, a, b) 2075 if_OPT_ISO_COLORS(screen, { 2076 swapAColor(0, 7); 2077 swapAColor(8, 15); 2078 }); 2079 2080 if (T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) 2081 T_COLOR(screen, TEXT_CURSOR) = T_COLOR(screen, TEXT_BG); 2082 2083#define swapTColor(a,b) swapAnyColor(Tcolors, a, b) 2084 swapTColor(TEXT_FG, TEXT_BG); 2085 swapTColor(MOUSE_FG, MOUSE_BG); 2086 2087 reallySwapColors(xw, listToSwap, numToSwap); 2088 2089 swapVTwinGCs(xw, &(screen->fullVwin)); 2090#ifndef NO_ACTIVE_ICON 2091 swapVTwinGCs(xw, &(screen->iconVwin)); 2092#endif /* NO_ACTIVE_ICON */ 2093 2094 xw->misc.re_verse = (Boolean) ! xw->misc.re_verse; 2095 2096 if (XtIsRealized((Widget) xw)) { 2097 xtermDisplayCursor(xw); 2098 } 2099#if OPT_TEK4014 2100 if (TEK4014_SHOWN(xw)) { 2101 TekScreen *tekscr = TekScreenOf(tekWidget); 2102 Window tekwin = TWindow(tekscr); 2103 recolor_cursor(screen, 2104 tekscr->arrow, 2105 T_COLOR(screen, MOUSE_FG), 2106 T_COLOR(screen, MOUSE_BG)); 2107 XDefineCursor(screen->display, tekwin, tekscr->arrow); 2108 } 2109#endif 2110 2111 if (screen->scrollWidget) 2112 ScrollBarReverseVideo(screen->scrollWidget); 2113 2114 if (XtIsRealized((Widget) xw)) { 2115 set_background(xw, -1); 2116 } 2117#if OPT_TEK4014 2118 TekReverseVideo(tekWidget); 2119#endif 2120 if (XtIsRealized((Widget) xw)) { 2121 xtermRepaint(xw); 2122 } 2123#if OPT_TEK4014 2124 if (TEK4014_SHOWN(xw)) { 2125 TekRepaint(tekWidget); 2126 } 2127#endif 2128 ReverseOldColors(); 2129 set_cursor_gcs(xw); 2130 update_reversevideo(); 2131 TRACE(("...ReverseVideo\n")); 2132} 2133 2134void 2135recolor_cursor(TScreen * screen, 2136 Cursor cursor, /* X cursor ID to set */ 2137 unsigned long fg, /* pixel indexes to look up */ 2138 unsigned long bg) /* pixel indexes to look up */ 2139{ 2140 Display *dpy = screen->display; 2141 XColor colordefs[2]; /* 0 is foreground, 1 is background */ 2142 2143 colordefs[0].pixel = fg; 2144 colordefs[1].pixel = bg; 2145 XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), 2146 colordefs, 2); 2147 XRecolorCursor(dpy, cursor, colordefs, colordefs + 1); 2148 return; 2149} 2150 2151#if OPT_RENDERFONT 2152static XftColor * 2153getXftColor(XtermWidget xw, Pixel pixel) 2154{ 2155#define CACHE_SIZE 4 2156 static struct { 2157 XftColor color; 2158 int use; 2159 } cache[CACHE_SIZE]; 2160 static int use; 2161 int i; 2162 int oldest, oldestuse; 2163 XColor color; 2164 2165 oldestuse = 0x7fffffff; 2166 oldest = 0; 2167 for (i = 0; i < CACHE_SIZE; i++) { 2168 if (cache[i].use) { 2169 if (cache[i].color.pixel == pixel) { 2170 cache[i].use = ++use; 2171 return &cache[i].color; 2172 } 2173 } 2174 if (cache[i].use < oldestuse) { 2175 oldestuse = cache[i].use; 2176 oldest = i; 2177 } 2178 } 2179 i = oldest; 2180 color.pixel = pixel; 2181 XQueryColor(TScreenOf(xw)->display, xw->core.colormap, &color); 2182 cache[i].color.color.red = color.red; 2183 cache[i].color.color.green = color.green; 2184 cache[i].color.color.blue = color.blue; 2185 cache[i].color.color.alpha = 0xffff; 2186 cache[i].color.pixel = pixel; 2187 cache[i].use = ++use; 2188 return &cache[i].color; 2189} 2190 2191/* 2192 * The cell-width is related to, but not the same as the wide-character width. 2193 * We will only get useful values from wcwidth() for codes above 255. 2194 * Otherwise, interpret according to internal data. 2195 */ 2196#if OPT_RENDERWIDE 2197 2198#if OPT_C1_PRINT 2199#define XtermCellWidth(xw, ch) \ 2200 (((ch) == 0 || (ch) == 127) \ 2201 ? 0 \ 2202 : (((ch) < 256) \ 2203 ? (((ch) >= 128 && (ch) < 160) \ 2204 ? (TScreenOf(xw)->c1_printable ? 1 : 0) \ 2205 : 1) \ 2206 : my_wcwidth(ch))) 2207#else 2208#define XtermCellWidth(xw, ch) \ 2209 (((ch) == 0 || (ch) == 127) \ 2210 ? 0 \ 2211 : (((ch) < 256) \ 2212 ? 1 \ 2213 : my_wcwidth(ch))) 2214#endif 2215 2216#endif /* OPT_RENDERWIDE */ 2217 2218#define XFT_FONT(name) screen->name.font 2219 2220#if OPT_ISO_COLORS 2221#define UseBoldFont(screen) (!(screen)->colorBDMode || ((screen)->veryBoldColors & BOLD)) 2222#else 2223#define UseBoldFont(screen) 1 2224#endif 2225/* 2226 * fontconfig/Xft combination prior to 2.2 has a problem with 2227 * CJK truetype 'double-width' (bi-width/monospace) fonts leading 2228 * to the 's p a c e d o u t' rendering. Consequently, we can't 2229 * rely on XftDrawString8/16 when one of those fonts is used. 2230 * Instead, we need to roll out our own using XftDrawCharSpec. 2231 * A patch in the same spirit (but in a rather different form) 2232 * was applied to gnome vte and gtk2 port of vim. 2233 * See http://bugzilla.mozilla.org/show_bug.cgi?id=196312 2234 */ 2235static int 2236xtermXftDrawString(XtermWidget xw, 2237 unsigned flags GCC_UNUSED, 2238 XftColor * color, 2239 XftFont * font, 2240 int x, 2241 int y, 2242 IChar * text, 2243 Cardinal len, 2244 Bool really) 2245{ 2246 TScreen *screen = TScreenOf(xw); 2247 int ncells = 0; 2248 2249 if (len != 0) { 2250#if OPT_RENDERWIDE 2251 XftCharSpec *sbuf; 2252 XftFont *wfont; 2253 Cardinal src, dst; 2254 XftFont *lastFont = 0; 2255 XftFont *currFont = 0; 2256 Cardinal start = 0; 2257 int charWidth; 2258 int fontnum = screen->menu_font_number; 2259 int fwidth = FontWidth(screen); 2260 2261#if OPT_ISO_COLORS 2262 if ((flags & UNDERLINE) 2263 && !screen->colorULMode 2264 && screen->italicULMode 2265 && XFT_FONT(renderWideItal[fontnum])) { 2266 wfont = XFT_FONT(renderWideItal[fontnum]); 2267 } else 2268#endif 2269 if ((flags & BOLDATTR(screen)) 2270 && UseBoldFont(screen) 2271 && XFT_FONT(renderWideBold[fontnum])) { 2272 wfont = XFT_FONT(renderWideBold[fontnum]); 2273 } else { 2274 wfont = XFT_FONT(renderWideNorm[fontnum]); 2275 } 2276 2277 BumpTypedBuffer(XftCharSpec, len); 2278 sbuf = BfBuf(XftCharSpec); 2279 2280 for (src = dst = 0; src < len; src++) { 2281 FcChar32 wc = *text++; 2282 2283 charWidth = XtermCellWidth(xw, (wchar_t) wc); 2284 if (charWidth < 0) 2285 continue; 2286 2287 sbuf[dst].ucs4 = wc; 2288 sbuf[dst].x = (short) (x + fwidth * ncells); 2289 sbuf[dst].y = (short) (y); 2290 2291 currFont = (charWidth == 2 && wfont != 0) ? wfont : font; 2292 ncells += charWidth; 2293 2294 if (lastFont != currFont) { 2295 if ((lastFont != 0) && really) { 2296 XftDrawCharSpec(screen->renderDraw, 2297 color, 2298 lastFont, 2299 sbuf + start, 2300 (int) (dst - start)); 2301 } 2302 start = dst; 2303 lastFont = currFont; 2304 } 2305 ++dst; 2306 } 2307 if ((dst != start) && really) { 2308 XftDrawCharSpec(screen->renderDraw, 2309 color, 2310 lastFont, 2311 sbuf + start, 2312 (int) (dst - start)); 2313 } 2314#else /* !OPT_RENDERWIDE */ 2315 if (really) { 2316 XftChar8 *buffer; 2317 int dst; 2318 2319 BumpTypedBuffer(XftChar8, len); 2320 buffer = BfBuf(XftChar8); 2321 2322 for (dst = 0; dst < (int) len; ++dst) 2323 buffer[dst] = CharOf(text[dst]); 2324 2325 XftDrawString8(screen->renderDraw, 2326 color, 2327 font, 2328 x, y, buffer, (int) len); 2329 } 2330 ncells = (int) len; 2331#endif 2332 } 2333 return ncells; 2334} 2335#define xtermXftWidth(xw, flags, color, font, x, y, chars, len) \ 2336 xtermXftDrawString(xw, flags, color, font, x, y, chars, len, False) 2337#endif /* OPT_RENDERFONT */ 2338 2339#if OPT_WIDE_CHARS 2340/* 2341 * Map characters commonly "fixed" by groff back to their ASCII equivalents. 2342 * Also map other useful equivalents. 2343 */ 2344unsigned 2345AsciiEquivs(unsigned ch) 2346{ 2347 switch (ch) { 2348 case 0x2010: /* groff "-" */ 2349 case 0x2011: 2350 case 0x2012: 2351 case 0x2013: 2352 case 0x2014: 2353 case 0x2015: 2354 case 0x2212: /* groff "\-" */ 2355 ch = '-'; 2356 break; 2357 case 0x2018: /* groff "`" */ 2358 ch = '`'; 2359 break; 2360 case 0x2019: /* groff ' */ 2361 ch = '\''; 2362 break; 2363 case 0x201C: /* groff lq */ 2364 case 0x201D: /* groff rq */ 2365 ch = '"'; 2366 break; 2367 case 0x2329: /* groff ".URL" */ 2368 ch = '<'; 2369 break; 2370 case 0x232a: /* groff ".URL" */ 2371 ch = '>'; 2372 break; 2373 default: 2374 if (ch >= 0xff01 && ch <= 0xff5e) { 2375 /* "Fullwidth" codes (actually double-width) */ 2376 ch -= 0xff00; 2377 ch += ANSI_SPA; 2378 break; 2379 } 2380 } 2381 return ch; 2382} 2383 2384/* 2385 * Actually this should be called "groff_workaround()" - for the places where 2386 * groff stomps on compatibility. Still, if enough people get used to it, 2387 * this might someday become a quasi-standard. 2388 */ 2389static int 2390ucs_workaround(XtermWidget xw, 2391 unsigned ch, 2392 unsigned flags, 2393 GC gc, 2394 int x, 2395 int y, 2396 int chrset, 2397 int on_wide) 2398{ 2399 TScreen *screen = TScreenOf(xw); 2400 int fixed = False; 2401 2402 if (screen->wide_chars && screen->utf8_mode && ch > 256) { 2403 IChar eqv = (IChar) AsciiEquivs(ch); 2404 2405 if (eqv != (IChar) ch) { 2406 int width = my_wcwidth((int) ch); 2407 2408 do { 2409 drawXtermText(xw, 2410 flags, 2411 gc, 2412 x, 2413 y, 2414 chrset, 2415 &eqv, 2416 1, 2417 on_wide); 2418 x += FontWidth(screen); 2419 eqv = '?'; 2420 } while (width-- > 1); 2421 2422 fixed = True; 2423 } else if (ch == HIDDEN_CHAR) { 2424 fixed = True; 2425 } 2426 } 2427 return fixed; 2428} 2429#endif 2430 2431/* 2432 * Use this when the characters will not fill the cell area properly. Fill the 2433 * area where we'll write the characters, otherwise we'll get gaps between 2434 * them, e.g., in the original background color. 2435 * 2436 * The cursor is a special case, because the XFillRectangle call only uses the 2437 * foreground, while we've set the cursor color in the background. So we need 2438 * a special GC for that. 2439 */ 2440static void 2441xtermFillCells(XtermWidget xw, 2442 unsigned flags, 2443 GC gc, 2444 int x, 2445 int y, 2446 Cardinal len) 2447{ 2448 TScreen *screen = TScreenOf(xw); 2449 VTwin *currentWin = WhichVWin(screen); 2450 2451 if (!(flags & NOBACKGROUND)) { 2452 CgsEnum srcId = getCgsId(xw, currentWin, gc); 2453 CgsEnum dstId = gcMAX; 2454 Pixel fg = getCgsFore(xw, currentWin, gc); 2455 Pixel bg = getCgsBack(xw, currentWin, gc); 2456 2457 switch (srcId) { 2458 case gcVTcursNormal: 2459 case gcVTcursReverse: 2460 dstId = gcVTcursOutline; 2461 break; 2462 case gcVTcursFilled: 2463 case gcVTcursOutline: 2464 /* FIXME */ 2465 break; 2466 case gcNorm: 2467 dstId = gcNormReverse; 2468 break; 2469 case gcNormReverse: 2470 dstId = gcNorm; 2471 break; 2472 case gcBold: 2473 dstId = gcBoldReverse; 2474 break; 2475 case gcBoldReverse: 2476 dstId = gcBold; 2477 break; 2478#if OPT_BOX_CHARS 2479 case gcLine: 2480 case gcDots: 2481 /* FIXME */ 2482 break; 2483#endif 2484#if OPT_DEC_CHRSET 2485 case gcCNorm: 2486 case gcCBold: 2487 /* FIXME */ 2488 break; 2489#endif 2490#if OPT_WIDE_CHARS 2491 case gcWide: 2492 dstId = gcWideReverse; 2493 break; 2494 case gcWBold: 2495 dstId = gcBoldReverse; 2496 break; 2497 case gcWideReverse: 2498 case gcWBoldReverse: 2499 /* FIXME */ 2500 break; 2501#endif 2502#if OPT_TEK4014 2503 case gcTKcurs: 2504 /* FIXME */ 2505 break; 2506#endif 2507 case gcMAX: 2508 break; 2509 } 2510 2511 if (dstId != gcMAX) { 2512 setCgsFore(xw, currentWin, dstId, bg); 2513 setCgsBack(xw, currentWin, dstId, fg); 2514 2515 XFillRectangle(screen->display, VWindow(screen), 2516 getCgsGC(xw, currentWin, dstId), 2517 x, y, 2518 len * (Cardinal) FontWidth(screen), 2519 (unsigned) FontHeight(screen)); 2520 } 2521 } 2522} 2523 2524#if OPT_TRACE 2525static void 2526xtermSetClipRectangles(Display * dpy, 2527 GC gc, 2528 int x, 2529 int y, 2530 XRectangle * rp, 2531 Cardinal nr, 2532 int order) 2533{ 2534#if 0 2535 TScreen *screen = TScreenOf(term); 2536 Drawable draw = VWindow(screen); 2537 2538 XSetClipMask(dpy, gc, None); 2539 XDrawRectangle(screen->display, draw, gc, 2540 x + rp->x - 1, 2541 y + rp->y - 1, 2542 rp->width, 2543 rp->height); 2544#endif 2545 2546 XSetClipRectangles(dpy, gc, 2547 x, y, rp, (int) nr, order); 2548 TRACE(("clipping @(%3d,%3d) (%3d,%3d)..(%3d,%3d)\n", 2549 y, x, 2550 rp->y, rp->x, rp->height, rp->width)); 2551} 2552 2553#else 2554#define xtermSetClipRectangles(dpy, gc, x, y, rp, nr, order) \ 2555 XSetClipRectangles(dpy, gc, x, y, rp, (int) nr, order) 2556#endif 2557 2558#if OPT_CLIP_BOLD 2559/* 2560 * This special case is a couple of percent slower, but avoids a lot of pixel 2561 * trash in rxcurses' hanoi.cmd demo (e.g., 10x20 font). 2562 */ 2563#define beginClipping(screen,gc,pwidth,plength) \ 2564 if (screen->use_clipping && (pwidth > 2)) { \ 2565 XRectangle clip; \ 2566 int clip_x = x; \ 2567 int clip_y = y - FontHeight(screen) + FontDescent(screen); \ 2568 clip.x = 0; \ 2569 clip.y = 0; \ 2570 clip.height = (unsigned short) FontHeight(screen); \ 2571 clip.width = (unsigned short) (pwidth * plength); \ 2572 xtermSetClipRectangles(screen->display, gc, \ 2573 clip_x, clip_y, \ 2574 &clip, 1, Unsorted); \ 2575 } 2576#define endClipping(screen,gc) \ 2577 XSetClipMask(screen->display, gc, None) 2578#else 2579#define beginClipping(screen,gc,pwidth,plength) /* nothing */ 2580#define endClipping(screen,gc) /* nothing */ 2581#endif /* OPT_CLIP_BOLD */ 2582 2583#if OPT_CLIP_BOLD && OPT_RENDERFONT && defined(HAVE_XFTDRAWSETCLIP) && defined(HAVE_XFTDRAWSETCLIPRECTANGLES) 2584#define beginXftClipping(screen,px,py,plength) \ 2585 if (screen->use_clipping && (FontWidth(screen) > 2)) { \ 2586 XRectangle clip; \ 2587 int clip_x = px; \ 2588 int clip_y = py - FontHeight(screen) + FontDescent(screen); \ 2589 clip.x = 0; \ 2590 clip.y = 0; \ 2591 clip.height = (unsigned short) (FontHeight(screen)); \ 2592 clip.width = (unsigned short) (FontWidth(screen) * plength); \ 2593 XftDrawSetClipRectangles (screen->renderDraw, \ 2594 clip_x, clip_y, \ 2595 &clip, 1); \ 2596 } 2597#define endXftClipping(screen) \ 2598 XftDrawSetClip (screen->renderDraw, 0) 2599#else 2600#define beginXftClipping(screen,px,py,plength) /* nothing */ 2601#define endXftClipping(screen) /* nothing */ 2602#endif /* OPT_CLIP_BOLD */ 2603 2604#if OPT_RENDERFONT 2605static int 2606drawClippedXftString(XtermWidget xw, 2607 unsigned flags, 2608 XftFont * font, 2609 XftColor * fg_color, 2610 int x, 2611 int y, 2612 IChar * text, 2613 Cardinal len) 2614{ 2615 int ncells = xtermXftWidth(xw, flags, 2616 fg_color, 2617 font, x, y, 2618 text, 2619 len); 2620 TScreen *screen = TScreenOf(xw); 2621 2622 beginXftClipping(screen, x, y, ncells); 2623 xtermXftDrawString(xw, flags, 2624 fg_color, 2625 font, x, y, 2626 text, 2627 len, 2628 True); 2629 endXftClipping(screen); 2630 return ncells; 2631} 2632#endif 2633 2634#ifndef NO_ACTIVE_ICON 2635#define WhichVFontData(screen,name) \ 2636 (IsIcon(screen) ? &((screen)->fnt_icon) \ 2637 : &((screen)->name)) 2638#else 2639#define WhichVFontData(screen,name) \ 2640 (&((screen)->name)) 2641#endif 2642 2643/* 2644 * Draws text with the specified combination of bold/underline. The return 2645 * value is the updated x position. 2646 */ 2647int 2648drawXtermText(XtermWidget xw, 2649 unsigned flags, 2650 GC gc, 2651 int x, 2652 int y, 2653 int chrset, 2654 IChar * text, 2655 Cardinal len, 2656 int on_wide) 2657{ 2658 TScreen *screen = TScreenOf(xw); 2659 Cardinal real_length = len; 2660 Cardinal underline_len = 0; 2661 /* Intended width of the font to draw (as opposed to the actual width of 2662 the X font, and the width of the default font) */ 2663 int font_width = ((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide; 2664 Bool did_ul = False; 2665 2666#if OPT_WIDE_CHARS 2667 if (text == 0) 2668 return 0; 2669#endif 2670#if OPT_DEC_CHRSET 2671 if (CSET_DOUBLE(chrset)) { 2672 /* We could try drawing double-size characters in the icon, but 2673 * given that the icon font is usually nil or nil2, there 2674 * doesn't seem to be much point. 2675 */ 2676 int inx = 0; 2677 GC gc2 = ((!IsIcon(screen) && screen->font_doublesize) 2678 ? xterm_DoubleGC(xw, (unsigned) chrset, flags, gc, &inx) 2679 : 0); 2680 2681 TRACE(("DRAWTEXT%c[%4d,%4d] (%d)%3d:%s\n", 2682 screen->cursor_state == OFF ? ' ' : '*', 2683 y, x, chrset, len, 2684 visibleIChars(text, len))); 2685 2686 if (gc2 != 0) { /* draw actual double-sized characters */ 2687 XFontStruct *fs = screen->double_fonts[inx].fs; 2688 2689#if OPT_RENDERFONT 2690 if (!UsingRenderFont(xw)) 2691#endif 2692 { 2693 XRectangle rect, *rp = ▭ 2694 Cardinal nr = 1; 2695 2696 font_width *= 2; 2697 flags |= DOUBLEWFONT; 2698 2699 rect.x = 0; 2700 rect.y = 0; 2701 rect.width = (unsigned short) ((int) len * font_width); 2702 rect.height = (unsigned short) (FontHeight(screen)); 2703 2704 TRACE(("drawing %s\n", visibleChrsetName((unsigned) chrset))); 2705 switch (chrset) { 2706 case CSET_DHL_TOP: 2707 rect.y = (short) -(fs->ascent / 2); 2708 y -= rect.y; 2709 flags |= DOUBLEHFONT; 2710 break; 2711 case CSET_DHL_BOT: 2712 rect.y = (short) (rect.height - (fs->ascent / 2)); 2713 y -= rect.y; 2714 flags |= DOUBLEHFONT; 2715 break; 2716 default: 2717 nr = 0; 2718 break; 2719 } 2720 2721 if (nr) { 2722 xtermSetClipRectangles(screen->display, gc2, 2723 x, y, rp, nr, YXBanded); 2724 } else { 2725 XSetClipMask(screen->display, gc2, None); 2726 } 2727 } 2728 2729 /* Call ourselves recursively with the new gc */ 2730 2731 /* 2732 * If we're trying to use proportional font, or if the 2733 * font server didn't give us what we asked for wrt 2734 * width, position each character independently. 2735 */ 2736 if (screen->fnt_prop 2737 || (fs->min_bounds.width != fs->max_bounds.width) 2738 || (fs->min_bounds.width != 2 * FontWidth(screen))) { 2739 /* It is hard to fall-through to the main 2740 branch: in a lot of places the check 2741 for the cached font info is for 2742 normal/bold fonts only. */ 2743 while (len--) { 2744 x = drawXtermText(xw, flags, gc2, 2745 x, y, 0, 2746 text++, 2747 1, on_wide); 2748 x += FontWidth(screen); 2749 } 2750 } else { 2751 x = drawXtermText(xw, flags, gc2, 2752 x, y, 0, 2753 text, 2754 len, on_wide); 2755 x += (int) len *FontWidth(screen); 2756 } 2757 2758 TRACE(("drawtext [%4d,%4d]\n", y, x)); 2759 } else { /* simulate double-sized characters */ 2760 unsigned need = 2 * len; 2761 IChar *temp = TypeMallocN(IChar, need); 2762 unsigned n = 0; 2763 2764 while (len--) { 2765 temp[n++] = *text++; 2766 temp[n++] = ' '; 2767 } 2768 x = drawXtermText(xw, 2769 flags, 2770 gc, 2771 x, y, 2772 0, 2773 temp, 2774 n, 2775 on_wide); 2776 free(temp); 2777 } 2778 return x; 2779 } 2780#endif 2781#if OPT_RENDERFONT 2782 if (UsingRenderFont(xw)) { 2783 VTwin *currentWin = WhichVWin(screen); 2784 Display *dpy = screen->display; 2785 XftFont *font; 2786 XGCValues values; 2787 int fontnum = screen->menu_font_number; 2788 int ncells; 2789 2790 if (!screen->renderDraw) { 2791 int scr; 2792 Drawable draw = VWindow(screen); 2793 Visual *visual; 2794 2795 scr = DefaultScreen(dpy); 2796 visual = DefaultVisual(dpy, scr); 2797 screen->renderDraw = XftDrawCreate(dpy, draw, visual, 2798 DefaultColormap(dpy, scr)); 2799 } 2800#if OPT_ISO_COLORS 2801 if ((flags & UNDERLINE) 2802 && !screen->colorULMode 2803 && screen->italicULMode 2804 && XFT_FONT(renderFontItal[fontnum])) { 2805 font = XFT_FONT(renderFontItal[fontnum]); 2806 did_ul = True; 2807 } else 2808#endif 2809 if ((flags & BOLDATTR(screen)) 2810 && UseBoldFont(screen) 2811 && XFT_FONT(renderFontBold[fontnum])) { 2812 font = XFT_FONT(renderFontBold[fontnum]); 2813 } else { 2814 font = XFT_FONT(renderFontNorm[fontnum]); 2815 } 2816 values.foreground = getCgsFore(xw, currentWin, gc); 2817 values.background = getCgsBack(xw, currentWin, gc); 2818 2819 if (!(flags & NOBACKGROUND)) { 2820 XftColor *bg_color = getXftColor(xw, values.background); 2821 ncells = xtermXftWidth(xw, flags, 2822 bg_color, 2823 font, x, y, 2824 text, 2825 len); 2826 XftDrawRect(screen->renderDraw, 2827 bg_color, 2828 x, y, 2829 (unsigned) (ncells * FontWidth(screen)), 2830 (unsigned) FontHeight(screen)); 2831 } 2832 2833 y += font->ascent; 2834#if OPT_BOX_CHARS 2835 { 2836 /* adding code to substitute simulated line-drawing characters */ 2837 int last, first = 0; 2838 Dimension old_wide, old_high = 0; 2839 int curX = x; 2840 2841 for (last = 0; last < (int) len; last++) { 2842 Boolean replace = False; 2843 Boolean missing = False; 2844 unsigned ch = (unsigned) text[last]; 2845 int nc; 2846#if OPT_WIDE_CHARS 2847 2848 if (xtermIsDecGraphic(ch)) { 2849 /* 2850 * Xft generally does not have the line-drawing characters 2851 * in cells 1-31. Assume this (we cannot inspect the 2852 * picture easily...), and attempt to fill in from real 2853 * line-drawing character in the font at the Unicode 2854 * position. Failing that, use our own box-characters. 2855 */ 2856 if (screen->force_box_chars 2857 || xtermXftMissing(xw, font, dec2ucs(ch))) { 2858 missing = 1; 2859 } else { 2860 ch = dec2ucs(ch); 2861 replace = True; 2862 } 2863 } else if (ch >= 256) { 2864 /* 2865 * If we're reading UTF-8 from the client, we may have a 2866 * line-drawing character. Translate it back to our 2867 * box-code if Xft tells us that the glyph is missing. 2868 */ 2869 if_OPT_WIDE_CHARS(screen, { 2870 unsigned part = ucs2dec(ch); 2871 if (xtermIsDecGraphic(part) && 2872 (screen->force_box_chars 2873 || xtermXftMissing(xw, font, ch))) { 2874 ch = part; 2875 missing = True; 2876 } 2877 }); 2878 } 2879#else 2880 if (xtermIsDecGraphic(ch)) { 2881 /* 2882 * Xft generally does not have the line-drawing characters 2883 * in cells 1-31. Check for this, and attempt to fill in 2884 * from real line-drawing character in the font at the 2885 * Unicode position. Failing that, use our own 2886 * box-characters. 2887 */ 2888 if (xtermXftMissing(xw, font, ch)) { 2889 missing = 1; 2890 } 2891 } 2892#endif 2893 2894 /* 2895 * If we now have one of our box-codes, draw it directly. 2896 */ 2897 if (missing || replace) { 2898 /* line drawing character time */ 2899 if (last > first) { 2900 nc = drawClippedXftString(xw, 2901 flags, 2902 font, 2903 getXftColor(xw, values.foreground), 2904 curX, 2905 y, 2906 text + first, 2907 (Cardinal) (last - first)); 2908 curX += nc * FontWidth(screen); 2909 underline_len += (Cardinal) nc; 2910 } 2911 if (missing) { 2912 old_wide = screen->fnt_wide; 2913 old_high = screen->fnt_high; 2914 screen->fnt_wide = (Dimension) FontWidth(screen); 2915 screen->fnt_high = (Dimension) FontHeight(screen); 2916 xtermDrawBoxChar(xw, ch, flags, gc, 2917 curX, y - FontAscent(screen), 1); 2918 curX += FontWidth(screen); 2919 underline_len += 1; 2920 screen->fnt_wide = old_wide; 2921 screen->fnt_high = old_high; 2922 } else { 2923 IChar ch2 = (IChar) ch; 2924 nc = drawClippedXftString(xw, 2925 flags, 2926 font, 2927 getXftColor(xw, values.foreground), 2928 curX, 2929 y, 2930 &ch2, 2931 1); 2932 curX += nc * FontWidth(screen); 2933 underline_len += (Cardinal) nc; 2934 } 2935 first = last + 1; 2936 } 2937 } 2938 if (last > first) { 2939 underline_len += (Cardinal) 2940 drawClippedXftString(xw, 2941 flags, 2942 font, 2943 getXftColor(xw, values.foreground), 2944 curX, 2945 y, 2946 text + first, 2947 (Cardinal) (last - first)); 2948 } 2949 } 2950#else 2951 { 2952 underline_len += (Cardinal) 2953 drawClippedXftString(xw, 2954 flags, 2955 font, 2956 getXftColor(xw, values.foreground), 2957 x, 2958 y, 2959 text, 2960 len); 2961 } 2962#endif /* OPT_BOX_CHARS */ 2963 2964 if ((flags & UNDERLINE) && screen->underline && !did_ul) { 2965 if (FontDescent(screen) > 1) 2966 y++; 2967 XDrawLine(screen->display, VWindow(screen), gc, 2968 x, y, 2969 x + (int) underline_len * FontWidth(screen) - 1, 2970 y); 2971 } 2972 return x + (int) len *FontWidth(screen); 2973 } 2974#endif /* OPT_RENDERFONT */ 2975 /* 2976 * If we're asked to display a proportional font, do this with a fixed 2977 * pitch. Yes, it's ugly. But we cannot distinguish the use of xterm 2978 * as a dumb terminal vs its use as in fullscreen programs such as vi. 2979 * Hint: do not try to use a proportional font in the icon. 2980 */ 2981 if (!IsIcon(screen) && !(flags & CHARBYCHAR) && screen->fnt_prop) { 2982 int adj, width; 2983 XTermFonts *font = ((flags & BOLDATTR(screen)) 2984 ? WhichVFontData(screen, fnts[fBold]) 2985 : WhichVFontData(screen, fnts[fNorm])); 2986 2987 while (len--) { 2988 int cells = WideCells(*text); 2989#if OPT_BOX_CHARS 2990#if OPT_WIDE_CHARS 2991 if (*text == HIDDEN_CHAR) { 2992 ++text; 2993 continue; 2994 } else 2995#endif 2996 if (IsXtermMissingChar(screen, *text, font)) { 2997 adj = 0; 2998 } else 2999#endif 3000 { 3001 if_WIDE_OR_NARROW(screen, { 3002 XChar2b temp[1]; 3003 temp[0].byte2 = LO_BYTE(*text); 3004 temp[0].byte1 = HI_BYTE(*text); 3005 width = XTextWidth16(font->fs, temp, 1); 3006 } 3007 , { 3008 char temp[1]; 3009 temp[0] = (char) LO_BYTE(*text); 3010 width = XTextWidth(font->fs, temp, 1); 3011 }); 3012 adj = (FontWidth(screen) - width) / 2; 3013 if (adj < 0) 3014 adj = 0; 3015 } 3016 xtermFillCells(xw, flags, gc, x, y, (Cardinal) cells); 3017 x = drawXtermText(xw, 3018 flags | NOBACKGROUND | CHARBYCHAR, 3019 gc, x + adj, y, chrset, 3020 text++, 1, on_wide) - adj; 3021 } 3022 return x; 3023 } 3024#if OPT_BOX_CHARS 3025 /* If the font is incomplete, draw some substitutions */ 3026 if (!IsIcon(screen) 3027 && !(flags & NOTRANSLATION) 3028 && (!screen->fnt_boxes || screen->force_box_chars)) { 3029 /* Fill in missing box-characters. 3030 Find regions without missing characters, and draw 3031 them calling ourselves recursively. Draw missing 3032 characters via xtermDrawBoxChar(). */ 3033 XTermFonts *font = ((flags & BOLDATTR(screen)) 3034 ? WhichVFontData(screen, fnts[fBold]) 3035 : WhichVFontData(screen, fnts[fNorm])); 3036 int last, first = 0; 3037 Bool drewBoxes = False; 3038 3039 for (last = 0; last < (int) len; last++) { 3040 unsigned ch = (unsigned) text[last]; 3041 Bool isMissing; 3042 int ch_width; 3043#if OPT_WIDE_CHARS 3044 3045 if (ch == HIDDEN_CHAR) { 3046 if (last > first) { 3047 x = drawXtermText(xw, flags | NOTRANSLATION, gc, 3048 x, y, 3049 chrset, text + first, 3050 (unsigned) (last - first), on_wide); 3051 } 3052 first = last + 1; 3053 drewBoxes = True; 3054 continue; 3055 } 3056 ch_width = my_wcwidth((int) ch); 3057 isMissing = 3058 IsXtermMissingChar(screen, ch, 3059 ((on_wide || ch_width > 1) 3060 && okFont(NormalWFont(screen))) 3061 ? WhichVFontData(screen, fnts[fWide]) 3062 : font); 3063#else 3064 isMissing = IsXtermMissingChar(screen, ch, font); 3065 ch_width = 1; 3066#endif 3067 /* 3068 * If the character is not missing, but we're in wide-character 3069 * mode and the character happens to be a wide-character that 3070 * corresponds to the line-drawing set, allow the forceBoxChars 3071 * resource (or menu entry) to force it to display using our 3072 * tables. 3073 */ 3074 if_OPT_WIDE_CHARS(screen, { 3075 if (!isMissing 3076 && ch > 255 3077 && ucs2dec(ch) < 32 3078 && TScreenOf(xw)->force_box_chars) { 3079 ch = ucs2dec(ch); 3080 isMissing = True; 3081 } 3082 }); 3083 3084 if (isMissing) { 3085 if (last > first) { 3086 x = drawXtermText(xw, flags | NOTRANSLATION, gc, 3087 x, y, 3088 chrset, text + first, 3089 (unsigned) (last - first), on_wide); 3090 } 3091#if OPT_WIDE_CHARS 3092 if (ucs_workaround(xw, ch, flags, gc, 3093 x, y, 3094 chrset, on_wide)) { 3095 /* 3096 * if true, we drew at least one cell whether or not it is 3097 * printable 3098 */ 3099 if (ch_width <= 0) 3100 ch_width = 1; 3101 } else 3102#endif 3103 { 3104 if (ch_width <= 0) 3105 ch_width = 1; 3106 xtermDrawBoxChar(xw, ch, flags, gc, 3107 x, y, 3108 ch_width); 3109 } 3110 x += (ch_width * FontWidth(screen)); 3111 first = last + 1; 3112 drewBoxes = True; 3113 } 3114 } 3115 if (last <= first) { 3116 return x; 3117 } 3118 text += first; 3119 len = (Cardinal) (last - first); 3120 flags |= NOTRANSLATION; 3121 if (drewBoxes) { 3122 return drawXtermText(xw, 3123 flags, 3124 gc, 3125 x, 3126 y, 3127 chrset, 3128 text, 3129 len, 3130 on_wide); 3131 } 3132 } 3133#endif /* OPT_BOX_CHARS */ 3134 /* 3135 * Behave as if the font has (maybe Unicode-replacements for) drawing 3136 * characters in the range 1-31 (either we were not asked to ignore them, 3137 * or the caller made sure that there is none). 3138 */ 3139 TRACE(("drawtext%c[%4d,%4d] (%d) %d:%s\n", 3140 screen->cursor_state == OFF ? ' ' : '*', 3141 y, x, chrset, len, 3142 visibleIChars(text, len))); 3143 y += FontAscent(screen); 3144 3145#if OPT_WIDE_CHARS 3146 3147 if (screen->wide_chars || screen->unicode_font) { 3148 XChar2b *buffer; 3149 Bool needWide = False; 3150 int ascent_adjust = 0; 3151 int src, dst; 3152 3153 BumpTypedBuffer(XChar2b, len); 3154 buffer = BfBuf(XChar2b); 3155 3156 for (src = dst = 0; src < (int) len; src++) { 3157 IChar ch = text[src]; 3158 3159 if (ch == HIDDEN_CHAR) 3160 continue; 3161 3162 if (!needWide 3163 && !IsIcon(screen) 3164 && ((on_wide || my_wcwidth((int) ch) > 1) 3165 && okFont(NormalWFont(screen)))) { 3166 needWide = True; 3167 } 3168 3169 /* 3170 * bitmap-fonts are limited to 16-bits. 3171 */ 3172#if OPT_WIDER_ICHAR 3173 if (ch > 0xffff) { 3174 ch = UCS_REPL; 3175 } 3176#endif 3177 buffer[dst].byte2 = LO_BYTE(ch); 3178 buffer[dst].byte1 = HI_BYTE(ch); 3179#if OPT_MINI_LUIT 3180#define UCS2SBUF(value) buffer[dst].byte2 = LO_BYTE(value);\ 3181 buffer[dst].byte1 = HI_BYTE(value) 3182 3183#define Map2Sbuf(from,to) (text[src] == from) { UCS2SBUF(to); } 3184 3185 if (screen->latin9_mode && !screen->utf8_mode && text[src] < 256) { 3186 3187 /* see http://www.cs.tut.fi/~jkorpela/latin9.html */ 3188 /* *INDENT-OFF* */ 3189 if Map2Sbuf(0xa4, 0x20ac) 3190 else if Map2Sbuf(0xa6, 0x0160) 3191 else if Map2Sbuf(0xa8, 0x0161) 3192 else if Map2Sbuf(0xb4, 0x017d) 3193 else if Map2Sbuf(0xb8, 0x017e) 3194 else if Map2Sbuf(0xbc, 0x0152) 3195 else if Map2Sbuf(0xbd, 0x0153) 3196 else if Map2Sbuf(0xbe, 0x0178) 3197 /* *INDENT-ON* */ 3198 3199 } 3200 if (screen->unicode_font 3201 && (text[src] == ANSI_DEL || 3202 text[src] < ANSI_SPA)) { 3203 unsigned ni = dec2ucs((unsigned) ((text[src] == ANSI_DEL) 3204 ? 0 3205 : text[src])); 3206 UCS2SBUF(ni); 3207 } 3208#endif /* OPT_MINI_LUIT */ 3209 ++dst; 3210 } 3211 /* FIXME This is probably wrong. But it works. */ 3212 underline_len = len; 3213 3214 /* Set the drawing font */ 3215 if (!(flags & (DOUBLEHFONT | DOUBLEWFONT))) { 3216 VTwin *currentWin = WhichVWin(screen); 3217 VTFontEnum fntId; 3218 CgsEnum cgsId; 3219 Pixel fg = getCgsFore(xw, currentWin, gc); 3220 Pixel bg = getCgsBack(xw, currentWin, gc); 3221 3222 if (needWide 3223 && (okFont(NormalWFont(screen)) || okFont(BoldWFont(screen)))) { 3224 if ((flags & BOLDATTR(screen)) != 0 3225 && okFont(BoldWFont(screen))) { 3226 fntId = fWBold; 3227 cgsId = gcWBold; 3228 } else { 3229 fntId = fWide; 3230 cgsId = gcWide; 3231 } 3232 } else if ((flags & BOLDATTR(screen)) != 0 3233 && okFont(BoldFont(screen))) { 3234 fntId = fBold; 3235 cgsId = gcBold; 3236 } else { 3237 fntId = fNorm; 3238 cgsId = gcNorm; 3239 } 3240 3241 setCgsFore(xw, currentWin, cgsId, fg); 3242 setCgsBack(xw, currentWin, cgsId, bg); 3243 gc = getCgsGC(xw, currentWin, cgsId); 3244 3245 if (fntId != fNorm) { 3246 XFontStruct *thisFp = WhichVFont(screen, fnts[fntId].fs); 3247 ascent_adjust = (thisFp->ascent 3248 - NormalFont(screen)->ascent); 3249 if (thisFp->max_bounds.width == 3250 NormalFont(screen)->max_bounds.width * 2) { 3251 underline_len = real_length = (Cardinal) (dst * 2); 3252 } else if (cgsId == gcWide || cgsId == gcWBold) { 3253 underline_len = real_length = (Cardinal) (dst * 2); 3254 xtermFillCells(xw, 3255 flags, 3256 gc, 3257 x, 3258 y - thisFp->ascent, 3259 real_length); 3260 } 3261 } 3262 } 3263 3264 if (flags & NOBACKGROUND) { 3265 XDrawString16(screen->display, 3266 VWindow(screen), gc, 3267 x, y + ascent_adjust, 3268 buffer, dst); 3269 } else { 3270 XDrawImageString16(screen->display, 3271 VWindow(screen), gc, 3272 x, y + ascent_adjust, 3273 buffer, dst); 3274 } 3275 3276 if ((flags & BOLDATTR(screen)) && screen->enbolden) { 3277 beginClipping(screen, gc, (Cardinal) font_width, len); 3278 XDrawString16(screen->display, VWindow(screen), gc, 3279 x + 1, 3280 y + ascent_adjust, 3281 buffer, dst); 3282 endClipping(screen, gc); 3283 } 3284 3285 } else 3286#endif /* OPT_WIDE_CHARS */ 3287 { 3288 int length = (int) len; /* X should have used unsigned */ 3289#if OPT_WIDE_CHARS 3290 char *buffer; 3291 int dst; 3292 3293 BumpTypedBuffer(char, len); 3294 buffer = BfBuf(char); 3295 3296 for (dst = 0; dst < length; ++dst) 3297 buffer[dst] = (char) LO_BYTE(text[dst]); 3298#else 3299 char *buffer = (char *) text; 3300#endif 3301 3302 if (flags & NOBACKGROUND) { 3303 XDrawString(screen->display, VWindow(screen), gc, 3304 x, y, buffer, length); 3305 } else { 3306 XDrawImageString(screen->display, VWindow(screen), gc, 3307 x, y, buffer, length); 3308 } 3309 underline_len = (Cardinal) length; 3310 if ((flags & BOLDATTR(screen)) && screen->enbolden) { 3311 beginClipping(screen, gc, font_width, length); 3312 XDrawString(screen->display, VWindow(screen), gc, 3313 x + 1, y, buffer, length); 3314 endClipping(screen, gc); 3315 } 3316 } 3317 3318 if ((flags & UNDERLINE) && screen->underline && !did_ul) { 3319 if (FontDescent(screen) > 1) 3320 y++; 3321 XDrawLine(screen->display, VWindow(screen), gc, 3322 x, y, (x + (int) underline_len * font_width - 1), y); 3323 } 3324 3325 return x + (int) real_length *FontWidth(screen); 3326} 3327 3328#if OPT_WIDE_CHARS 3329/* 3330 * Allocate buffer - workaround for wide-character interfaces. 3331 */ 3332void 3333allocXtermChars(ScrnPtr * buffer, Cardinal length) 3334{ 3335 if (*buffer == 0) { 3336 *buffer = (ScrnPtr) XtMalloc(length); 3337 } else { 3338 *buffer = (ScrnPtr) XtRealloc((char *) *buffer, length); 3339 } 3340} 3341#endif 3342 3343/* set up size hints for window manager; min 1 char by 1 char */ 3344void 3345xtermSizeHints(XtermWidget xw, int scrollbarWidth) 3346{ 3347 TScreen *screen = TScreenOf(xw); 3348 3349 TRACE(("xtermSizeHints\n")); 3350 TRACE((" border %d\n", xw->core.border_width)); 3351 TRACE((" scrollbar %d\n", scrollbarWidth)); 3352 3353 xw->hints.base_width = 2 * screen->border + scrollbarWidth; 3354 xw->hints.base_height = 2 * screen->border; 3355 3356#if OPT_TOOLBAR 3357 TRACE((" toolbar %d\n", ToolbarHeight(xw))); 3358 3359 xw->hints.base_height += ToolbarHeight(xw); 3360 xw->hints.base_height += BorderWidth(xw) * 2; 3361 xw->hints.base_width += BorderWidth(xw) * 2; 3362#endif 3363 3364 xw->hints.width_inc = FontWidth(screen); 3365 xw->hints.height_inc = FontHeight(screen); 3366 xw->hints.min_width = xw->hints.base_width + xw->hints.width_inc; 3367 xw->hints.min_height = xw->hints.base_height + xw->hints.height_inc; 3368 3369 xw->hints.width = MaxCols(screen) * FontWidth(screen) + xw->hints.min_width; 3370 xw->hints.height = MaxRows(screen) * FontHeight(screen) + xw->hints.min_height; 3371 3372 xw->hints.flags |= (PSize | PBaseSize | PMinSize | PResizeInc); 3373 3374 TRACE_HINTS(&(xw->hints)); 3375} 3376 3377void 3378getXtermSizeHints(XtermWidget xw) 3379{ 3380 TScreen *screen = TScreenOf(xw); 3381 long supp; 3382 3383 if (!XGetWMNormalHints(screen->display, XtWindow(SHELL_OF(xw)), 3384 &xw->hints, &supp)) 3385 memset(&xw->hints, 0, sizeof(xw->hints)); 3386 TRACE_HINTS(&(xw->hints)); 3387} 3388 3389/* 3390 * Returns a GC, selected according to the font (reverse/bold/normal) that is 3391 * required for the current position (implied). The GC is updated with the 3392 * current screen foreground and background colors. 3393 */ 3394GC 3395updatedXtermGC(XtermWidget xw, unsigned flags, unsigned fg_bg, Bool hilite) 3396{ 3397 TScreen *screen = TScreenOf(xw); 3398 VTwin *win = WhichVWin(screen); 3399 CgsEnum cgsId = gcMAX; 3400 unsigned my_fg = extract_fg(xw, fg_bg, flags); 3401 unsigned my_bg = extract_bg(xw, fg_bg, flags); 3402 Pixel fg_pix = getXtermForeground(xw, flags, my_fg); 3403 Pixel bg_pix = getXtermBackground(xw, flags, my_bg); 3404 Pixel xx_pix; 3405#if OPT_HIGHLIGHT_COLOR 3406 Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG); 3407 Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG); 3408 Boolean always = screen->hilite_color; 3409 Boolean use_selbg = (Boolean) (always || 3410 isNotForeground(xw, fg_pix, bg_pix, selbg_pix)); 3411 Boolean use_selfg = (Boolean) (always && 3412 isNotBackground(xw, fg_pix, bg_pix, selfg_pix)); 3413#endif 3414 3415 (void) fg_bg; 3416 (void) my_bg; 3417 (void) my_fg; 3418 3419 /* 3420 * Discard video attributes overridden by colorXXXMode's. 3421 */ 3422 checkVeryBoldColors(flags, my_fg); 3423 3424 if (ReverseOrHilite(screen, flags, hilite)) { 3425 if (flags & BOLDATTR(screen)) { 3426 cgsId = gcBoldReverse; 3427 } else { 3428 cgsId = gcNormReverse; 3429 } 3430 3431#if OPT_HIGHLIGHT_COLOR 3432 if (!screen->hilite_color) { 3433 if (selbg_pix != T_COLOR(screen, TEXT_FG) 3434 && selbg_pix != fg_pix 3435 && selbg_pix != bg_pix 3436 && selbg_pix != xw->dft_foreground) { 3437 bg_pix = fg_pix; 3438 fg_pix = selbg_pix; 3439 } 3440 } 3441#endif 3442 EXCHANGE(fg_pix, bg_pix, xx_pix); 3443#if OPT_HIGHLIGHT_COLOR 3444 if (screen->hilite_color) { 3445 if (screen->hilite_reverse) { 3446 if (use_selbg) { 3447 if (use_selfg) 3448 bg_pix = fg_pix; 3449 else 3450 fg_pix = bg_pix; 3451 } 3452 if (use_selbg) 3453 bg_pix = selbg_pix; 3454 if (use_selfg) 3455 fg_pix = selfg_pix; 3456 } 3457 } 3458#endif 3459 } else { 3460 if (flags & BOLDATTR(screen)) { 3461 cgsId = gcBold; 3462 } else { 3463 cgsId = gcNorm; 3464 } 3465 } 3466#if OPT_HIGHLIGHT_COLOR 3467 if (!screen->hilite_color || !screen->hilite_reverse) { 3468 if (hilite && !screen->hilite_reverse) { 3469 if (use_selbg) 3470 bg_pix = selbg_pix; 3471 if (use_selfg) 3472 fg_pix = selfg_pix; 3473 } 3474 } 3475#endif 3476 3477#if OPT_BLINK_TEXT 3478 if ((screen->blink_state == ON) && (!screen->blink_as_bold) && (flags & BLINK)) { 3479 fg_pix = bg_pix; 3480 } 3481#endif 3482 3483 setCgsFore(xw, win, cgsId, fg_pix); 3484 setCgsBack(xw, win, cgsId, bg_pix); 3485 return getCgsGC(xw, win, cgsId); 3486} 3487 3488/* 3489 * Resets the foreground/background of the GC returned by 'updatedXtermGC()' 3490 * to the values that would be set in SGR_Foreground and SGR_Background. This 3491 * duplicates some logic, but only modifies 1/4 as many GC's. 3492 */ 3493void 3494resetXtermGC(XtermWidget xw, unsigned flags, Bool hilite) 3495{ 3496 TScreen *screen = TScreenOf(xw); 3497 VTwin *win = WhichVWin(screen); 3498 CgsEnum cgsId = gcMAX; 3499 Pixel fg_pix = getXtermForeground(xw, flags, xw->cur_foreground); 3500 Pixel bg_pix = getXtermBackground(xw, flags, xw->cur_background); 3501 3502 checkVeryBoldColors(flags, xw->cur_foreground); 3503 3504 if (ReverseOrHilite(screen, flags, hilite)) { 3505 if (flags & BOLDATTR(screen)) { 3506 cgsId = gcBoldReverse; 3507 } else { 3508 cgsId = gcNormReverse; 3509 } 3510 3511 setCgsFore(xw, win, cgsId, bg_pix); 3512 setCgsBack(xw, win, cgsId, fg_pix); 3513 3514 } else { 3515 if (flags & BOLDATTR(screen)) { 3516 cgsId = gcBold; 3517 } else { 3518 cgsId = gcNorm; 3519 } 3520 3521 setCgsFore(xw, win, cgsId, fg_pix); 3522 setCgsBack(xw, win, cgsId, bg_pix); 3523 } 3524} 3525 3526#if OPT_ISO_COLORS 3527/* 3528 * Extract the foreground-color index from a color pair. 3529 * If we've got BOLD or UNDERLINE color-mode active, those will be used. 3530 */ 3531unsigned 3532extract_fg(XtermWidget xw, unsigned color, unsigned flags) 3533{ 3534 unsigned fg = ExtractForeground(color); 3535 3536 if (TScreenOf(xw)->colorAttrMode 3537 || (fg == ExtractBackground(color))) { 3538 fg = MapToColorMode(fg, TScreenOf(xw), flags); 3539 } 3540 return fg; 3541} 3542 3543/* 3544 * Extract the background-color index from a color pair. 3545 * If we've got INVERSE color-mode active, that will be used. 3546 */ 3547unsigned 3548extract_bg(XtermWidget xw, unsigned color, unsigned flags) 3549{ 3550 unsigned bg = ExtractBackground(color); 3551 3552 if (TScreenOf(xw)->colorAttrMode 3553 || (bg == ExtractForeground(color))) { 3554 if (TScreenOf(xw)->colorRVMode && (flags & INVERSE)) 3555 bg = COLOR_RV; 3556 } 3557 return bg; 3558} 3559 3560/* 3561 * Combine the current foreground and background into a single 8-bit number. 3562 * Note that we're storing the SGR foreground, since cur_foreground may be set 3563 * to COLOR_UL, COLOR_BD or COLOR_BL, which would make the code larger than 8 3564 * bits. 3565 * 3566 * This assumes that fg/bg are equal when we override with one of the special 3567 * attribute colors. 3568 */ 3569CellColor 3570makeColorPair(int fg, int bg) 3571{ 3572 unsigned my_bg = (bg >= 0) && (bg < NUM_ANSI_COLORS) ? (unsigned) bg : 0; 3573 unsigned my_fg = (fg >= 0) && (fg < NUM_ANSI_COLORS) ? (unsigned) fg : my_bg; 3574 3575 return (CellColor) (my_fg | (my_bg << COLOR_BITS)); 3576} 3577 3578/* 3579 * Using the "current" SGR background, clear a rectangle. 3580 */ 3581void 3582ClearCurBackground(XtermWidget xw, 3583 int top, 3584 int left, 3585 unsigned height, 3586 unsigned width) 3587{ 3588 TScreen *screen = TScreenOf(xw); 3589 3590 TRACE(("ClearCurBackground(%d,%d,%d,%d) %d\n", 3591 top, left, height, width, xw->cur_background)); 3592 3593 if (VWindow(screen)) { 3594 set_background(xw, xw->cur_background); 3595 3596 XClearArea(screen->display, VWindow(screen), 3597 left, top, width, height, False); 3598 3599 set_background(xw, -1); 3600 } 3601} 3602#endif /* OPT_ISO_COLORS */ 3603 3604/* 3605 * Returns a single base character for the given cell. 3606 */ 3607unsigned 3608getXtermCell(TScreen * screen, int row, int col) 3609{ 3610 LineData *ld = getLineData(screen, row); 3611 3612 assert(ld && (col < (int) ld->lineSize)); 3613 return ((ld && (col < (int) ld->lineSize)) 3614 ? ld->charData[col] 3615 : (unsigned) ' '); 3616} 3617 3618/* 3619 * Sets a single base character for the given cell. 3620 */ 3621void 3622putXtermCell(TScreen * screen, int row, int col, int ch) 3623{ 3624 LineData *ld = getLineData(screen, row); 3625 3626 assert(ld && (col < (int) ld->lineSize)); 3627 if (ld && (col < (int) ld->lineSize)) { 3628 ld->charData[col] = (CharData) ch; 3629 if_OPT_WIDE_CHARS(screen, { 3630 size_t off; 3631 for_each_combData(off, ld) { 3632 ld->combData[off][col] = 0; 3633 } 3634 }); 3635 } 3636} 3637 3638#if OPT_WIDE_CHARS 3639/* 3640 * Add a combining character for the given cell 3641 */ 3642void 3643addXtermCombining(TScreen * screen, int row, int col, unsigned ch) 3644{ 3645 if (ch != 0) { 3646 LineData *ld = getLineData(screen, row); 3647 size_t off; 3648 3649 TRACE(("addXtermCombining %d,%d %#x (%d)\n", 3650 row, col, ch, my_wcwidth((wchar_t) ch))); 3651 3652 for_each_combData(off, ld) { 3653 if (!ld->combData[off][col]) { 3654 ld->combData[off][col] = (CharData) ch; 3655 break; 3656 } 3657 } 3658 } 3659} 3660#endif 3661 3662#ifdef HAVE_CONFIG_H 3663#ifdef USE_MY_MEMMOVE 3664void * 3665my_memmove(void *s1, void *s2, size_t n) 3666{ 3667 if (n != 0) { 3668 char *p1 = (char *) s1; 3669 char *p2 = (char *) s2; 3670 3671 if ((p1 + n > p2) && (p2 + n > p1)) { 3672 static char *bfr; 3673 static size_t length; 3674 size_t j; 3675 if (length < n) { 3676 length = (n * 3) / 2; 3677 bfr = ((bfr != 0) 3678 ? TypeRealloc(char, length, bfr) 3679 : TypeMallocN(char, length)); 3680 if (bfr == NULL) 3681 SysError(ERROR_MMALLOC); 3682 } 3683 for (j = 0; j < n; j++) 3684 bfr[j] = p2[j]; 3685 p2 = bfr; 3686 } 3687 while (n-- != 0) 3688 p1[n] = p2[n]; 3689 } 3690 return s1; 3691} 3692#endif /* USE_MY_MEMMOVE */ 3693 3694#ifndef HAVE_STRERROR 3695char * 3696my_strerror(int n) 3697{ 3698 extern char *sys_errlist[]; 3699 extern int sys_nerr; 3700 if (n > 0 && n < sys_nerr) 3701 return sys_errlist[n]; 3702 return "?"; 3703} 3704#endif 3705#endif 3706 3707void 3708update_keyboard_type(void) 3709{ 3710 update_delete_del(); 3711 update_tcap_fkeys(); 3712 update_old_fkeys(); 3713 update_hp_fkeys(); 3714 update_sco_fkeys(); 3715 update_sun_fkeys(); 3716 update_sun_kbd(); 3717} 3718 3719void 3720set_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set) 3721{ 3722 xtermKeyboardType save = xw->keyboard.type; 3723 3724 TRACE(("set_keyboard_type(%s, %s) currently %s\n", 3725 visibleKeyboardType(type), 3726 BtoS(set), 3727 visibleKeyboardType(xw->keyboard.type))); 3728 if (set) { 3729 xw->keyboard.type = type; 3730 } else { 3731 xw->keyboard.type = keyboardIsDefault; 3732 } 3733 3734 if (save != xw->keyboard.type) { 3735 update_keyboard_type(); 3736 } 3737} 3738 3739void 3740toggle_keyboard_type(XtermWidget xw, xtermKeyboardType type) 3741{ 3742 xtermKeyboardType save = xw->keyboard.type; 3743 3744 TRACE(("toggle_keyboard_type(%s) currently %s\n", 3745 visibleKeyboardType(type), 3746 visibleKeyboardType(xw->keyboard.type))); 3747 if (xw->keyboard.type == type) { 3748 xw->keyboard.type = keyboardIsDefault; 3749 } else { 3750 xw->keyboard.type = type; 3751 } 3752 3753 if (save != xw->keyboard.type) { 3754 update_keyboard_type(); 3755 } 3756} 3757 3758void 3759init_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set) 3760{ 3761 static Bool wasSet = False; 3762 3763 TRACE(("init_keyboard_type(%s, %s) currently %s\n", 3764 visibleKeyboardType(type), 3765 BtoS(set), 3766 visibleKeyboardType(xw->keyboard.type))); 3767 if (set) { 3768 if (wasSet) { 3769 fprintf(stderr, "Conflicting keyboard type option (%u/%u)\n", 3770 xw->keyboard.type, type); 3771 } 3772 xw->keyboard.type = type; 3773 wasSet = True; 3774 update_keyboard_type(); 3775 } 3776} 3777 3778/* 3779 * If the keyboardType resource is set, use that, overriding the individual 3780 * boolean resources for different keyboard types. 3781 */ 3782void 3783decode_keyboard_type(XtermWidget xw, XTERM_RESOURCE * rp) 3784{ 3785#define DATA(n, t, f) { n, t, XtOffsetOf(XTERM_RESOURCE, f) } 3786#define FLAG(n) *(Boolean *)(((char *)rp) + table[n].offset) 3787 static struct { 3788 const char *name; 3789 xtermKeyboardType type; 3790 unsigned offset; 3791 } table[] = { 3792#if OPT_HP_FUNC_KEYS 3793 DATA(NAME_HP_KT, keyboardIsHP, hpFunctionKeys), 3794#endif 3795#if OPT_SCO_FUNC_KEYS 3796 DATA(NAME_SCO_KT, keyboardIsSCO, scoFunctionKeys), 3797#endif 3798#if OPT_SUN_FUNC_KEYS 3799 DATA(NAME_SUN_KT, keyboardIsSun, sunFunctionKeys), 3800#endif 3801#if OPT_SUNPC_KBD 3802 DATA(NAME_VT220_KT, keyboardIsVT220, sunKeyboard), 3803#endif 3804#if OPT_TCAP_FKEYS 3805 DATA(NAME_TCAP_KT, keyboardIsTermcap, termcapKeys), 3806#endif 3807 }; 3808 Cardinal n; 3809 3810 TRACE(("decode_keyboard_type(%s)\n", rp->keyboardType)); 3811 if (!x_strcasecmp(rp->keyboardType, "unknown")) { 3812 /* 3813 * Let the individual resources comprise the keyboard-type. 3814 */ 3815 for (n = 0; n < XtNumber(table); ++n) 3816 init_keyboard_type(xw, table[n].type, FLAG(n)); 3817 } else if (!x_strcasecmp(rp->keyboardType, "default")) { 3818 /* 3819 * Set the keyboard-type to the Sun/PC type, allowing modified 3820 * function keys, etc. 3821 */ 3822 for (n = 0; n < XtNumber(table); ++n) 3823 init_keyboard_type(xw, table[n].type, False); 3824 } else { 3825 Bool found = False; 3826 3827 /* 3828 * Choose an individual keyboard type. 3829 */ 3830 for (n = 0; n < XtNumber(table); ++n) { 3831 if (!x_strcasecmp(rp->keyboardType, table[n].name + 1)) { 3832 FLAG(n) = True; 3833 found = True; 3834 } else { 3835 FLAG(n) = False; 3836 } 3837 init_keyboard_type(xw, table[n].type, FLAG(n)); 3838 } 3839 if (!found) { 3840 fprintf(stderr, 3841 "KeyboardType resource \"%s\" not found\n", 3842 rp->keyboardType); 3843 } 3844 } 3845#undef DATA 3846#undef FLAG 3847} 3848 3849#if OPT_WIDE_CHARS 3850#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH) 3851/* 3852 * If xterm is running in a UTF-8 locale, it is still possible to encounter 3853 * old runtime configurations which yield incomplete or inaccurate data. 3854 */ 3855static Bool 3856systemWcwidthOk(int samplesize, int samplepass) 3857{ 3858 wchar_t n; 3859 int oops = 0; 3860 3861 for (n = 21; n <= 25; ++n) { 3862 int code = (int) dec2ucs((unsigned) n); 3863 int system_code = wcwidth(code); 3864 int intern_code = mk_wcwidth(code); 3865 3866 /* 3867 * Solaris 10 wcwidth() returns "2" for all of the line-drawing (page 3868 * 0x2500) and most of the geometric shapes (a few are excluded, just 3869 * to make it more difficult to use). Do a sanity check to avoid using 3870 * it. 3871 */ 3872 if ((system_code < 0 && intern_code >= 1) 3873 || (system_code >= 0 && intern_code != system_code)) { 3874 TRACE(("systemWcwidthOk: broken system line-drawing wcwidth\n")); 3875 oops += (samplepass + 1); 3876 break; 3877 } 3878 } 3879 3880 for (n = 0; n < (wchar_t) samplesize; ++n) { 3881 int system_code = wcwidth(n); 3882 int intern_code = mk_wcwidth(n); 3883 3884 /* 3885 * Since mk_wcwidth() is designed to check for nonspacing characters, 3886 * and has rough range-checks for double-width characters, it will 3887 * generally not detect cases where a code has not been assigned. 3888 * 3889 * Some experimentation with GNU libc suggests that up to 1/4 of the 3890 * codes would differ, simply because the runtime library would have a 3891 * table listing the unassigned codes, and return -1 for those. If 3892 * mk_wcwidth() has no information about a code, it returns 1. On the 3893 * other hand, if the runtime returns a positive number, the two should 3894 * agree. 3895 * 3896 * The "up to" is measured for 4k, 8k, 16k of data. With only 1k, the 3897 * number of differences was only 77. However, that is only one 3898 * system, and this is only a sanity check to avoid using broken 3899 * libraries. 3900 */ 3901 if ((system_code < 0 && intern_code >= 1) 3902 || (system_code >= 0 && intern_code != system_code)) { 3903 ++oops; 3904 } 3905 } 3906 TRACE(("systemWcwidthOk: %d/%d mismatches, allowed %d\n", 3907 oops, samplesize, samplepass)); 3908 return (oops <= samplepass); 3909} 3910#endif /* HAVE_WCWIDTH */ 3911 3912void 3913decode_wcwidth(XtermWidget xw) 3914{ 3915 int mode = ((xw->misc.cjk_width ? 2 : 0) 3916 + (xw->misc.mk_width ? 1 : 0) 3917 + 1); 3918 3919 switch (mode) { 3920 default: 3921#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH) 3922 if (xtermEnvUTF8() && 3923 systemWcwidthOk(xw->misc.mk_samplesize, xw->misc.mk_samplepass)) { 3924 my_wcwidth = wcwidth; 3925 TRACE(("using system wcwidth() function\n")); 3926 break; 3927 } 3928 /* FALLTHRU */ 3929#endif 3930 case 2: 3931 my_wcwidth = &mk_wcwidth; 3932 TRACE(("using MK wcwidth() function\n")); 3933 break; 3934 case 3: 3935 case 4: 3936 my_wcwidth = &mk_wcwidth_cjk; 3937 TRACE(("using MK-CJK wcwidth() function\n")); 3938 break; 3939 } 3940 3941 for (first_widechar = 128; first_widechar < 4500; ++first_widechar) { 3942 if (my_wcwidth((int) first_widechar) > 1) { 3943 TRACE(("first_widechar %#x\n", first_widechar)); 3944 break; 3945 } 3946 } 3947} 3948#endif 3949