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