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