util.c revision 5307cd1a
1/* $XTermId: util.c,v 1.932 2023/05/28 13:29:49 tom Exp $ */ 2 3/* 4 * Copyright 1999-2022,2023 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 <string.h> 67#include <ctype.h> 68#include <assert.h> 69 70#if OPT_WIDE_CHARS 71#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH) 72#include <wchar.h> 73#endif 74#include <wcwidth.h> 75#endif 76 77#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H 78#include <X11/extensions/Xinerama.h> 79#endif /* HAVE_X11_EXTENSIONS_XINERAMA_H */ 80 81#include <graphics.h> 82 83#define IncrementSavedLines(amount) \ 84 if (screen->savedlines < screen->savelines) { \ 85 if ((screen->savedlines += amount) > screen->savelines) \ 86 screen->savedlines = screen->savelines; \ 87 ScrollBarDrawThumb(xw, 1); \ 88 } 89 90static int handle_translated_exposure(XtermWidget xw, 91 int rect_x, 92 int rect_y, 93 int rect_width, 94 int rect_height); 95static void ClearLeft(XtermWidget xw); 96static void CopyWait(XtermWidget xw); 97static void horizontal_copy_area(XtermWidget xw, 98 int firstchar, 99 int nchars, 100 int amount); 101static void vertical_copy_area(XtermWidget xw, 102 int firstline, 103 int nlines, 104 int amount, 105 int left, 106 int right); 107 108#if OPT_WIDE_CHARS 109unsigned first_widechar; 110int (*my_wcwidth) (wchar_t); 111#endif 112 113#if OPT_WIDE_CHARS 114/* 115 * We will modify the 'n' cells beginning at the current position. 116 * Some of those cells may be part of multi-column characters, including 117 * carryover from the left. Find the limits of the multi-column characters 118 * that we should fill with blanks, return true if filling is needed. 119 */ 120int 121DamagedCells(TScreen *screen, unsigned n, int *klp, int *krp, int row, int col) 122{ 123 CLineData *ld = getLineData(screen, row); 124 int result = False; 125 126 assert(ld); 127 if (col < (int) ld->lineSize) { 128 int nn = (int) n; 129 int kl = col; 130 int kr = col + nn; 131 132 if (kr >= (int) ld->lineSize) { 133 nn = (ld->lineSize - col - 1); 134 kr = col + nn; 135 } 136 137 if (nn > 0) { 138 assert(kl < (int) ld->lineSize); 139 if (ld->charData[kl] == HIDDEN_CHAR) { 140 while (kl > 0) { 141 if (ld->charData[--kl] != HIDDEN_CHAR) { 142 break; 143 } 144 } 145 } else { 146 kl = col + 1; 147 } 148 149 assert(kr < (int) ld->lineSize); 150 if (ld->charData[kr] == HIDDEN_CHAR) { 151 while (kr < screen->max_col) { 152 assert((kr + 1) < (int) ld->lineSize); 153 if (ld->charData[++kr] != HIDDEN_CHAR) { 154 --kr; 155 break; 156 } 157 } 158 } else { 159 kr = col - 1; 160 } 161 162 if (klp) 163 *klp = kl; 164 if (krp) 165 *krp = kr; 166 result = (kr >= kl); 167 } 168 } 169 170 return result; 171} 172 173int 174DamagedCurCells(TScreen *screen, unsigned n, int *klp, int *krp) 175{ 176 return DamagedCells(screen, n, klp, krp, screen->cur_row, screen->cur_col); 177} 178#endif /* OPT_WIDE_CHARS */ 179 180/* 181 * These routines are used for the jump scroll feature 182 */ 183void 184FlushScroll(XtermWidget xw) 185{ 186 TScreen *screen = TScreenOf(xw); 187 int i; 188 int shift = INX2ROW(screen, 0); 189 int bot = screen->max_row - shift; 190 int refreshtop; 191 int refreshheight; 192 int scrolltop; 193 int scrollheight; 194 int left = ScrnLeftMargin(xw); 195 int right = ScrnRightMargin(xw); 196 Boolean full_lines = (Boolean) ((left == 0) && (right == screen->max_col)); 197 198 if (screen->cursor_state) 199 HideCursor(xw); 200 201 TRACE(("FlushScroll %s-lines scroll:%d refresh %d\n", 202 full_lines ? "full" : "partial", 203 screen->scroll_amt, 204 screen->refresh_amt)); 205 206 if (screen->scroll_amt > 0) { 207 /* 208 * Lines will be scrolled "up". 209 */ 210 refreshheight = screen->refresh_amt; 211 scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1; 212 refreshtop = screen->bot_marg - refreshheight + 1 + shift; 213 i = screen->max_row - screen->scroll_amt + 1; 214 if (refreshtop > i) { 215 refreshtop = i; 216 } 217 218 /* 219 * If this is the normal (not alternate) screen, and the top margin is 220 * at the top of the screen, then we will shift full lines scrolled out 221 * of the scrolling region into the saved-lines. 222 */ 223 if (screen->scrollWidget 224 && !screen->whichBuf 225 && full_lines 226 && screen->top_marg == 0) { 227 scrolltop = 0; 228 scrollheight += shift; 229 if (scrollheight > i) 230 scrollheight = i; 231 i = screen->bot_marg - bot; 232 if (i > 0) { 233 refreshheight -= i; 234 if (refreshheight < screen->scroll_amt) { 235 refreshheight = screen->scroll_amt; 236 } 237 } 238 IncrementSavedLines(screen->scroll_amt); 239 } else { 240 scrolltop = screen->top_marg + shift; 241 i = bot - (screen->bot_marg - screen->refresh_amt + screen->scroll_amt); 242 if (i > 0) { 243 if (bot < screen->bot_marg) { 244 refreshheight = screen->scroll_amt + i; 245 } 246 } else { 247 scrollheight += i; 248 refreshheight = screen->scroll_amt; 249 i = screen->top_marg + screen->scroll_amt - 1 - bot; 250 if (i > 0) { 251 refreshtop += i; 252 refreshheight -= i; 253 } 254 } 255 } 256 } else { 257 /* 258 * Lines will be scrolled "down". 259 */ 260 refreshheight = -screen->refresh_amt; 261 scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1; 262 refreshtop = screen->top_marg + shift; 263 scrolltop = refreshtop + refreshheight; 264 i = screen->bot_marg - bot; 265 if (i > 0) { 266 scrollheight -= i; 267 } 268 i = screen->top_marg + refreshheight - 1 - bot; 269 if (i > 0) { 270 refreshheight -= i; 271 } 272 } 273 274 vertical_copy_area(xw, 275 scrolltop + screen->scroll_amt, 276 scrollheight, 277 screen->scroll_amt, 278 left, 279 right); 280 ScrollSelection(screen, -(screen->scroll_amt), False); 281 screen->scroll_amt = 0; 282 screen->refresh_amt = 0; 283 284 if (refreshheight > 0) { 285 ClearCurBackground(xw, 286 refreshtop, 287 left, 288 (unsigned) refreshheight, 289 (unsigned) (right + 1 - left), 290 (unsigned) FontWidth(screen)); 291 ScrnRefresh(xw, 292 refreshtop, 293 0, 294 refreshheight, 295 MaxCols(screen), 296 False); 297 } 298 xtermTimedDbe(xw); 299 return; 300} 301 302/* 303 * Returns true if there are lines off-screen due to scrolling which should 304 * include the current line. If false, the line is visible and we should 305 * paint it now rather than waiting for the line to become visible. 306 */ 307static Bool 308AddToRefresh(XtermWidget xw) 309{ 310 TScreen *screen = TScreenOf(xw); 311 int amount = screen->refresh_amt; 312 int row = screen->cur_row; 313 Bool result; 314 315 if (amount == 0) { 316 result = False; 317 } else if (amount > 0) { 318 int bottom; 319 320 if (row == (bottom = screen->bot_marg) - amount) { 321 screen->refresh_amt++; 322 result = True; 323 } else { 324 result = (row >= bottom - amount + 1 && row <= bottom); 325 } 326 } else { 327 int top; 328 329 amount = -amount; 330 if (row == (top = screen->top_marg) + amount) { 331 screen->refresh_amt--; 332 result = True; 333 } else { 334 result = (row <= top + amount - 1 && row >= top); 335 } 336 } 337 338 /* 339 * If this line is visible, and there are scrolled-off lines, flush out 340 * those which are now visible. 341 */ 342 if (!result && screen->scroll_amt) 343 FlushScroll(xw); 344 345 return result; 346} 347 348/* 349 * Returns true if the current row is in the visible area (it should be for 350 * screen operations) and incidentally flush the scrolled-in lines which 351 * have newly become visible. 352 */ 353static Bool 354AddToVisible(XtermWidget xw) 355{ 356 TScreen *screen = TScreenOf(xw); 357 Bool result = False; 358 359 if (INX2ROW(screen, screen->cur_row) <= LastRowNumber(screen)) { 360 if (!AddToRefresh(xw)) { 361 result = True; 362 } 363 } 364 return result; 365} 366 367/* 368 * If we're scrolling, leave the selection intact if possible. 369 * If it will bump into one of the extremes of the saved-lines, truncate that. 370 * If the selection is not entirely contained within the margins and not 371 * entirely outside the margins, clear it. 372 */ 373static void 374adjustHiliteOnFwdScroll(XtermWidget xw, int amount, Bool all_lines) 375{ 376 TScreen *screen = TScreenOf(xw); 377 int lo_row = (all_lines 378 ? (screen->bot_marg - screen->savelines) 379 : screen->top_marg); 380 int hi_row = screen->bot_marg; 381 int left = ScrnLeftMargin(xw); 382 int right = ScrnRightMargin(xw); 383 384 TRACE2(("adjustSelection FWD %s by %d (%s)\n", 385 screen->whichBuf ? "alternate" : "normal", 386 amount, 387 all_lines ? "all" : "visible")); 388 TRACE2((" before highlite %d.%d .. %d.%d\n", 389 screen->startH.row, 390 screen->startH.col, 391 screen->endH.row, 392 screen->endH.col)); 393 TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg)); 394 TRACE2((" limits %d..%d\n", lo_row, hi_row)); 395 396 if ((left > 0 || right < screen->max_col) && 397 ((screen->startH.row >= lo_row && 398 screen->startH.row - amount <= hi_row) || 399 (screen->endH.row >= lo_row && 400 screen->endH.row - amount <= hi_row))) { 401 /* 402 * This could be improved slightly by excluding the special case where 403 * the selection is on a single line outside left/right margins. 404 */ 405 TRACE2(("deselect because selection overlaps with scrolled partial-line\n")); 406 ScrnDisownSelection(xw); 407 } else if (screen->startH.row >= lo_row 408 && screen->startH.row - amount < lo_row) { 409 /* truncate the selection because its start would move out of region */ 410 if (lo_row + amount <= screen->endH.row) { 411 TRACE2(("truncate selection by changing start %d.%d to %d.%d\n", 412 screen->startH.row, 413 screen->startH.col, 414 lo_row + amount, 415 0)); 416 screen->startH.row = lo_row + amount; 417 screen->startH.col = 0; 418 } else { 419 TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n", 420 screen->startH.row, 421 screen->startH.col, 422 screen->endH.row, 423 screen->endH.col, 424 -amount, 425 lo_row, 426 hi_row)); 427 ScrnDisownSelection(xw); 428 } 429 } else if (screen->startH.row <= hi_row && screen->endH.row > hi_row) { 430 TRACE2(("deselect because selection straddles top-margin\n")); 431 ScrnDisownSelection(xw); 432 } else if (screen->startH.row < lo_row && screen->endH.row > lo_row) { 433 TRACE2(("deselect because selection straddles bottom-margin\n")); 434 ScrnDisownSelection(xw); 435 } 436 437 TRACE2((" after highlite %d.%d .. %d.%d\n", 438 screen->startH.row, 439 screen->startH.col, 440 screen->endH.row, 441 screen->endH.col)); 442} 443 444/* 445 * This is the same as adjustHiliteOnFwdScroll(), but reversed. In this case, 446 * only the visible lines are affected. 447 */ 448static void 449adjustHiliteOnBakScroll(XtermWidget xw, int amount) 450{ 451 TScreen *screen = TScreenOf(xw); 452 int lo_row = screen->top_marg; 453 int hi_row = screen->bot_marg; 454 455 TRACE2(("adjustSelection BAK %s by %d (%s)\n", 456 screen->whichBuf ? "alternate" : "normal", 457 amount, 458 "visible")); 459 TRACE2((" before highlite %d.%d .. %d.%d\n", 460 screen->startH.row, 461 screen->startH.col, 462 screen->endH.row, 463 screen->endH.col)); 464 TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg)); 465 466 if (screen->endH.row >= hi_row 467 && screen->endH.row + amount > hi_row) { 468 /* truncate the selection because its start would move out of region */ 469 if (hi_row - amount >= screen->startH.row) { 470 TRACE2(("truncate selection by changing start %d.%d to %d.%d\n", 471 screen->startH.row, 472 screen->startH.col, 473 hi_row - amount, 474 0)); 475 screen->endH.row = hi_row - amount; 476 screen->endH.col = 0; 477 } else { 478 TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n", 479 screen->startH.row, 480 screen->startH.col, 481 screen->endH.row, 482 screen->endH.col, 483 amount, 484 lo_row, 485 hi_row)); 486 ScrnDisownSelection(xw); 487 } 488 } else if (screen->endH.row >= lo_row && screen->startH.row < lo_row) { 489 ScrnDisownSelection(xw); 490 } else if (screen->endH.row > hi_row && screen->startH.row > hi_row) { 491 ScrnDisownSelection(xw); 492 } 493 494 TRACE2((" after highlite %d.%d .. %d.%d\n", 495 screen->startH.row, 496 screen->startH.col, 497 screen->endH.row, 498 screen->endH.col)); 499} 500 501/* 502 * Move cells in LineData's on the current screen to simulate scrolling by the 503 * given amount of lines. 504 */ 505static void 506scrollInMargins(XtermWidget xw, int amount, int top) 507{ 508 TScreen *screen = TScreenOf(xw); 509 LineData *src; 510 LineData *dst; 511 int row; 512 int left = ScrnLeftMargin(xw); 513 int right = ScrnRightMargin(xw); 514 int length = right + 1 - left; 515 516 if_OPT_WIDE_CHARS(screen, { 517 if (amount != 0) { 518 for (row = top; row <= screen->bot_marg; ++row) { 519 LineData *ld; 520 if ((ld = getLineData(screen, row + amount)) != 0) { 521 if (left > 0) { 522 if (ld->charData[left] == HIDDEN_CHAR) { 523 Clear1Cell(ld, left - 1); 524 Clear1Cell(ld, left); 525 } 526 } 527 if (right + 1 < (int) ld->lineSize) { 528 if (ld->charData[right + 1] == HIDDEN_CHAR) { 529 Clear1Cell(ld, right); 530 Clear1Cell(ld, right + 1); 531 } 532 } 533 } 534 } 535 } 536 }); 537 538 if (amount > 0) { 539 for (row = top; row <= screen->bot_marg - amount; ++row) { 540 if ((src = getLineData(screen, row + amount)) != 0 541 && (dst = getLineData(screen, row)) != 0) { 542 CopyCells(screen, src, dst, left, length, False); 543 } 544 } 545 while (row <= screen->bot_marg) { 546 ClearCells(xw, 0, (unsigned) length, row, left); 547 ++row; 548 } 549 } else if (amount < 0) { 550 for (row = screen->bot_marg; row >= top - amount; --row) { 551 if ((src = getLineData(screen, row + amount)) != 0 552 && (dst = getLineData(screen, row)) != 0) { 553 CopyCells(screen, src, dst, left, length, True); 554 } 555 } 556 while (row >= top) { 557 ClearCells(xw, 0, (unsigned) length, row, left); 558 --row; 559 } 560 } 561} 562 563#if OPT_WIDE_CHARS 564/* 565 * If we're repainting a section of wide-characters that, e.g., ClearCells has 566 * repaired when finding double-cell characters, then we should account for 567 * that in the repaint. 568 */ 569static void 570ScrnUpdate2(XtermWidget xw, 571 int toprow, 572 int leftcol, 573 int nrows, 574 int ncols, 575 Bool force) 576{ 577 if_OPT_WIDE_CHARS(TScreenOf(xw), { 578 if (leftcol + ncols <= TScreenOf(xw)->max_col) 579 ncols++; 580 if (leftcol > 0) { 581 leftcol--; 582 ncols++; 583 } 584 }); 585 ScrnUpdate(xw, toprow, leftcol, nrows, ncols, force); 586} 587#else 588#define ScrnUpdate2(xw, toprow, leftcol, nrows, ncols, force) \ 589 ScrnUpdate(xw, toprow, leftcol, nrows, ncols, force) 590#endif 591 592/* 593 * scrolls the screen by amount lines, erases bottom, doesn't alter 594 * cursor position (i.e. cursor moves down amount relative to text). 595 * All done within the scrolling region, of course. 596 * requires: amount > 0 597 */ 598void 599xtermScroll(XtermWidget xw, int amount) 600{ 601 TScreen *screen = TScreenOf(xw); 602 int i; 603 int refreshtop = 0; 604 int refreshheight; 605 Boolean save_wrap = screen->do_wrap; 606 int left = ScrnLeftMargin(xw); 607 int right = ScrnRightMargin(xw); 608 Boolean scroll_all_lines = (Boolean) (screen->scrollWidget 609 && !screen->whichBuf 610 && screen->top_marg == 0); 611 Boolean scroll_full_line = ((left == 0) && (right == screen->max_col)); 612 613 TRACE(("xtermScroll count=%d (top %d, saved %d)\n", amount, 614 screen->topline, screen->savelines)); 615 616 screen->cursor_busy += 1; 617 screen->cursor_moved = True; 618 619 if (screen->cursor_state) 620 HideCursor(xw); 621 622 i = screen->bot_marg - screen->top_marg + 1; 623 if (amount > i) 624 amount = i; 625 626 if (!scroll_full_line) { 627 refreshheight = 0; 628 } else 629#if OPT_SCROLL_LOCK 630 if ((screen->allowScrollLock && screen->scroll_lock) 631 || (screen->autoScrollLock && screen->topline < 0)) { 632 refreshheight = 0; 633 screen->scroll_amt = 0; 634 screen->refresh_amt = 0; 635 if (--(screen->topline) < -screen->savelines) { 636 screen->topline = -screen->savelines; 637 screen->scroll_dirty = True; 638 } 639 if (++(screen->savedlines) > screen->savelines) { 640 screen->savedlines = screen->savelines; 641 } 642 } else 643#endif 644 { 645 if (ScrnHaveSelection(screen)) 646 adjustHiliteOnFwdScroll(xw, amount, scroll_all_lines); 647 648 if (screen->jumpscroll) { 649 if (screen->scroll_amt > 0) { 650 if (!screen->fastscroll) { 651 if (screen->refresh_amt + amount > i) 652 FlushScroll(xw); 653 } 654 screen->scroll_amt += amount; 655 screen->refresh_amt += amount; 656 } else { 657 if (!screen->fastscroll) { 658 if (screen->scroll_amt < 0) 659 FlushScroll(xw); 660 } 661 screen->scroll_amt = amount; 662 screen->refresh_amt = amount; 663 } 664 refreshheight = 0; 665 } else { 666 int scrolltop; 667 int scrollheight; 668 int shift; 669 int bot; 670 671 ScrollSelection(screen, -(amount), False); 672 if (amount == i) { 673 ClearScreen(xw); 674 goto done; 675 } 676 677 shift = INX2ROW(screen, 0); 678 bot = screen->max_row - shift; 679 scrollheight = i - amount; 680 refreshheight = amount; 681 682 if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) > 683 (i = screen->max_row - refreshheight + 1)) 684 refreshtop = i; 685 686 if (scroll_all_lines) { 687 scrolltop = 0; 688 if ((scrollheight += shift) > i) 689 scrollheight = i; 690 IncrementSavedLines(amount); 691 } else { 692 scrolltop = screen->top_marg + shift; 693 if ((i = screen->bot_marg - bot) > 0) { 694 scrollheight -= i; 695 if ((i = screen->top_marg + amount - 1 - bot) >= 0) { 696 refreshtop += i; 697 refreshheight -= i; 698 } 699 } 700 } 701 702 if (screen->multiscroll && amount == 1 && 703 screen->topline == 0 && screen->top_marg == 0 && 704 screen->bot_marg == screen->max_row) { 705 if (screen->incopy < 0 && screen->scrolls == 0) 706 CopyWait(xw); 707 screen->scrolls++; 708 } 709 710 vertical_copy_area(xw, 711 scrolltop + amount, 712 scrollheight, 713 amount, 714 left, 715 right); 716 717 if (refreshheight > 0) { 718 ClearCurBackground(xw, 719 refreshtop, 720 left, 721 (unsigned) refreshheight, 722 (unsigned) (right + 1 - left), 723 (unsigned) FontWidth(screen)); 724 if (refreshheight > shift) 725 refreshheight = shift; 726 } 727 } 728 } 729 730 if (amount > 0) { 731 if (left > 0 || right < screen->max_col) { 732 scrollInMargins(xw, amount, screen->top_marg); 733 ScrnUpdate2(xw, 734 screen->top_marg, 735 left, 736 screen->bot_marg + 1 - screen->top_marg, 737 right + 1 - left, 738 True); 739 } else if (scroll_all_lines) { 740 ScrnDeleteLine(xw, 741 screen->saveBuf_index, 742 screen->bot_marg + screen->savelines, 743 0, 744 (unsigned) amount); 745 } else { 746 ScrnDeleteLine(xw, 747 screen->visbuf, 748 screen->bot_marg, 749 screen->top_marg, 750 (unsigned) amount); 751 } 752 } 753 754 scroll_displayed_graphics(xw, amount); 755 756 if (refreshheight > 0) { 757 ScrnRefresh(xw, 758 refreshtop, 759 left, 760 refreshheight, 761 right + 1 - left, 762 False); 763 } 764 765 done: 766 screen->do_wrap = save_wrap; 767 screen->cursor_busy -= 1; 768 TRACE(("...xtermScroll count=%d (top %d, saved %d)\n", amount, 769 screen->topline, screen->savelines)); 770 return; 771} 772 773/* 774 * This is from ISO 6429, not found in any of DEC's terminals. 775 */ 776void 777xtermScrollLR(XtermWidget xw, int amount, Bool toLeft) 778{ 779 if (amount > 0) { 780 xtermColScroll(xw, amount, toLeft, ScrnLeftMargin(xw)); 781 } 782} 783 784/* 785 * Implement DECBI/DECFI (back/forward column index) 786 */ 787void 788xtermColIndex(XtermWidget xw, Bool toLeft) 789{ 790 TScreen *screen = TScreenOf(xw); 791 792 if (toLeft) { 793 if (ScrnIsColInMargins(screen, screen->cur_col)) { 794 if (screen->cur_col == ScrnLeftMargin(xw)) { 795 xtermColScroll(xw, 1, False, screen->cur_col); 796 } else { 797 CursorBack(xw, 1); 798 } 799 } else { 800 CursorBack(xw, 1); 801 } 802 } else { 803 if (ScrnIsColInMargins(screen, screen->cur_col)) { 804 if (screen->cur_col == ScrnRightMargin(xw)) { 805 xtermColScroll(xw, 1, True, ScrnLeftMargin(xw)); 806 } else { 807 CursorForward(xw, 1); 808 } 809 } else { 810 CursorForward(xw, 1); 811 } 812 } 813} 814 815/* 816 * Implement DECDC/DECIC (delete/insert column) 817 */ 818void 819xtermColScroll(XtermWidget xw, int amount, Bool toLeft, int at_col) 820{ 821 TScreen *screen = TScreenOf(xw); 822 823 if (amount > 0) { 824 int min_row; 825 int max_row; 826 827 if (ScrnHaveRowMargins(screen)) { 828 min_row = screen->top_marg; 829 max_row = screen->bot_marg; 830 } else { 831 min_row = 0; 832 max_row = screen->max_row; 833 } 834 835 if (screen->cur_row >= min_row 836 && screen->cur_row <= max_row 837 && screen->cur_col >= screen->lft_marg 838 && screen->cur_col <= screen->rgt_marg) { 839 int save_row = screen->cur_row; 840 int save_col = screen->cur_col; 841 int row; 842 843 screen->cur_col = at_col; 844 if (toLeft) { 845 for (row = min_row; row <= max_row; row++) { 846 screen->cur_row = row; 847 ScrnDeleteChar(xw, (unsigned) amount); 848 } 849 } else { 850 for (row = min_row; row <= max_row; row++) { 851 screen->cur_row = row; 852 ScrnInsertChar(xw, (unsigned) amount); 853 } 854 } 855 screen->cur_row = save_row; 856 screen->cur_col = save_col; 857 xtermRepaint(xw); 858 } 859 } 860} 861 862/* 863 * Reverse scrolls the screen by amount lines, erases top, doesn't alter 864 * cursor position (i.e. cursor moves up amount relative to text). 865 * All done within the scrolling region, of course. 866 * Requires: amount > 0 867 */ 868void 869RevScroll(XtermWidget xw, int amount) 870{ 871 TScreen *screen = TScreenOf(xw); 872 int i = screen->bot_marg - screen->top_marg + 1; 873 int left = ScrnLeftMargin(xw); 874 int right = ScrnRightMargin(xw); 875 Boolean scroll_full_line = ((left == 0) && (right == screen->max_col)); 876 877 TRACE(("RevScroll count=%d\n", amount)); 878 879 screen->cursor_busy += 1; 880 screen->cursor_moved = True; 881 882 if (screen->cursor_state) 883 HideCursor(xw); 884 885 if (amount > i) 886 amount = i; 887 888 if (ScrnHaveSelection(screen)) 889 adjustHiliteOnBakScroll(xw, amount); 890 891 if (!scroll_full_line) { 892 ; 893 } else if (screen->jumpscroll) { 894 if (screen->scroll_amt < 0) { 895 if (-screen->refresh_amt + amount > i) 896 FlushScroll(xw); 897 screen->scroll_amt -= amount; 898 screen->refresh_amt -= amount; 899 } else { 900 if (screen->scroll_amt > 0) 901 FlushScroll(xw); 902 screen->scroll_amt = -amount; 903 screen->refresh_amt = -amount; 904 } 905 } else { 906 int shift = INX2ROW(screen, 0); 907 int bot = screen->max_row - shift; 908 int refreshheight = amount; 909 int refreshtop = screen->top_marg + shift; 910 int scrollheight = (screen->bot_marg 911 - screen->top_marg - refreshheight + 1); 912 int scrolltop = refreshtop + refreshheight; 913 914 if ((i = screen->bot_marg - bot) > 0) 915 scrollheight -= i; 916 if ((i = screen->top_marg + refreshheight - 1 - bot) > 0) 917 refreshheight -= i; 918 919 if (screen->multiscroll && amount == 1 && 920 screen->topline == 0 && screen->top_marg == 0 && 921 screen->bot_marg == screen->max_row) { 922 if (screen->incopy < 0 && screen->scrolls == 0) 923 CopyWait(xw); 924 screen->scrolls++; 925 } 926 927 vertical_copy_area(xw, 928 scrolltop - amount, 929 scrollheight, 930 -amount, 931 left, 932 right); 933 934 if (refreshheight > 0) { 935 ClearCurBackground(xw, 936 refreshtop, 937 left, 938 (unsigned) refreshheight, 939 (unsigned) (right + 1 - left), 940 (unsigned) FontWidth(screen)); 941 } 942 } 943 if (amount > 0) { 944 if (left > 0 || right < screen->max_col) { 945 scrollInMargins(xw, -amount, screen->top_marg); 946 ScrnUpdate2(xw, 947 screen->top_marg, 948 left, 949 screen->bot_marg + 1 - screen->top_marg, 950 right + 1 - left, 951 True); 952 } else { 953 ScrnInsertLine(xw, 954 screen->visbuf, 955 screen->bot_marg, 956 screen->top_marg, 957 (unsigned) amount); 958 } 959 } 960 screen->cursor_busy -= 1; 961 return; 962} 963 964#if OPT_ZICONBEEP 965void 966initZIconBeep(void) 967{ 968 if (resource.zIconBeep > 100 || resource.zIconBeep < -100) { 969 resource.zIconBeep = 0; /* was 100, but I prefer to defaulting off. */ 970 xtermWarning("a number between -100 and 100 is required for zIconBeep. 0 used by default\n"); 971 } 972} 973 974static char * 975getIconName(void) 976{ 977 static char *icon_name; 978 static Arg args[] = 979 { 980 {XtNiconName, (XtArgVal) & icon_name} 981 }; 982 983 icon_name = NULL; 984 XtGetValues(toplevel, args, XtNumber(args)); 985 return icon_name; 986} 987 988static void 989setZIconBeep(XtermWidget xw) 990{ 991 TScreen *screen = TScreenOf(xw); 992 993 /* Flag icon name with "***" on window output when iconified. 994 */ 995 if (resource.zIconBeep && mapstate == IsUnmapped && !screen->zIconBeep_flagged) { 996 char *icon_name = getIconName(); 997 if (icon_name != NULL) { 998 screen->zIconBeep_flagged = True; 999 ChangeIconName(xw, icon_name); 1000 } 1001 xtermBell(xw, XkbBI_Info, 0); 1002 } 1003 mapstate = -1; 1004} 1005 1006/* 1007 * If warning should be given then give it 1008 */ 1009Boolean 1010showZIconBeep(XtermWidget xw, char *name) 1011{ 1012 Boolean code = False; 1013 1014 if (resource.zIconBeep && TScreenOf(xw)->zIconBeep_flagged) { 1015 char *format = resource.zIconFormat; 1016 char *newname = malloc(strlen(name) + strlen(format) + 2); 1017 if (!newname) { 1018 xtermWarning("malloc failed in showZIconBeep\n"); 1019 } else { 1020 char *marker = strstr(format, "%s"); 1021 char *result = newname; 1022 if (marker != 0) { 1023 size_t skip = (size_t) (marker - format); 1024 if (skip) { 1025 strncpy(result, format, skip); 1026 result += skip; 1027 } 1028 strcpy(result, name); 1029 strcat(result, marker + 2); 1030 } else { 1031 strcpy(result, format); 1032 strcat(result, name); 1033 } 1034 ChangeGroup(xw, XtNiconName, newname); 1035 free(newname); 1036 } 1037 code = True; 1038 } 1039 return code; 1040} 1041 1042/* 1043 * Restore the icon name, resetting the state for zIconBeep. 1044 */ 1045void 1046resetZIconBeep(XtermWidget xw) 1047{ 1048 TScreen *screen = TScreenOf(xw); 1049 1050 if (screen->zIconBeep_flagged) { 1051 char *icon_name = getIconName(); 1052 screen->zIconBeep_flagged = False; 1053 if (icon_name != NULL) { 1054 char *buf = malloc(strlen(icon_name) + 1); 1055 if (buf == NULL) { 1056 screen->zIconBeep_flagged = True; 1057 } else { 1058 char *format = resource.zIconFormat; 1059 char *marker = strstr(format, "%s"); 1060 Boolean found = False; 1061 1062 if (marker != 0) { 1063 if (marker == format 1064 || !strncmp(icon_name, format, (size_t) (marker - format))) { 1065 found = True; 1066 strcpy(buf, icon_name + (marker - format)); 1067 marker += 2; 1068 if (*marker != '\0') { 1069 size_t len_m = strlen(marker); 1070 size_t len_b = strlen(buf); 1071 if (len_m < len_b 1072 && !strcmp(buf + len_b - len_m, marker)) { 1073 buf[len_b - len_m] = '\0'; 1074 } 1075 } 1076 } 1077 } else if (!strncmp(icon_name, format, strlen(format))) { 1078 strcpy(buf, icon_name + strlen(format)); 1079 found = True; 1080 } 1081 if (found) 1082 ChangeIconName(xw, buf); 1083 free(buf); 1084 } 1085 } 1086 } 1087} 1088#else 1089#define setZIconBeep(xw) /* nothing */ 1090#endif /* OPT_ZICONBEEP */ 1091 1092/* 1093 * write a string str of length len onto the screen at 1094 * the current cursor position. update cursor position. 1095 */ 1096void 1097WriteText(XtermWidget xw, IChar *str, Cardinal len) 1098{ 1099 TScreen *screen = TScreenOf(xw); 1100 XTermDraw params; 1101 CLineData *ld = 0; 1102 unsigned attr_flags = xw->flags; 1103 CellColor fg_bg = xtermColorPair(xw); 1104 unsigned cells = visual_width(str, len); 1105 GC currentGC; 1106 1107 TRACE(("WriteText %d (%2d,%2d) %3d:%s\n", 1108 screen->topline, 1109 screen->cur_row, 1110 screen->cur_col, 1111 len, visibleIChars(str, len))); 1112 1113 if (cells + (unsigned) screen->cur_col > (unsigned) MaxCols(screen)) { 1114 cells = (unsigned) (MaxCols(screen) - screen->cur_col); 1115 } 1116 1117 if (screen->cur_row <= screen->max_row 1118 && ScrnHaveSelection(screen) 1119 && ScrnIsRowInSelection(screen, INX2ROW(screen, screen->cur_row))) { 1120 ScrnDisownSelection(xw); 1121 } 1122#if OPT_ISO_COLORS 1123 /* if colorBDMode is set, and enabled */ 1124 if (screen->colorBDMode && 1125 screen->boldColors && 1126 !hasDirectFG(attr_flags) && 1127 /* and bold foreground color on bold background color */ 1128 GetCellColorFG(fg_bg) > COLOR_7 && 1129 GetCellColorFG(fg_bg) < MIN_ANSI_COLORS && 1130 /* and both colors are the same */ 1131 GetCellColorFG(fg_bg) == GetCellColorBG(fg_bg)) 1132 /* clear BOLD flag, else it will be colorBD on bold background color */ 1133 UIntClr(attr_flags, BOLD); 1134#endif 1135 1136 /* if we are in insert-mode, reserve space for the new cells */ 1137 if (attr_flags & INSERT) { 1138 InsertChar(xw, cells); 1139 } 1140 1141 if (AddToVisible(xw) 1142 && ((ld = getLineData(screen, screen->cur_row))) != 0) { 1143 unsigned test; 1144 1145 if (screen->cursor_state) 1146 HideCursor(xw); 1147 1148 /* 1149 * If we overwrite part of a multi-column character, fill the rest 1150 * of it with blanks. 1151 */ 1152 if_OPT_WIDE_CHARS(screen, { 1153 int kl; 1154 int kr; 1155 if (DamagedCurCells(screen, cells, &kl, &kr)) 1156 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1)); 1157 }); 1158 1159 if (attr_flags & INVISIBLE) { 1160 Cardinal n; 1161 for (n = 0; n < cells; ++n) 1162 str[n] = ' '; 1163 } 1164 1165 TRACE(("WriteText calling drawXtermText (%d) (%d,%d)\n", 1166 LineCharSet(screen, ld), 1167 screen->cur_row, 1168 screen->cur_col)); 1169 1170 test = attr_flags; 1171#if OPT_ISO_COLORS 1172 { 1173 int fg; 1174 if (screen->colorAttrMode) { 1175 fg = MapToColorMode(xw->cur_foreground, screen, attr_flags); 1176 } else { 1177 fg = xw->cur_foreground; 1178 } 1179 checkVeryBoldColors(test, fg); 1180 } 1181#endif 1182 1183 /* make sure that the correct GC is current */ 1184 currentGC = updatedXtermGC(xw, attr_flags, fg_bg, False); 1185 1186 /* *INDENT-EQLS* */ 1187 params.xw = xw; 1188 params.attr_flags = (test & DRAWX_MASK); 1189 params.draw_flags = 0; 1190 params.this_chrset = LineCharSet(screen, ld); 1191 params.real_chrset = CSET_SWL; 1192 params.on_wide = 0; 1193 1194 drawXtermText(¶ms, 1195 currentGC, 1196 LineCursorX(screen, ld, screen->cur_col), 1197 CursorY(screen, screen->cur_row), 1198 str, len); 1199 1200 resetXtermGC(xw, attr_flags, False); 1201 } 1202 1203 ScrnWriteText(xw, str, attr_flags, fg_bg, len); 1204 CursorForward(xw, (int) cells); 1205 1206 if (screen->cur_row <= screen->max_row) { 1207 setZIconBeep(xw); 1208 } 1209 return; 1210} 1211 1212/* 1213 * If cursor not in scrolling region, returns. Else, 1214 * inserts n blank lines at the cursor's position. Lines above the 1215 * bottom margin are lost. 1216 */ 1217void 1218InsertLine(XtermWidget xw, int n) 1219{ 1220 TScreen *screen = TScreenOf(xw); 1221 int i; 1222 int left = ScrnLeftMargin(xw); 1223 int right = ScrnRightMargin(xw); 1224 Boolean scroll_full_line = ((left == 0) && (right == screen->max_col)); 1225 1226 if (!ScrnIsRowInMargins(screen, screen->cur_row) 1227 || screen->cur_col < left 1228 || screen->cur_col > right) 1229 return; 1230 1231 TRACE(("InsertLine count=%d\n", n)); 1232 1233 set_cur_col(screen, ScrnLeftMargin(xw)); 1234 if (screen->cursor_state) 1235 HideCursor(xw); 1236 1237 if (ScrnHaveSelection(screen) 1238 && ScrnAreRowsInSelection(screen, 1239 INX2ROW(screen, screen->top_marg), 1240 INX2ROW(screen, screen->cur_row - 1)) 1241 && ScrnAreRowsInSelection(screen, 1242 INX2ROW(screen, screen->cur_row), 1243 INX2ROW(screen, screen->bot_marg))) { 1244 ScrnDisownSelection(xw); 1245 } 1246 1247 ResetWrap(screen); 1248 if (n > (i = screen->bot_marg - screen->cur_row + 1)) 1249 n = i; 1250 if (screen->jumpscroll && scroll_full_line) { 1251 if (screen->scroll_amt <= 0 && 1252 screen->cur_row <= -screen->refresh_amt) { 1253 if (-screen->refresh_amt + n > MaxRows(screen)) 1254 FlushScroll(xw); 1255 screen->scroll_amt -= n; 1256 screen->refresh_amt -= n; 1257 } else { 1258 if (screen->scroll_amt) 1259 FlushScroll(xw); 1260 } 1261 } 1262 if (!screen->scroll_amt && scroll_full_line) { 1263 int shift = INX2ROW(screen, 0); 1264 int bot = screen->max_row - shift; 1265 int refreshheight = n; 1266 int refreshtop = screen->cur_row + shift; 1267 int scrolltop = refreshtop + refreshheight; 1268 int scrollheight = (screen->bot_marg 1269 - screen->cur_row - refreshheight + 1); 1270 1271 if ((i = screen->bot_marg - bot) > 0) 1272 scrollheight -= i; 1273 if ((i = screen->cur_row + refreshheight - 1 - bot) > 0) 1274 refreshheight -= i; 1275 vertical_copy_area(xw, scrolltop - n, scrollheight, -n, left, right); 1276 if (refreshheight > 0) { 1277 ClearCurBackground(xw, 1278 refreshtop, 1279 left, 1280 (unsigned) refreshheight, 1281 (unsigned) (right + 1 - left), 1282 (unsigned) FontWidth(screen)); 1283 } 1284 } 1285 if (n > 0) { 1286 if (scroll_full_line) { 1287 ScrnInsertLine(xw, 1288 screen->visbuf, 1289 screen->bot_marg, 1290 screen->cur_row, 1291 (unsigned) n); 1292 } else { 1293 scrollInMargins(xw, -n, screen->cur_row); 1294 ScrnUpdate2(xw, 1295 screen->cur_row, 1296 left, 1297 screen->bot_marg + 1 - screen->cur_row, 1298 right + 1 - left, 1299 True); 1300 } 1301 } 1302} 1303 1304/* 1305 * If cursor not in scrolling region, returns. Else, deletes n lines 1306 * at the cursor's position, lines added at bottom margin are blank. 1307 */ 1308void 1309DeleteLine(XtermWidget xw, int n, Bool canSave) 1310{ 1311 TScreen *screen = TScreenOf(xw); 1312 int i; 1313 int left = ScrnLeftMargin(xw); 1314 int right = ScrnRightMargin(xw); 1315 Boolean scroll_all_lines = (Boolean) (screen->scrollWidget 1316 && !screen->whichBuf 1317 && screen->cur_row == 0); 1318 Boolean scroll_full_line = ((left == 0) && (right == screen->max_col)); 1319 1320 if (!ScrnIsRowInMargins(screen, screen->cur_row) || 1321 !ScrnIsColInMargins(screen, screen->cur_col)) 1322 return; 1323 1324 TRACE(("DeleteLine count=%d\n", n)); 1325 1326 set_cur_col(screen, ScrnLeftMargin(xw)); 1327 if (screen->cursor_state) 1328 HideCursor(xw); 1329 1330 if (n > (i = screen->bot_marg - screen->cur_row + 1)) { 1331 n = i; 1332 } 1333 if (ScrnHaveSelection(screen) 1334 && ScrnAreRowsInSelection(screen, 1335 INX2ROW(screen, screen->cur_row), 1336 INX2ROW(screen, screen->cur_row + n - 1))) { 1337 ScrnDisownSelection(xw); 1338 } 1339 1340 ResetWrap(screen); 1341 if (screen->jumpscroll && scroll_full_line) { 1342 if (screen->scroll_amt >= 0 && screen->cur_row == screen->top_marg) { 1343 if (screen->refresh_amt + n > MaxRows(screen)) 1344 FlushScroll(xw); 1345 if (canSave) { 1346 screen->scroll_amt += n; 1347 screen->refresh_amt += n; 1348 } 1349 } else { 1350 if (screen->scroll_amt) 1351 FlushScroll(xw); 1352 } 1353 } 1354 1355 /* adjust screen->buf */ 1356 if (n > 0) { 1357 if (left > 0 || right < screen->max_col) { 1358 scrollInMargins(xw, n, screen->cur_row); 1359 } else if (canSave && scroll_all_lines) { 1360 ScrnDeleteLine(xw, 1361 screen->saveBuf_index, 1362 screen->bot_marg + screen->savelines, 1363 0, 1364 (unsigned) n); 1365 } else { 1366 ScrnDeleteLine(xw, 1367 screen->visbuf, 1368 screen->bot_marg, 1369 screen->cur_row, 1370 (unsigned) n); 1371 } 1372 } 1373 1374 /* repaint the screen, as needed */ 1375 if (!scroll_full_line) { 1376 ScrnUpdate2(xw, 1377 screen->cur_row, 1378 left, 1379 screen->bot_marg + 1 - screen->cur_row, 1380 right + 1 - left, 1381 True); 1382 } else if (!screen->scroll_amt) { 1383 int shift = INX2ROW(screen, 0); 1384 int bot = screen->max_row - shift; 1385 int refreshtop; 1386 int refreshheight = n; 1387 int scrolltop; 1388 int scrollheight = i - n; 1389 1390 if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) > 1391 (i = screen->max_row - refreshheight + 1)) 1392 refreshtop = i; 1393 if (canSave && scroll_all_lines) { 1394 scrolltop = 0; 1395 if ((scrollheight += shift) > i) 1396 scrollheight = i; 1397 IncrementSavedLines(n); 1398 } else { 1399 scrolltop = screen->cur_row + shift; 1400 if ((i = screen->bot_marg - bot) > 0) { 1401 scrollheight -= i; 1402 if ((i = screen->cur_row + n - 1 - bot) >= 0) { 1403 refreshheight -= i; 1404 } 1405 } 1406 } 1407 vertical_copy_area(xw, scrolltop + n, scrollheight, n, left, right); 1408 if (shift > 0 && refreshheight > 0) { 1409 int rows = refreshheight; 1410 if (rows > shift) 1411 rows = shift; 1412 ScrnUpdate(xw, refreshtop, 0, rows, MaxCols(screen), True); 1413 refreshtop += shift; 1414 refreshheight -= shift; 1415 } 1416 if (refreshheight > 0) { 1417 ClearCurBackground(xw, 1418 refreshtop, 1419 left, 1420 (unsigned) refreshheight, 1421 (unsigned) (right + 1 - left), 1422 (unsigned) FontWidth(screen)); 1423 } 1424 } 1425} 1426 1427/* 1428 * Insert n blanks at the cursor's position, no wraparound 1429 */ 1430void 1431InsertChar(XtermWidget xw, unsigned n) 1432{ 1433 TScreen *screen = TScreenOf(xw); 1434 CLineData *ld; 1435 unsigned limit; 1436 int row = INX2ROW(screen, screen->cur_row); 1437 int left = ScrnLeftMargin(xw); 1438 int right = ScrnRightMargin(xw); 1439 1440 if (screen->cursor_state) 1441 HideCursor(xw); 1442 1443 TRACE(("InsertChar count=%d\n", n)); 1444 1445 if (ScrnHaveSelection(screen) 1446 && ScrnIsRowInSelection(screen, row)) { 1447 ScrnDisownSelection(xw); 1448 } 1449 ResetWrap(screen); 1450 1451 limit = (unsigned) (right + 1 - screen->cur_col); 1452 1453 if (n > limit) 1454 n = limit; 1455 1456 if (screen->cur_col < left || screen->cur_col > right) { 1457 n = 0; 1458 } else if (AddToVisible(xw) 1459 && (ld = getLineData(screen, screen->cur_row)) != 0) { 1460 int col = right + 1 - (int) n; 1461 1462 /* 1463 * If we shift part of a multi-column character, fill the rest 1464 * of it with blanks. Do similar repair for the text which will 1465 * be shifted into the right-margin. 1466 */ 1467 if_OPT_WIDE_CHARS(screen, { 1468 int kl; 1469 int kr = screen->cur_col; 1470 if (DamagedCurCells(screen, n, &kl, (int *) 0) && kr > kl) { 1471 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1)); 1472 } 1473 kr = screen->max_col - (int) n + 1; 1474 if (DamagedCells(screen, n, &kl, (int *) 0, 1475 screen->cur_row, 1476 kr) && kr > kl) { 1477 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1)); 1478 } 1479 }); 1480 1481#if OPT_DEC_CHRSET 1482 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1483 col = MaxCols(screen) / 2 - (int) n; 1484 } 1485#endif 1486 /* 1487 * prevent InsertChar from shifting the end of a line over 1488 * if it is being appended to 1489 */ 1490 if (non_blank_line(screen, screen->cur_row, 1491 screen->cur_col, MaxCols(screen))) { 1492 horizontal_copy_area(xw, screen->cur_col, 1493 col - screen->cur_col, 1494 (int) n); 1495 } 1496 1497 ClearCurBackground(xw, 1498 INX2ROW(screen, screen->cur_row), 1499 screen->cur_col, 1500 1U, 1501 n, 1502 (unsigned) LineFontWidth(screen, ld)); 1503 } 1504 if (n != 0) { 1505 /* adjust screen->buf */ 1506 ScrnInsertChar(xw, n); 1507 } 1508} 1509 1510/* 1511 * Deletes n chars at the cursor's position, no wraparound. 1512 */ 1513void 1514DeleteChar(XtermWidget xw, unsigned n) 1515{ 1516 TScreen *screen = TScreenOf(xw); 1517 CLineData *ld; 1518 unsigned limit; 1519 int row = INX2ROW(screen, screen->cur_row); 1520 int right = ScrnRightMargin(xw); 1521 1522 if (screen->cursor_state) 1523 HideCursor(xw); 1524 1525 if (!ScrnIsColInMargins(screen, screen->cur_col)) 1526 return; 1527 1528 TRACE(("DeleteChar count=%d\n", n)); 1529 1530 if (ScrnHaveSelection(screen) 1531 && ScrnIsRowInSelection(screen, row)) { 1532 ScrnDisownSelection(xw); 1533 } 1534 ResetWrap(screen); 1535 1536 limit = (unsigned) (right + 1 - screen->cur_col); 1537 1538 if (n > limit) 1539 n = limit; 1540 1541 if (AddToVisible(xw) 1542 && (ld = getLineData(screen, screen->cur_row)) != 0) { 1543 int col = right + 1 - (int) n; 1544 1545 /* 1546 * If we delete part of a multi-column character, fill the rest 1547 * of it with blanks. 1548 */ 1549 if_OPT_WIDE_CHARS(screen, { 1550 int kl; 1551 int kr; 1552 if (DamagedCurCells(screen, n, &kl, &kr)) 1553 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1)); 1554 }); 1555 1556#if OPT_DEC_CHRSET 1557 if (CSET_DOUBLE(GetLineDblCS(ld))) { 1558 col = MaxCols(screen) / 2 - (int) n; 1559 } 1560#endif 1561 horizontal_copy_area(xw, 1562 (screen->cur_col + (int) n), 1563 col - screen->cur_col, 1564 -((int) n)); 1565 1566 ClearCurBackground(xw, 1567 INX2ROW(screen, screen->cur_row), 1568 col, 1569 1U, 1570 n, 1571 (unsigned) LineFontWidth(screen, ld)); 1572 } 1573 if (n != 0) { 1574 /* adjust screen->buf */ 1575 ScrnDeleteChar(xw, n); 1576 } 1577} 1578 1579/* 1580 * Clear from cursor position to beginning of display, inclusive. 1581 */ 1582static void 1583ClearAbove(XtermWidget xw) 1584{ 1585 TScreen *screen = TScreenOf(xw); 1586 1587 if (screen->protected_mode != OFF_PROTECT) { 1588 int row; 1589 unsigned len = (unsigned) MaxCols(screen); 1590 1591 assert(screen->max_col >= 0); 1592 for (row = 0; row < screen->cur_row; row++) 1593 ClearInLine(xw, row, 0, len); 1594 ClearInLine(xw, screen->cur_row, 0, (unsigned) screen->cur_col); 1595 } else { 1596 int top; 1597 1598 if (screen->cursor_state) 1599 HideCursor(xw); 1600 if ((top = INX2ROW(screen, 0)) <= screen->max_row) { 1601 int height; 1602 1603 if (screen->scroll_amt) 1604 FlushScroll(xw); 1605 if ((height = screen->cur_row + top) > screen->max_row) 1606 height = screen->max_row + 1; 1607 if ((height -= top) > 0) { 1608 chararea_clear_displayed_graphics(screen, 1609 0, 1610 top, 1611 MaxCols(screen), 1612 height); 1613 1614 ClearCurBackground(xw, 1615 top, 1616 0, 1617 (unsigned) height, 1618 (unsigned) MaxCols(screen), 1619 (unsigned) FontWidth(screen)); 1620 } 1621 } 1622 ClearBufRows(xw, 0, screen->cur_row - 1); 1623 } 1624 1625 ClearLeft(xw); 1626} 1627 1628/* 1629 * Clear from cursor position to end of display, inclusive. 1630 */ 1631static void 1632ClearBelow(XtermWidget xw) 1633{ 1634 TScreen *screen = TScreenOf(xw); 1635 1636 ClearRight(xw, -1); 1637 1638 if (screen->protected_mode != OFF_PROTECT) { 1639 int row; 1640 unsigned len = (unsigned) MaxCols(screen); 1641 1642 assert(screen->max_col >= 0); 1643 for (row = screen->cur_row + 1; row <= screen->max_row; row++) 1644 ClearInLine(xw, row, 0, len); 1645 } else { 1646 int top; 1647 1648 if ((top = INX2ROW(screen, screen->cur_row)) <= screen->max_row) { 1649 if (screen->scroll_amt) 1650 FlushScroll(xw); 1651 if (++top <= screen->max_row) { 1652 chararea_clear_displayed_graphics(screen, 1653 0, 1654 top, 1655 MaxCols(screen), 1656 (screen->max_row - top + 1)); 1657 ClearCurBackground(xw, 1658 top, 1659 0, 1660 (unsigned) (screen->max_row - top + 1), 1661 (unsigned) MaxCols(screen), 1662 (unsigned) FontWidth(screen)); 1663 } 1664 } 1665 ClearBufRows(xw, screen->cur_row + 1, screen->max_row); 1666 } 1667} 1668 1669/* 1670 * Clear the given row, for the given range of columns, returning 1 if no 1671 * protected characters were found, 0 otherwise. 1672 */ 1673static int 1674ClearInLine2(XtermWidget xw, int flags, int row, int col, unsigned len) 1675{ 1676 TScreen *screen = TScreenOf(xw); 1677 CLineData *ld; 1678 int rc = 1; 1679 1680 TRACE(("ClearInLine(row=%d, col=%d, len=%d) vs %d..%d\n", 1681 row, col, len, 1682 screen->startH.row, 1683 screen->startH.col)); 1684 1685 if (ScrnHaveSelection(screen) 1686 && ScrnIsRowInSelection(screen, row)) { 1687 ScrnDisownSelection(xw); 1688 } 1689 1690 if (col + (int) len >= MaxCols(screen)) { 1691 len = (unsigned) (MaxCols(screen) - col); 1692 } 1693 1694 /* If we've marked protected text on the screen, we'll have to 1695 * check each time we do an erase. 1696 */ 1697 if (screen->protected_mode != OFF_PROTECT) { 1698 unsigned n; 1699 IAttr *attrs = getLineData(screen, row)->attribs + col; 1700 int saved_mode = screen->protected_mode; 1701 Bool done; 1702 1703 /* disable this branch during recursion */ 1704 screen->protected_mode = OFF_PROTECT; 1705 1706 do { 1707 done = True; 1708 for (n = 0; n < len; n++) { 1709 if (attrs[n] & PROTECTED) { 1710 rc = 0; /* found a protected segment */ 1711 if (n != 0) { 1712 ClearInLine(xw, row, col, n); 1713 } 1714 while ((n < len) 1715 && (attrs[n] & PROTECTED)) { 1716 n++; 1717 } 1718 done = False; 1719 break; 1720 } 1721 } 1722 /* setup for another segment, past the protected text */ 1723 if (!done) { 1724 attrs += n; 1725 col += (int) n; 1726 len -= n; 1727 } 1728 } while (!done); 1729 1730 screen->protected_mode = saved_mode; 1731 if ((int) len <= 0) { 1732 return 0; 1733 } 1734 } 1735 /* fall through to the final non-protected segment */ 1736 1737 if (screen->cursor_state) 1738 HideCursor(xw); 1739 ResetWrap(screen); 1740 1741 if (AddToVisible(xw) 1742 && (ld = getLineData(screen, row)) != 0) { 1743 1744 ClearCurBackground(xw, 1745 INX2ROW(screen, row), 1746 col, 1747 1U, 1748 len, 1749 (unsigned) LineFontWidth(screen, ld)); 1750 } 1751 1752 if (len != 0) { 1753 ClearCells(xw, flags, len, row, col); 1754 } 1755 1756 return rc; 1757} 1758 1759int 1760ClearInLine(XtermWidget xw, int row, int col, unsigned len) 1761{ 1762 TScreen *screen = TScreenOf(xw); 1763 int flags = 0; 1764 1765 /* 1766 * If we're clearing to the end of the line, we won't count this as 1767 * "drawn" characters. We'll only do cut/paste on "drawn" characters, 1768 * so this has the effect of suppressing trailing blanks from a 1769 * selection. 1770 */ 1771 if (col + (int) len < MaxCols(screen)) { 1772 flags |= CHARDRAWN; 1773 } 1774 return ClearInLine2(xw, flags, row, col, len); 1775} 1776 1777/* 1778 * Clear the next n characters on the cursor's line, including the cursor's 1779 * position. 1780 */ 1781void 1782ClearRight(XtermWidget xw, int n) 1783{ 1784 TScreen *screen = TScreenOf(xw); 1785 LineData *ld; 1786 unsigned len = (unsigned) (MaxCols(screen) - screen->cur_col); 1787 1788 assert(screen->max_col >= 0); 1789 assert(screen->max_col >= screen->cur_col); 1790 1791 if (n < 0) /* the remainder of the line */ 1792 n = MaxCols(screen); 1793 if (n == 0) /* default for 'ECH' */ 1794 n = 1; 1795 1796 if (len > (unsigned) n) 1797 len = (unsigned) n; 1798 1799 ld = getLineData(screen, screen->cur_row); 1800 if (AddToVisible(xw)) { 1801 if_OPT_WIDE_CHARS(screen, { 1802 int col = screen->cur_col; 1803 int row = screen->cur_row; 1804 int kl; 1805 int kr; 1806 if (DamagedCurCells(screen, len, &kl, &kr) && kr >= kl) { 1807 int xx = col; 1808 if (kl < xx) { 1809 ClearInLine2(xw, 0, row, kl, (unsigned) (xx - kl)); 1810 } 1811 xx = col + (int) len - 1; 1812 if (kr > xx) { 1813 ClearInLine2(xw, 0, row, xx + 1, (unsigned) (kr - xx)); 1814 } 1815 } 1816 }); 1817 (void) ClearInLine(xw, screen->cur_row, screen->cur_col, len); 1818 } else { 1819 ScrnClearCells(xw, screen->cur_row, screen->cur_col, len); 1820 } 1821 1822 /* with the right part cleared, we can't be wrapping */ 1823 LineClrWrapped(ld); 1824 ShowWrapMarks(xw, screen->cur_row, ld); 1825 ResetWrap(screen); 1826} 1827 1828/* 1829 * Clear first part of cursor's line, inclusive. 1830 */ 1831static void 1832ClearLeft(XtermWidget xw) 1833{ 1834 TScreen *screen = TScreenOf(xw); 1835 unsigned len = (unsigned) screen->cur_col + 1; 1836 1837 assert(screen->cur_col >= 0); 1838 if (AddToVisible(xw)) { 1839 if_OPT_WIDE_CHARS(screen, { 1840 int row = screen->cur_row; 1841 int kl; 1842 int kr; 1843 if (DamagedCurCells(screen, 1, &kl, &kr) && kr >= kl) { 1844 ClearInLine2(xw, 0, row, kl, (unsigned) (kr - kl + 1)); 1845 } 1846 }); 1847 (void) ClearInLine(xw, screen->cur_row, 0, len); 1848 } else { 1849 ScrnClearCells(xw, screen->cur_row, 0, len); 1850 } 1851} 1852 1853/* 1854 * Erase the cursor's line. 1855 */ 1856void 1857ClearLine(XtermWidget xw) 1858{ 1859 TScreen *screen = TScreenOf(xw); 1860 unsigned len = (unsigned) MaxCols(screen); 1861 1862 assert(screen->max_col >= 0); 1863 (void) ClearInLine(xw, screen->cur_row, 0, len); 1864} 1865 1866void 1867ClearScreen(XtermWidget xw) 1868{ 1869 TScreen *screen = TScreenOf(xw); 1870 int top; 1871 1872 TRACE(("ClearScreen\n")); 1873 1874 if (screen->cursor_state) 1875 HideCursor(xw); 1876 1877 ScrnDisownSelection(xw); 1878 ResetWrap(screen); 1879 if ((top = INX2ROW(screen, 0)) <= screen->max_row) { 1880 if (screen->scroll_amt) 1881 FlushScroll(xw); 1882 chararea_clear_displayed_graphics(screen, 1883 0, 1884 top, 1885 MaxCols(screen), 1886 (screen->max_row - top + 1)); 1887 ClearCurBackground(xw, 1888 top, 1889 0, 1890 (unsigned) (screen->max_row - top + 1), 1891 (unsigned) MaxCols(screen), 1892 (unsigned) FontWidth(screen)); 1893 } 1894 ClearBufRows(xw, 0, screen->max_row); 1895} 1896 1897/* 1898 * If we've written protected text DEC-style, and are issuing a non-DEC 1899 * erase, temporarily reset the protected_mode flag so that the erase will 1900 * ignore the protected flags. 1901 */ 1902void 1903do_erase_char(XtermWidget xw, int param, int mode) 1904{ 1905 TScreen *screen = TScreenOf(xw); 1906 int saved_mode = screen->protected_mode; 1907 1908 if (saved_mode == DEC_PROTECT 1909 && saved_mode != mode) { 1910 screen->protected_mode = OFF_PROTECT; 1911 } 1912 1913 ClearRight(xw, param); 1914 screen->protected_mode = saved_mode; 1915} 1916 1917void 1918do_erase_line(XtermWidget xw, int param, int mode) 1919{ 1920 TScreen *screen = TScreenOf(xw); 1921 int saved_mode = screen->protected_mode; 1922 1923 if (saved_mode == DEC_PROTECT 1924 && saved_mode != mode) { 1925 screen->protected_mode = OFF_PROTECT; 1926 } 1927 1928 switch (param) { 1929 case -1: /* DEFAULT */ 1930 case 0: 1931 ClearRight(xw, -1); 1932 break; 1933 case 1: 1934 ClearLeft(xw); 1935 break; 1936 case 2: 1937 ClearLine(xw); 1938 break; 1939 } 1940 screen->protected_mode = saved_mode; 1941} 1942 1943/* 1944 * Just like 'do_erase_line()', except that this intercepts ED controls. If we 1945 * clear the whole screen, we'll get the return-value from ClearInLine, and 1946 * find if there were any protected characters left. If not, reset the 1947 * protected mode flag in the screen data (it's slower). 1948 */ 1949void 1950do_erase_display(XtermWidget xw, int param, int mode) 1951{ 1952 TScreen *screen = TScreenOf(xw); 1953 int saved_mode = screen->protected_mode; 1954 1955 if (saved_mode == DEC_PROTECT 1956 && saved_mode != mode) 1957 screen->protected_mode = OFF_PROTECT; 1958 1959 switch (param) { 1960 case -1: /* DEFAULT */ 1961 case 0: 1962 if (screen->cur_row == 0 1963 && screen->cur_col == 0) { 1964 screen->protected_mode = saved_mode; 1965 do_erase_display(xw, 2, mode); 1966 saved_mode = screen->protected_mode; 1967 } else 1968 ClearBelow(xw); 1969 break; 1970 1971 case 1: 1972 if (screen->cur_row == screen->max_row 1973 && screen->cur_col == screen->max_col) { 1974 screen->protected_mode = saved_mode; 1975 do_erase_display(xw, 2, mode); 1976 saved_mode = screen->protected_mode; 1977 } else 1978 ClearAbove(xw); 1979 break; 1980 1981 case 2: 1982 /* 1983 * We use 'ClearScreen()' throughout the remainder of the 1984 * program for places where we don't care if the characters are 1985 * protected or not. So we modify the logic around this call 1986 * on 'ClearScreen()' to handle protected characters. 1987 */ 1988 if (screen->protected_mode != OFF_PROTECT) { 1989 int row; 1990 int rc = 1; 1991 unsigned len = (unsigned) MaxCols(screen); 1992 1993 assert(screen->max_col >= 0); 1994 for (row = 0; row <= screen->max_row; row++) 1995 rc &= ClearInLine(xw, row, 0, len); 1996 if (rc != 0) 1997 saved_mode = OFF_PROTECT; 1998 } else { 1999 ClearScreen(xw); 2000 } 2001 break; 2002 2003 case 3: 2004 /* xterm addition - erase saved lines. */ 2005 if (screen->eraseSavedLines) { 2006 screen->savedlines = 0; 2007 ScrollBarDrawThumb(xw, 1); 2008 } 2009 break; 2010 } 2011 screen->protected_mode = saved_mode; 2012} 2013 2014static Boolean 2015row_has_data(TScreen *screen, int row) 2016{ 2017 Boolean result = False; 2018 CLineData *ld; 2019 2020 if ((ld = getLineData(screen, row)) != 0) { 2021 int col; 2022 2023 for (col = 0; col < screen->max_col; ++col) { 2024 if (ld->attribs[col] & CHARDRAWN && ld->charData[col] != ' ') { 2025 result = True; 2026 break; 2027 } 2028 } 2029 } 2030 return result; 2031} 2032 2033static Boolean 2034screen_has_data(XtermWidget xw) 2035{ 2036 TScreen *screen = TScreenOf(xw); 2037 Boolean result = False; 2038 int row; 2039 2040 for (row = 0; row < screen->max_row; ++row) { 2041 if (row_has_data(screen, row)) { 2042 result = True; 2043 break; 2044 } 2045 } 2046 return result; 2047} 2048 2049static void 2050do_extra_scroll(XtermWidget xw, Bool trimmed) 2051{ 2052 TScreen *screen = TScreenOf(xw); 2053 2054 if (screen_has_data(xw)) { 2055 TRACE(("do_extra_scroll buffer=%d, trimmed=%s\n", screen->whichBuf, 2056 BtoS(trimmed))); 2057 if (trimmed) { 2058 int row; 2059 Boolean hadData = (Boolean) ((screen->saved_fifo > 0) 2060 ? row_has_data(screen, -1) 2061 : False); 2062 2063 for (row = 0; row < screen->max_row; ++row) { 2064 Boolean hasData = row_has_data(screen, row); 2065 if (hasData || hadData) { 2066 LineData *dst = addScrollback(screen); 2067 LineData *src = getLineData(screen, row); 2068 copyLineData(dst, src); 2069 IncrementSavedLines(1); 2070 } 2071 hadData = hasData; 2072 } 2073 } else { 2074 xtermScroll(xw, screen->max_row); 2075 FlushScroll(xw); 2076 } 2077 xtermRepaint(xw); 2078 } 2079} 2080 2081/* 2082 * Like tiXtraScroll, perform a scroll up of the page contents. 2083 * 2084 * In this case, it happens for the special case when erasing the whole 2085 * display, e.g., an erase-below starting from the upper-left corner of the 2086 * screen, or if the erasure applies to the whole screen. 2087 */ 2088void 2089do_cd_xtra_scroll(XtermWidget xw, int param) 2090{ 2091 TScreen *screen = TScreenOf(xw); 2092 2093 TRACE(("do_cd_xtra_scroll param %d, @%d,%d vs %d,%d\n", param, 2094 screen->cur_row, 2095 screen->cur_col, 2096 ScrnTopMargin(xw), 2097 ScrnLeftMargin(xw))); 2098 if (xw->misc.cdXtraScroll 2099 && (param == 2 || 2100 (param == 0 2101 && screen->cur_col <= ScrnLeftMargin(xw) 2102 && screen->cur_row <= ScrnTopMargin(xw)))) { 2103 do_extra_scroll(xw, (xw->misc.cdXtraScroll == edTrim)); 2104 } 2105} 2106 2107/* 2108 * Scroll the page up (saving it). This is called when doing terminal 2109 * initialization (ti) or exiting from that (te). 2110 */ 2111void 2112do_ti_xtra_scroll(XtermWidget xw) 2113{ 2114 if (xw->misc.tiXtraScroll) { 2115 do_extra_scroll(xw, False); 2116 } 2117} 2118 2119static void 2120CopyWait(XtermWidget xw) 2121{ 2122 TScreen *screen = TScreenOf(xw); 2123 XEvent reply; 2124 XEvent *rep = &reply; 2125#ifndef NO_ACTIVE_ICON 2126 int retries = 0; 2127#endif 2128 2129#if USE_DOUBLE_BUFFER 2130 if (resource.buffered) 2131 return; 2132#endif 2133 2134 for (;;) { 2135#ifndef NO_ACTIVE_ICON 2136 if (xw->work.active_icon != eiFalse) { 2137 /* 2138 * The XWindowEvent call blocks until an event is available. That 2139 * can hang when using active-icon and iconifying/deiconifying 2140 * while the terminal is receiving lots of output. Checking with 2141 * this call on the other hand may lose exposure events which 2142 * arrive too late. As a compromise, try several times with a 2143 * time-delay before assuming no more events are available. 2144 */ 2145 if (XCheckWindowEvent(screen->display, 2146 VWindow(screen), 2147 ExposureMask, 2148 &reply)) { 2149 retries = 0; 2150 } else { 2151 if (++retries >= 1000) 2152 return; 2153 usleep(100U); /* wait 0.1msec */ 2154 continue; 2155 } 2156 } else 2157#endif 2158 XWindowEvent(screen->display, VWindow(screen), ExposureMask, &reply); 2159 switch (reply.type) { 2160 case Expose: 2161 HandleExposure(xw, &reply); 2162 break; 2163 case NoExpose: 2164 case GraphicsExpose: 2165 if (screen->incopy <= 0) { 2166 screen->incopy = 1; 2167 if (screen->scrolls > 0) 2168 screen->scrolls--; 2169 } 2170 if (reply.type == GraphicsExpose) 2171 HandleExposure(xw, &reply); 2172 2173 if ((reply.type == NoExpose) || 2174 ((XExposeEvent *) rep)->count == 0) { 2175 if (screen->incopy <= 0 && screen->scrolls > 0) 2176 screen->scrolls--; 2177 if (screen->scrolls == 0) { 2178 screen->incopy = 0; 2179 return; 2180 } 2181 screen->incopy = -1; 2182 } 2183 break; 2184 } 2185 } 2186} 2187 2188/* 2189 * used by vertical_copy_area and and horizontal_copy_area 2190 */ 2191static void 2192copy_area(XtermWidget xw, 2193 int src_x, 2194 int src_y, 2195 unsigned width, 2196 unsigned height, 2197 int dest_x, 2198 int dest_y) 2199{ 2200 TScreen *screen = TScreenOf(xw); 2201 2202 if (width != 0 && height != 0) { 2203 /* wait for previous CopyArea to complete unless 2204 multiscroll is enabled and active */ 2205 if (screen->incopy && screen->scrolls == 0) 2206 CopyWait(xw); 2207 screen->incopy = -1; 2208 2209 /* save for translating Expose events */ 2210 screen->copy_src_x = src_x; 2211 screen->copy_src_y = src_y; 2212 screen->copy_width = width; 2213 screen->copy_height = height; 2214 screen->copy_dest_x = dest_x; 2215 screen->copy_dest_y = dest_y; 2216 2217 XCopyArea(screen->display, 2218 VDrawable(screen), VDrawable(screen), 2219 NormalGC(xw, screen), 2220 src_x, src_y, width, height, dest_x, dest_y); 2221 } 2222} 2223 2224/* 2225 * use when inserting or deleting characters on the current line 2226 */ 2227static void 2228horizontal_copy_area(XtermWidget xw, 2229 int firstchar, /* char pos on screen to start copying at */ 2230 int nchars, 2231 int amount) /* number of characters to move right */ 2232{ 2233 TScreen *screen = TScreenOf(xw); 2234 CLineData *ld; 2235 2236 if ((ld = getLineData(screen, screen->cur_row)) != 0) { 2237 int src_x = LineCursorX(screen, ld, firstchar); 2238 int src_y = CursorY(screen, screen->cur_row); 2239 2240 copy_area(xw, src_x, src_y, 2241 (unsigned) (nchars * LineFontWidth(screen, ld)), 2242 (unsigned) FontHeight(screen), 2243 src_x + amount * LineFontWidth(screen, ld), src_y); 2244 } 2245} 2246 2247/* 2248 * use when inserting or deleting lines from the screen 2249 */ 2250static void 2251vertical_copy_area(XtermWidget xw, 2252 int firstline, /* line on screen to start copying at */ 2253 int nlines, 2254 int amount, /* number of lines to move up (neg=down) */ 2255 int left, 2256 int right) 2257{ 2258 TScreen *screen = TScreenOf(xw); 2259 2260 TRACE(("vertical_copy_area - firstline=%d nlines=%d left=%d right=%d amount=%d\n", 2261 firstline, nlines, left, right, amount)); 2262 2263 if (nlines > 0) { 2264 int src_x = CursorX(screen, left); 2265 int src_y = firstline * FontHeight(screen) + screen->border; 2266 unsigned int w = (unsigned) ((right + 1 - left) * FontWidth(screen)); 2267 unsigned int h = (unsigned) (nlines * FontHeight(screen)); 2268 int dst_x = src_x; 2269 int dst_y = src_y - amount * FontHeight(screen); 2270 2271 copy_area(xw, src_x, src_y, w, h, dst_x, dst_y); 2272 2273 if (screen->show_wrap_marks) { 2274 int row; 2275 int first = firstline - amount; 2276 int last = firstline + nlines + amount; 2277 2278 for (row = first; row < last; ++row) { 2279 CLineData *ld; 2280 int mapped = amount + row + screen->topline; 2281 2282 if ((ld = getLineData(screen, mapped)) != 0) { 2283 ShowWrapMarks(xw, row, ld); 2284 } 2285 } 2286 } 2287 } 2288} 2289 2290/* 2291 * use when scrolling the entire screen 2292 */ 2293void 2294scrolling_copy_area(XtermWidget xw, 2295 int firstline, /* line on screen to start copying at */ 2296 int nlines, 2297 int amount) /* number of lines to move up (neg=down) */ 2298{ 2299 2300 if (nlines > 0) { 2301 vertical_copy_area(xw, firstline, nlines, amount, 0, TScreenOf(xw)->max_col); 2302 } 2303} 2304 2305/* 2306 * Handler for Expose events on the VT widget. 2307 * Returns 1 iff the area where the cursor was got refreshed. 2308 */ 2309int 2310HandleExposure(XtermWidget xw, XEvent *event) 2311{ 2312 TScreen *screen = TScreenOf(xw); 2313 XExposeEvent *reply = (XExposeEvent *) event; 2314 2315#ifndef NO_ACTIVE_ICON 2316 if (reply->window == screen->iconVwin.window) { 2317 WhichVWin(screen) = &screen->iconVwin; 2318 TRACE(("HandleExposure - icon\n")); 2319 } else { 2320 WhichVWin(screen) = &screen->fullVwin; 2321 TRACE(("HandleExposure - normal\n")); 2322 } 2323 TRACE((" event %d,%d %dx%d\n", 2324 reply->y, 2325 reply->x, 2326 reply->height, 2327 reply->width)); 2328#endif /* NO_ACTIVE_ICON */ 2329 2330 /* if not doing CopyArea or if this is a GraphicsExpose, don't translate */ 2331 if (!screen->incopy || event->type != Expose) { 2332 return handle_translated_exposure(xw, reply->x, reply->y, 2333 reply->width, 2334 reply->height); 2335 } else { 2336 /* compute intersection of area being copied with 2337 area being exposed. */ 2338 int both_x1 = Max(screen->copy_src_x, reply->x); 2339 int both_y1 = Max(screen->copy_src_y, reply->y); 2340 int both_x2 = Min(screen->copy_src_x + (int) screen->copy_width, 2341 (reply->x + (int) reply->width)); 2342 int both_y2 = Min(screen->copy_src_y + (int) screen->copy_height, 2343 (reply->y + (int) reply->height)); 2344 int value = 0; 2345 2346 /* was anything copied affected? */ 2347 if (both_x2 > both_x1 && both_y2 > both_y1) { 2348 /* do the copied area */ 2349 value = handle_translated_exposure 2350 (xw, reply->x + screen->copy_dest_x - screen->copy_src_x, 2351 reply->y + screen->copy_dest_y - screen->copy_src_y, 2352 reply->width, reply->height); 2353 } 2354 /* was anything not copied affected? */ 2355 if (reply->x < both_x1 || reply->y < both_y1 2356 || reply->x + reply->width > both_x2 2357 || reply->y + reply->height > both_y2) 2358 value = handle_translated_exposure(xw, reply->x, reply->y, 2359 reply->width, reply->height); 2360 2361 return value; 2362 } 2363} 2364 2365static void 2366set_background(XtermWidget xw, int color) 2367{ 2368 TScreen *screen = TScreenOf(xw); 2369 Pixel c = getXtermBG(xw, xw->flags, color); 2370 2371#if OPT_WIDE_ATTRS 2372 TRACE(("set_background(%d) %#lx %s\n", color, c, 2373 ((xw->flags & ATR_DIRECT_BG) 2374 ? "direct" 2375 : "indexed"))); 2376#else 2377 TRACE(("set_background(%d) %#lx\n", color, c)); 2378#endif 2379 XSetWindowBackground(screen->display, VShellWindow(xw), c); 2380 XSetWindowBackground(screen->display, VWindow(screen), c); 2381 initBorderGC(xw, WhichVWin(screen)); 2382} 2383 2384void 2385xtermClear2(XtermWidget xw, int x, int y, unsigned width, unsigned height) 2386{ 2387 TScreen *screen = TScreenOf(xw); 2388 VTwin *vwin = WhichVWin(screen); 2389 Drawable draw = VDrawable(screen); 2390 GC gc; 2391 2392 if ((gc = vwin->border_gc) != 0) { 2393 int vmark1 = screen->border; 2394 int vmark2 = vwin->height + vmark1; 2395 int hmark1 = OriginX(screen); 2396 int hmark2 = vwin->width + hmark1; 2397 if (y < vmark1) { 2398 int yy = y + (int) height; 2399 int h1 = (yy <= vmark1) ? (yy - y) : (vmark1 - y); 2400 XFillRectangle(screen->display, draw, gc, 2401 x, y, width, (unsigned) h1); 2402 if (yy > vmark1) { 2403 xtermClear2(xw, x, vmark1, width, (unsigned) (yy - vmark1)); 2404 } 2405 } else if (y < vmark2) { 2406 int yy = y + (int) height; 2407 int h2 = (yy <= vmark2) ? (yy - y) : (vmark2 - y); 2408 int xb = x; 2409 int xx = x + (int) width; 2410 int ww = (int) width; 2411 if (x < hmark1) { 2412 int w1 = (xx <= hmark1) ? (xx - x) : (hmark1 - x); 2413 XFillRectangle(screen->display, draw, gc, 2414 x, y, (unsigned) w1, (unsigned) h2); 2415 x += w1; 2416 ww -= w1; 2417 } 2418 if ((ww > 0) && (x < hmark2)) { 2419 int w2 = (xx <= hmark2) ? (xx - x) : (hmark2 - x); 2420#if USE_DOUBLE_BUFFER 2421 if (resource.buffered) { 2422 XFillRectangle(screen->display, draw, 2423 FillerGC(xw, screen), 2424 x, y, (unsigned) w2, (unsigned) h2); 2425 } else 2426#endif 2427 XClearArea(screen->display, VWindow(screen), 2428 x, y, (unsigned) w2, (unsigned) h2, False); 2429 x += w2; 2430 ww -= w2; 2431 } 2432 if (ww > 0) { 2433 XFillRectangle(screen->display, draw, gc, 2434 x, y, (unsigned) ww, (unsigned) h2); 2435 } 2436 if (yy > vmark2) { 2437 xtermClear2(xw, xb, vmark2, width, (unsigned) (yy - vmark2)); 2438 } 2439 } else { 2440 XFillRectangle(screen->display, draw, gc, x, y, width, height); 2441 } 2442 } else { 2443#if USE_DOUBLE_BUFFER 2444 if (resource.buffered) { 2445 gc = FillerGC(xw, screen); 2446 XFillRectangle(screen->display, draw, gc, 2447 x, y, width, height); 2448 } else 2449#endif 2450 XClearArea(screen->display, 2451 VWindow(screen), 2452 x, y, width, height, False); 2453 } 2454} 2455 2456/* 2457 * Called by the ExposeHandler to do the actual repaint after the coordinates 2458 * have been translated to allow for any CopyArea in progress. 2459 * The rectangle passed in is pixel coordinates. 2460 */ 2461static int 2462handle_translated_exposure(XtermWidget xw, 2463 int rect_x, 2464 int rect_y, 2465 int rect_width, 2466 int rect_height) 2467{ 2468 TScreen *screen = TScreenOf(xw); 2469 int toprow, leftcol, nrows, ncols; 2470 int x0, x1; 2471 int y0, y1; 2472 int result = 0; 2473 2474 TRACE(("handle_translated_exposure at %d,%d size %dx%d\n", 2475 rect_y, rect_x, rect_height, rect_width)); 2476 2477 x0 = (rect_x - OriginX(screen)); 2478 x1 = (x0 + rect_width); 2479 2480 y0 = (rect_y - OriginY(screen)); 2481 y1 = (y0 + rect_height); 2482 2483 if (x0 < 0 || 2484 y0 < 0 || 2485 x1 > Width(screen) || 2486 y1 > PlusStatusLine(screen, Height(screen))) { 2487 set_background(xw, -1); 2488 xtermClear2(xw, 2489 rect_x, 2490 rect_y, 2491 (unsigned) rect_width, 2492 (unsigned) rect_height); 2493 } 2494 toprow = y0 / FontHeight(screen); 2495 if (toprow < 0) 2496 toprow = 0; 2497 2498 leftcol = x0 / FontWidth(screen); 2499 if (leftcol < 0) 2500 leftcol = 0; 2501 2502 nrows = (y1 - 1) / FontHeight(screen) - toprow + 1; 2503 ncols = (x1 - 1) / FontWidth(screen) - leftcol + 1; 2504 toprow -= screen->scrolls; 2505 if (toprow < 0) { 2506 nrows += toprow; 2507 toprow = 0; 2508 } 2509 if (toprow + nrows > PlusStatusLine(screen, MaxRows(screen))) 2510 nrows = PlusStatusLine(screen, MaxRows(screen)) - toprow; 2511 if (leftcol + ncols > MaxCols(screen)) 2512 ncols = MaxCols(screen) - leftcol; 2513 2514 if (nrows > 0 && ncols > 0) { 2515 ScrnRefresh(xw, toprow, leftcol, nrows, ncols, True); 2516 first_map_occurred(); 2517 if (screen->cur_row >= toprow && 2518 screen->cur_row < toprow + nrows && 2519 screen->cur_col >= leftcol && 2520 screen->cur_col < leftcol + ncols) { 2521 result = 1; 2522 } 2523 2524 } 2525 TRACE(("...handle_translated_exposure %d\n", result)); 2526 return (result); 2527} 2528 2529/***====================================================================***/ 2530 2531void 2532GetColors(XtermWidget xw, ScrnColors * pColors) 2533{ 2534 TScreen *screen = TScreenOf(xw); 2535 int n; 2536 2537 pColors->which = 0; 2538 for (n = 0; n < NCOLORS; ++n) { 2539 SET_COLOR_VALUE(pColors, n, T_COLOR(screen, n)); 2540 } 2541} 2542 2543void 2544ChangeColors(XtermWidget xw, ScrnColors * pNew) 2545{ 2546 Bool repaint = False; 2547 TScreen *screen = TScreenOf(xw); 2548 VTwin *win = WhichVWin(screen); 2549 2550 TRACE(("ChangeColors\n")); 2551 2552 if (COLOR_DEFINED(pNew, TEXT_CURSOR)) { 2553 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_CURSOR); 2554 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR))); 2555 FreeMarkGCs(xw); 2556 /* no repaint needed */ 2557 } else if ((T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) && 2558 (COLOR_DEFINED(pNew, TEXT_FG))) { 2559 if (T_COLOR(screen, TEXT_CURSOR) != COLOR_VALUE(pNew, TEXT_FG)) { 2560 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_FG); 2561 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR))); 2562 if (screen->Vshow) 2563 repaint = True; 2564 } 2565 FreeMarkGCs(xw); 2566 } 2567 2568 if (COLOR_DEFINED(pNew, TEXT_FG)) { 2569 Pixel fg = COLOR_VALUE(pNew, TEXT_FG); 2570 T_COLOR(screen, TEXT_FG) = fg; 2571 TRACE(("... TEXT_FG: %#lx\n", T_COLOR(screen, TEXT_FG))); 2572 if (screen->Vshow) { 2573 setCgsFore(xw, win, gcNorm, fg); 2574 setCgsBack(xw, win, gcNormReverse, fg); 2575 setCgsFore(xw, win, gcBold, fg); 2576 setCgsBack(xw, win, gcBoldReverse, fg); 2577 repaint = True; 2578 } 2579 FreeMarkGCs(xw); 2580 } 2581 2582 if (COLOR_DEFINED(pNew, TEXT_BG)) { 2583 Pixel bg = COLOR_VALUE(pNew, TEXT_BG); 2584 T_COLOR(screen, TEXT_BG) = bg; 2585 TRACE(("... TEXT_BG: %#lx\n", T_COLOR(screen, TEXT_BG))); 2586 if (screen->Vshow) { 2587 setCgsBack(xw, win, gcNorm, bg); 2588 setCgsFore(xw, win, gcNormReverse, bg); 2589 setCgsBack(xw, win, gcBold, bg); 2590 setCgsFore(xw, win, gcBoldReverse, bg); 2591 set_background(xw, -1); 2592 repaint = True; 2593 } 2594 } 2595#if OPT_HIGHLIGHT_COLOR 2596 if (COLOR_DEFINED(pNew, HIGHLIGHT_BG)) { 2597 if (T_COLOR(screen, HIGHLIGHT_BG) != COLOR_VALUE(pNew, HIGHLIGHT_BG)) { 2598 T_COLOR(screen, HIGHLIGHT_BG) = COLOR_VALUE(pNew, HIGHLIGHT_BG); 2599 TRACE(("... HIGHLIGHT_BG: %#lx\n", T_COLOR(screen, HIGHLIGHT_BG))); 2600 if (screen->Vshow) 2601 repaint = True; 2602 } 2603 } 2604 if (COLOR_DEFINED(pNew, HIGHLIGHT_FG)) { 2605 if (T_COLOR(screen, HIGHLIGHT_FG) != COLOR_VALUE(pNew, HIGHLIGHT_FG)) { 2606 T_COLOR(screen, HIGHLIGHT_FG) = COLOR_VALUE(pNew, HIGHLIGHT_FG); 2607 TRACE(("... HIGHLIGHT_FG: %#lx\n", T_COLOR(screen, HIGHLIGHT_FG))); 2608 if (screen->Vshow) 2609 repaint = True; 2610 } 2611 } 2612#endif 2613 2614 if (COLOR_DEFINED(pNew, MOUSE_FG) || (COLOR_DEFINED(pNew, MOUSE_BG))) { 2615 if (COLOR_DEFINED(pNew, MOUSE_FG)) { 2616 T_COLOR(screen, MOUSE_FG) = COLOR_VALUE(pNew, MOUSE_FG); 2617 TRACE(("... MOUSE_FG: %#lx\n", T_COLOR(screen, MOUSE_FG))); 2618 } 2619 if (COLOR_DEFINED(pNew, MOUSE_BG)) { 2620 T_COLOR(screen, MOUSE_BG) = COLOR_VALUE(pNew, MOUSE_BG); 2621 TRACE(("... MOUSE_BG: %#lx\n", T_COLOR(screen, MOUSE_BG))); 2622 } 2623 2624 if (screen->Vshow) { 2625 recolor_cursor(screen, 2626 screen->pointer_cursor, 2627 T_COLOR(screen, MOUSE_FG), 2628 T_COLOR(screen, MOUSE_BG)); 2629 XDefineCursor(screen->display, VWindow(screen), 2630 screen->pointer_cursor); 2631 } 2632#if OPT_TEK4014 2633 if (TEK4014_SHOWN(xw)) { 2634 TekScreen *tekscr = TekScreenOf(tekWidget); 2635 Window tekwin = TWindow(tekscr); 2636 if (tekwin) { 2637 recolor_cursor(screen, 2638 tekscr->arrow, 2639 T_COLOR(screen, MOUSE_FG), 2640 T_COLOR(screen, MOUSE_BG)); 2641 XDefineCursor(screen->display, tekwin, tekscr->arrow); 2642 } 2643 } 2644#endif 2645 /* no repaint needed */ 2646 } 2647 2648 if (COLOR_DEFINED(pNew, TEXT_FG) || 2649 COLOR_DEFINED(pNew, TEXT_BG) || 2650 COLOR_DEFINED(pNew, TEXT_CURSOR)) { 2651 if (set_cursor_gcs(xw) && screen->Vshow) { 2652 repaint = True; 2653 } 2654 } 2655#if OPT_TEK4014 2656 if (COLOR_DEFINED(pNew, TEK_FG) || 2657 COLOR_DEFINED(pNew, TEK_BG)) { 2658 ChangeTekColors(tekWidget, screen, pNew); 2659 if (TEK4014_SHOWN(xw)) { 2660 TekRepaint(tekWidget); 2661 } 2662 } else if (COLOR_DEFINED(pNew, TEK_CURSOR)) { 2663 ChangeTekColors(tekWidget, screen, pNew); 2664 } 2665#endif 2666 if (repaint) 2667 xtermRepaint(xw); 2668} 2669 2670void 2671xtermClear(XtermWidget xw) 2672{ 2673 TScreen *screen = TScreenOf(xw); 2674 2675 TRACE(("xtermClear\n")); 2676 xtermClear2(xw, 0, 0, FullWidth(screen), FullHeight(screen)); 2677} 2678 2679void 2680xtermRepaint(XtermWidget xw) 2681{ 2682 TScreen *screen = TScreenOf(xw); 2683 2684 TRACE(("xtermRepaint\n")); 2685 xtermClear(xw); 2686 ScrnRefresh(xw, 0, 0, LastRowNumber(screen) + 1, MaxCols(screen), True); 2687} 2688 2689/***====================================================================***/ 2690 2691Boolean 2692isDefaultForeground(const char *name) 2693{ 2694 return (Boolean) !x_strcasecmp(name, XtDefaultForeground); 2695} 2696 2697Boolean 2698isDefaultBackground(const char *name) 2699{ 2700 return (Boolean) !x_strcasecmp(name, XtDefaultBackground); 2701} 2702 2703/***====================================================================***/ 2704 2705typedef struct { 2706 Pixel fg; 2707 Pixel bg; 2708} ToSwap; 2709 2710#if OPT_HIGHLIGHT_COLOR 2711#define hc_param ,Bool hilite_color 2712#define hc_value ,screen->hilite_color 2713#else 2714#define hc_param /* nothing */ 2715#define hc_value /* nothing */ 2716#endif 2717 2718/* 2719 * Use this to swap the foreground/background color values in the resource 2720 * data, and to build up a list of the pairs which must be swapped in the 2721 * GC cache. 2722 */ 2723static void 2724swapLocally(ToSwap * list, int *count, ColorRes * fg, ColorRes * bg hc_param) 2725{ 2726 ColorRes tmp; 2727 Boolean found = False; 2728 2729 Pixel fg_color = fg->value; 2730 Pixel bg_color = bg->value; 2731 2732#if OPT_HIGHLIGHT_COLOR 2733 if ((fg_color != bg_color) || !hilite_color) 2734#endif 2735 { 2736 int n; 2737 2738 EXCHANGE(*fg, *bg, tmp); 2739 for (n = 0; n < *count; ++n) { 2740 if ((list[n].fg == fg_color && list[n].bg == bg_color) 2741 || (list[n].fg == bg_color && list[n].bg == fg_color)) { 2742 found = True; 2743 break; 2744 } 2745 } 2746 if (!found) { 2747 list[*count].fg = fg_color; 2748 list[*count].bg = bg_color; 2749 *count = *count + 1; 2750 TRACE(("swapLocally fg %#lx, bg %#lx ->%d\n", 2751 fg_color, bg_color, *count)); 2752 } 2753 } 2754} 2755 2756static void 2757reallySwapColors(XtermWidget xw, ToSwap * list, int count) 2758{ 2759 int j, k; 2760 2761 TRACE(("reallySwapColors\n")); 2762 for (j = 0; j < count; ++j) { 2763 for_each_text_gc(k) { 2764 redoCgs(xw, list[j].fg, list[j].bg, (CgsEnum) k); 2765 } 2766 } 2767 FreeMarkGCs(xw); 2768} 2769 2770static void 2771swapVTwinGCs(XtermWidget xw, VTwin *win) 2772{ 2773 swapCgs(xw, win, gcNorm, gcNormReverse); 2774 swapCgs(xw, win, gcBold, gcBoldReverse); 2775} 2776 2777void 2778ReverseVideo(XtermWidget xw) 2779{ 2780 TScreen *screen = TScreenOf(xw); 2781 ToSwap listToSwap[5]; 2782 int numToSwap = 0; 2783 2784 TRACE(("ReverseVideo now %s\n", BtoS(xw->misc.re_verse))); 2785 2786 /* 2787 * Swap SGR foreground and background colors. By convention, these are 2788 * the colors assigned to "black" (SGR #0) and "white" (SGR #7). Also, 2789 * SGR #8 and SGR #15 are the bold (or bright) versions of SGR #0 and 2790 * #7, respectively. 2791 * 2792 * We don't swap colors that happen to match the screen's foreground 2793 * and background because that tends to produce bizarre effects. 2794 */ 2795#define swapAnyColor(name,a,b) swapLocally(listToSwap, &numToSwap, &(screen->name[a]), &(screen->name[b]) hc_value) 2796#define swapAColor(a,b) swapAnyColor(Acolors, a, b) 2797 if_OPT_ISO_COLORS(screen, { 2798 swapAColor(0, 7); 2799 swapAColor(8, 15); 2800 }); 2801 2802 if (T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) { 2803 T_COLOR(screen, TEXT_CURSOR) = T_COLOR(screen, TEXT_BG); 2804 } 2805#define swapTColor(a,b) swapAnyColor(Tcolors, a, b) 2806 swapTColor(TEXT_FG, TEXT_BG); 2807 swapTColor(MOUSE_FG, MOUSE_BG); 2808 2809 reallySwapColors(xw, listToSwap, numToSwap); 2810 2811 swapVTwinGCs(xw, &(screen->fullVwin)); 2812#ifndef NO_ACTIVE_ICON 2813 swapVTwinGCs(xw, &(screen->iconVwin)); 2814#endif /* NO_ACTIVE_ICON */ 2815 2816 xw->misc.re_verse = (Boolean) !xw->misc.re_verse; 2817 TRACE(("...swapping done, set ReverseVideo %s\n", BtoS(xw->misc.re_verse))); 2818 2819 if (XtIsRealized((Widget) xw)) { 2820 xtermDisplayPointer(xw); 2821 } 2822#if OPT_TEK4014 2823 if (TEK4014_SHOWN(xw)) { 2824 TekScreen *tekscr = TekScreenOf(tekWidget); 2825 Window tekwin = TWindow(tekscr); 2826 recolor_cursor(screen, 2827 tekscr->arrow, 2828 T_COLOR(screen, MOUSE_FG), 2829 T_COLOR(screen, MOUSE_BG)); 2830 XDefineCursor(screen->display, tekwin, tekscr->arrow); 2831 } 2832#endif 2833 2834 if (screen->scrollWidget) 2835 ScrollBarReverseVideo(screen->scrollWidget); 2836 2837 if (XtIsRealized((Widget) xw)) { 2838 set_background(xw, -1); 2839 } 2840#if OPT_TEK4014 2841 TekReverseVideo(xw, tekWidget); 2842#endif 2843 if (XtIsRealized((Widget) xw)) { 2844 xtermRepaint(xw); 2845 } 2846#if OPT_TEK4014 2847 if (TEK4014_SHOWN(xw)) { 2848 TekRepaint(tekWidget); 2849 } 2850#endif 2851 ReverseOldColors(xw); 2852 set_cursor_gcs(xw); 2853 update_reversevideo(); 2854 TRACE(("...ReverseVideo now %s\n", BtoS(xw->misc.re_verse))); 2855} 2856 2857void 2858recolor_cursor(TScreen *screen, 2859 Cursor cursor, /* X cursor ID to set */ 2860 unsigned long fg, /* pixel indexes to look up */ 2861 unsigned long bg) /* pixel indexes to look up */ 2862{ 2863 Display *dpy = screen->display; 2864 XColor colordefs[2]; /* 0 is foreground, 1 is background */ 2865 2866 colordefs[0].pixel = fg; 2867 colordefs[1].pixel = bg; 2868 XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), 2869 colordefs, 2); 2870 XRecolorCursor(dpy, cursor, colordefs, colordefs + 1); 2871 cleanup_colored_cursor(); 2872 return; 2873} 2874 2875#if OPT_RENDERFONT 2876#define XFT_CACHE_LIMIT ((unsigned)(~0) >> 1) 2877#define XFT_CACHE_SIZE 16 2878typedef struct { 2879 XftColor color; 2880 unsigned use; 2881} XftColorCache; 2882 2883static int 2884compare_xft_color_cache(const void *a, const void *b) 2885{ 2886 return (int) (((const XftColorCache *) a)->use - 2887 ((const XftColorCache *) b)->use); 2888} 2889 2890static XftColor * 2891getXftColor(XtermWidget xw, Pixel pixel) 2892{ 2893 static XftColorCache cache[XFT_CACHE_SIZE + 1]; 2894 static unsigned latest_use; 2895 int i; 2896 int oldest; 2897 unsigned oldest_use; 2898 XColor color; 2899 Boolean found = False; 2900 2901 (void) xw; 2902 oldest_use = XFT_CACHE_LIMIT; 2903 oldest = 0; 2904 if (latest_use == XFT_CACHE_LIMIT) { 2905 latest_use = 0; 2906 qsort(cache, (size_t) XFT_CACHE_SIZE, sizeof(XftColorCache), compare_xft_color_cache); 2907 for (i = 0; i < XFT_CACHE_SIZE; i++) { 2908 if (cache[i].use) { 2909 cache[i].use = ++latest_use; 2910 } 2911 } 2912 } 2913 for (i = 0; i < XFT_CACHE_SIZE; i++) { 2914 if (cache[i].use) { 2915 if (cache[i].color.pixel == pixel) { 2916 found = True; 2917 break; 2918 } 2919 } 2920 if (cache[i].use < oldest_use) { 2921 oldest_use = cache[i].use; 2922 oldest = i; 2923 } 2924 } 2925 if (!found) { 2926 i = oldest; 2927 color.pixel = pixel; 2928 (void) QueryOneColor(xw, &color); 2929 cache[i].color.color.red = color.red; 2930 cache[i].color.color.green = color.green; 2931 cache[i].color.color.blue = color.blue; 2932 cache[i].color.color.alpha = 0xffff; 2933 cache[i].color.pixel = pixel; 2934 } 2935 cache[i].use = ++latest_use; 2936 return &cache[i].color; 2937} 2938 2939/* 2940 * The cell-width is related to, but not the same as the wide-character width. 2941 * We will only get useful values from wcwidth() for codes above 255. 2942 * Otherwise, interpret according to internal data. 2943 */ 2944#if OPT_RENDERWIDE 2945 2946#if OPT_C1_PRINT 2947#define XtermCellWidth(xw, ch) \ 2948 (((ch) == 0 || (ch) == 127) \ 2949 ? 0 \ 2950 : (((ch) < 256) \ 2951 ? (((ch) >= 128 && (ch) < 160) \ 2952 ? (TScreenOf(xw)->c1_printable ? 1 : 0) \ 2953 : 1) \ 2954 : CharWidth(TScreenOf(xw), ch))) 2955#else 2956#define XtermCellWidth(xw, ch) \ 2957 (((ch) == 0 || (ch) == 127) \ 2958 ? 0 \ 2959 : (((ch) < 256) \ 2960 ? 1 \ 2961 : CharWidth(TScreenOf(xw), ch))) 2962#endif 2963 2964#endif /* OPT_RENDERWIDE */ 2965 2966#define XFT_DATA(which) getMyXftFont(params->xw, which, fontnum) 2967 2968#if OPT_ISO_COLORS 2969#define UseBoldFont(screen) (!(screen)->colorBDMode || ((screen)->veryBoldColors & BOLD)) 2970#else 2971#define UseBoldFont(screen) 1 2972#endif 2973 2974#if OPT_RENDERWIDE 2975/* 2976 * Find Xft (truetype) double-width font for the given normal/bold attributes. 2977 */ 2978static XTermXftFonts * 2979getWideXftFont(XTermDraw * params, 2980 unsigned attr_flags) 2981{ 2982 TScreen *screen = TScreenOf(params->xw); 2983 int fontnum = screen->menu_font_number; 2984 XTermXftFonts *result = 0; 2985 2986#if OPT_WIDE_ATTRS 2987 if ((attr_flags & ATR_ITALIC) 2988#if OPT_ISO_COLORS 2989 && !screen->colorITMode 2990#endif 2991 ) { 2992 if ((attr_flags & BOLDATTR(screen)) 2993 && UseBoldFont(screen) 2994 && XFT_DATA(fWBtal)) { 2995 result = XFT_DATA(fWBtal); 2996 } else if (XFT_DATA(fWItal)) { 2997 result = XFT_DATA(fWItal); 2998 } 2999 } 3000 if (result != 0) { 3001 ; /* skip the other tests */ 3002 } else 3003#endif 3004#if OPT_ISO_COLORS 3005 if ((attr_flags & UNDERLINE) 3006 && !screen->colorULMode 3007 && screen->italicULMode 3008 && XFT_DATA(fWItal)) { 3009 result = XFT_DATA(fWItal); 3010 } else 3011#endif 3012 if ((attr_flags & BOLDATTR(screen)) 3013 && UseBoldFont(screen) 3014 && XFT_DATA(fWBold)) { 3015 result = XFT_DATA(fWBold); 3016 } else { 3017 result = XFT_DATA(fWide); 3018 } 3019 return result; 3020} 3021#endif /* OPT_RENDERWIDE */ 3022 3023/* 3024 * Find Xft (truetype) single-width font for the given normal/bold attributes. 3025 */ 3026static XTermXftFonts * 3027getNormXftFont(XTermDraw * params, 3028 unsigned attr_flags, 3029 Bool *did_ul) 3030{ 3031 TScreen *screen = TScreenOf(params->xw); 3032 int fontnum = screen->menu_font_number; 3033 XTermXftFonts *result = NULL; 3034 3035 (void) did_ul; 3036#if OPT_DEC_CHRSET 3037 if (CSET_DOUBLE(params->real_chrset)) { 3038 result = xterm_DoubleFT(params, params->real_chrset, attr_flags); 3039 } 3040 if (result != 0) { 3041 ; /* found a usable double-sized font */ 3042 } else 3043#endif 3044#if OPT_WIDE_ATTRS 3045 if ((attr_flags & ATR_ITALIC) 3046#if OPT_ISO_COLORS 3047 && !screen->colorITMode 3048#endif 3049 ) { 3050 if ((attr_flags & BOLDATTR(screen)) 3051 && UseBoldFont(screen) 3052 && XFT_DATA(fBtal)) { 3053 result = XFT_DATA(fBtal); 3054 } else if (XFT_DATA(fItal)) { 3055 result = XFT_DATA(fItal); 3056 } 3057 } 3058 if (result != NULL) { 3059 ; /* skip the other tests */ 3060 } else 3061#endif 3062#if OPT_ISO_COLORS 3063 if ((attr_flags & UNDERLINE) 3064 && !screen->colorULMode 3065 && screen->italicULMode 3066 && XFT_DATA(fItal)) { 3067 result = XFT_DATA(fItal); 3068 *did_ul = True; 3069 } else 3070#endif 3071 if ((attr_flags & BOLDATTR(screen)) 3072 && UseBoldFont(screen) 3073 && XFT_DATA(fBold)) { 3074 result = XFT_DATA(fBold); 3075 } else { 3076 result = XFT_DATA(fNorm); 3077 } 3078 return result; 3079} 3080 3081#if OPT_RENDERWIDE 3082#define pickXftData(width, nf, wf) (((width == 2) && ((wf) != NULL) && XftFp(wf) != NULL) ? (wf) : (nf)) 3083#define pickXftFont(width, nf, wf) (((width == 2) && ((wf) != NULL)) ? (wf) : (nf)) 3084#else 3085#define pickXftData(width, nf, wf) (nf) 3086#define pickXftFont(width, nf, wf) (nf) 3087#endif 3088 3089/* 3090 * fontconfig/Xft combination prior to 2.2 has a problem with 3091 * CJK truetype 'double-width' (bi-width/monospace) fonts leading 3092 * to the 's p a c e d o u t' rendering. Consequently, we can't 3093 * rely on XftDrawString8/16 when one of those fonts is used. 3094 * Instead, we need to roll out our own using XftDrawCharSpec. 3095 * A patch in the same spirit (but in a rather different form) 3096 * was applied to gnome vte and gtk2 port of vim. 3097 * See http://bugzilla.mozilla.org/show_bug.cgi?id=196312 3098 */ 3099static int 3100xtermXftDrawString(XTermDraw * params, 3101 unsigned attr_flags, 3102 XftColor *color, 3103 XftFont *font, 3104 int x, 3105 int y, 3106 const IChar *text, 3107 Cardinal len, 3108 Bool really) 3109{ 3110 TScreen *screen = TScreenOf(params->xw); 3111 int ncells = 0; 3112 3113 (void) attr_flags; 3114 if (len != 0) { 3115#if OPT_RENDERWIDE 3116 XftCharSpec *sbuf; 3117 XTermXftFonts *wdata = getWideXftFont(params, attr_flags); 3118 XftFont *wfont = XftFp(wdata); 3119 Cardinal src, dst; 3120 XftFont *lastFont = 0; 3121 XftFont *currFont = 0; 3122 Cardinal start = 0; 3123 int charWidth; 3124 int fwidth = FontWidth(screen); 3125#if OPT_DEC_CHRSET 3126 Boolean forceDbl = CSET_DOUBLE(params->real_chrset); 3127#else 3128 Boolean forceDbl = False; 3129#endif 3130 3131 BumpTypedBuffer(XftCharSpec, 2 * len); 3132 sbuf = BfBuf(XftCharSpec); 3133 3134 for (src = dst = 0; src < len; src++) { 3135 FcChar32 wc = *text++; 3136 3137 charWidth = XtermCellWidth(params->xw, (wchar_t) wc); 3138 if (charWidth < 0) 3139 continue; 3140 3141 sbuf[dst].ucs4 = wc; 3142 sbuf[dst].x = (short) (x + fwidth * ncells); 3143 sbuf[dst].y = (short) (y); 3144 3145 currFont = pickXftFont(charWidth, font, wfont); 3146 ncells += charWidth; 3147 3148 if (lastFont != currFont) { 3149 if ((lastFont != 0) && really) { 3150 XftDrawCharSpec(screen->renderDraw, 3151 color, 3152 lastFont, 3153 sbuf + start, 3154 (int) (dst - start)); 3155 } 3156 start = dst; 3157 lastFont = currFont; 3158 } 3159 ++dst; 3160 3161 if (forceDbl && charWidth < 2) { 3162 sbuf[dst].ucs4 = ' '; 3163 sbuf[dst].x = (short) (x + fwidth * ncells); 3164 sbuf[dst].y = (short) (y); 3165 ++dst; 3166 ncells += charWidth; 3167 } 3168 } 3169 if ((dst != start) && really) { 3170 XftDrawCharSpec(screen->renderDraw, 3171 color, 3172 lastFont, 3173 sbuf + start, 3174 (int) (dst - start)); 3175 } 3176#else /* !OPT_RENDERWIDE */ 3177 if (really) { 3178 XftChar8 *buffer; 3179 int dst; 3180 3181 BumpTypedBuffer(XftChar8, len); 3182 buffer = BfBuf(XftChar8); 3183 3184 for (dst = 0; dst < (int) len; ++dst) 3185 buffer[dst] = CharOf(text[dst]); 3186 3187 XftDrawString8(screen->renderDraw, 3188 color, 3189 font, 3190 x, y, buffer, (int) len); 3191 } 3192 ncells = (int) len; 3193#endif 3194 xtermNeedSwap(params->xw, 1); 3195 } 3196 return ncells; 3197} 3198#define xtermXftWidth(params, attr_flags, color, font, x, y, chars, len) \ 3199 xtermXftDrawString(params, attr_flags, color, font, x, y, chars, len, False) 3200#endif /* OPT_RENDERFONT */ 3201 3202#if OPT_WIDE_CHARS 3203/* 3204 * Map characters commonly "fixed" by groff back to their ASCII equivalents. 3205 * Also map other useful equivalents. 3206 */ 3207unsigned 3208AsciiEquivs(unsigned ch) 3209{ 3210 switch (ch) { 3211 case 0x2010: /* groff "-" */ 3212 case 0x2011: 3213 case 0x2012: 3214 case 0x2013: 3215 case 0x2014: 3216 case 0x2015: 3217 case 0x2212: /* groff "\-" */ 3218 ch = '-'; 3219 break; 3220 case 0x2018: /* groff "`" */ 3221 ch = '`'; 3222 break; 3223 case 0x2019: /* groff ' */ 3224 ch = '\''; 3225 break; 3226 case 0x201C: /* groff lq */ 3227 case 0x201D: /* groff rq */ 3228 ch = '"'; 3229 break; 3230 case 0x2329: /* groff ".URL" */ 3231 ch = '<'; 3232 break; 3233 case 0x232a: /* groff ".URL" */ 3234 ch = '>'; 3235 break; 3236 default: 3237 if (ch >= 0xff01 && ch <= 0xff5e) { 3238 /* "Fullwidth" codes (actually double-width) */ 3239 ch -= 0xff00; 3240 ch += ANSI_SPA; 3241 break; 3242 } 3243 } 3244 return ch; 3245} 3246 3247/* 3248 * Actually this should be called "groff_workaround()" - for the places where 3249 * groff stomps on compatibility. Still, if enough people get used to it, 3250 * this might someday become a quasi-standard. 3251 */ 3252#if OPT_BOX_CHARS 3253static int 3254ucs_workaround(XTermDraw * params, 3255 unsigned ch, 3256 GC gc, 3257 int x, 3258 int y) 3259{ 3260 TScreen *screen = TScreenOf(params->xw); 3261 int fixed = False; 3262 3263 if (screen->wide_chars && screen->utf8_mode && ch > 256) { 3264 IChar eqv = (IChar) AsciiEquivs(ch); 3265 3266 if (eqv != (IChar) ch) { 3267 int width = CharWidth(screen, ch); 3268 3269 do { 3270 drawXtermText(params, 3271 gc, 3272 x, 3273 y, 3274 &eqv, 3275 1); 3276 x += FontWidth(screen); 3277 eqv = BAD_ASCII; 3278 } while (width-- > 1); 3279 3280 fixed = True; 3281 } else if (ch == HIDDEN_CHAR) { 3282 fixed = True; 3283 } 3284 } 3285 return fixed; 3286} 3287#endif /* OPT_BOX_CHARS */ 3288#endif /* OPT_WIDE_CHARS */ 3289 3290/* 3291 * Use this when the characters will not fill the cell area properly. Fill the 3292 * area where we'll write the characters, otherwise we'll get gaps between 3293 * them, e.g., in the original background color. 3294 * 3295 * The cursor is a special case, because the XFillRectangle call only uses the 3296 * foreground, while we've set the cursor color in the background. So we need 3297 * a special GC for that. 3298 */ 3299static void 3300xtermFillCells(XTermDraw * params, 3301 GC gc, 3302 int x, 3303 int y, 3304 Cardinal len) 3305{ 3306 TScreen *screen = TScreenOf(params->xw); 3307 VTwin *currentWin = WhichVWin(screen); 3308 3309 if (!(params->draw_flags & NOBACKGROUND)) { 3310 CgsEnum srcId = getCgsId(params->xw, currentWin, gc); 3311 CgsEnum dstId = gcMAX; 3312 Pixel fg = getCgsFore(params->xw, currentWin, gc); 3313 Pixel bg = getCgsBack(params->xw, currentWin, gc); 3314 3315 switch (srcId) { 3316 case gcVTcursNormal: 3317 case gcVTcursReverse: 3318 dstId = gcVTcursOutline; 3319 break; 3320 case gcVTcursFilled: 3321 case gcVTcursOutline: 3322 break; 3323 case gcNorm: 3324 dstId = gcNormReverse; 3325 break; 3326 case gcNormReverse: 3327 dstId = gcNorm; 3328 break; 3329 case gcBold: 3330 dstId = gcBoldReverse; 3331 break; 3332 case gcBoldReverse: 3333 dstId = gcBold; 3334 break; 3335 case gcBorder: 3336 case gcFiller: 3337 dstId = srcId; 3338 break; 3339#if OPT_BOX_CHARS 3340 case gcLine: 3341 case gcDots: 3342 break; 3343#endif 3344#if OPT_DEC_CHRSET 3345 case gcCNorm: 3346 case gcCBold: 3347 break; 3348#endif 3349#if OPT_WIDE_CHARS 3350 case gcWide: 3351 dstId = gcWideReverse; 3352 break; 3353 case gcWBold: 3354 dstId = gcBoldReverse; 3355 break; 3356 case gcWideReverse: 3357 case gcWBoldReverse: 3358 break; 3359#endif 3360#if OPT_TEK4014 3361 case gcTKcurs: 3362 break; 3363#endif 3364 case gcMAX: 3365 break; 3366 } 3367 3368 if (dstId != gcMAX) { 3369 setCgsFore(params->xw, currentWin, dstId, bg); 3370 setCgsBack(params->xw, currentWin, dstId, fg); 3371 3372 XFillRectangle(screen->display, VDrawable(screen), 3373 getCgsGC(params->xw, currentWin, dstId), 3374 x, y, 3375 len * (Cardinal) FontWidth(screen), 3376 (unsigned) FontHeight(screen)); 3377 } 3378 } 3379} 3380 3381#if OPT_TRACE 3382static void 3383xtermSetClipRectangles(Display *dpy, 3384 GC gc, 3385 int x, 3386 int y, 3387 XRectangle * rp, 3388 Cardinal nr, 3389 int order) 3390{ 3391#if 0 3392 TScreen *screen = TScreenOf(term); 3393 Drawable draw = VDrawable(screen); 3394 3395 XSetClipMask(dpy, gc, None); 3396 XDrawRectangle(screen->display, draw, gc, 3397 x + rp->x - 1, 3398 y + rp->y - 1, 3399 rp->width, 3400 rp->height); 3401#endif 3402 3403 XSetClipRectangles(dpy, gc, 3404 x, y, rp, (int) nr, order); 3405 TRACE(("clipping @(%3d,%3d) (%3d,%3d)..(%3d,%3d)\n", 3406 y, x, 3407 rp->y, rp->x, rp->height, rp->width)); 3408} 3409 3410#else 3411#define xtermSetClipRectangles(dpy, gc, x, y, rp, nr, order) \ 3412 XSetClipRectangles(dpy, gc, x, y, rp, (int) nr, order) 3413#endif 3414 3415#if OPT_CLIP_BOLD 3416/* 3417 * This special case is a couple of percent slower, but avoids a lot of pixel 3418 * trash in rxcurses' hanoi.cmd demo (e.g., 10x20 font). 3419 */ 3420#define beginClipping(screen,gc,pwidth,plength) \ 3421 if (pwidth > 2) { \ 3422 if (screen->use_clipping) { \ 3423 XRectangle clip; \ 3424 int clip_x = x; \ 3425 int clip_y = y - FontHeight(screen) + FontDescent(screen); \ 3426 clip.x = 0; \ 3427 clip.y = 0; \ 3428 clip.height = (unsigned short) FontHeight(screen); \ 3429 clip.width = (unsigned short) ((pwidth) * (plength)); \ 3430 xtermSetClipRectangles(screen->display, gc, \ 3431 clip_x, clip_y, \ 3432 &clip, 1, Unsorted); \ 3433 } else if (screen->use_border_clipping) { \ 3434 XRectangle clip; \ 3435 clip.x = 0; \ 3436 clip.y = 0; \ 3437 clip.height = (unsigned short) Height(screen); \ 3438 clip.width = (unsigned short) Width(screen); \ 3439 xtermSetClipRectangles(screen->display, gc, \ 3440 0, 0, \ 3441 &clip, 1, Unsorted); \ 3442 } \ 3443 } 3444#define endClipping(screen,gc) \ 3445 XSetClipMask(screen->display, gc, None) 3446#else 3447#define beginClipping(screen,gc,pwidth,plength) /* nothing */ 3448#define endClipping(screen,gc) /* nothing */ 3449#endif /* OPT_CLIP_BOLD */ 3450 3451#if OPT_RENDERFONT 3452static int 3453drawClippedXftString(XTermDraw * params, 3454 unsigned attr_flags, 3455 XftFont *font, 3456 XftColor *fg_color, 3457 int x, 3458 int y, 3459 const IChar *text, 3460 Cardinal len) 3461{ 3462 int ncells = xtermXftWidth(params, attr_flags, 3463 fg_color, 3464 font, x, y, 3465 text, 3466 len); 3467 XtermWidget xw = params->xw; 3468 TScreen *screen = TScreenOf(xw); 3469 int fontHigh = FontHeight(screen); 3470 int fontWide = FontWidth(screen); 3471 3472 if (fontWide > 2) { 3473 int plength = (ncells ? ncells : 1); 3474 Boolean halfHigh = False; 3475#if OPT_DEC_CHRSET 3476 Boolean halfWide = False; 3477 3478 switch (params->real_chrset) { 3479 case CSET_SWL: 3480 break; 3481 case CSET_DWL: 3482 halfWide = True; 3483 break; 3484 case CSET_DHL_TOP: 3485 halfHigh = True; 3486 halfWide = True; 3487 break; 3488 case CSET_DHL_BOT: 3489 halfHigh = True; 3490 halfWide = True; 3491 break; 3492 } 3493 if (CSET_DOUBLE(params->real_chrset)) { 3494 fontHigh = font->height; 3495 fontWide = font->max_advance_width; 3496 /* check if this is really a double-height font */ 3497#define DoubleScale(macro,field) \ 3498 (int) (macro(screen) * (1.0 + (Max(20, xw->misc.field) / 100.))) 3499 if (halfHigh) { 3500 int wantHigh = DoubleScale(FontHeight, limit_fontheight); 3501 halfHigh = (fontHigh >= wantHigh); 3502 TRACE(("comparing fontHigh %d/%d vs %d:" 3503 " double-height %s for %s\n", 3504 fontHigh, FontHeight(screen), 3505 wantHigh, BtoS(halfHigh), 3506 visibleDblChrset(params->real_chrset))); 3507 } 3508 fontHigh = (halfHigh 3509 ? (2 * FontHeight(screen)) 3510 : FontHeight(screen)); 3511 /* check if this is really a double-width font */ 3512 if (halfWide) { 3513 int wantWide = DoubleScale(FontWidth, limit_fontwidth); 3514 halfWide = (fontWide >= wantWide); 3515 TRACE(("comparing fontWide %d/%d vs %d:" 3516 " double-width %s for %s\n", 3517 fontWide, FontWidth(screen), 3518 wantWide, BtoS(halfWide), 3519 visibleDblChrset(params->real_chrset))); 3520 } 3521 fontWide = (halfWide 3522 ? (2 * FontWidth(screen)) 3523 : FontWidth(screen)); 3524 } 3525#endif 3526 if (screen->use_clipping || halfHigh) { 3527 XRectangle clip; 3528 double adds = ((double) screen->scale_height - 1.0f) * fontHigh; 3529 int height = dimRound(adds + fontHigh); 3530 int descnt = dimRound(adds / 2.0) + FontDescent(screen); 3531 int clip_x = (x); 3532 int clip_y = (y) - height + descnt; 3533 3534 clip.x = 0; 3535 clip.y = 0; 3536 clip.height = (Dimension) height; 3537 clip.width = (Dimension) (fontWide * (Dimension) (plength)); 3538 3539#if OPT_DEC_CHRSET 3540 if (halfHigh) { 3541 int adjust; 3542 3543 clip.height = (unsigned short) FontHeight(screen); 3544 clip_y += descnt; 3545 if (params->real_chrset == CSET_DHL_BOT) { 3546 y -= clip.height; 3547 } 3548 adjust = ((clip_y - OriginY(screen)) % FontHeight(screen)); 3549 if (adjust) { 3550 if (adjust > FontHeight(screen) / 2) 3551 adjust -= FontHeight(screen); 3552 clip_y -= adjust; 3553 } 3554 } 3555#endif 3556 XftDrawSetClipRectangles(screen->renderDraw, 3557 clip_x, clip_y, 3558 &clip, 1); 3559 } else if (screen->use_border_clipping) { 3560 XRectangle clip; 3561 3562 clip.x = (Position) OriginX(screen); 3563 clip.y = (Position) OriginY(screen); 3564 clip.height = (Dimension) Height(screen); 3565 clip.width = (Dimension) Width(screen); 3566 3567 XftDrawSetClipRectangles(screen->renderDraw, 3568 0, 0, 3569 &clip, 1); 3570 } 3571 } 3572 3573 xtermXftDrawString(params, attr_flags, 3574 fg_color, 3575 font, x, y + ScaleShift(screen), 3576 text, 3577 len, 3578 True); 3579 XftDrawSetClip(screen->renderDraw, 0); 3580 return ncells; 3581} 3582#endif 3583 3584#ifndef NO_ACTIVE_ICON 3585#define WhichVFontData(screen,name) \ 3586 (IsIcon(screen) ? getIconicFont(screen) \ 3587 : GetNormalFont(screen, name)) 3588#else 3589#define WhichVFontData(screen,name) \ 3590 GetNormalFont(screen, name) 3591#endif 3592 3593static void 3594drawUnderline(XtermWidget xw, 3595 GC gc, 3596 unsigned attr_flags, 3597 unsigned underline_len, 3598 int font_width, 3599 int x, 3600 int y, 3601 Bool did_ul) 3602{ 3603 TScreen *screen = TScreenOf(xw); 3604 3605 if (screen->underline && !did_ul) { 3606 int repeat = 0; 3607 int descent = FontDescent(screen); 3608 int length = x + (int) underline_len * font_width - 1; 3609 3610#if OPT_WIDE_ATTRS 3611 if ((attr_flags & ATR_STRIKEOUT)) { 3612 int where = y - ((3 * FontAscent(screen)) / 8); 3613 XDrawLine(screen->display, VDrawable(screen), gc, 3614 x, where, 3615 length, 3616 where); 3617 } 3618 if ((attr_flags & ATR_DBL_UNDER)) { 3619 repeat = 2; 3620 } else 3621#endif 3622 if ((attr_flags & UNDERLINE)) { 3623 repeat = 1; 3624 } 3625 while (repeat-- > 0) { 3626 if (descent-- > 1) 3627 y++; 3628 XDrawLine(screen->display, VDrawable(screen), gc, 3629 x, y, 3630 length, 3631 y); 3632 } 3633 } 3634} 3635 3636#if OPT_WIDE_ATTRS 3637/* 3638 * As a special case, we are currently allowing italic fonts to be inexact 3639 * matches for the normal font's size. That introduces a problem: either the 3640 * ascent or descent may be shorter, leaving a gap that has to be filled in. 3641 * Or they may be larger, requiring clipping. Check for both cases. 3642 */ 3643static int 3644fixupItalics(XTermDraw * params, 3645 GC gc, 3646 XTermFonts * curFont, 3647 int y, int x, 3648 int font_width, 3649 Cardinal len) 3650{ 3651 TScreen *screen = TScreenOf(params->xw); 3652 VTwin *cgsWin = WhichVWin(screen); 3653 XFontStruct *realFp = curFont->fs; 3654 XFontStruct *thisFp = getCgsFont(params->xw, cgsWin, gc)->fs; 3655 int need_clipping = 0; 3656 int need_filling = 0; 3657 3658 if (thisFp->ascent > realFp->ascent) 3659 need_clipping = 1; 3660 else if (thisFp->ascent < realFp->ascent) 3661 need_filling = 1; 3662 3663 if (thisFp->descent > realFp->descent) 3664 need_clipping = 1; 3665 else if (thisFp->descent < realFp->descent) 3666 need_filling = 1; 3667 3668 if (need_clipping) { 3669 beginClipping(screen, gc, font_width, (int) len); 3670 } 3671 if (need_filling) { 3672 xtermFillCells(params, 3673 gc, 3674 x, 3675 y - realFp->ascent, 3676 len); 3677 } 3678 return need_clipping; 3679} 3680#endif 3681 3682#if OPT_DEC_CHRSET 3683static int 3684fakeDoubleChars(XTermDraw * params, 3685 GC gc, 3686 int y, 3687 int x, 3688 const IChar *text, 3689 Cardinal len) 3690{ 3691 unsigned need = 2 * len; 3692 IChar *temp = TypeMallocN(IChar, need); 3693 3694 if (temp != 0) { 3695 unsigned n = 0; 3696 XTermDraw recur = *params; 3697 3698 recur.this_chrset = CSET_SWL; 3699 3700 while (len--) { 3701 temp[n++] = *text++; 3702 temp[n++] = ' '; 3703 } 3704 x = drawXtermText(&recur, 3705 gc, 3706 x, y, 3707 temp, 3708 n); 3709 free(temp); 3710 } 3711 return x; 3712} 3713#endif /* OPT_DEC_CHRSET */ 3714 3715#define SetMissing(tag) \ 3716 TRACE(("%s %s: missing %d %04X\n", __FILE__, tag, missing, ch)); \ 3717 missing = 1 3718 3719#define MaxImageString 255 3720 3721#define UCS2SBUF(value) buffer2[dst].byte2 = LO_BYTE(value);\ 3722 buffer2[dst].byte1 = HI_BYTE(value) 3723 3724#if OPT_WIDE_CHARS 3725static int 3726xtermDrawMissing(TScreen *screen, unsigned flags, GC gc, int x, int y, int ncells) 3727{ 3728 /* *INDENT-EQLS* */ 3729 int width = FontWidth(screen) * ncells; 3730 int height = FontHeight(screen); 3731 int descent = FontDescent(screen); 3732 int thick = Max((height / 16), 1); 3733 int thick2 = 2 * thick; 3734 int yhigh = height - thick2; 3735 int too_big = (flags & (DOUBLEWFONT | DOUBLEHFONT)) != 0; 3736 3737 TRACE(("*missing [%4d,%4d] %dx%d (%d)/%d%s%s%s%s\n", 3738 y, x, 3739 height, width, 3740 ncells, 3741 descent, 3742 flags ? " recur" : "", 3743 flags & DOUBLEFIRST ? "*" : "", 3744 flags & DOUBLEWFONT ? ":W" : "", 3745 flags & DOUBLEHFONT ? ":H" : "")); 3746 if (width > thick2 && height > thick2) { 3747 if (too_big) { 3748 if (flags & DOUBLEWFONT) { 3749 width *= 2; 3750 } 3751 if (flags & DOUBLEHFONT) { 3752 if (flags & DOUBLEFIRST) { 3753 height *= 2; 3754 height -= thick; 3755 } else { 3756 height += thick; 3757 } 3758 descent *= 2; 3759 } 3760 } else { 3761 beginClipping(screen, gc, (Cardinal) width, (Cardinal) ncells); 3762 } 3763#if OPT_BOX_CHARS 3764 if (screen->force_all_chars) 3765#endif 3766 { 3767 int xpos = x; 3768 int ypos = (y - height + descent + thick); 3769 unsigned high = (unsigned) yhigh; 3770 unsigned wide = (unsigned) (width - thick2); 3771 3772 XSetLineAttributes(screen->display, gc, 3773 (unsigned) thick, 3774 LineOnOffDash, 3775 CapProjecting, 3776 JoinMiter); 3777 XDrawImageString(screen->display, VDrawable(screen), gc, 3778 x, y, 3779 " ", 3780 Min(4, ncells)); 3781 XDrawRectangle(screen->display, 3782 VDrawable(screen), gc, 3783 xpos, ypos, 3784 wide, high); 3785 } 3786 if (!too_big) { 3787 endClipping(screen, gc); 3788 } 3789 } 3790 return x + width; 3791} 3792 3793static int 3794xtermPartString16(TScreen *screen, unsigned flags, GC gc, int x, int y, int length) 3795{ 3796 if (length > 0) { 3797 XChar2b *buffer2 = BfBuf(XChar2b); 3798 Char *buffer1 = BfBuf(Char); 3799 int n; 3800 Bool eightBit = True; 3801 3802 for (n = 0; n < length; ++n) { 3803 if (buffer2[n].byte1 != 0) { 3804 eightBit = False; 3805 break; 3806 } 3807 buffer1[n] = buffer2[n].byte2; 3808 } 3809 3810 if ((flags & NOBACKGROUND)) { 3811 if (eightBit) { 3812 XDrawString(screen->display, 3813 VDrawable(screen), gc, 3814 x, y, 3815 (char *) buffer1, length); 3816 } else { 3817 XDrawString16(screen->display, 3818 VDrawable(screen), gc, 3819 x, y, 3820 buffer2, length); 3821 } 3822 } else { 3823 int b_pos; 3824 int b_max = MaxImageString; 3825 for (b_pos = 0; b_pos < length; b_pos += b_max) { 3826 if (b_pos + b_max > length) 3827 b_max = (length - b_pos); 3828 if (eightBit) { 3829 XDrawImageString(screen->display, 3830 VDrawable(screen), gc, 3831 x + (b_pos * FontWidth(screen)), 3832 y, 3833 (char *) buffer1 + b_pos, 3834 b_max); 3835 } else { 3836 XDrawImageString16(screen->display, 3837 VDrawable(screen), gc, 3838 x + (b_pos * FontWidth(screen)), 3839 y, 3840 buffer2 + b_pos, 3841 b_max); 3842 } 3843 } 3844 } 3845 x += length * FontWidth(screen); 3846 } 3847 return x; 3848} 3849 3850static int 3851xtermFullString16(XtermWidget xw, unsigned flags, GC gc, int x, int y, int length) 3852{ 3853 TScreen *screen = TScreenOf(xw); 3854 int src, dst; 3855 IChar *mapped = BfBuf(IChar); 3856 XChar2b *buffer2 = BfBuf(XChar2b); 3857 VTwin *currentWin = WhichVWin(screen); 3858 XTermFonts *xf = getCgsFont(xw, currentWin, gc); 3859 XTermFonts *fp = xf ? xf : getNormalFont(screen, fNorm); 3860 3861 for (src = dst = 0; src < (int) length; src++) { 3862 IChar ch = mapped[src]; 3863 int ch_width = CharWidth(screen, ch); 3864 /* 3865 * X11 bitmap-fonts are limited to 16-bits. 3866 */ 3867 if ( 3868#if OPT_WIDER_ICHAR 3869 (ch > NARROW_ICHAR) || 3870#endif 3871 xtermMissingChar(ch, fp)) { 3872 x = xtermPartString16(screen, flags, gc, x, y, dst); 3873 x = xtermDrawMissing(screen, flags, gc, x, y, ch_width); 3874 dst = 0; 3875 } else { 3876 UCS2SBUF(ch); 3877 ++dst; 3878 } 3879 } 3880 3881 x = xtermPartString16(screen, flags, gc, x, y, dst); 3882 return x; 3883} 3884#endif /* OPT_WIDE_CHARS */ 3885 3886static void 3887xtermPartString(TScreen *screen, unsigned flags, GC gc, int x, int y, int length) 3888{ 3889 Char *buffer1 = BfBuf(Char); 3890 3891 if ((flags & NOBACKGROUND)) { 3892 XDrawString(screen->display, VDrawable(screen), gc, 3893 x, y, (char *) buffer1, length); 3894 } else { 3895 int b_pos; 3896 int b_max = MaxImageString; 3897 for (b_pos = 0; b_pos < length; b_pos += b_max) { 3898 if (b_pos + b_max > length) 3899 b_max = (length - b_pos); 3900 XDrawImageString(screen->display, 3901 VDrawable(screen), gc, 3902 x + (b_pos * FontWidth(screen)), 3903 y, 3904 (char *) (buffer1 + b_pos), 3905 b_max); 3906 } 3907 } 3908} 3909 3910static void 3911xtermDrawString(TScreen *screen, unsigned flags, GC gc, int x, int y, int length) 3912{ 3913 IChar *mapped = BfBuf(IChar); 3914 Char *buffer1 = BfBuf(Char); 3915 3916 int dst; 3917 3918 for (dst = 0; dst < length; ++dst) 3919 buffer1[dst] = (Char) LO_BYTE(mapped[dst]); 3920 3921 xtermPartString(screen, flags, gc, x, y, length); 3922} 3923 3924/* 3925 * Draws text with the specified combination of bold/underline. The return 3926 * value is the updated x position. 3927 */ 3928int 3929drawXtermText(XTermDraw * params, 3930 GC gc, 3931 int start_x, 3932 int start_y, 3933 const IChar *text, 3934 Cardinal len) 3935{ 3936 XTermDraw recur = *params; 3937 TScreen *screen = TScreenOf(recur.xw); 3938 int x = start_x; 3939 int y = start_y; 3940 int y_shift = ScaleShift(screen); 3941 Cardinal real_length = len; 3942 Cardinal underline_len = 0; 3943 /* Intended width of the font to draw (as opposed to the actual width of 3944 the X font, and the width of the default font) */ 3945 int font_width = (((recur.draw_flags & DOUBLEWFONT) ? 2 : 1) 3946 * screen->fnt_wide); 3947 Bool did_ul = False; 3948 XTermFonts *curFont; 3949 3950#if OPT_WIDE_ATTRS 3951 int need_clipping = 0; 3952#endif 3953 3954#if OPT_WIDE_CHARS 3955 Bool need_wide; 3956#endif 3957 3958#if OPT_WIDE_CHARS 3959 if (text == 0) 3960 return 0; 3961#endif 3962 TRACE(("DRAWTEXT%c[%4d,%4d] (%d)%3d:%s\n", 3963 screen->cursor_state == OFF ? ' ' : '*', 3964 y, x, recur.this_chrset, len, 3965 visibleIChars(text, len))); 3966 3967#if OPT_DEC_CHRSET 3968 if (CSET_DOUBLE(recur.this_chrset)) { 3969 /* We could try drawing double-size characters in the icon, but 3970 * given that the icon font is usually nil or nil2, there 3971 * doesn't seem to be much point. 3972 */ 3973 int inx = 0; 3974 GC gc2; 3975 3976#if OPT_RENDERFONT 3977 if (UsingRenderFont(recur.xw)) { 3978 if (!IsIcon(screen) && screen->font_doublesize) { 3979 int next; 3980 TRACE(("drawing %s\n", visibleDblChrset((unsigned) recur.this_chrset))); 3981 recur.real_chrset = recur.this_chrset; 3982 recur.this_chrset = CSET_SWL; 3983 next = drawXtermText(&recur, 3984 gc, 3985 x, y, 3986 text, 3987 len); 3988 x += (next - x) * 2; 3989 } else { 3990 x = fakeDoubleChars(&recur, 3991 gc, y, x, 3992 text, len); 3993 } 3994 } else 3995#endif 3996 if ((!IsIcon(screen) && screen->font_doublesize) 3997 && (gc2 = xterm_DoubleGC(&recur, gc, &inx)) != 0) { 3998 /* draw actual double-sized characters */ 3999 XFontStruct *fs = getDoubleFont(screen, inx)->fs; 4000 XRectangle rect, *rp = ▭ 4001 Cardinal nr = 1; 4002 Cardinal nlen; 4003 int ncells = (int) len; 4004 4005 font_width *= 2; 4006 recur.draw_flags |= DOUBLEWFONT; 4007 4008 for (nlen = 0; nlen < len; ++nlen) { 4009 int ch_width = CharWidth(screen, text[nlen]); 4010 if (ch_width > 1) 4011 ncells += (ch_width - 1); 4012 } 4013 4014 rect.x = 0; 4015 rect.y = 0; 4016 rect.width = (unsigned short) (ncells * font_width); 4017 rect.height = (unsigned short) (FontHeight(screen)); 4018 4019 TRACE(("drawing %s\n", visibleDblChrset((unsigned) recur.this_chrset))); 4020 switch (recur.this_chrset) { 4021 case CSET_DHL_TOP: 4022 rect.y = (short) -(fs->ascent / 2); 4023 y -= rect.y; 4024 recur.draw_flags |= (DOUBLEHFONT | DOUBLEFIRST); 4025 break; 4026 case CSET_DHL_BOT: 4027 rect.y = (short) (rect.height - (fs->ascent / 2)); 4028 y -= rect.y; 4029 recur.draw_flags |= DOUBLEHFONT; 4030 recur.draw_flags &= (unsigned) ~DOUBLEFIRST; 4031 break; 4032 case CSET_DWL: 4033 break; 4034 default: 4035 nr = 0; 4036 break; 4037 } 4038 4039 if (nr) { 4040 xtermSetClipRectangles(screen->display, gc2, 4041 x, y, rp, nr, YXBanded); 4042 xtermFillCells(&recur, gc, x, y + rect.y, 4043 (Cardinal) ncells * 2); 4044 } else { 4045 XSetClipMask(screen->display, gc2, None); 4046 } 4047 4048 /* Call ourselves recursively with the new gc */ 4049 4050 /* 4051 * If we're trying to use proportional font, or if the 4052 * font server didn't give us what we asked for wrt 4053 * width, position each character independently. 4054 */ 4055 if (screen->fnt_prop 4056 || (fs->min_bounds.width != fs->max_bounds.width) 4057 || (fs->min_bounds.width != 2 * FontWidth(screen))) { 4058 /* It is hard to fall-through to the main 4059 branch: in a lot of places the check 4060 for the cached font info is for 4061 normal/bold fonts only. */ 4062 XTermDraw param2 = recur; 4063 param2.this_chrset = CSET_SWL; 4064 while (len--) { 4065 int next = drawXtermText(¶m2, 4066 gc2, 4067 x, y, 4068 text++, 4069 1); 4070 x += (next - x) * 2; 4071 } 4072 } else { 4073 int next; 4074 XTermDraw param2 = recur; 4075 param2.this_chrset = CSET_SWL; 4076 next = drawXtermText(¶m2, 4077 gc2, 4078 x, y, 4079 text, 4080 len); 4081 x += (next - x) * 2; 4082 } 4083 4084 } else { /* simulate double-sized characters */ 4085 x = fakeDoubleChars(&recur, 4086 gc, y, x, 4087 text, len); 4088 } 4089 TRACE(("DrewText [%4d,%4d] @%d\n", y, x, __LINE__)); 4090 return x; 4091 } 4092#endif 4093#if OPT_RENDERFONT 4094 if (UsingRenderFont(recur.xw)) { 4095 VTwin *currentWin = WhichVWin(screen); 4096 Display *dpy = screen->display; 4097 XTermXftFonts *ndata; 4098 XGCValues values; 4099#if OPT_WIDE_CHARS && OPT_BOX_CHARS 4100 XTermXftFonts *ndata0; 4101#endif 4102#if OPT_RENDERWIDE && OPT_BOX_CHARS 4103 XTermXftFonts *wdata; 4104 XTermXftFonts *wdata0; 4105#endif 4106 int ncells = 0; 4107 4108#if OPT_DEC_CHRSET 4109 /* 4110 * If this is a VT100-style double-width font, ensure that everything 4111 * is printed using two-columns per character. 4112 */ 4113 Boolean forceDbl = CSET_DOUBLE(recur.real_chrset); 4114#else 4115 Boolean forceDbl = False; 4116#endif 4117 4118 (void) forceDbl; 4119 /* 4120 * Defer creating the drawable until we need it. 4121 */ 4122 if (!screen->renderDraw) { 4123 int scr; 4124 Drawable draw = VDrawable(screen); 4125 Visual *visual; 4126 4127 scr = DefaultScreen(dpy); 4128 visual = DefaultVisual(dpy, scr); 4129 screen->renderDraw = XftDrawCreate(dpy, draw, visual, 4130 DefaultColormap(dpy, scr)); 4131 } 4132 4133 /* 4134 * ndata0/wdata0 provide fallback to non-bolded Xft font if a glyph is 4135 * not found in the bold version. 4136 */ 4137#define IS_BOLD (recur.attr_flags & BOLDATTR(screen)) 4138#define NOT_BOLD (recur.attr_flags & ~BOLDATTR(screen)) 4139 ndata = getNormXftFont(&recur, recur.attr_flags, &did_ul); 4140#if OPT_WIDE_CHARS && OPT_BOX_CHARS 4141 ndata0 = IS_BOLD ? getNormXftFont(&recur, NOT_BOLD, &did_ul) : ndata; 4142#endif 4143#if OPT_RENDERWIDE && OPT_BOX_CHARS 4144 wdata = getWideXftFont(&recur, recur.attr_flags); 4145 wdata0 = IS_BOLD ? getWideXftFont(&recur, NOT_BOLD) : wdata; 4146#endif 4147 4148#define GET_XFT_FG() getXftColor(recur.xw, values.foreground) 4149#define GET_XFT_BG() getXftColor(recur.xw, values.background) 4150 4151 values.foreground = getCgsFore(recur.xw, currentWin, gc); 4152 values.background = getCgsBack(recur.xw, currentWin, gc); 4153 4154 if (!(recur.draw_flags & NOBACKGROUND)) { 4155 XftColor *bg_color = GET_XFT_BG(); 4156 int nc = xtermXftWidth(&recur, recur.attr_flags, 4157 bg_color, 4158 XftFp(ndata), x, y, 4159 text, 4160 len); 4161 XftDrawRect(screen->renderDraw, 4162 bg_color, 4163 x, y, 4164 (unsigned) (nc * FontWidth(screen)), 4165 (unsigned) FontHeight(screen)); 4166 } 4167 4168 y += XftFp(ndata)->ascent; 4169#if OPT_BOX_CHARS 4170 { 4171 /* adding code to substitute simulated line-drawing characters */ 4172 int last, first = 0; 4173 int curX = x; 4174 4175 for (last = 0; last < (int) len; last++) { 4176 Boolean replace = False; 4177 Boolean missing = False; 4178 unsigned ch = (unsigned) text[last]; 4179 int ch_width = CharWidth(screen, ch); 4180 int filler = 0; 4181#if OPT_WIDE_CHARS 4182 int needed = forceDbl ? 2 : ch_width; 4183 XTermXftFonts *currData = pickXftData(needed, ndata, wdata); 4184 XftFont *tempFont = 0; 4185#define CURR_TEMP (tempFont ? tempFont : XftFp(currData)) 4186 4187 if (xtermIsDecGraphic(ch) || ch == 0) { 4188 /* 4189 * Xft generally does not have the line-drawing characters 4190 * in cells 0-31. Assume this (we cannot inspect the 4191 * picture easily...), and attempt to fill in from real 4192 * line-drawing character in the font at the Unicode 4193 * position. Failing that, use our own box-characters. 4194 */ 4195 if (screen->force_box_chars 4196 || screen->broken_box_chars 4197 || xtermXftMissing(recur.xw, 4198 currData, 0, 4199 XftFp(currData), 4200 dec2ucs(screen, ch))) { 4201 SetMissing("case 1"); 4202 } else { 4203 ch = dec2ucs(screen, ch); 4204 replace = True; 4205 } 4206 } else if (ch >= 256) { 4207 /* 4208 * If we're reading UTF-8 from the client, we may have a 4209 * line-drawing character. Translate it back to our 4210 * box-code if Xft tells us that the glyph is missing. 4211 */ 4212 if_OPT_WIDE_CHARS(screen, { 4213 unsigned part = ucs2dec(screen, ch); 4214 if (xtermIsDecGraphic(part)) { 4215 if (screen->force_box_chars 4216 || screen->broken_box_chars) { 4217 SetMissing("case 2"); 4218 ch = part; 4219 } 4220 } 4221 if (!missing && xtermXftMissing(recur.xw, 4222 currData, 0, 4223 XftFp(currData), ch)) { 4224 int found = findXftGlyph(recur.xw, currData, ch); 4225 XftFont *test; 4226 if (found >= 0) { 4227 test = XftFpN(currData, found); 4228 } else { 4229 test = pickXftFont(needed, 4230 XftFp(ndata0), 4231 XftFp(wdata0)); 4232 } 4233 if (!xtermXftMissing(recur.xw, 4234 currData, found, 4235 test, ch)) { 4236 tempFont = test; 4237 replace = True; 4238 filler = 0; 4239 } else if ((part = AsciiEquivs(ch)) != ch) { 4240 filler = needed - 1; 4241 ch = part; 4242 replace = True; 4243 } else if (ch != HIDDEN_CHAR) { 4244 SetMissing("case 3"); 4245 } 4246 } 4247 }); 4248 } 4249#else 4250 XTermXftFonts *currData = ndata; 4251#define CURR_TEMP XftFp(currData) 4252 if (xtermIsDecGraphic(ch)) { 4253 /* 4254 * Xft generally does not have the line-drawing characters 4255 * in cells 1-31. Check for this, and attempt to fill in 4256 * from real line-drawing character in the font at the 4257 * Unicode position. Failing that, use our own 4258 * box-characters. 4259 */ 4260 if (xtermXftMissing(recur.xw, 4261 currData, 0, 4262 XftFp(currData), ch)) { 4263 SetMissing("case 4"); 4264 } 4265 } 4266#endif 4267 4268 /* 4269 * If we now have one of our box-codes, draw it directly. 4270 */ 4271 if (missing || replace) { 4272 /* line drawing character time */ 4273 if (last > first) { 4274 int nc = drawClippedXftString(&recur, 4275 recur.attr_flags, 4276 XftFp(currData), 4277 GET_XFT_FG(), 4278 curX, 4279 y, 4280 text + first, 4281 (Cardinal) (last - first)); 4282 curX += nc * FontWidth(screen); 4283 underline_len += (Cardinal) nc; 4284 } 4285 if (missing) { 4286 Dimension old_wide = screen->fnt_wide; 4287 Dimension old_high = screen->fnt_high; 4288 screen->fnt_wide = (Dimension) FontWidth(screen); 4289 screen->fnt_high = (Dimension) FontHeight(screen); 4290 4291 xtermDrawBoxChar(&recur, ch, 4292 gc, 4293 curX, 4294 y - FontAscent(screen), 4295 1, 4296 True); 4297 curX += FontWidth(screen); 4298 underline_len += 1; 4299 screen->fnt_wide = old_wide; 4300 screen->fnt_high = old_high; 4301 } else { 4302 IChar ch2 = (IChar) ch; 4303 int nc = drawClippedXftString(&recur, 4304 recur.attr_flags, 4305 CURR_TEMP, 4306 GET_XFT_FG(), 4307 curX, 4308 y, 4309 &ch2, 4310 1); 4311 curX += nc * FontWidth(screen); 4312 underline_len += (Cardinal) nc; 4313 if (filler) { 4314 ch2 = ' '; 4315 nc = drawClippedXftString(&recur, 4316 recur.attr_flags, 4317 CURR_TEMP, 4318 GET_XFT_FG(), 4319 curX, 4320 y, 4321 &ch2, 4322 1); 4323 curX += nc * FontWidth(screen); 4324 underline_len += (Cardinal) nc; 4325 } 4326 } 4327 first = last + 1; 4328 } 4329 if (ch_width > 0) 4330 ncells += ch_width; 4331 } 4332 if (last > first) { 4333 int nc = drawClippedXftString(&recur, 4334 recur.attr_flags, 4335 XftFp(ndata), 4336 GET_XFT_FG(), 4337 curX, 4338 y, 4339 text + first, 4340 (Cardinal) (last - first)); 4341 underline_len += (Cardinal) nc; 4342 } 4343 } 4344#else 4345 { 4346 int nc = drawClippedXftString(&recur, 4347 recur.attr_flags, 4348 XftFp(ndata), 4349 GET_XFT_FG(), 4350 x, 4351 y, 4352 text, 4353 len); 4354 underline_len += (Cardinal) nc; 4355 ncells = nc; 4356 } 4357#endif /* OPT_BOX_CHARS */ 4358 4359 drawUnderline(recur.xw, 4360 gc, 4361 recur.attr_flags, 4362 underline_len, 4363 FontWidth(screen), 4364 x, 4365 y + y_shift, 4366 did_ul); 4367 4368 x += (int) ncells *FontWidth(screen); 4369 4370 TRACE(("DrewText [%4d,%4d] @%d\n", y, x, __LINE__)); 4371 return x; 4372 } 4373#endif /* OPT_RENDERFONT */ 4374 curFont = ((recur.attr_flags & BOLDATTR(screen)) 4375 ? WhichVFontData(screen, fBold) 4376 : WhichVFontData(screen, fNorm)); 4377 /* 4378 * If we're asked to display a proportional font, do this with a fixed 4379 * pitch. Yes, it's ugly. But we cannot distinguish the use of xterm 4380 * as a dumb terminal vs its use as in fullscreen programs such as vi. 4381 * Hint: do not try to use a proportional font in the icon. 4382 */ 4383 if (!IsIcon(screen) && !(recur.draw_flags & CHARBYCHAR) && screen->fnt_prop) { 4384 int adj, width; 4385 4386 while (len--) { 4387 int cells = WideCells(*text); 4388#if OPT_BOX_CHARS 4389#if OPT_WIDE_CHARS 4390 if (*text == HIDDEN_CHAR) { 4391 ++text; 4392 continue; 4393 } else 4394#endif 4395 if (IsXtermMissingChar(screen, *text, curFont)) { 4396 adj = 0; 4397 } else 4398#endif 4399 { 4400 if_WIDE_OR_NARROW(screen, { 4401 XChar2b temp[1]; 4402 temp[0].byte2 = LO_BYTE(*text); 4403 temp[0].byte1 = HI_BYTE(*text); 4404 width = XTextWidth16(curFont->fs, temp, 1); 4405 } 4406 , { 4407 char temp[1]; 4408 temp[0] = (char) LO_BYTE(*text); 4409 width = XTextWidth(curFont->fs, temp, 1); 4410 }); 4411 adj = (FontWidth(screen) - width) / 2; 4412 if (adj < 0) 4413 adj = 0; 4414 } 4415 xtermFillCells(&recur, gc, x, y, (Cardinal) cells); 4416 recur.draw_flags |= (NOBACKGROUND | CHARBYCHAR); 4417 x = drawXtermText(&recur, 4418 gc, x + adj, y, 4419 text++, 1) - adj; 4420 } 4421 4422 TRACE(("DrewText [%4d,%4d] @%d\n", y, x, __LINE__)); 4423 return x; 4424 } 4425#if OPT_BOX_CHARS 4426 /* 4427 * Draw some substitutions, if needed. The font may not include the 4428 * line-drawing set, or it may be incomplete (in which case we'll draw an 4429 * empty space via xtermDrawBoxChar), or we may be told to force our 4430 * line-drawing. 4431 * 4432 * The empty space is a special case which can be overridden with the 4433 * showMissingGlyphs resource to produce an outline. Not all fonts in 4434 * "modern" (sic) X provide an empty space; some use a thick outline or 4435 * something like the replacement character. If you would rather not see 4436 * that, you can set assumeAllChars. 4437 */ 4438 if (!IsIcon(screen) 4439 && !(recur.draw_flags & NOTRANSLATION) 4440 && (!screen->fnt_boxes 4441 || (FontIsIncomplete(curFont) && !screen->assume_all_chars) 4442 || recur.xw->work.force_wideFont 4443 || screen->force_box_chars)) { 4444 /* 4445 * Fill in missing box-characters. Find regions without missing 4446 * characters, and draw them calling ourselves recursively. Draw 4447 * missing characters via xtermDrawBoxChar(). 4448 */ 4449 int last, first = 0; 4450 Bool drewBoxes = False; 4451 4452 for (last = 0; last < (int) len; last++) { 4453 unsigned ch = (unsigned) text[last]; 4454 Bool isMissing; 4455 int ch_width; 4456#if OPT_WIDE_CHARS 4457 4458 if (ch == HIDDEN_CHAR) { 4459 if (last > first) { 4460 XTermDraw param2 = recur; 4461 param2.draw_flags |= NOTRANSLATION; 4462 x = drawXtermText(¶m2, 4463 gc, 4464 x, y, 4465 text + first, 4466 (unsigned) (last - first)); 4467 } 4468 first = last + 1; 4469 drewBoxes = True; 4470 continue; 4471 } 4472 ch_width = CharWidth(screen, ch); 4473 isMissing = 4474 IsXtermMissingChar(screen, ch, 4475 ((recur.on_wide || ch_width > 1) 4476 && okFont(NormalWFont(screen))) 4477 ? WhichVFontData(screen, fWide) 4478 : curFont); 4479#else 4480 isMissing = IsXtermMissingChar(screen, ch, curFont); 4481 ch_width = 1; 4482#endif 4483 /* 4484 * If the character is not missing, but we're in wide-character 4485 * mode and the character happens to be a wide-character that 4486 * corresponds to the line-drawing set, allow the forceBoxChars 4487 * resource (or menu entry) to force it to display using our 4488 * tables. 4489 */ 4490 if_OPT_WIDE_CHARS(screen, { 4491 if (!isMissing 4492 && TScreenOf(recur.xw)->force_box_chars) { 4493 if (ch > 255 4494 && ucs2dec(screen, ch) < 32) { 4495 ch = ucs2dec(screen, ch); 4496 isMissing = True; 4497 } else if (ch < 32) { 4498 isMissing = True; 4499 } 4500 } 4501 }); 4502 4503 if (isMissing) { 4504 if (last > first) { 4505 XTermDraw param2 = recur; 4506 param2.draw_flags |= NOTRANSLATION; 4507 x = drawXtermText(&recur, 4508 gc, 4509 x, y, 4510 text + first, 4511 (unsigned) (last - first)); 4512 } 4513#if OPT_WIDE_CHARS 4514 if (ch_width <= 0 && ch < 32) 4515 ch_width = 1; /* special case for line-drawing */ 4516 else if (ch_width < 0) 4517 ch_width = 1; /* special case for combining char */ 4518 if (!ucs_workaround(&recur, ch, gc, x, y)) { 4519 xtermDrawBoxChar(&recur, ch, gc, x, y, ch_width, False); 4520 } 4521#else 4522 xtermDrawBoxChar(&recur, ch, gc, x, y, ch_width, False); 4523#endif 4524 x += (ch_width * FontWidth(screen)); 4525 first = last + 1; 4526 drewBoxes = True; 4527 } else if (ch_width == 2 4528 && recur.xw->work.force_wideFont 4529 && !(recur.draw_flags & NOTRANSLATION)) { 4530 XTermDraw param2 = recur; 4531 param2.draw_flags |= NOTRANSLATION; 4532 /* 4533 * Not a "box" character, but a special case treated similarly. 4534 */ 4535 (void) drawXtermText(¶m2, 4536 gc, 4537 x, y, 4538 text + first, 4539 (unsigned) (1 + last - first)); 4540 x += (ch_width * FontWidth(screen)); 4541 first = last + 1; 4542 drewBoxes = True; 4543 } 4544 } 4545 if (last <= first) { 4546 TRACE(("DrewText [%4d,%4d] @%d\n", y, x, __LINE__)); 4547 return x; 4548 } 4549 text += first; 4550 len = (Cardinal) (last - first); 4551 recur.draw_flags |= NOTRANSLATION; 4552 if (drewBoxes) { 4553 x = drawXtermText(&recur, 4554 gc, 4555 x, 4556 y, 4557 text, 4558 len); 4559 TRACE(("DrewText [%4d,%4d] @%d\n", y, x, __LINE__)); 4560 return x; 4561 } 4562 } 4563#endif /* OPT_BOX_CHARS */ 4564 /* 4565 * Behave as if the font has (maybe Unicode-replacements for) drawing 4566 * characters in the range 1-31 (either we were not asked to ignore them, 4567 * or the caller made sure that there is none). 4568 */ 4569#if OPT_WIDE_ATTRS 4570#define AttrFlags() recur.attr_flags 4571#define DrawFlags() recur.draw_flags 4572#else 4573#define AttrFlags() (recur.attr_flags & DRAWX_MASK) 4574#define DrawFlags() (recur.draw_flags & (unsigned)~DRAWX_MASK) 4575#endif 4576 TRACE(("drawtext%c[%4d,%4d] {%#x,%#x} (%d) %d:%s\n", 4577 screen->cursor_state == OFF ? ' ' : '*', 4578 y, x, 4579 AttrFlags(), 4580 DrawFlags(), 4581 recur.this_chrset, len, 4582 visibleIChars(text, len))); 4583 if (screen->scale_height != 1.0f) { 4584 xtermFillCells(&recur, gc, x, y, (Cardinal) len); 4585 } 4586 y += FontAscent(screen); 4587 4588#if OPT_WIDE_CHARS 4589 4590 need_wide = False; 4591 if (screen->wide_chars || screen->unicode_font) { 4592 int src; 4593 for (src = 0; src < (int) len; src++) { 4594 IChar ch = text[src]; 4595 if (ch > 0xff) { 4596 need_wide = True; 4597 break; 4598 } 4599 } 4600 } 4601 4602 if (need_wide) { 4603 IChar *mapped; 4604 Bool needWide = False; 4605 int src, dst; 4606 Bool useBoldFont; 4607 int ascent_adjust = 0; 4608 4609 BumpTypedBuffer(XChar2b, len); 4610 BumpTypedBuffer(Char, len); 4611 BumpTypedBuffer(IChar, len); 4612 mapped = BfBuf(IChar); 4613 4614 /* transform characters first, to decide how to draw them */ 4615 for (src = 0; src < (int) len; src++) { 4616 IChar ch = text[src]; 4617 if (ch != HIDDEN_CHAR) { 4618#if OPT_BOX_CHARS 4619 if ((screen->fnt_boxes == 1) && (ch >= 256)) { 4620 unsigned part = ucs2dec(screen, ch); 4621 if (part < 32) 4622 ch = (IChar) part; 4623 } 4624#endif 4625#if OPT_MINI_LUIT 4626#define Map2Sbuf(from,to) (ch == from) { ch = to; } 4627 if (screen->latin9_mode && !screen->utf8_mode && ch < 256) { 4628 4629 /* see http://www.cs.tut.fi/~jkorpela/latin9.html */ 4630 /* *INDENT-OFF* */ 4631 if Map2Sbuf(0xa4, 0x20ac) 4632 else if Map2Sbuf(0xa6, 0x0160) 4633 else if Map2Sbuf(0xa8, 0x0161) 4634 else if Map2Sbuf(0xb4, 0x017d) 4635 else if Map2Sbuf(0xb8, 0x017e) 4636 else if Map2Sbuf(0xbc, 0x0152) 4637 else if Map2Sbuf(0xbd, 0x0153) 4638 else if Map2Sbuf(0xbe, 0x0178) 4639 /* *INDENT-ON* */ 4640 4641 } 4642 if (screen->unicode_font 4643 && (ch == ANSI_DEL || 4644 ch < ANSI_SPA)) { 4645 ch = (IChar) dec2ucs(screen, 4646 (unsigned) ((ch == ANSI_DEL) ? 0 : ch)); 4647 } 4648#endif /* OPT_MINI_LUIT */ 4649 } 4650 mapped[src] = ch; 4651 } 4652 4653 for (src = dst = 0; src < (int) len; src++) { 4654 IChar ch = mapped[src]; 4655 4656 if (ch != HIDDEN_CHAR) { 4657 int ch_width = CharWidth(screen, ch); 4658 if (!needWide 4659 && !IsIcon(screen) 4660 && ((recur.on_wide || ch_width > 1) 4661 && okFont(NormalWFont(screen)))) { 4662 needWide = True; 4663 } 4664 ++dst; 4665 } 4666 } 4667 4668 /* 4669 * Check for special case where the bold font lacks glyphs found in the 4670 * normal font, and drop down to normal fonts with overstriking to help 4671 * show the actual characters. 4672 */ 4673 useBoldFont = ((recur.attr_flags & BOLDATTR(screen)) != 0); 4674 if (useBoldFont) { 4675 XTermFonts *norm = 0; 4676 XTermFonts *bold = 0; 4677 Bool noBold, noNorm; 4678 4679 (void) norm; 4680 if (needWide && okFont(BoldWFont(screen))) { 4681 norm = WhichVFontData(screen, fWide); 4682 bold = WhichVFontData(screen, fWBold); 4683 } else if (okFont(BoldFont(screen))) { 4684 norm = WhichVFontData(screen, fNorm); 4685 bold = WhichVFontData(screen, fBold); 4686 } else { 4687 useBoldFont = False; 4688 } 4689 4690 if (useBoldFont && FontIsIncomplete(bold)) { 4691 for (src = 0; src < (int) len; src++) { 4692 IChar ch = mapped[src]; 4693 4694 if (ch == HIDDEN_CHAR) 4695 continue; 4696 4697 noBold = IsXtermMissingChar(screen, ch, bold); 4698 if (noBold) { 4699 noNorm = IsXtermMissingChar(screen, ch, norm); 4700 if (!noNorm) { 4701 useBoldFont = False; 4702 break; 4703 } 4704 } 4705 } 4706 } 4707 } 4708 4709 /* FIXME This is probably wrong. But it works. */ 4710 underline_len = len; 4711 4712 /* Set the drawing font */ 4713 if (!(recur.draw_flags & (DOUBLEHFONT | DOUBLEWFONT))) { 4714 VTwin *currentWin = WhichVWin(screen); 4715 VTFontEnum fntId; 4716 CgsEnum cgsId; 4717 Pixel fg = getCgsFore(recur.xw, currentWin, gc); 4718 Pixel bg = getCgsBack(recur.xw, currentWin, gc); 4719 4720 if (needWide 4721 && useBoldFont 4722 && okFont(BoldWFont(screen))) { 4723 fntId = fWBold; 4724 cgsId = gcWBold; 4725 } else if (needWide) { 4726 fntId = fWide; 4727 cgsId = gcWide; 4728 } else if (useBoldFont) { 4729 fntId = fBold; 4730 cgsId = gcBold; 4731 } else { 4732 fntId = fNorm; 4733 cgsId = gcNorm; 4734 } 4735 4736 setCgsFore(recur.xw, currentWin, cgsId, fg); 4737 setCgsBack(recur.xw, currentWin, cgsId, bg); 4738 gc = getCgsGC(recur.xw, currentWin, cgsId); 4739 4740#if OPT_WIDE_ATTRS 4741#if OPT_DEC_CHRSET 4742 if (!(CSET_DOUBLE(recur.this_chrset) || (recur.draw_flags & DOUBLEWFONT))) 4743#endif 4744 { 4745 need_clipping = fixupItalics(&recur, 4746 gc, 4747 getCgsFont(recur.xw, 4748 currentWin, gc), 4749 y, x, font_width, len); 4750 } 4751#endif 4752 if (fntId != fNorm) { 4753 XFontStruct *thisFp = WhichVFont(screen, fntId); 4754 ascent_adjust = (thisFp->ascent 4755 - NormalFont(screen)->ascent); 4756 if (thisFp->max_bounds.width == 4757 NormalFont(screen)->max_bounds.width * 2) { 4758 underline_len = real_length = (Cardinal) (dst * 2); 4759 } else if (cgsId == gcWide || cgsId == gcWBold) { 4760 underline_len = real_length = (Cardinal) (dst * 2); 4761 xtermFillCells(&recur, 4762 gc, 4763 x, 4764 y - thisFp->ascent, 4765 real_length); 4766 } 4767 } 4768 } 4769 4770 xtermFullString16(recur.xw, recur.draw_flags, gc, 4771 x, y + y_shift + ascent_adjust, dst); 4772#if OPT_WIDE_ATTRS 4773 if (need_clipping) { 4774 endClipping(screen, gc); 4775 } 4776#endif 4777 4778 if ((recur.attr_flags & BOLDATTR(screen)) && (screen->enbolden || !useBoldFont)) { 4779 if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) { 4780 beginClipping(screen, gc, (Cardinal) font_width, len); 4781 } 4782 xtermFullString16(recur.xw, recur.draw_flags | NOBACKGROUND, 4783 gc, x + 1, y + y_shift + ascent_adjust, dst); 4784 if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) { 4785 endClipping(screen, gc); 4786 } 4787 } 4788 4789 } else 4790#endif /* OPT_WIDE_CHARS */ 4791 { 4792 IChar *mapped; 4793 Cardinal dst; 4794 4795 BumpTypedBuffer(IChar, len); 4796 BumpTypedBuffer(Char, len); 4797 4798 mapped = BfBuf(IChar); 4799 for (dst = 0; dst < len; ++dst) 4800 mapped[dst] = text[dst]; 4801 4802#if OPT_WIDE_ATTRS 4803#if OPT_DEC_CHRSET 4804 if (!(CSET_DOUBLE(recur.this_chrset) || (recur.draw_flags & DOUBLEWFONT))) 4805#endif 4806 { 4807 need_clipping = fixupItalics(&recur, gc, curFont, 4808 y, x, font_width, len); 4809 } 4810#endif 4811 4812 xtermDrawString(screen, recur.draw_flags, gc, 4813 x, y + y_shift, (int) len); 4814 4815#if OPT_WIDE_ATTRS 4816 if (need_clipping) { 4817 endClipping(screen, gc); 4818 } 4819#endif 4820 underline_len = len; 4821 if ((recur.attr_flags & BOLDATTR(screen)) && screen->enbolden) { 4822 if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) { 4823 beginClipping(screen, gc, font_width, (int) len); 4824 } 4825 xtermDrawString(screen, (recur.draw_flags | NOBACKGROUND), 4826 gc, x + 1, y + y_shift, (int) len); 4827 if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) { 4828 endClipping(screen, gc); 4829 } 4830 } 4831 } 4832 4833 drawUnderline(recur.xw, 4834 gc, 4835 recur.attr_flags, 4836 underline_len, 4837 font_width, 4838 x, 4839 y + y_shift, 4840 did_ul); 4841 4842 x += ((int) real_length) * FontWidth(screen); 4843 TRACE(("DrewText [%4d,%4d] @%d\n", y, x, __LINE__)); 4844 return x; 4845} 4846 4847#if OPT_WIDE_CHARS 4848/* 4849 * Allocate buffer - workaround for wide-character interfaces. 4850 */ 4851void 4852allocXtermChars(ScrnPtr *buffer, Cardinal length) 4853{ 4854 if (*buffer == 0) { 4855 *buffer = (ScrnPtr) XtMalloc(length); 4856 } else { 4857 *buffer = (ScrnPtr) XtRealloc((char *) *buffer, length); 4858 } 4859} 4860#endif 4861 4862/* set up size hints for window manager; min 1 char by 1 char */ 4863void 4864xtermSizeHints(XtermWidget xw, int scrollbarWidth) 4865{ 4866 TScreen *screen = TScreenOf(xw); 4867 4868 TRACE(("xtermSizeHints\n")); 4869 TRACE((" border %d\n", xw->core.border_width)); 4870 TRACE((" scrollbar %d\n", scrollbarWidth)); 4871 4872 xw->hints.base_width = 2 * screen->border + scrollbarWidth; 4873 xw->hints.base_height = 2 * screen->border; 4874 4875#if OPT_TOOLBAR 4876 TRACE((" toolbar %d\n", ToolbarHeight(xw))); 4877 4878 xw->hints.base_height += ToolbarHeight(xw); 4879 xw->hints.base_height += BorderWidth(xw) * 2; 4880 xw->hints.base_width += BorderWidth(xw) * 2; 4881#endif 4882 4883 if (xw->misc.resizeByPixel) { 4884 xw->hints.width_inc = 1; 4885 xw->hints.height_inc = 1; 4886 } else { 4887 xw->hints.width_inc = FontWidth(screen); 4888 xw->hints.height_inc = FontHeight(screen); 4889 } 4890 xw->hints.min_width = xw->hints.base_width + xw->hints.width_inc; 4891 xw->hints.min_height = xw->hints.base_height + xw->hints.height_inc; 4892 4893 xw->hints.width = MaxCols(screen) * FontWidth(screen) + xw->hints.min_width; 4894 xw->hints.height = MaxRows(screen) * FontHeight(screen) + xw->hints.min_height; 4895 4896 xw->hints.flags |= (PSize | PBaseSize | PMinSize | PResizeInc); 4897 4898 TRACE_HINTS(&(xw->hints)); 4899} 4900 4901void 4902getXtermSizeHints(XtermWidget xw) 4903{ 4904 TScreen *screen = TScreenOf(xw); 4905 long supp; 4906 4907 if (!XGetWMNormalHints(screen->display, VShellWindow(xw), 4908 &xw->hints, &supp)) 4909 memset(&xw->hints, 0, sizeof(xw->hints)); 4910 TRACE_HINTS(&(xw->hints)); 4911} 4912 4913CgsEnum 4914whichXtermCgs(XtermWidget xw, unsigned attr_flags, Bool hilite) 4915{ 4916 TScreen *screen = TScreenOf(xw); 4917 CgsEnum cgsId = gcMAX; 4918 4919 if (ReverseOrHilite(screen, attr_flags, hilite)) { 4920 if (attr_flags & BOLDATTR(screen)) { 4921 cgsId = gcBoldReverse; 4922 } else { 4923 cgsId = gcNormReverse; 4924 } 4925 } else { 4926 if (attr_flags & BOLDATTR(screen)) { 4927 cgsId = gcBold; 4928 } else { 4929 cgsId = gcNorm; 4930 } 4931 } 4932 return cgsId; 4933} 4934 4935/* 4936 * Returns a GC, selected according to the font (reverse/bold/normal) that is 4937 * required for the current position (implied). The GC is updated with the 4938 * current screen foreground and background colors. 4939 */ 4940GC 4941updatedXtermGC(XtermWidget xw, unsigned attr_flags, CellColor fg_bg, 4942 Bool hilite) 4943{ 4944 TScreen *screen = TScreenOf(xw); 4945 VTwin *win = WhichVWin(screen); 4946 CgsEnum cgsId = whichXtermCgs(xw, attr_flags, hilite); 4947 Pixel my_fg = extract_fg(xw, fg_bg, attr_flags); 4948 Pixel my_bg = extract_bg(xw, fg_bg, attr_flags); 4949 Pixel fg_pix = getXtermFG(xw, attr_flags, (int) my_fg); 4950 Pixel bg_pix = getXtermBG(xw, attr_flags, (int) my_bg); 4951 Pixel xx_pix; 4952#if OPT_HIGHLIGHT_COLOR 4953 Boolean reverse2 = ((attr_flags & INVERSE) && hilite); 4954 Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG); 4955 Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG); 4956 Boolean always = screen->hilite_color; 4957 Boolean use_selbg = (Boolean) (always && 4958 isNotForeground(xw, fg_pix, bg_pix, selbg_pix)); 4959 Boolean use_selfg = (Boolean) (always && 4960 isNotBackground(xw, fg_pix, bg_pix, selfg_pix)); 4961#endif 4962 4963 (void) fg_bg; 4964 (void) my_bg; 4965 (void) my_fg; 4966 4967 /* 4968 * Discard video attributes overridden by colorXXXMode's. 4969 */ 4970 checkVeryBoldColors(attr_flags, my_fg); 4971 4972 if (ReverseOrHilite(screen, attr_flags, hilite)) { 4973#if OPT_HIGHLIGHT_COLOR 4974 if (!screen->hilite_color) { 4975 if (selbg_pix != T_COLOR(screen, TEXT_FG) 4976 && selbg_pix != fg_pix 4977 && selbg_pix != bg_pix 4978 && selbg_pix != xw->dft_foreground) { 4979 bg_pix = fg_pix; 4980 fg_pix = selbg_pix; 4981 } 4982 } 4983#endif 4984 EXCHANGE(fg_pix, bg_pix, xx_pix); 4985#if OPT_HIGHLIGHT_COLOR 4986 if (screen->hilite_color) { 4987 if (screen->hilite_reverse) { 4988 if (use_selbg) { 4989 if (use_selfg) { 4990 bg_pix = fg_pix; 4991 } else { 4992 fg_pix = bg_pix; 4993 bg_pix = selbg_pix; 4994 } 4995 } 4996 if (use_selfg) 4997 fg_pix = selfg_pix; 4998 } 4999 } 5000#endif 5001 } else if ((attr_flags & INVERSE) && hilite) { 5002#if OPT_HIGHLIGHT_COLOR 5003 if (!screen->hilite_color) { 5004 if (selbg_pix != T_COLOR(screen, TEXT_FG) 5005 && selbg_pix != fg_pix 5006 && selbg_pix != bg_pix 5007 && selbg_pix != xw->dft_foreground) { 5008 bg_pix = fg_pix; 5009 fg_pix = selbg_pix; 5010 } 5011 } 5012#endif 5013 /* double-reverse... EXCHANGE(fg_pix, bg_pix, xx_pix); */ 5014#if OPT_HIGHLIGHT_COLOR 5015 if (screen->hilite_color) { 5016 if (screen->hilite_reverse) { 5017 if (use_selbg) { 5018 if (use_selfg ^ reverse2) { 5019 bg_pix = fg_pix; 5020 } else { 5021 fg_pix = bg_pix; 5022 } 5023 if (reverse2) { 5024 fg_pix = selbg_pix; 5025 } else { 5026 bg_pix = selbg_pix; 5027 } 5028 } 5029 if (use_selfg) { 5030 if (reverse2) { 5031 bg_pix = selfg_pix; 5032 } else { 5033 fg_pix = selfg_pix; 5034 } 5035 } 5036 } 5037 } 5038#endif 5039 } 5040#if OPT_HIGHLIGHT_COLOR 5041 if (!screen->hilite_color || !screen->hilite_reverse) { 5042 if (hilite && !screen->hilite_reverse) { 5043 if (use_selbg) { 5044 if (reverse2) 5045 fg_pix = selbg_pix; 5046 else 5047 bg_pix = selbg_pix; 5048 } 5049 if (use_selfg) { 5050 if (reverse2) 5051 bg_pix = selfg_pix; 5052 else 5053 fg_pix = selfg_pix; 5054 } 5055 } 5056 } 5057#endif 5058 5059#if OPT_BLINK_TEXT 5060 if ((screen->blink_state == ON) && 5061 (!screen->blink_as_bold) && 5062 (attr_flags & BLINK)) { 5063 fg_pix = bg_pix; 5064 } 5065#endif 5066 5067 setCgsFore(xw, win, cgsId, fg_pix); 5068 setCgsBack(xw, win, cgsId, bg_pix); 5069 return getCgsGC(xw, win, cgsId); 5070} 5071 5072/* 5073 * Resets the foreground/background of the GC returned by 'updatedXtermGC()' 5074 * to the values that would be set in SGR_Foreground and SGR_Background. This 5075 * duplicates some logic, but only modifies 1/4 as many GC's. 5076 */ 5077void 5078resetXtermGC(XtermWidget xw, unsigned attr_flags, Bool hilite) 5079{ 5080 TScreen *screen = TScreenOf(xw); 5081 VTwin *win = WhichVWin(screen); 5082 CgsEnum cgsId = whichXtermCgs(xw, attr_flags, hilite); 5083 Pixel fg_pix = getXtermFG(xw, attr_flags, xw->cur_foreground); 5084 Pixel bg_pix = getXtermBG(xw, attr_flags, xw->cur_background); 5085 5086 checkVeryBoldColors(attr_flags, xw->cur_foreground); 5087 5088 if (ReverseOrHilite(screen, attr_flags, hilite)) { 5089 setCgsFore(xw, win, cgsId, bg_pix); 5090 setCgsBack(xw, win, cgsId, fg_pix); 5091 } else { 5092 setCgsFore(xw, win, cgsId, fg_pix); 5093 setCgsBack(xw, win, cgsId, bg_pix); 5094 } 5095} 5096 5097#if OPT_ISO_COLORS 5098/* 5099 * Extract the foreground-color index from a color pair. 5100 * If we've got BOLD or UNDERLINE color-mode active, those will be used. 5101 */ 5102Pixel 5103extract_fg(XtermWidget xw, CellColor color, unsigned attr_flags) 5104{ 5105 unsigned fg = ExtractForeground(color); 5106 5107 if (TScreenOf(xw)->colorAttrMode 5108 || (fg == ExtractBackground(color))) { 5109 fg = MapToColorMode(fg, TScreenOf(xw), attr_flags); 5110 } 5111 return fg; 5112} 5113 5114/* 5115 * Extract the background-color index from a color pair. 5116 * If we've got INVERSE color-mode active, that will be used. 5117 */ 5118Pixel 5119extract_bg(XtermWidget xw, CellColor color, unsigned attr_flags) 5120{ 5121 unsigned bg = ExtractBackground(color); 5122 5123 if (TScreenOf(xw)->colorAttrMode 5124 || (bg == ExtractForeground(color))) { 5125 if (TScreenOf(xw)->colorRVMode && (attr_flags & INVERSE)) 5126 bg = COLOR_RV; 5127 } 5128 return bg; 5129} 5130 5131/* 5132 * Combine the current foreground and background into a single 8-bit number. 5133 * Note that we're storing the SGR foreground, since cur_foreground may be set 5134 * to COLOR_UL, COLOR_BD or COLOR_BL, which would make the code larger than 8 5135 * bits. 5136 * 5137 * This assumes that fg/bg are equal when we override with one of the special 5138 * attribute colors. 5139 */ 5140CellColor 5141makeColorPair(XtermWidget xw) 5142{ 5143 CellColor result; 5144 5145#if OPT_DIRECT_COLOR 5146 result.fg = xw->cur_foreground; 5147 result.bg = xw->cur_background; 5148#else 5149 int fg = xw->cur_foreground; 5150 int bg = xw->cur_background; 5151 unsigned my_bg = okIndexedColor(bg) ? (unsigned) bg : 0; 5152 unsigned my_fg = okIndexedColor(fg) ? (unsigned) fg : my_bg; 5153 5154 result = (CellColor) (my_fg | (my_bg << COLOR_BITS)); 5155#endif 5156 5157 return result; 5158} 5159 5160/* 5161 * Using the "current" SGR background, clear a rectangle. 5162 */ 5163void 5164ClearCurBackground(XtermWidget xw, 5165 int top, 5166 int left, 5167 unsigned height, 5168 unsigned width, 5169 unsigned fw) 5170{ 5171 TScreen *screen = TScreenOf(xw); 5172 int actual_rows = PlusStatusLine(screen, screen->max_row + 1); 5173 Boolean visible = (((int) width > 0) 5174 && ((left + (int) width) <= screen->max_col + 1) 5175 && (((int) height + top) <= actual_rows)); 5176 5177 TRACE(("ClearCurBackground %d,%d %dx%d%s with %d %s\n", 5178 top, left, height, width, 5179 IsStatusShown(screen) ? "*" : "", 5180 xw->cur_background, 5181 visible ? "(ok)" : "(err)")); 5182 5183 if (VWindow(screen) && visible) { 5184 set_background(xw, xw->cur_background); 5185 5186 xtermClear2(xw, 5187 CursorX2(screen, left, fw), 5188 CursorY2(screen, top), 5189 (width * fw), 5190 (height * (unsigned) FontHeight(screen))); 5191 5192 set_background(xw, -1); 5193 } 5194} 5195#endif /* OPT_ISO_COLORS */ 5196 5197Pixel 5198getXtermBackground(XtermWidget xw, unsigned attr_flags, int color) 5199{ 5200 Pixel result = T_COLOR(TScreenOf(xw), TEXT_BG); 5201 5202#if OPT_ISO_COLORS 5203 if (color >= 0) { 5204 if_OPT_DIRECT_COLOR2_else(TScreenOf(xw), (attr_flags & ATR_DIRECT_BG), { 5205 result = (Pixel) color; 5206 }) if ((attr_flags & BG_COLOR) && (color < MAXCOLORS)) { 5207 result = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[color]); 5208 } 5209 } 5210#else 5211 (void) attr_flags; 5212 (void) color; 5213#endif 5214 return result; 5215} 5216 5217#if OPT_ISO_COLORS && OPT_WIDE_ATTRS 5218#if OPT_SGR2_HASH 5219typedef struct _DimColorHT { 5220 Pixel org; 5221 Pixel dim; 5222} DimColorHT; 5223 5224static unsigned 5225jhash1(unsigned char *key, size_t len) 5226{ 5227 unsigned hash; 5228 size_t i; 5229 5230 for (hash = 0, i = 0; i < len; ++i) { 5231 hash += key[i]; 5232 hash += (hash << 10); 5233 hash ^= (hash >> 6); 5234 } 5235 hash += (hash << 3); 5236 hash ^= (hash >> 11); 5237 hash += (hash << 15); 5238 return hash; 5239} 5240 5241static unsigned 5242computeFaint(XtermWidget xw, unsigned value, unsigned compare) 5243{ 5244 TScreen *screen = TScreenOf(xw); 5245 if (screen->faint_relative) { 5246 value = (unsigned) ((value + compare) / 2); 5247 } else { 5248 value = (unsigned) ((2 * value) / 3); 5249 } 5250 return value; 5251} 5252#endif /* OPT_SGR2_HASH */ 5253#endif /* OPT_ISO_COLORS && OPT_WIDE_ATTRS */ 5254 5255Pixel 5256getXtermForeground(XtermWidget xw, unsigned attr_flags, int color) 5257{ 5258 Pixel result = T_COLOR(TScreenOf(xw), TEXT_FG); 5259 5260#if OPT_ISO_COLORS 5261 if_OPT_DIRECT_COLOR2_else(TScreenOf(xw), (attr_flags & ATR_DIRECT_FG), { 5262 result = (Pixel) color; 5263 }) 5264 if ((attr_flags & FG_COLOR) && 5265 (color >= 0 && color < MAXCOLORS)) { 5266 result = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[color]); 5267 } 5268#else 5269 (void) attr_flags; 5270 (void) color; 5271#endif 5272 5273#if OPT_ISO_COLORS && OPT_WIDE_ATTRS 5274 if ((attr_flags & ATR_FAINT)) { 5275#if OPT_SGR2_HASH 5276#define DIM_IT(n) work.n = (unsigned short) computeFaint(xw, work.n, bkg.n) 5277#define SizeOfHT ((unsigned) sizeof(unsigned long) * CHAR_BIT) 5278 static DimColorHT ht[SizeOfHT]; 5279 Pixel bg = T_COLOR(TScreenOf(xw), TEXT_BG); 5280 XColor work; 5281 Pixel p; 5282 5283 if ((color >= 0) 5284 || (result != (Pixel) color)) { 5285 static unsigned long have = 0; 5286 static Boolean have_bg = False; 5287 static XColor bkg; 5288 5289 /* cache bkg color in r/g/b */ 5290 if (!have_bg || bg != bkg.pixel) { 5291 bkg.pixel = bg; 5292 have_bg = QueryOneColor(xw, &bkg); 5293 have = 0; /* invalidate color cache */ 5294 } 5295 if (have_bg) { 5296 unsigned hv; 5297 hv = jhash1((unsigned char *) &result, sizeof(result)); 5298 hv %= SizeOfHT; 5299 5300 if ((have & (1UL << hv)) 5301 && ht[hv].org == result) { 5302 result = ht[hv].dim; /* return cached color */ 5303 } else { 5304 work.pixel = result; 5305 if (QueryOneColor(xw, &work)) { 5306 DIM_IT(red); 5307 DIM_IT(green); 5308 DIM_IT(blue); 5309 p = result; 5310 if (allocateBestRGB(xw, &work)) { 5311 result = work.pixel; 5312 } 5313 5314 /* cache the result */ 5315 have |= (1UL << hv); 5316 ht[hv].org = p; 5317 ht[hv].dim = result; 5318 } 5319 } 5320 } 5321 } 5322#else /* !OPT_SGR2_HASH */ 5323#define DIM_IT(n) work.n = (unsigned short) ((2 * (unsigned)work.n) / 3) 5324 static Pixel last_in; 5325 static Pixel last_out; 5326 if ((result != last_in) 5327 && ((color >= 0) 5328 || (result != (Pixel) color))) { 5329 XColor work; 5330 last_in = result; 5331 work.pixel = result; 5332 if (QueryOneColor(xw, &work)) { 5333 DIM_IT(red); 5334 DIM_IT(green); 5335 DIM_IT(blue); 5336 if (allocateBestRGB(xw, &work)) { 5337 result = work.pixel; 5338 } 5339 } 5340 last_out = result; 5341 } else { 5342 result = last_out; 5343 } 5344#endif /* OPT_SGR2_HASH */ 5345 } 5346#endif 5347 return result; 5348} 5349 5350/* 5351 * Returns a single base character for the given cell. 5352 */ 5353unsigned 5354getXtermCell(TScreen *screen, int row, int col) 5355{ 5356 CLineData *ld = getLineData(screen, row); 5357 5358 return ((ld && (col < (int) ld->lineSize)) 5359 ? ld->charData[col] 5360 : (unsigned) ' '); 5361} 5362 5363/* 5364 * Sets a single base character for the given cell. 5365 */ 5366void 5367putXtermCell(TScreen *screen, int row, int col, int ch) 5368{ 5369 LineData *ld = getLineData(screen, row); 5370 5371 if (ld && (col < (int) ld->lineSize)) { 5372 ld->charData[col] = (CharData) ch; 5373 if_OPT_WIDE_CHARS(screen, { 5374 size_t off; 5375 for_each_combData(off, ld) { 5376 ld->combData[off][col] = 0; 5377 } 5378 }); 5379 } 5380} 5381 5382#if OPT_WIDE_CHARS 5383/* 5384 * Add a combining character for the given cell 5385 */ 5386void 5387addXtermCombining(TScreen *screen, int row, int col, unsigned ch) 5388{ 5389 if (ch != 0) { 5390 LineData *ld = getLineData(screen, row); 5391 size_t off; 5392 5393 TRACE(("addXtermCombining %d,%d U+%04X (%d)\n", 5394 row, col, ch, CharWidth(screen, ch))); 5395 5396 for_each_combData(off, ld) { 5397 if (!ld->combData[off][col]) { 5398 ld->combData[off][col] = (CharData) ch; 5399 break; 5400 } 5401 } 5402 } 5403} 5404 5405unsigned 5406getXtermCombining(TScreen *screen, int row, int col, int off) 5407{ 5408 CLineData *ld = getLineData(screen, row); 5409 return (ld->combSize ? ld->combData[off][col] : 0U); 5410} 5411#endif 5412 5413void 5414update_keyboard_type(void) 5415{ 5416 update_delete_del(); 5417 update_tcap_fkeys(); 5418 update_old_fkeys(); 5419 update_hp_fkeys(); 5420 update_sco_fkeys(); 5421 update_sun_fkeys(); 5422 update_sun_kbd(); 5423} 5424 5425void 5426set_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set) 5427{ 5428 xtermKeyboardType save = xw->keyboard.type; 5429 5430 TRACE(("set_keyboard_type(%s, %s) currently %s\n", 5431 visibleKeyboardType(type), 5432 BtoS(set), 5433 visibleKeyboardType(xw->keyboard.type))); 5434 if (set) { 5435 xw->keyboard.type = type; 5436 } else { 5437 xw->keyboard.type = keyboardIsDefault; 5438 } 5439 5440 if (save != xw->keyboard.type) { 5441 update_keyboard_type(); 5442 } 5443} 5444 5445void 5446toggle_keyboard_type(XtermWidget xw, xtermKeyboardType type) 5447{ 5448 xtermKeyboardType save = xw->keyboard.type; 5449 5450 TRACE(("toggle_keyboard_type(%s) currently %s\n", 5451 visibleKeyboardType(type), 5452 visibleKeyboardType(xw->keyboard.type))); 5453 if (xw->keyboard.type == type) { 5454 xw->keyboard.type = keyboardIsDefault; 5455 } else { 5456 xw->keyboard.type = type; 5457 } 5458 5459 if (save != xw->keyboard.type) { 5460 update_keyboard_type(); 5461 } 5462} 5463 5464const char * 5465visibleKeyboardType(xtermKeyboardType type) 5466{ 5467 const char *result = "?"; 5468 switch (type) { 5469 CASETYPE(keyboardIsLegacy); /* bogus vt220 codes for F1-F4, etc. */ 5470 CASETYPE(keyboardIsDefault); 5471 CASETYPE(keyboardIsHP); 5472 CASETYPE(keyboardIsSCO); 5473 CASETYPE(keyboardIsSun); 5474 CASETYPE(keyboardIsTermcap); 5475 CASETYPE(keyboardIsVT220); 5476 } 5477 return result; 5478} 5479 5480static void 5481init_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set) 5482{ 5483 TRACE(("init_keyboard_type(%s, %s) currently %s\n", 5484 visibleKeyboardType(type), 5485 BtoS(set), 5486 visibleKeyboardType(xw->keyboard.type))); 5487 if (set) { 5488 /* 5489 * Check for conflicts, e.g., if someone asked for both Sun and HP 5490 * function keys. 5491 */ 5492 if (guard_keyboard_type) { 5493 xtermWarning("Conflicting keyboard type option (%s/%s)\n", 5494 visibleKeyboardType(xw->keyboard.type), 5495 visibleKeyboardType(type)); 5496 } 5497 xw->keyboard.type = type; 5498 guard_keyboard_type = True; 5499 update_keyboard_type(); 5500 } 5501} 5502 5503/* 5504 * If the keyboardType resource is set, use that, overriding the individual 5505 * boolean resources for different keyboard types. 5506 */ 5507void 5508decode_keyboard_type(XtermWidget xw, XTERM_RESOURCE * rp) 5509{ 5510#define DATA(n, t, f) { n, t, XtOffsetOf(XTERM_RESOURCE, f) } 5511#define FLAG(n) *(Boolean *)(((char *)rp) + table[n].offset) 5512 static struct { 5513 const char *name; 5514 xtermKeyboardType type; 5515 unsigned offset; 5516 } table[] = { 5517 DATA(NAME_OLD_KT, keyboardIsLegacy, oldKeyboard), 5518#if OPT_HP_FUNC_KEYS 5519 DATA(NAME_HP_KT, keyboardIsHP, hpFunctionKeys), 5520#endif 5521#if OPT_SCO_FUNC_KEYS 5522 DATA(NAME_SCO_KT, keyboardIsSCO, scoFunctionKeys), 5523#endif 5524#if OPT_SUN_FUNC_KEYS 5525 DATA(NAME_SUN_KT, keyboardIsSun, sunFunctionKeys), 5526#endif 5527#if OPT_SUNPC_KBD 5528 DATA(NAME_VT220_KT, keyboardIsVT220, sunKeyboard), 5529#endif 5530#if OPT_TCAP_FKEYS 5531 DATA(NAME_TCAP_KT, keyboardIsTermcap, termcapKeys), 5532#endif 5533 }; 5534 Cardinal n; 5535 TScreen *screen = TScreenOf(xw); 5536 5537 TRACE(("decode_keyboard_type(%s)\n", rp->keyboardType)); 5538 if (!x_strcasecmp(rp->keyboardType, "unknown")) { 5539 /* 5540 * Let the individual resources comprise the keyboard-type. 5541 */ 5542 for (n = 0; n < XtNumber(table); ++n) 5543 init_keyboard_type(xw, table[n].type, FLAG(n)); 5544 } else if (!x_strcasecmp(rp->keyboardType, "default")) { 5545 /* 5546 * Set the keyboard-type to the Sun/PC type, allowing modified 5547 * function keys, etc. 5548 */ 5549 for (n = 0; n < XtNumber(table); ++n) 5550 init_keyboard_type(xw, table[n].type, False); 5551 } else { 5552 Bool found = False; 5553 5554 /* 5555 * Special case: oldXtermFKeys should have been like the others. 5556 */ 5557 if (!x_strcasecmp(rp->keyboardType, NAME_OLD_KT)) { 5558 TRACE(("special case, setting oldXtermFKeys\n")); 5559 screen->old_fkeys = True; 5560 screen->old_fkeys0 = True; 5561 } 5562 5563 /* 5564 * Choose an individual keyboard type. 5565 */ 5566 for (n = 0; n < XtNumber(table); ++n) { 5567 if (!x_strcasecmp(rp->keyboardType, table[n].name + 1)) { 5568 FLAG(n) = True; 5569 found = True; 5570 } else { 5571 FLAG(n) = False; 5572 } 5573 init_keyboard_type(xw, table[n].type, FLAG(n)); 5574 } 5575 if (!found) { 5576 xtermWarning("KeyboardType resource \"%s\" not found\n", 5577 rp->keyboardType); 5578 } 5579 } 5580#undef DATA 5581#undef FLAG 5582} 5583 5584#if OPT_WIDE_CHARS 5585#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH) 5586/* 5587 * If xterm is running in a UTF-8 locale, it is still possible to encounter 5588 * old runtime configurations which yield incomplete or inaccurate data. 5589 */ 5590static Bool 5591systemWcwidthOk(int samplesize, int samplepass) 5592{ 5593 wchar_t n; 5594 int oops = 0; 5595 5596 for (n = 21; n <= 25; ++n) { 5597 wchar_t code = (wchar_t) dec2ucs(NULL, (unsigned) n); 5598 int system_code = wcwidth(code); 5599 int intern_code = mk_wcwidth(code); 5600 5601 /* 5602 * Solaris 10 wcwidth() returns "2" for all of the line-drawing (page 5603 * 0x2500) and most of the geometric shapes (a few are excluded, just 5604 * to make it more difficult to use). Do a sanity check to avoid using 5605 * it. 5606 */ 5607 if ((system_code < 0 && intern_code >= 1) 5608 || (system_code >= 0 && intern_code != system_code)) { 5609 TRACE(("systemWcwidthOk: broken system line-drawing wcwidth\n")); 5610 oops += (samplepass + 1); 5611 break; 5612 } 5613 } 5614 5615 for (n = 0; n < (wchar_t) samplesize; ++n) { 5616 int system_code = wcwidth(n); 5617 int intern_code = mk_wcwidth(n); 5618 5619 /* 5620 * When this check was originally implemented, there were few if any 5621 * libraries with full Unicode coverage. Time passes, and it is 5622 * possible to make a full comparison of the BMP. There are some 5623 * differences: mk_wcwidth() marks some codes as combining and some 5624 * as single-width, differing from GNU libc. 5625 */ 5626 if ((system_code < 0 && intern_code >= 1) 5627 || (system_code >= 0 && intern_code != system_code)) { 5628 TRACE((".. width(U+%04X) = %d, expected %d\n", 5629 (unsigned) n, system_code, intern_code)); 5630 if (++oops > samplepass) 5631 break; 5632 } 5633 } 5634 TRACE(("systemWcwidthOk: %d/%d mismatches, allowed %d\n", 5635 oops, (int) n, samplepass)); 5636 return (oops <= samplepass); 5637} 5638#endif /* HAVE_WCWIDTH */ 5639 5640void 5641decode_wcwidth(XtermWidget xw) 5642{ 5643 int mode = ((xw->misc.cjk_width ? 2 : 0) 5644 + (xw->misc.mk_width ? 1 : 0) 5645 + 1); 5646 5647 switch (mode) { 5648 default: 5649#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH) 5650 if (xtermEnvUTF8() && 5651 systemWcwidthOk(xw->misc.mk_samplesize, xw->misc.mk_samplepass)) { 5652 my_wcwidth = wcwidth; 5653 TRACE(("using system wcwidth() function\n")); 5654 break; 5655 } 5656#endif 5657 /* FALLTHRU */ 5658 case 2: 5659 my_wcwidth = &mk_wcwidth; 5660 TRACE(("using MK wcwidth() function\n")); 5661 break; 5662 case 3: 5663 /* FALLTHRU */ 5664 case 4: 5665 my_wcwidth = &mk_wcwidth_cjk; 5666 TRACE(("using MK-CJK wcwidth() function\n")); 5667 break; 5668 } 5669 5670 for (first_widechar = 128; first_widechar < 4500; ++first_widechar) { 5671 if (my_wcwidth((wchar_t) first_widechar) > 1) { 5672 TRACE(("first_widechar %#x\n", first_widechar)); 5673 break; 5674 } 5675 } 5676} 5677#endif 5678 5679/* 5680 * Extend a (normally) boolean resource value by checking for additional values 5681 * which will be mapped into true/false. 5682 */ 5683int 5684extendedBoolean(const char *value, const FlagList * table, Cardinal limit) 5685{ 5686 int result = -1; 5687 long check; 5688 char *next; 5689 Cardinal n; 5690 5691 if ((x_strcasecmp(value, "true") == 0) 5692 || (x_strcasecmp(value, "yes") == 0) 5693 || (x_strcasecmp(value, "on") == 0)) { 5694 result = True; 5695 } else if ((x_strcasecmp(value, "false") == 0) 5696 || (x_strcasecmp(value, "no") == 0) 5697 || (x_strcasecmp(value, "off") == 0)) { 5698 result = False; 5699 } else if ((check = strtol(value, &next, 0)) >= 0 && FullS2L(value, next)) { 5700 if (check >= (long) limit) /* i.e., past False=0, True=1 */ 5701 check = True; 5702 result = (int) check; 5703 } else { 5704 for (n = 0; n < limit - 2; ++n) { 5705 if (table[n].name == NULL) { 5706 break; 5707 } else if (x_strcasecmp(value, table[n].name) == 0) { 5708 result = table[n].code; 5709 break; 5710 } 5711 } 5712 } 5713 5714 if (result < 0) { 5715 xtermWarning("Unrecognized keyword: %s\n", value); 5716 result = False; 5717 } 5718 5719 TRACE(("extendedBoolean(%s) = %d\n", value, result)); 5720 return result; 5721} 5722 5723/* 5724 * Something like round() from math library, but round() is less widely-used 5725 * than xterm. Also, there are no negative numbers to complicate this. 5726 */ 5727int 5728dimRound(double value) 5729{ 5730 int result = (int) value; 5731 if (result < value) 5732 ++result; 5733 return result; 5734} 5735 5736/* 5737 * Find the geometry of the specified Xinerama screen 5738 */ 5739static void 5740find_xinerama_screen(Display *display, int screen, struct Xinerama_geometry *ret) 5741{ 5742#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H 5743 XineramaScreenInfo *screens; 5744 int nb_screens; 5745 5746 if (screen == -1) /* already inited */ 5747 return; 5748 screens = XineramaQueryScreens(display, &nb_screens); 5749 if (screen >= nb_screens) { 5750 xtermWarning("Xinerama screen %d does not exist\n", screen); 5751 return; 5752 } 5753 if (screen == -2) { 5754 int ptr_x, ptr_y; 5755 int dummy_int, i; 5756 unsigned dummy_uint; 5757 Window dummy_win; 5758 if (nb_screens == 0) 5759 return; 5760 XQueryPointer(display, DefaultRootWindow(display), 5761 &dummy_win, &dummy_win, 5762 &ptr_x, &ptr_y, 5763 &dummy_int, &dummy_int, &dummy_uint); 5764 for (i = 0; i < nb_screens; i++) { 5765 if ((ptr_x - screens[i].x_org) < screens[i].width && 5766 (ptr_y - screens[i].y_org) < screens[i].height) { 5767 screen = i; 5768 break; 5769 } 5770 } 5771 if (screen < 0) { 5772 xtermWarning("Mouse not in any Xinerama screen, using 0\n"); 5773 screen = 0; 5774 } 5775 } 5776 ret->scr_x = screens[screen].x_org; 5777 ret->scr_y = screens[screen].y_org; 5778 ret->scr_w = screens[screen].width; 5779 ret->scr_h = screens[screen].height; 5780#else /* HAVE_X11_EXTENSIONS_XINERAMA_H */ 5781 (void) display; 5782 (void) ret; 5783 if (screen > 0) 5784 xtermWarning("Xinerama support not enabled\n"); 5785#endif /* HAVE_X11_EXTENSIONS_XINERAMA_H */ 5786} 5787 5788/* 5789 * Parse the screen code after the @ in a geometry string. 5790 */ 5791static void 5792parse_xinerama_screen(Display *display, const char *str, struct Xinerama_geometry *ret) 5793{ 5794 int screen = -1; 5795 char *end; 5796 5797 if (*str == 'g') { 5798 screen = -1; 5799 str++; 5800 } else if (*str == 'c') { 5801 screen = -2; 5802 str++; 5803 } else { 5804 long s = strtol(str, &end, 0); 5805 if (FullS2L(str, end) && ((int) s >= 0)) { 5806 screen = (int) s; 5807 str = end; 5808 } 5809 } 5810 if (*str) { 5811 xtermWarning("invalid Xinerama specification '%s'\n", str); 5812 return; 5813 } 5814 if (screen == -1) /* already done */ 5815 return; 5816 find_xinerama_screen(display, screen, ret); 5817} 5818 5819/* 5820 * Parse a geometry string with extra Xinerama specification: 5821 * <w>x<h>+<x>+<y>@<screen>. 5822 */ 5823int 5824XParseXineramaGeometry(Display *display, char *parsestring, struct Xinerama_geometry *ret) 5825{ 5826 char *at, buf[128]; 5827 5828 ret->scr_x = 0; 5829 ret->scr_y = 0; 5830 ret->scr_w = DisplayWidth(display, DefaultScreen(display)); 5831 ret->scr_h = DisplayHeight(display, DefaultScreen(display)); 5832 at = strchr(parsestring, '@'); 5833 if (at != NULL && (size_t) (at - parsestring) < sizeof(buf) - 1) { 5834 memcpy(buf, parsestring, (size_t) (at - parsestring)); 5835 buf[at - parsestring] = 0; 5836 parsestring = buf; 5837 parse_xinerama_screen(display, at + 1, ret); 5838 } 5839 return ((strlen(parsestring) <= MAX_U_STRING) 5840 ? XParseGeometry(parsestring, &ret->x, &ret->y, &ret->w, &ret->h) 5841 : 0); 5842} 5843 5844#if USE_DOUBLE_BUFFER 5845Window 5846VDrawable(TScreen *screen) 5847{ 5848 screen->needSwap = 1; 5849 return WhichVWin(screen)->drawable; 5850} 5851#endif 5852 5853#if OPT_RENDERFONT 5854#ifndef discardRenderDraw 5855void 5856discardRenderDraw(TScreen *screen) 5857{ 5858 if (screen->renderDraw) { 5859 XftDrawDestroy(screen->renderDraw); 5860 screen->renderDraw = NULL; 5861 } 5862} 5863#endif 5864#endif /* OPT_RENDERFONT */ 5865 5866char * 5867xtermSetLocale(int category, String after) 5868{ 5869 char *before = x_strdup(setlocale(category, 0)); 5870 5871 (void) setlocale(category, after); 5872 TRACE(("before setlocale :%s\n", NonNull(before))); 5873 TRACE(("updated locale :%s\n", NonNull(setlocale(category, 0)))); 5874 return before; 5875} 5876 5877void 5878xtermResetLocale(int category, char *before) 5879{ 5880 (void) setlocale(category, before); 5881 free(before); 5882 TRACE(("restored locale :%s\n", NonNull(setlocale(category, 0)))); 5883} 5884