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