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