1 /* $XTermId: util.c,v 1.543 2011/02/09 10:11:44 tom Exp $ */
4 * Copyright 1999-2010,2011 by Thomas E. Dickey
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
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
33 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
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.
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
62 #include <fontutils.h>
70 #if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
76 static int handle_translated_exposure(XtermWidget xw,
81 static void ClearLeft(XtermWidget xw);
82 static void CopyWait(XtermWidget xw);
83 static void horizontal_copy_area(XtermWidget xw,
87 static void vertical_copy_area(XtermWidget xw,
93 unsigned first_widechar;
94 int (*my_wcwidth) (wchar_t);
99 * We will modify the 'n' cells beginning at the current position.
100 * Some of those cells may be part of multi-column characters, including
101 * carryover from the left. Find the limits of the multi-column characters
102 * that we should fill with blanks, return true if filling is needed.
105 DamagedCells(TScreen * screen, unsigned n, int *klp, int *krp, int row, int col)
107 LineData *ld = getLineData(screen, row);
111 if (col < (int) ld->lineSize) {
116 if (kr >= ld->lineSize) {
117 nn = (ld->lineSize - col - 1);
122 assert(kl < ld->lineSize);
123 if (ld->charData[kl] == HIDDEN_CHAR) {
125 if (ld->charData[--kl] != HIDDEN_CHAR) {
133 assert(kr < (int) ld->lineSize);
134 if (ld->charData[kr] == HIDDEN_CHAR) {
135 while (kr < screen->max_col) {
136 assert((kr + 1) < (int) ld->lineSize);
137 if (ld->charData[++kr] != HIDDEN_CHAR) {
158 DamagedCurCells(TScreen * screen, unsigned n, int *klp, int *krp)
160 return DamagedCells(screen, n, klp, krp, screen->cur_row, screen->cur_col);
162 #endif /* OPT_WIDE_CHARS */
165 * These routines are used for the jump scroll feature
168 FlushScroll(XtermWidget xw)
170 TScreen *screen = TScreenOf(xw);
172 int shift = INX2ROW(screen, 0);
173 int bot = screen->max_row - shift;
179 if (screen->cursor_state)
181 if (screen->scroll_amt > 0) {
182 refreshheight = screen->refresh_amt;
183 scrollheight = screen->bot_marg - screen->top_marg -
185 if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
186 (i = screen->max_row - screen->scroll_amt + 1))
188 if (screen->scrollWidget
190 && screen->top_marg == 0) {
192 if ((scrollheight += shift) > i)
194 if ((i = screen->bot_marg - bot) > 0 &&
195 (refreshheight -= i) < screen->scroll_amt)
196 refreshheight = screen->scroll_amt;
197 if ((i = screen->savedlines) < screen->savelines) {
198 if ((i += screen->scroll_amt) >
200 i = screen->savelines;
201 screen->savedlines = i;
202 ScrollBarDrawThumb(screen->scrollWidget);
205 scrolltop = screen->top_marg + shift;
206 if ((i = bot - (screen->bot_marg - screen->refresh_amt +
207 screen->scroll_amt)) > 0) {
208 if (bot < screen->bot_marg)
209 refreshheight = screen->scroll_amt + i;
212 refreshheight = screen->scroll_amt;
213 if ((i = screen->top_marg + screen->scroll_amt -
221 refreshheight = -screen->refresh_amt;
222 scrollheight = screen->bot_marg - screen->top_marg -
224 refreshtop = screen->top_marg + shift;
225 scrolltop = refreshtop + refreshheight;
226 if ((i = screen->bot_marg - bot) > 0)
228 if ((i = screen->top_marg + refreshheight - 1 - bot) > 0)
231 scrolling_copy_area(xw, scrolltop + screen->scroll_amt,
232 scrollheight, screen->scroll_amt);
233 ScrollSelection(screen, -(screen->scroll_amt), False);
234 screen->scroll_amt = 0;
235 screen->refresh_amt = 0;
236 if (refreshheight > 0) {
237 ClearCurBackground(xw,
238 (int) refreshtop * FontHeight(screen) + screen->border,
239 (int) OriginX(screen),
240 (unsigned) (refreshheight * FontHeight(screen)),
241 (unsigned) Width(screen));
242 ScrnRefresh(xw, refreshtop, 0, refreshheight,
243 MaxCols(screen), False);
249 * Returns true if there are lines off-screen due to scrolling which should
250 * include the current line. If false, the line is visible and we should
251 * paint it now rather than waiting for the line to become visible.
254 AddToRefresh(XtermWidget xw)
256 TScreen *screen = TScreenOf(xw);
257 int amount = screen->refresh_amt;
258 int row = screen->cur_row;
263 } else if (amount > 0) {
266 if (row == (bottom = screen->bot_marg) - amount) {
267 screen->refresh_amt++;
270 result = (row >= bottom - amount + 1 && row <= bottom);
276 if (row == (top = screen->top_marg) + amount) {
277 screen->refresh_amt--;
280 result = (row <= top + amount - 1 && row >= top);
285 * If this line is visible, and there are scrolled-off lines, flush out
286 * those which are now visible.
288 if (!result && screen->scroll_amt)
295 * Returns true if the current row is in the visible area (it should be for
296 * screen operations) and incidentally flush the scrolled-in lines which
297 * have newly become visible.
300 AddToVisible(XtermWidget xw)
302 TScreen *screen = TScreenOf(xw);
305 if (INX2ROW(screen, screen->cur_row) <= screen->max_row) {
306 if (!AddToRefresh(xw)) {
314 * If we're scrolling, leave the selection intact if possible.
315 * If it will bump into one of the extremes of the saved-lines, truncate that.
316 * If the selection is not contained within the scrolled region, clear it.
319 adjustHiliteOnFwdScroll(XtermWidget xw, int amount, Bool all_lines)
321 TScreen *screen = TScreenOf(xw);
322 int lo_row = (all_lines
323 ? (screen->bot_marg - screen->savelines)
325 int hi_row = screen->bot_marg;
327 TRACE2(("adjustSelection FWD %s by %d (%s)\n",
328 screen->whichBuf ? "alternate" : "normal",
330 all_lines ? "all" : "visible"));
331 TRACE2((" before highlite %d.%d .. %d.%d\n",
336 TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg));
337 TRACE2((" limits %d..%d\n", lo_row, hi_row));
339 if (screen->startH.row >= lo_row
340 && screen->startH.row - amount < lo_row) {
341 /* truncate the selection because its start would move out of region */
342 if (lo_row + amount <= screen->endH.row) {
343 TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
348 screen->startH.row = lo_row + amount;
349 screen->startH.col = 0;
351 TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
359 ScrnDisownSelection(xw);
361 } else if (screen->startH.row <= hi_row && screen->endH.row > hi_row) {
362 ScrnDisownSelection(xw);
363 } else if (screen->startH.row < lo_row && screen->endH.row > lo_row) {
364 ScrnDisownSelection(xw);
367 TRACE2((" after highlite %d.%d .. %d.%d\n",
375 * This is the same as adjustHiliteOnFwdScroll(), but reversed. In this case,
376 * only the visible lines are affected.
379 adjustHiliteOnBakScroll(XtermWidget xw, int amount)
381 TScreen *screen = TScreenOf(xw);
382 int lo_row = screen->top_marg;
383 int hi_row = screen->bot_marg;
385 TRACE2(("adjustSelection BAK %s by %d (%s)\n",
386 screen->whichBuf ? "alternate" : "normal",
389 TRACE2((" before highlite %d.%d .. %d.%d\n",
394 TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg));
396 if (screen->endH.row >= hi_row
397 && screen->endH.row + amount > hi_row) {
398 /* truncate the selection because its start would move out of region */
399 if (hi_row - amount >= screen->startH.row) {
400 TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
405 screen->endH.row = hi_row - amount;
406 screen->endH.col = 0;
408 TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
416 ScrnDisownSelection(xw);
418 } else if (screen->endH.row >= lo_row && screen->startH.row < lo_row) {
419 ScrnDisownSelection(xw);
420 } else if (screen->endH.row > hi_row && screen->startH.row > hi_row) {
421 ScrnDisownSelection(xw);
424 TRACE2((" after highlite %d.%d .. %d.%d\n",
432 * scrolls the screen by amount lines, erases bottom, doesn't alter
433 * cursor position (i.e. cursor moves down amount relative to text).
434 * All done within the scrolling region, of course.
435 * requires: amount > 0
438 xtermScroll(XtermWidget xw, int amount)
440 TScreen *screen = TScreenOf(xw);
441 int i = screen->bot_marg - screen->top_marg + 1;
448 Boolean scroll_all_lines = (Boolean) (screen->scrollWidget
450 && screen->top_marg == 0);
452 TRACE(("xtermScroll count=%d\n", amount));
454 screen->cursor_busy += 1;
455 screen->cursor_moved = True;
457 if (screen->cursor_state)
464 if (screen->allowScrollLock && screen->scroll_lock) {
466 screen->scroll_amt = 0;
467 screen->refresh_amt = 0;
468 if (--(screen->topline) < -screen->savelines) {
469 screen->topline = -screen->savelines;
470 screen->scroll_dirty = True;
472 if (++(screen->savedlines) > screen->savelines) {
473 screen->savedlines = screen->savelines;
478 if (ScrnHaveSelection(screen))
479 adjustHiliteOnFwdScroll(xw, amount, scroll_all_lines);
481 if (screen->jumpscroll) {
482 if (screen->scroll_amt > 0) {
483 if (!screen->fastscroll) {
484 if (screen->refresh_amt + amount > i)
487 screen->scroll_amt += amount;
488 screen->refresh_amt += amount;
490 if (!screen->fastscroll) {
491 if (screen->scroll_amt < 0)
494 screen->scroll_amt = amount;
495 screen->refresh_amt = amount;
499 ScrollSelection(screen, -(amount), False);
502 screen->cursor_busy -= 1;
506 shift = INX2ROW(screen, 0);
507 bot = screen->max_row - shift;
508 scrollheight = i - amount;
509 refreshheight = amount;
511 if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
512 (i = screen->max_row - refreshheight + 1))
515 if (scroll_all_lines) {
517 if ((scrollheight += shift) > i)
519 if ((i = screen->savedlines) < screen->savelines) {
520 if ((i += amount) > screen->savelines)
521 i = screen->savelines;
522 screen->savedlines = i;
523 ScrollBarDrawThumb(screen->scrollWidget);
526 scrolltop = screen->top_marg + shift;
527 if ((i = screen->bot_marg - bot) > 0) {
529 if ((i = screen->top_marg + amount - 1 - bot) >= 0) {
536 if (screen->multiscroll && amount == 1 &&
537 screen->topline == 0 && screen->top_marg == 0 &&
538 screen->bot_marg == screen->max_row) {
539 if (screen->incopy < 0 && screen->scrolls == 0)
544 scrolling_copy_area(xw, scrolltop + amount, scrollheight, amount);
546 if (refreshheight > 0) {
547 ClearCurBackground(xw,
548 (int) refreshtop * FontHeight(screen) + screen->border,
549 (int) OriginX(screen),
550 (unsigned) (refreshheight * FontHeight(screen)),
551 (unsigned) Width(screen));
552 if (refreshheight > shift)
553 refreshheight = shift;
559 if (scroll_all_lines) {
561 screen->saveBuf_index,
562 screen->bot_marg + screen->savelines,
574 if (refreshheight > 0) {
575 ScrnRefresh(xw, refreshtop, 0, refreshheight,
576 MaxCols(screen), False);
579 screen->cursor_busy -= 1;
584 * Reverse scrolls the screen by amount lines, erases top, doesn't alter
585 * cursor position (i.e. cursor moves up amount relative to text).
586 * All done within the scrolling region, of course.
587 * Requires: amount > 0
590 RevScroll(XtermWidget xw, int amount)
592 TScreen *screen = TScreenOf(xw);
593 int i = screen->bot_marg - screen->top_marg + 1;
601 TRACE(("RevScroll count=%d\n", amount));
603 screen->cursor_busy += 1;
604 screen->cursor_moved = True;
606 if (screen->cursor_state)
612 if (ScrnHaveSelection(screen))
613 adjustHiliteOnBakScroll(xw, amount);
615 if (screen->jumpscroll) {
616 if (screen->scroll_amt < 0) {
617 if (-screen->refresh_amt + amount > i)
619 screen->scroll_amt -= amount;
620 screen->refresh_amt -= amount;
622 if (screen->scroll_amt > 0)
624 screen->scroll_amt = -amount;
625 screen->refresh_amt = -amount;
628 shift = INX2ROW(screen, 0);
629 bot = screen->max_row - shift;
630 refreshheight = amount;
631 scrollheight = screen->bot_marg - screen->top_marg -
633 refreshtop = screen->top_marg + shift;
634 scrolltop = refreshtop + refreshheight;
635 if ((i = screen->bot_marg - bot) > 0)
637 if ((i = screen->top_marg + refreshheight - 1 - bot) > 0)
640 if (screen->multiscroll && amount == 1 &&
641 screen->topline == 0 && screen->top_marg == 0 &&
642 screen->bot_marg == screen->max_row) {
643 if (screen->incopy < 0 && screen->scrolls == 0)
648 scrolling_copy_area(xw, scrolltop - amount, scrollheight, -amount);
650 if (refreshheight > 0) {
651 ClearCurBackground(xw,
652 (int) refreshtop * FontHeight(screen) + screen->border,
653 (int) OriginX(screen),
654 (unsigned) (refreshheight * FontHeight(screen)),
655 (unsigned) Width(screen));
665 screen->cursor_busy -= 1;
670 * write a string str of length len onto the screen at
671 * the current cursor position. update cursor position.
674 WriteText(XtermWidget xw, IChar * str, Cardinal len)
676 TScreen *screen = TScreenOf(xw);
680 unsigned flags = xw->flags;
681 CellColor fg_bg = makeColorPair(xw->cur_foreground, xw->cur_background);
682 unsigned cells = visual_width(str, len);
685 TRACE(("WriteText %d (%2d,%2d) %3d:%s\n",
689 len, visibleIChar(str, len)));
691 if (cells + (unsigned) screen->cur_col > (unsigned) MaxCols(screen)) {
692 cells = (unsigned) (MaxCols(screen) - screen->cur_col);
695 if (ScrnHaveSelection(screen)
696 && ScrnIsLineInSelection(screen, INX2ROW(screen, screen->cur_row))) {
697 ScrnDisownSelection(xw);
700 /* if we are in insert-mode, reserve space for the new cells */
701 if (flags & INSERT) {
702 InsertChar(xw, cells);
706 && ((ld = getLineData(screen, screen->cur_row))) != 0) {
707 if (screen->cursor_state)
711 * If we overwrite part of a multi-column character, fill the rest
714 if_OPT_WIDE_CHARS(screen, {
717 if (DamagedCurCells(screen, cells, &kl, &kr))
718 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
721 if (flags & INVISIBLE) {
723 for (n = 0; n < cells; ++n)
727 TRACE(("WriteText calling drawXtermText (%d) (%d,%d)\n",
728 LineCharSet(screen, ld),
734 if (screen->colorAttrMode) {
735 fg = MapToColorMode(xw->cur_foreground, screen, flags);
737 fg = xw->cur_foreground;
739 checkVeryBoldColors(test, fg);
742 /* make sure that the correct GC is current */
743 currentGC = updatedXtermGC(xw, flags, fg_bg, False);
745 drawXtermText(xw, test & DRAWX_MASK, currentGC,
746 LineCursorX(screen, ld, screen->cur_col),
747 CursorY(screen, screen->cur_row),
748 LineCharSet(screen, ld),
751 resetXtermGC(xw, flags, False);
754 ScrnWriteText(xw, str, flags, fg_bg, len);
755 CursorForward(screen, (int) cells);
757 /* Flag icon name with "***" on window output when iconified.
759 if (resource.zIconBeep && mapstate == IsUnmapped && !screen->zIconBeep_flagged) {
760 static char *icon_name;
763 {XtNiconName, (XtArgVal) & icon_name}
767 XtGetValues(toplevel, args, XtNumber(args));
769 if (icon_name != NULL) {
770 screen->zIconBeep_flagged = True;
771 ChangeIconName(xw, icon_name);
773 xtermBell(xw, XkbBI_Info, 0);
776 #endif /* OPT_ZICONBEEP */
781 * If cursor not in scrolling region, returns. Else,
782 * inserts n blank lines at the cursor's position. Lines above the
783 * bottom margin are lost.
786 InsertLine(XtermWidget xw, int n)
788 TScreen *screen = TScreenOf(xw);
797 if (!ScrnIsLineInMargins(screen, screen->cur_row))
800 TRACE(("InsertLine count=%d\n", n));
802 if (screen->cursor_state)
805 if (ScrnHaveSelection(screen)
806 && ScrnAreLinesInSelection(screen,
807 INX2ROW(screen, screen->top_marg),
808 INX2ROW(screen, screen->cur_row - 1))
809 && ScrnAreLinesInSelection(screen,
810 INX2ROW(screen, screen->cur_row),
811 INX2ROW(screen, screen->bot_marg))) {
812 ScrnDisownSelection(xw);
815 screen->do_wrap = False;
816 if (n > (i = screen->bot_marg - screen->cur_row + 1))
818 if (screen->jumpscroll) {
819 if (screen->scroll_amt <= 0 &&
820 screen->cur_row <= -screen->refresh_amt) {
821 if (-screen->refresh_amt + n > MaxRows(screen))
823 screen->scroll_amt -= n;
824 screen->refresh_amt -= n;
826 if (screen->scroll_amt)
830 if (!screen->scroll_amt) {
831 shift = INX2ROW(screen, 0);
832 bot = screen->max_row - shift;
834 scrollheight = screen->bot_marg - screen->cur_row - refreshheight + 1;
835 refreshtop = screen->cur_row + shift;
836 scrolltop = refreshtop + refreshheight;
837 if ((i = screen->bot_marg - bot) > 0)
839 if ((i = screen->cur_row + refreshheight - 1 - bot) > 0)
841 vertical_copy_area(xw, scrolltop - n, scrollheight, -n);
842 if (refreshheight > 0) {
843 ClearCurBackground(xw,
844 (int) refreshtop * FontHeight(screen) + screen->border,
845 (int) OriginX(screen),
846 (unsigned) (refreshheight * FontHeight(screen)),
847 (unsigned) Width(screen));
860 * If cursor not in scrolling region, returns. Else, deletes n lines
861 * at the cursor's position, lines added at bottom margin are blank.
864 DeleteLine(XtermWidget xw, int n)
866 TScreen *screen = TScreenOf(xw);
874 Boolean scroll_all_lines = (Boolean) (screen->scrollWidget
876 && screen->cur_row == 0);
878 if (!ScrnIsLineInMargins(screen, screen->cur_row))
881 TRACE(("DeleteLine count=%d\n", n));
883 if (screen->cursor_state)
886 if (n > (i = screen->bot_marg - screen->cur_row + 1)) {
889 if (ScrnHaveSelection(screen)
890 && ScrnAreLinesInSelection(screen,
891 INX2ROW(screen, screen->cur_row),
892 INX2ROW(screen, screen->cur_row + n - 1))) {
893 ScrnDisownSelection(xw);
896 screen->do_wrap = False;
897 if (screen->jumpscroll) {
898 if (screen->scroll_amt >= 0 && screen->cur_row == screen->top_marg) {
899 if (screen->refresh_amt + n > MaxRows(screen))
901 screen->scroll_amt += n;
902 screen->refresh_amt += n;
904 if (screen->scroll_amt)
909 /* adjust screen->buf */
911 if (scroll_all_lines)
913 screen->saveBuf_index,
914 screen->bot_marg + screen->savelines,
925 /* repaint the screen, as needed */
926 if (!screen->scroll_amt) {
927 shift = INX2ROW(screen, 0);
928 bot = screen->max_row - shift;
929 scrollheight = i - n;
931 if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
932 (i = screen->max_row - refreshheight + 1))
934 if (scroll_all_lines) {
936 if ((scrollheight += shift) > i)
938 if ((i = screen->savedlines) < screen->savelines) {
939 if ((i += n) > screen->savelines)
940 i = screen->savelines;
941 screen->savedlines = i;
942 ScrollBarDrawThumb(screen->scrollWidget);
945 scrolltop = screen->cur_row + shift;
946 if ((i = screen->bot_marg - bot) > 0) {
948 if ((i = screen->cur_row + n - 1 - bot) >= 0) {
953 vertical_copy_area(xw, scrolltop + n, scrollheight, n);
954 if (shift > 0 && refreshheight > 0) {
955 int rows = refreshheight;
958 ScrnUpdate(xw, refreshtop, 0, rows, MaxCols(screen), True);
960 refreshheight -= shift;
962 if (refreshheight > 0) {
963 ClearCurBackground(xw,
964 (int) refreshtop * FontHeight(screen) + screen->border,
965 (int) OriginX(screen),
966 (unsigned) (refreshheight * FontHeight(screen)),
967 (unsigned) Width(screen));
973 * Insert n blanks at the cursor's position, no wraparound
976 InsertChar(XtermWidget xw, unsigned n)
978 TScreen *screen = TScreenOf(xw);
981 int row = INX2ROW(screen, screen->cur_row);
983 if (screen->cursor_state)
986 TRACE(("InsertChar count=%d\n", n));
988 if (ScrnHaveSelection(screen)
989 && ScrnIsLineInSelection(screen, row)) {
990 ScrnDisownSelection(xw);
992 screen->do_wrap = False;
994 assert(screen->cur_col <= screen->max_col);
995 limit = (unsigned) (MaxCols(screen) - screen->cur_col);
1001 if (AddToVisible(xw)
1002 && (ld = getLineData(screen, screen->cur_row)) != 0) {
1003 int col = MaxCols(screen) - (int) n;
1006 * If we shift part of a multi-column character, fill the rest
1007 * of it with blanks. Do similar repair for the text which will
1008 * be shifted into the right-margin.
1010 if_OPT_WIDE_CHARS(screen, {
1012 int kr = screen->cur_col;
1013 if (DamagedCurCells(screen, n, &kl, (int *) 0) && kr > kl) {
1014 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
1016 kr = screen->max_col - (int) n + 1;
1017 if (DamagedCells(screen, n, &kl, (int *) 0,
1020 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
1025 if (CSET_DOUBLE(GetLineDblCS(ld))) {
1026 col = MaxCols(screen) / 2 - (int) n;
1030 * prevent InsertChar from shifting the end of a line over
1031 * if it is being appended to
1033 if (non_blank_line(screen, screen->cur_row,
1034 screen->cur_col, MaxCols(screen))) {
1035 horizontal_copy_area(xw, screen->cur_col,
1036 col - screen->cur_col,
1040 ClearCurBackground(xw,
1041 CursorY(screen, screen->cur_row),
1042 LineCursorX(screen, ld, screen->cur_col),
1043 (unsigned) FontHeight(screen),
1044 n * (unsigned) LineFontWidth(screen, ld));
1046 /* adjust screen->buf */
1047 ScrnInsertChar(xw, n);
1051 * Deletes n chars at the cursor's position, no wraparound.
1054 DeleteChar(XtermWidget xw, unsigned n)
1056 TScreen *screen = TScreenOf(xw);
1059 int row = INX2ROW(screen, screen->cur_row);
1061 if (screen->cursor_state)
1064 TRACE(("DeleteChar count=%d\n", n));
1066 if (ScrnHaveSelection(screen)
1067 && ScrnIsLineInSelection(screen, row)) {
1068 ScrnDisownSelection(xw);
1070 screen->do_wrap = False;
1072 assert(screen->cur_col <= screen->max_col);
1073 limit = (unsigned) (MaxCols(screen) - screen->cur_col);
1079 if (AddToVisible(xw)
1080 && (ld = getLineData(screen, screen->cur_row)) != 0) {
1081 int col = MaxCols(screen) - (int) n;
1084 * If we delete part of a multi-column character, fill the rest
1085 * of it with blanks.
1087 if_OPT_WIDE_CHARS(screen, {
1090 if (DamagedCurCells(screen, n, &kl, &kr))
1091 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
1095 if (CSET_DOUBLE(GetLineDblCS(ld))) {
1096 col = MaxCols(screen) / 2 - (int) n;
1099 horizontal_copy_area(xw,
1100 (screen->cur_col + (int) n),
1101 col - screen->cur_col,
1104 ClearCurBackground(xw,
1105 CursorY(screen, screen->cur_row),
1106 LineCursorX(screen, ld, col),
1107 (unsigned) FontHeight(screen),
1108 n * (unsigned) LineFontWidth(screen, ld));
1111 /* adjust screen->buf */
1112 ScrnDeleteChar(xw, n);
1117 * Clear from cursor position to beginning of display, inclusive.
1120 ClearAbove(XtermWidget xw)
1122 TScreen *screen = TScreenOf(xw);
1124 if (screen->protected_mode != OFF_PROTECT) {
1126 unsigned len = (unsigned) MaxCols(screen);
1128 assert(screen->max_col >= 0);
1129 for (row = 0; row <= screen->max_row; row++)
1130 ClearInLine(xw, row, 0, len);
1134 if (screen->cursor_state)
1136 if ((top = INX2ROW(screen, 0)) <= screen->max_row) {
1137 if (screen->scroll_amt)
1139 if ((height = screen->cur_row + top) > screen->max_row)
1140 height = screen->max_row + 1;
1141 if ((height -= top) > 0) {
1142 ClearCurBackground(xw,
1143 top * FontHeight(screen) + screen->border,
1145 (unsigned) (height * FontHeight(screen)),
1146 (unsigned) (Width(screen)));
1149 ClearBufRows(xw, 0, screen->cur_row - 1);
1156 * Clear from cursor position to end of display, inclusive.
1159 ClearBelow(XtermWidget xw)
1161 TScreen *screen = TScreenOf(xw);
1165 if (screen->protected_mode != OFF_PROTECT) {
1167 unsigned len = (unsigned) MaxCols(screen);
1169 assert(screen->max_col >= 0);
1170 for (row = screen->cur_row + 1; row <= screen->max_row; row++)
1171 ClearInLine(xw, row, 0, len);
1175 if ((top = INX2ROW(screen, screen->cur_row)) <= screen->max_row) {
1176 if (screen->scroll_amt)
1178 if (++top <= screen->max_row) {
1179 ClearCurBackground(xw,
1180 top * FontHeight(screen) + screen->border,
1182 (unsigned) ((screen->max_row - top + 1)
1183 * FontHeight(screen)),
1184 (unsigned) (Width(screen)));
1187 ClearBufRows(xw, screen->cur_row + 1, screen->max_row);
1192 * Clear the given row, for the given range of columns, returning 1 if no
1193 * protected characters were found, 0 otherwise.
1196 ClearInLine2(XtermWidget xw, int flags, int row, int col, unsigned len)
1198 TScreen *screen = TScreenOf(xw);
1202 TRACE(("ClearInLine(row=%d, col=%d, len=%d) vs %d..%d\n",
1205 screen->startH.col));
1207 if (ScrnHaveSelection(screen)
1208 && ScrnIsLineInSelection(screen, row)) {
1209 ScrnDisownSelection(xw);
1212 if (col + (int) len >= MaxCols(screen)) {
1213 len = (unsigned) (MaxCols(screen) - col);
1216 /* If we've marked protected text on the screen, we'll have to
1217 * check each time we do an erase.
1219 if (screen->protected_mode != OFF_PROTECT) {
1221 Char *attrs = getLineData(screen, row)->attribs + col;
1222 int saved_mode = screen->protected_mode;
1225 /* disable this branch during recursion */
1226 screen->protected_mode = OFF_PROTECT;
1230 for (n = 0; n < len; n++) {
1231 if (attrs[n] & PROTECTED) {
1232 rc = 0; /* found a protected segment */
1234 ClearInLine(xw, row, col, n);
1237 && (attrs[n] & PROTECTED)) {
1244 /* setup for another segment, past the protected text */
1252 screen->protected_mode = saved_mode;
1253 if ((int) len <= 0) {
1257 /* fall through to the final non-protected segment */
1259 if (screen->cursor_state)
1261 screen->do_wrap = False;
1263 if (AddToVisible(xw)
1264 && (ld = getLineData(screen, row)) != 0) {
1266 ClearCurBackground(xw,
1267 CursorY(screen, row),
1268 LineCursorX(screen, ld, col),
1269 (unsigned) FontHeight(screen),
1270 len * (unsigned) LineFontWidth(screen, ld));
1274 ClearCells(xw, flags, len, row, col);
1281 ClearInLine(XtermWidget xw, int row, int col, unsigned len)
1283 TScreen *screen = TScreenOf(xw);
1287 * If we're clearing to the end of the line, we won't count this as
1288 * "drawn" characters. We'll only do cut/paste on "drawn" characters,
1289 * so this has the effect of suppressing trailing blanks from a
1292 if (col + (int) len < MaxCols(screen)) {
1295 return ClearInLine2(xw, flags, row, col, len);
1299 * Clear the next n characters on the cursor's line, including the cursor's
1303 ClearRight(XtermWidget xw, int n)
1305 TScreen *screen = TScreenOf(xw);
1307 unsigned len = (unsigned) (MaxCols(screen) - screen->cur_col);
1309 assert(screen->max_col >= 0);
1310 assert(screen->max_col >= screen->cur_col);
1312 if (n < 0) /* the remainder of the line */
1313 n = MaxCols(screen);
1314 if (n == 0) /* default for 'ECH' */
1317 if (len > (unsigned) n)
1320 ld = getLineData(screen, screen->cur_row);
1321 if (AddToVisible(xw)) {
1322 if_OPT_WIDE_CHARS(screen, {
1323 int col = screen->cur_col;
1324 int row = screen->cur_row;
1328 if (DamagedCurCells(screen, len, &kl, &kr) && kr >= kl) {
1331 ClearInLine2(xw, 0, row, kl, (unsigned) (xx - kl));
1333 xx = col + (int) len - 1;
1335 ClearInLine2(xw, 0, row, xx + 1, (unsigned) (kr - xx));
1339 (void) ClearInLine(xw, screen->cur_row, screen->cur_col, len);
1341 ScrnClearCells(xw, screen->cur_row, screen->cur_col, len);
1344 /* with the right part cleared, we can't be wrapping */
1346 if (screen->show_wrap_marks) {
1347 ShowWrapMarks(xw, screen->cur_row, ld);
1349 screen->do_wrap = False;
1353 * Clear first part of cursor's line, inclusive.
1356 ClearLeft(XtermWidget xw)
1358 TScreen *screen = TScreenOf(xw);
1359 unsigned len = (unsigned) screen->cur_col + 1;
1361 assert(screen->cur_col >= 0);
1362 if (AddToVisible(xw)) {
1363 if_OPT_WIDE_CHARS(screen, {
1364 int row = screen->cur_row;
1367 if (DamagedCurCells(screen, 1, &kl, &kr) && kr >= kl) {
1368 ClearInLine2(xw, 0, row, kl, (unsigned) (kr - kl + 1));
1371 (void) ClearInLine(xw, screen->cur_row, 0, len);
1373 ScrnClearCells(xw, screen->cur_row, 0, len);
1378 * Erase the cursor's line.
1381 ClearLine(XtermWidget xw)
1383 TScreen *screen = TScreenOf(xw);
1384 unsigned len = (unsigned) MaxCols(screen);
1386 assert(screen->max_col >= 0);
1387 (void) ClearInLine(xw, screen->cur_row, 0, len);
1391 ClearScreen(XtermWidget xw)
1393 TScreen *screen = TScreenOf(xw);
1396 if (screen->cursor_state)
1399 ScrnDisownSelection(xw);
1400 screen->do_wrap = False;
1401 if ((top = INX2ROW(screen, 0)) <= screen->max_row) {
1402 if (screen->scroll_amt)
1404 ClearCurBackground(xw,
1405 top * FontHeight(screen) + screen->border,
1407 (unsigned) ((screen->max_row - top + 1)
1408 * FontHeight(screen)),
1409 (unsigned) Width(screen));
1411 ClearBufRows(xw, 0, screen->max_row);
1415 * If we've written protected text DEC-style, and are issuing a non-DEC
1416 * erase, temporarily reset the protected_mode flag so that the erase will
1417 * ignore the protected flags.
1420 do_erase_line(XtermWidget xw, int param, int mode)
1422 TScreen *screen = TScreenOf(xw);
1423 int saved_mode = screen->protected_mode;
1425 if (saved_mode == DEC_PROTECT
1426 && saved_mode != mode) {
1427 screen->protected_mode = OFF_PROTECT;
1431 case -1: /* DEFAULT */
1442 screen->protected_mode = saved_mode;
1446 * Just like 'do_erase_line()', except that this intercepts ED controls. If we
1447 * clear the whole screen, we'll get the return-value from ClearInLine, and
1448 * find if there were any protected characters left. If not, reset the
1449 * protected mode flag in the screen data (it's slower).
1452 do_erase_display(XtermWidget xw, int param, int mode)
1454 TScreen *screen = TScreenOf(xw);
1455 int saved_mode = screen->protected_mode;
1457 if (saved_mode == DEC_PROTECT
1458 && saved_mode != mode)
1459 screen->protected_mode = OFF_PROTECT;
1462 case -1: /* DEFAULT */
1464 if (screen->cur_row == 0
1465 && screen->cur_col == 0) {
1466 screen->protected_mode = saved_mode;
1467 do_erase_display(xw, 2, mode);
1468 saved_mode = screen->protected_mode;
1474 if (screen->cur_row == screen->max_row
1475 && screen->cur_col == screen->max_col) {
1476 screen->protected_mode = saved_mode;
1477 do_erase_display(xw, 2, mode);
1478 saved_mode = screen->protected_mode;
1485 * We use 'ClearScreen()' throughout the remainder of the
1486 * program for places where we don't care if the characters are
1487 * protected or not. So we modify the logic around this call
1488 * on 'ClearScreen()' to handle protected characters.
1490 if (screen->protected_mode != OFF_PROTECT) {
1493 unsigned len = (unsigned) MaxCols(screen);
1495 assert(screen->max_col >= 0);
1496 for (row = 0; row <= screen->max_row; row++)
1497 rc &= ClearInLine(xw, row, 0, len);
1499 saved_mode = OFF_PROTECT;
1506 /* xterm addition - erase saved lines. */
1507 screen->savedlines = 0;
1508 ScrollBarDrawThumb(screen->scrollWidget);
1511 screen->protected_mode = saved_mode;
1515 CopyWait(XtermWidget xw)
1517 TScreen *screen = TScreenOf(xw);
1519 XEvent *rep = &reply;
1522 XWindowEvent(screen->display, VWindow(screen),
1523 ExposureMask, &reply);
1524 switch (reply.type) {
1526 HandleExposure(xw, &reply);
1529 case GraphicsExpose:
1530 if (screen->incopy <= 0) {
1532 if (screen->scrolls > 0)
1535 if (reply.type == GraphicsExpose)
1536 HandleExposure(xw, &reply);
1538 if ((reply.type == NoExpose) ||
1539 ((XExposeEvent *) rep)->count == 0) {
1540 if (screen->incopy <= 0 && screen->scrolls > 0)
1542 if (screen->scrolls == 0) {
1546 screen->incopy = -1;
1554 * used by vertical_copy_area and and horizontal_copy_area
1557 copy_area(XtermWidget xw,
1565 TScreen *screen = TScreenOf(xw);
1567 if (width != 0 && height != 0) {
1568 /* wait for previous CopyArea to complete unless
1569 multiscroll is enabled and active */
1570 if (screen->incopy && screen->scrolls == 0)
1572 screen->incopy = -1;
1574 /* save for translating Expose events */
1575 screen->copy_src_x = src_x;
1576 screen->copy_src_y = src_y;
1577 screen->copy_width = width;
1578 screen->copy_height = height;
1579 screen->copy_dest_x = dest_x;
1580 screen->copy_dest_y = dest_y;
1582 XCopyArea(screen->display,
1583 VWindow(screen), VWindow(screen),
1584 NormalGC(xw, screen),
1585 src_x, src_y, width, height, dest_x, dest_y);
1590 * use when inserting or deleting characters on the current line
1593 horizontal_copy_area(XtermWidget xw,
1594 int firstchar, /* char pos on screen to start copying at */
1596 int amount) /* number of characters to move right */
1598 TScreen *screen = TScreenOf(xw);
1601 if ((ld = getLineData(screen, screen->cur_row)) != 0) {
1602 int src_x = LineCursorX(screen, ld, firstchar);
1603 int src_y = CursorY(screen, screen->cur_row);
1605 copy_area(xw, src_x, src_y,
1606 (unsigned) (nchars * LineFontWidth(screen, ld)),
1607 (unsigned) FontHeight(screen),
1608 src_x + amount * LineFontWidth(screen, ld), src_y);
1613 * use when inserting or deleting lines from the screen
1616 vertical_copy_area(XtermWidget xw,
1617 int firstline, /* line on screen to start copying at */
1619 int amount) /* number of lines to move up (neg=down) */
1621 TScreen *screen = TScreenOf(xw);
1624 int src_x = OriginX(screen);
1625 int src_y = firstline * FontHeight(screen) + screen->border;
1627 copy_area(xw, src_x, src_y,
1628 (unsigned) Width(screen),
1629 (unsigned) (nlines * FontHeight(screen)),
1630 src_x, src_y - amount * FontHeight(screen));
1631 if (screen->show_wrap_marks) {
1634 for (row = firstline; row < firstline + nlines; ++row) {
1635 if ((ld = getLineData(screen, row)) != 0) {
1636 ShowWrapMarks(xw, row, ld);
1644 * use when scrolling the entire screen
1647 scrolling_copy_area(XtermWidget xw,
1648 int firstline, /* line on screen to start copying at */
1650 int amount) /* number of lines to move up (neg=down) */
1654 vertical_copy_area(xw, firstline, nlines, amount);
1659 * Handler for Expose events on the VT widget.
1660 * Returns 1 iff the area where the cursor was got refreshed.
1663 HandleExposure(XtermWidget xw, XEvent * event)
1665 TScreen *screen = TScreenOf(xw);
1666 XExposeEvent *reply = (XExposeEvent *) event;
1668 #ifndef NO_ACTIVE_ICON
1669 if (reply->window == screen->iconVwin.window) {
1670 WhichVWin(screen) = &screen->iconVwin;
1671 TRACE(("HandleExposure - icon"));
1673 WhichVWin(screen) = &screen->fullVwin;
1674 TRACE(("HandleExposure - normal"));
1676 TRACE((" event %d,%d %dx%d\n",
1681 #endif /* NO_ACTIVE_ICON */
1683 /* if not doing CopyArea or if this is a GraphicsExpose, don't translate */
1684 if (!screen->incopy || event->type != Expose)
1685 return handle_translated_exposure(xw, reply->x, reply->y,
1689 /* compute intersection of area being copied with
1690 area being exposed. */
1691 int both_x1 = Max(screen->copy_src_x, reply->x);
1692 int both_y1 = Max(screen->copy_src_y, reply->y);
1693 int both_x2 = Min(screen->copy_src_x + (int) screen->copy_width,
1694 (reply->x + (int) reply->width));
1695 int both_y2 = Min(screen->copy_src_y + (int) screen->copy_height,
1696 (reply->y + (int) reply->height));
1699 /* was anything copied affected? */
1700 if (both_x2 > both_x1 && both_y2 > both_y1) {
1701 /* do the copied area */
1702 value = handle_translated_exposure
1703 (xw, reply->x + screen->copy_dest_x - screen->copy_src_x,
1704 reply->y + screen->copy_dest_y - screen->copy_src_y,
1705 reply->width, reply->height);
1707 /* was anything not copied affected? */
1708 if (reply->x < both_x1 || reply->y < both_y1
1709 || reply->x + reply->width > both_x2
1710 || reply->y + reply->height > both_y2)
1711 value = handle_translated_exposure(xw, reply->x, reply->y,
1712 reply->width, reply->height);
1719 set_background(XtermWidget xw, int color GCC_UNUSED)
1721 TScreen *screen = TScreenOf(xw);
1722 Pixel c = getXtermBackground(xw, xw->flags, color);
1724 TRACE(("set_background(%d) %#lx\n", color, c));
1725 XSetWindowBackground(screen->display, VShellWindow(xw), c);
1726 XSetWindowBackground(screen->display, VWindow(screen), c);
1730 * Called by the ExposeHandler to do the actual repaint after the coordinates
1731 * have been translated to allow for any CopyArea in progress.
1732 * The rectangle passed in is pixel coordinates.
1735 handle_translated_exposure(XtermWidget xw,
1741 TScreen *screen = TScreenOf(xw);
1742 int toprow, leftcol, nrows, ncols;
1747 TRACE(("handle_translated_exposure at %d,%d size %dx%d\n",
1748 rect_y, rect_x, rect_height, rect_width));
1750 x0 = (rect_x - OriginX(screen));
1751 x1 = (x0 + rect_width);
1753 y0 = (rect_y - OriginY(screen));
1754 y1 = (y0 + rect_height);
1758 x1 > Width(screen) ||
1759 y1 > Height(screen))) {
1760 set_background(xw, -1);
1761 XClearArea(screen->display, VWindow(screen),
1764 (unsigned) rect_width,
1765 (unsigned) rect_height, False);
1767 toprow = y0 / FontHeight(screen);
1771 leftcol = x0 / FontWidth(screen);
1775 nrows = (y1 - 1) / FontHeight(screen) - toprow + 1;
1776 ncols = (x1 - 1) / FontWidth(screen) - leftcol + 1;
1777 toprow -= screen->scrolls;
1782 if (toprow + nrows > MaxRows(screen))
1783 nrows = MaxRows(screen) - toprow;
1784 if (leftcol + ncols > MaxCols(screen))
1785 ncols = MaxCols(screen) - leftcol;
1787 if (nrows > 0 && ncols > 0) {
1788 ScrnRefresh(xw, toprow, leftcol, nrows, ncols, True);
1789 first_map_occurred();
1790 if (screen->cur_row >= toprow &&
1791 screen->cur_row < toprow + nrows &&
1792 screen->cur_col >= leftcol &&
1793 screen->cur_col < leftcol + ncols) {
1798 TRACE(("...handle_translated_exposure %d\n", result));
1802 /***====================================================================***/
1805 GetColors(XtermWidget xw, ScrnColors * pColors)
1807 TScreen *screen = TScreenOf(xw);
1811 for (n = 0; n < NCOLORS; ++n) {
1812 SET_COLOR_VALUE(pColors, n, T_COLOR(screen, n));
1817 ChangeColors(XtermWidget xw, ScrnColors * pNew)
1819 Bool repaint = False;
1820 TScreen *screen = TScreenOf(xw);
1821 VTwin *win = WhichVWin(screen);
1823 TRACE(("ChangeColors\n"));
1825 if (COLOR_DEFINED(pNew, TEXT_CURSOR)) {
1826 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_CURSOR);
1827 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR)));
1828 /* no repaint needed */
1829 } else if ((T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) &&
1830 (COLOR_DEFINED(pNew, TEXT_FG))) {
1831 if (T_COLOR(screen, TEXT_CURSOR) != COLOR_VALUE(pNew, TEXT_FG)) {
1832 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_FG);
1833 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR)));
1839 if (COLOR_DEFINED(pNew, TEXT_FG)) {
1840 Pixel fg = COLOR_VALUE(pNew, TEXT_FG);
1841 T_COLOR(screen, TEXT_FG) = fg;
1842 TRACE(("... TEXT_FG: %#lx\n", T_COLOR(screen, TEXT_FG)));
1843 if (screen->Vshow) {
1844 setCgsFore(xw, win, gcNorm, fg);
1845 setCgsBack(xw, win, gcNormReverse, fg);
1846 setCgsFore(xw, win, gcBold, fg);
1847 setCgsBack(xw, win, gcBoldReverse, fg);
1852 if (COLOR_DEFINED(pNew, TEXT_BG)) {
1853 Pixel bg = COLOR_VALUE(pNew, TEXT_BG);
1854 T_COLOR(screen, TEXT_BG) = bg;
1855 TRACE(("... TEXT_BG: %#lx\n", T_COLOR(screen, TEXT_BG)));
1856 if (screen->Vshow) {
1857 setCgsBack(xw, win, gcNorm, bg);
1858 setCgsFore(xw, win, gcNormReverse, bg);
1859 setCgsBack(xw, win, gcBold, bg);
1860 setCgsFore(xw, win, gcBoldReverse, bg);
1861 set_background(xw, -1);
1865 #if OPT_HIGHLIGHT_COLOR
1866 if (COLOR_DEFINED(pNew, HIGHLIGHT_BG)) {
1867 if (T_COLOR(screen, HIGHLIGHT_BG) != COLOR_VALUE(pNew, HIGHLIGHT_BG)) {
1868 T_COLOR(screen, HIGHLIGHT_BG) = COLOR_VALUE(pNew, HIGHLIGHT_BG);
1869 TRACE(("... HIGHLIGHT_BG: %#lx\n", T_COLOR(screen, HIGHLIGHT_BG)));
1874 if (COLOR_DEFINED(pNew, HIGHLIGHT_FG)) {
1875 if (T_COLOR(screen, HIGHLIGHT_FG) != COLOR_VALUE(pNew, HIGHLIGHT_FG)) {
1876 T_COLOR(screen, HIGHLIGHT_FG) = COLOR_VALUE(pNew, HIGHLIGHT_FG);
1877 TRACE(("... HIGHLIGHT_FG: %#lx\n", T_COLOR(screen, HIGHLIGHT_FG)));
1884 if (COLOR_DEFINED(pNew, MOUSE_FG) || (COLOR_DEFINED(pNew, MOUSE_BG))) {
1885 if (COLOR_DEFINED(pNew, MOUSE_FG)) {
1886 T_COLOR(screen, MOUSE_FG) = COLOR_VALUE(pNew, MOUSE_FG);
1887 TRACE(("... MOUSE_FG: %#lx\n", T_COLOR(screen, MOUSE_FG)));
1889 if (COLOR_DEFINED(pNew, MOUSE_BG)) {
1890 T_COLOR(screen, MOUSE_BG) = COLOR_VALUE(pNew, MOUSE_BG);
1891 TRACE(("... MOUSE_BG: %#lx\n", T_COLOR(screen, MOUSE_BG)));
1894 if (screen->Vshow) {
1895 recolor_cursor(screen,
1896 screen->pointer_cursor,
1897 T_COLOR(screen, MOUSE_FG),
1898 T_COLOR(screen, MOUSE_BG));
1899 XDefineCursor(screen->display, VWindow(screen),
1900 screen->pointer_cursor);
1903 if (TEK4014_SHOWN(xw)) {
1904 TekScreen *tekscr = TekScreenOf(tekWidget);
1905 Window tekwin = TWindow(tekscr);
1907 recolor_cursor(screen,
1909 T_COLOR(screen, MOUSE_FG),
1910 T_COLOR(screen, MOUSE_BG));
1911 XDefineCursor(screen->display, tekwin, tekscr->arrow);
1915 /* no repaint needed */
1918 if (COLOR_DEFINED(pNew, TEXT_FG) ||
1919 COLOR_DEFINED(pNew, TEXT_BG) ||
1920 COLOR_DEFINED(pNew, TEXT_CURSOR)) {
1921 if (set_cursor_gcs(xw) && screen->Vshow) {
1926 if (COLOR_DEFINED(pNew, TEK_FG) ||
1927 COLOR_DEFINED(pNew, TEK_BG)) {
1928 ChangeTekColors(tekWidget, screen, pNew);
1929 if (TEK4014_SHOWN(xw)) {
1930 TekRepaint(tekWidget);
1932 } else if (COLOR_DEFINED(pNew, TEK_CURSOR)) {
1933 ChangeTekColors(tekWidget, screen, pNew);
1941 xtermClear(XtermWidget xw)
1943 TScreen *screen = TScreenOf(xw);
1945 TRACE(("xtermClear\n"));
1946 XClearWindow(screen->display, VWindow(screen));
1950 xtermRepaint(XtermWidget xw)
1952 TScreen *screen = TScreenOf(xw);
1954 TRACE(("xtermRepaint\n"));
1956 ScrnRefresh(xw, 0, 0, MaxRows(screen), MaxCols(screen), True);
1959 /***====================================================================***/
1962 isDefaultForeground(const char *name)
1964 return (Boolean) ! x_strcasecmp(name, XtDefaultForeground);
1968 isDefaultBackground(const char *name)
1970 return (Boolean) ! x_strcasecmp(name, XtDefaultBackground);
1975 * Check for Unicode BIDI control characters, which may be miscategorized via
1976 * wcwidth() and iswprint() as zero-width printable characters.
1979 isWideControl(unsigned ch)
2001 /***====================================================================***/
2008 #if OPT_HIGHLIGHT_COLOR
2009 #define hc_param ,Bool hilite_color
2010 #define hc_value ,screen->hilite_color
2012 #define hc_param /* nothing */
2013 #define hc_value /* nothing */
2017 * Use this to swap the foreground/background color values in the resource
2018 * data, and to build up a list of the pairs which must be swapped in the
2022 swapLocally(ToSwap * list, int *count, ColorRes * fg, ColorRes * bg hc_param)
2026 Boolean found = False;
2029 Pixel fg_color = fg->value;
2030 Pixel bg_color = bg->value;
2032 Pixel fg_color = *fg;
2033 Pixel bg_color = *bg;
2036 #if OPT_HIGHLIGHT_COLOR
2037 if ((fg_color != bg_color) || !hilite_color)
2040 EXCHANGE(*fg, *bg, tmp);
2041 for (n = 0; n < *count; ++n) {
2042 if ((list[n].fg == fg_color && list[n].bg == bg_color)
2043 || (list[n].fg == bg_color && list[n].bg == fg_color)) {
2049 list[*count].fg = fg_color;
2050 list[*count].bg = bg_color;
2051 *count = *count + 1;
2052 TRACE(("swapLocally fg %#lx, bg %#lx ->%d\n",
2053 fg_color, bg_color, *count));
2059 reallySwapColors(XtermWidget xw, ToSwap * list, int count)
2063 TRACE(("reallySwapColors\n"));
2064 for (j = 0; j < count; ++j) {
2065 for_each_text_gc(k) {
2066 redoCgs(xw, list[j].fg, list[j].bg, (CgsEnum) k);
2072 swapVTwinGCs(XtermWidget xw, VTwin * win)
2074 swapCgs(xw, win, gcNorm, gcNormReverse);
2075 swapCgs(xw, win, gcBold, gcBoldReverse);
2079 ReverseVideo(XtermWidget xw)
2081 TScreen *screen = TScreenOf(xw);
2082 ToSwap listToSwap[5];
2085 TRACE(("ReverseVideo\n"));
2088 * Swap SGR foreground and background colors. By convention, these are
2089 * the colors assigned to "black" (SGR #0) and "white" (SGR #7). Also,
2090 * SGR #8 and SGR #15 are the bold (or bright) versions of SGR #0 and
2093 * We don't swap colors that happen to match the screen's foreground
2094 * and background because that tends to produce bizarre effects.
2096 #define swapAnyColor(name,a,b) swapLocally(listToSwap, &numToSwap, &(screen->name[a]), &(screen->name[b]) hc_value)
2097 #define swapAColor(a,b) swapAnyColor(Acolors, a, b)
2098 if_OPT_ISO_COLORS(screen, {
2103 if (T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG))
2104 T_COLOR(screen, TEXT_CURSOR) = T_COLOR(screen, TEXT_BG);
2106 #define swapTColor(a,b) swapAnyColor(Tcolors, a, b)
2107 swapTColor(TEXT_FG, TEXT_BG);
2108 swapTColor(MOUSE_FG, MOUSE_BG);
2110 reallySwapColors(xw, listToSwap, numToSwap);
2112 swapVTwinGCs(xw, &(screen->fullVwin));
2113 #ifndef NO_ACTIVE_ICON
2114 swapVTwinGCs(xw, &(screen->iconVwin));
2115 #endif /* NO_ACTIVE_ICON */
2117 xw->misc.re_verse = (Boolean) ! xw->misc.re_verse;
2119 if (XtIsRealized((Widget) xw)) {
2120 xtermDisplayCursor(xw);
2123 if (TEK4014_SHOWN(xw)) {
2124 TekScreen *tekscr = TekScreenOf(tekWidget);
2125 Window tekwin = TWindow(tekscr);
2126 recolor_cursor(screen,
2128 T_COLOR(screen, MOUSE_FG),
2129 T_COLOR(screen, MOUSE_BG));
2130 XDefineCursor(screen->display, tekwin, tekscr->arrow);
2134 if (screen->scrollWidget)
2135 ScrollBarReverseVideo(screen->scrollWidget);
2137 if (XtIsRealized((Widget) xw)) {
2138 set_background(xw, -1);
2141 TekReverseVideo(tekWidget);
2143 if (XtIsRealized((Widget) xw)) {
2147 if (TEK4014_SHOWN(xw)) {
2148 TekRepaint(tekWidget);
2153 update_reversevideo();
2154 TRACE(("...ReverseVideo\n"));
2158 recolor_cursor(TScreen * screen,
2159 Cursor cursor, /* X cursor ID to set */
2160 unsigned long fg, /* pixel indexes to look up */
2161 unsigned long bg) /* pixel indexes to look up */
2163 Display *dpy = screen->display;
2164 XColor colordefs[2]; /* 0 is foreground, 1 is background */
2166 colordefs[0].pixel = fg;
2167 colordefs[1].pixel = bg;
2168 XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),
2170 XRecolorCursor(dpy, cursor, colordefs, colordefs + 1);
2176 getXftColor(XtermWidget xw, Pixel pixel)
2178 #define CACHE_SIZE 4
2182 } cache[CACHE_SIZE];
2185 int oldest, oldestuse;
2188 oldestuse = 0x7fffffff;
2190 for (i = 0; i < CACHE_SIZE; i++) {
2192 if (cache[i].color.pixel == pixel) {
2193 cache[i].use = ++use;
2194 return &cache[i].color;
2197 if (cache[i].use < oldestuse) {
2198 oldestuse = cache[i].use;
2203 color.pixel = pixel;
2204 XQueryColor(TScreenOf(xw)->display, xw->core.colormap, &color);
2205 cache[i].color.color.red = color.red;
2206 cache[i].color.color.green = color.green;
2207 cache[i].color.color.blue = color.blue;
2208 cache[i].color.color.alpha = 0xffff;
2209 cache[i].color.pixel = pixel;
2210 cache[i].use = ++use;
2211 return &cache[i].color;
2215 * The cell-width is related to, but not the same as the wide-character width.
2216 * We will only get useful values from wcwidth() for codes above 255.
2217 * Otherwise, interpret according to internal data.
2222 #define XtermCellWidth(xw, ch) \
2223 (((ch) == 0 || (ch) == 127) \
2226 ? (((ch) >= 128 && (ch) < 160) \
2227 ? (TScreenOf(xw)->c1_printable ? 1 : 0) \
2231 #define XtermCellWidth(xw, ch) \
2232 (((ch) == 0 || (ch) == 127) \
2239 #endif /* OPT_RENDERWIDE */
2241 #define XFT_FONT(name) screen->name.font
2244 #define UseBoldFont(screen) (!(screen)->colorBDMode || ((screen)->veryBoldColors & BOLD))
2246 #define UseBoldFont(screen) 1
2249 * fontconfig/Xft combination prior to 2.2 has a problem with
2250 * CJK truetype 'double-width' (bi-width/monospace) fonts leading
2251 * to the 's p a c e d o u t' rendering. Consequently, we can't
2252 * rely on XftDrawString8/16 when one of those fonts is used.
2253 * Instead, we need to roll out our own using XftDrawCharSpec.
2254 * A patch in the same spirit (but in a rather different form)
2255 * was applied to gnome vte and gtk2 port of vim.
2256 * See http://bugzilla.mozilla.org/show_bug.cgi?id=196312
2259 xtermXftDrawString(XtermWidget xw,
2260 unsigned flags GCC_UNUSED,
2269 TScreen *screen = TScreenOf(xw);
2277 XftFont *lastFont = 0;
2278 XftFont *currFont = 0;
2281 int fontnum = screen->menu_font_number;
2282 int fwidth = FontWidth(screen);
2285 if ((flags & UNDERLINE)
2286 && !screen->colorULMode
2287 && screen->italicULMode
2288 && XFT_FONT(renderWideItal[fontnum])) {
2289 wfont = XFT_FONT(renderWideItal[fontnum]);
2292 if ((flags & BOLDATTR(screen))
2293 && UseBoldFont(screen)
2294 && XFT_FONT(renderWideBold[fontnum])) {
2295 wfont = XFT_FONT(renderWideBold[fontnum]);
2297 wfont = XFT_FONT(renderWideNorm[fontnum]);
2300 BumpTypedBuffer(XftCharSpec, len);
2301 sbuf = BfBuf(XftCharSpec);
2303 for (src = dst = 0; src < len; src++) {
2304 FcChar32 wc = *text++;
2306 charWidth = XtermCellWidth(xw, (wchar_t) wc);
2310 sbuf[dst].ucs4 = wc;
2311 sbuf[dst].x = (short) (x + fwidth * ncells);
2312 sbuf[dst].y = (short) (y);
2314 currFont = (charWidth == 2 && wfont != 0) ? wfont : font;
2315 ncells += charWidth;
2317 if (lastFont != currFont) {
2318 if ((lastFont != 0) && really) {
2319 XftDrawCharSpec(screen->renderDraw,
2323 (int) (dst - start));
2326 lastFont = currFont;
2330 if ((dst != start) && really) {
2331 XftDrawCharSpec(screen->renderDraw,
2335 (int) (dst - start));
2337 #else /* !OPT_RENDERWIDE */
2342 BumpTypedBuffer(XftChar8, len);
2343 buffer = BfBuf(XftChar8);
2345 for (dst = 0; dst < (int) len; ++dst)
2346 buffer[dst] = CharOf(text[dst]);
2348 XftDrawString8(screen->renderDraw,
2351 x, y, buffer, (int) len);
2358 #define xtermXftWidth(xw, flags, color, font, x, y, chars, len) \
2359 xtermXftDrawString(xw, flags, color, font, x, y, chars, len, False)
2360 #endif /* OPT_RENDERFONT */
2364 * Map characters commonly "fixed" by groff back to their ASCII equivalents.
2365 * Also map other useful equivalents.
2368 AsciiEquivs(unsigned ch)
2371 case 0x2010: /* groff "-" */
2377 case 0x2212: /* groff "\-" */
2380 case 0x2018: /* groff "`" */
2383 case 0x2019: /* groff ' */
2386 case 0x201C: /* groff lq */
2387 case 0x201D: /* groff rq */
2390 case 0x2329: /* groff ".URL" */
2393 case 0x232a: /* groff ".URL" */
2397 if (ch >= 0xff01 && ch <= 0xff5e) {
2398 /* "Fullwidth" codes (actually double-width) */
2408 * Actually this should be called "groff_workaround()" - for the places where
2409 * groff stomps on compatibility. Still, if enough people get used to it,
2410 * this might someday become a quasi-standard.
2413 ucs_workaround(XtermWidget xw,
2422 TScreen *screen = TScreenOf(xw);
2425 if (screen->wide_chars && screen->utf8_mode && ch > 256) {
2426 IChar eqv = (IChar) AsciiEquivs(ch);
2428 if (eqv != (IChar) ch) {
2429 int width = my_wcwidth((int) ch);
2441 x += FontWidth(screen);
2443 } while (width-- > 1);
2446 } else if (ch == HIDDEN_CHAR) {
2455 * Use this when the characters will not fill the cell area properly. Fill the
2456 * area where we'll write the characters, otherwise we'll get gaps between
2457 * them, e.g., in the original background color.
2459 * The cursor is a special case, because the XFillRectangle call only uses the
2460 * foreground, while we've set the cursor color in the background. So we need
2461 * a special GC for that.
2464 xtermFillCells(XtermWidget xw,
2471 TScreen *screen = TScreenOf(xw);
2472 VTwin *currentWin = WhichVWin(screen);
2474 if (!(flags & NOBACKGROUND)) {
2475 CgsEnum srcId = getCgsId(xw, currentWin, gc);
2476 CgsEnum dstId = gcMAX;
2477 Pixel fg = getCgsFore(xw, currentWin, gc);
2478 Pixel bg = getCgsBack(xw, currentWin, gc);
2481 case gcVTcursNormal:
2482 case gcVTcursReverse:
2483 dstId = gcVTcursOutline;
2485 case gcVTcursFilled:
2486 case gcVTcursOutline:
2490 dstId = gcNormReverse;
2496 dstId = gcBoldReverse;
2515 dstId = gcWideReverse;
2518 dstId = gcBoldReverse;
2521 case gcWBoldReverse:
2534 if (dstId != gcMAX) {
2535 setCgsFore(xw, currentWin, dstId, bg);
2536 setCgsBack(xw, currentWin, dstId, fg);
2538 XFillRectangle(screen->display, VWindow(screen),
2539 getCgsGC(xw, currentWin, dstId),
2541 len * (Cardinal) FontWidth(screen),
2542 (unsigned) FontHeight(screen));
2549 xtermSetClipRectangles(Display * dpy,
2558 TScreen *screen = TScreenOf(term);
2559 Drawable draw = VWindow(screen);
2561 XSetClipMask(dpy, gc, None);
2562 XDrawRectangle(screen->display, draw, gc,
2569 XSetClipRectangles(dpy, gc,
2570 x, y, rp, (int) nr, order);
2571 TRACE(("clipping @(%3d,%3d) (%3d,%3d)..(%3d,%3d)\n",
2573 rp->y, rp->x, rp->height, rp->width));
2577 #define xtermSetClipRectangles(dpy, gc, x, y, rp, nr, order) \
2578 XSetClipRectangles(dpy, gc, x, y, rp, (int) nr, order)
2583 * This special case is a couple of percent slower, but avoids a lot of pixel
2584 * trash in rxcurses' hanoi.cmd demo (e.g., 10x20 font).
2586 #define beginClipping(screen,gc,pwidth,plength) \
2587 if (screen->use_clipping && (pwidth > 2)) { \
2590 int clip_y = y - FontHeight(screen) + FontDescent(screen); \
2593 clip.height = (unsigned short) FontHeight(screen); \
2594 clip.width = (unsigned short) (pwidth * plength); \
2595 xtermSetClipRectangles(screen->display, gc, \
2597 &clip, 1, Unsorted); \
2599 #define endClipping(screen,gc) \
2600 XSetClipMask(screen->display, gc, None)
2602 #define beginClipping(screen,gc,pwidth,plength) /* nothing */
2603 #define endClipping(screen,gc) /* nothing */
2604 #endif /* OPT_CLIP_BOLD */
2606 #if OPT_CLIP_BOLD && OPT_RENDERFONT && defined(HAVE_XFTDRAWSETCLIP) && defined(HAVE_XFTDRAWSETCLIPRECTANGLES)
2607 #define beginXftClipping(screen,px,py,plength) \
2608 if (screen->use_clipping && (FontWidth(screen) > 2)) { \
2611 int clip_y = py - FontHeight(screen) + FontDescent(screen); \
2614 clip.height = (unsigned short) (FontHeight(screen)); \
2615 clip.width = (unsigned short) (FontWidth(screen) * plength); \
2616 XftDrawSetClipRectangles (screen->renderDraw, \
2620 #define endXftClipping(screen) \
2621 XftDrawSetClip (screen->renderDraw, 0)
2623 #define beginXftClipping(screen,px,py,plength) /* nothing */
2624 #define endXftClipping(screen) /* nothing */
2625 #endif /* OPT_CLIP_BOLD */
2629 drawClippedXftString(XtermWidget xw,
2632 XftColor * fg_color,
2638 int ncells = xtermXftWidth(xw, flags,
2643 TScreen *screen = TScreenOf(xw);
2645 beginXftClipping(screen, x, y, ncells);
2646 xtermXftDrawString(xw, flags,
2652 endXftClipping(screen);
2657 #ifndef NO_ACTIVE_ICON
2658 #define WhichVFontData(screen,name) \
2659 (IsIcon(screen) ? &((screen)->fnt_icon) \
2660 : &((screen)->name))
2662 #define WhichVFontData(screen,name) \
2667 * Draws text with the specified combination of bold/underline. The return
2668 * value is the updated x position.
2671 drawXtermText(XtermWidget xw,
2681 TScreen *screen = TScreenOf(xw);
2682 Cardinal real_length = len;
2683 Cardinal underline_len = 0;
2684 /* Intended width of the font to draw (as opposed to the actual width of
2685 the X font, and the width of the default font) */
2686 int font_width = ((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide;
2687 Bool did_ul = False;
2694 if (CSET_DOUBLE(chrset)) {
2695 /* We could try drawing double-size characters in the icon, but
2696 * given that the icon font is usually nil or nil2, there
2697 * doesn't seem to be much point.
2700 GC gc2 = ((!IsIcon(screen) && screen->font_doublesize)
2701 ? xterm_DoubleGC(xw, (unsigned) chrset, flags, gc, &inx)
2704 TRACE(("DRAWTEXT%c[%4d,%4d] (%d)%3d:%s\n",
2705 screen->cursor_state == OFF ? ' ' : '*',
2707 visibleIChars(text, len)));
2709 if (gc2 != 0) { /* draw actual double-sized characters */
2710 XFontStruct *fs = screen->double_fonts[inx].fs;
2713 if (!UsingRenderFont(xw))
2716 XRectangle rect, *rp = ▭
2720 flags |= DOUBLEWFONT;
2724 rect.width = (unsigned short) ((int) len * font_width);
2725 rect.height = (unsigned short) (FontHeight(screen));
2727 TRACE(("drawing %s\n", visibleChrsetName((unsigned) chrset)));
2730 rect.y = (short) -(fs->ascent / 2);
2732 flags |= DOUBLEHFONT;
2735 rect.y = (short) (rect.height - (fs->ascent / 2));
2737 flags |= DOUBLEHFONT;
2745 xtermSetClipRectangles(screen->display, gc2,
2746 x, y, rp, nr, YXBanded);
2748 XSetClipMask(screen->display, gc2, None);
2752 /* Call ourselves recursively with the new gc */
2755 * If we're trying to use proportional font, or if the
2756 * font server didn't give us what we asked for wrt
2757 * width, position each character independently.
2759 if (screen->fnt_prop
2760 || (fs->min_bounds.width != fs->max_bounds.width)
2761 || (fs->min_bounds.width != 2 * FontWidth(screen))) {
2762 /* It is hard to fall-through to the main
2763 branch: in a lot of places the check
2764 for the cached font info is for
2765 normal/bold fonts only. */
2767 x = drawXtermText(xw, flags, gc2,
2771 x += FontWidth(screen);
2774 x = drawXtermText(xw, flags, gc2,
2778 x += (int) len *FontWidth(screen);
2781 TRACE(("drawtext [%4d,%4d]\n", y, x));
2782 } else { /* simulate double-sized characters */
2783 unsigned need = 2 * len;
2784 IChar *temp = TypeMallocN(IChar, need);
2788 temp[n++] = *text++;
2791 x = drawXtermText(xw,
2805 if (UsingRenderFont(xw)) {
2806 VTwin *currentWin = WhichVWin(screen);
2807 Display *dpy = screen->display;
2810 int fontnum = screen->menu_font_number;
2813 if (!screen->renderDraw) {
2815 Drawable draw = VWindow(screen);
2818 scr = DefaultScreen(dpy);
2819 visual = DefaultVisual(dpy, scr);
2820 screen->renderDraw = XftDrawCreate(dpy, draw, visual,
2821 DefaultColormap(dpy, scr));
2824 if ((flags & UNDERLINE)
2825 && !screen->colorULMode
2826 && screen->italicULMode
2827 && XFT_FONT(renderFontItal[fontnum])) {
2828 font = XFT_FONT(renderFontItal[fontnum]);
2832 if ((flags & BOLDATTR(screen))
2833 && UseBoldFont(screen)
2834 && XFT_FONT(renderFontBold[fontnum])) {
2835 font = XFT_FONT(renderFontBold[fontnum]);
2837 font = XFT_FONT(renderFontNorm[fontnum]);
2839 values.foreground = getCgsFore(xw, currentWin, gc);
2840 values.background = getCgsBack(xw, currentWin, gc);
2842 if (!(flags & NOBACKGROUND)) {
2843 XftColor *bg_color = getXftColor(xw, values.background);
2844 ncells = xtermXftWidth(xw, flags,
2849 XftDrawRect(screen->renderDraw,
2852 (unsigned) (ncells * FontWidth(screen)),
2853 (unsigned) FontHeight(screen));
2859 /* adding code to substitute simulated line-drawing characters */
2860 int last, first = 0;
2861 Dimension old_wide, old_high = 0;
2864 for (last = 0; last < (int) len; last++) {
2865 Boolean replace = False;
2866 Boolean missing = False;
2867 unsigned ch = (unsigned) text[last];
2871 if (xtermIsDecGraphic(ch)) {
2873 * Xft generally does not have the line-drawing characters
2874 * in cells 1-31. Assume this (we cannot inspect the
2875 * picture easily...), and attempt to fill in from real
2876 * line-drawing character in the font at the Unicode
2877 * position. Failing that, use our own box-characters.
2879 if (screen->force_box_chars
2880 || xtermXftMissing(xw, font, dec2ucs(ch))) {
2886 } else if (ch >= 256) {
2888 * If we're reading UTF-8 from the client, we may have a
2889 * line-drawing character. Translate it back to our
2890 * box-code if Xft tells us that the glyph is missing.
2892 if_OPT_WIDE_CHARS(screen, {
2893 unsigned part = ucs2dec(ch);
2894 if (xtermIsDecGraphic(part) &&
2895 (screen->force_box_chars
2896 || xtermXftMissing(xw, font, ch))) {
2903 if (xtermIsDecGraphic(ch)) {
2905 * Xft generally does not have the line-drawing characters
2906 * in cells 1-31. Check for this, and attempt to fill in
2907 * from real line-drawing character in the font at the
2908 * Unicode position. Failing that, use our own
2911 if (xtermXftMissing(xw, font, ch)) {
2918 * If we now have one of our box-codes, draw it directly.
2920 if (missing || replace) {
2921 /* line drawing character time */
2923 nc = drawClippedXftString(xw,
2926 getXftColor(xw, values.foreground),
2930 (Cardinal) (last - first));
2931 curX += nc * FontWidth(screen);
2932 underline_len += (Cardinal) nc;
2935 old_wide = screen->fnt_wide;
2936 old_high = screen->fnt_high;
2937 screen->fnt_wide = (Dimension) FontWidth(screen);
2938 screen->fnt_high = (Dimension) FontHeight(screen);
2939 xtermDrawBoxChar(xw, ch, flags, gc,
2940 curX, y - FontAscent(screen), 1);
2941 curX += FontWidth(screen);
2943 screen->fnt_wide = old_wide;
2944 screen->fnt_high = old_high;
2946 IChar ch2 = (IChar) ch;
2947 nc = drawClippedXftString(xw,
2950 getXftColor(xw, values.foreground),
2955 curX += nc * FontWidth(screen);
2956 underline_len += (Cardinal) nc;
2962 underline_len += (Cardinal)
2963 drawClippedXftString(xw,
2966 getXftColor(xw, values.foreground),
2970 (Cardinal) (last - first));
2975 underline_len += (Cardinal)
2976 drawClippedXftString(xw,
2979 getXftColor(xw, values.foreground),
2985 #endif /* OPT_BOX_CHARS */
2987 if ((flags & UNDERLINE) && screen->underline && !did_ul) {
2988 if (FontDescent(screen) > 1)
2990 XDrawLine(screen->display, VWindow(screen), gc,
2992 x + (int) underline_len * FontWidth(screen) - 1,
2995 return x + (int) len *FontWidth(screen);
2997 #endif /* OPT_RENDERFONT */
2999 * If we're asked to display a proportional font, do this with a fixed
3000 * pitch. Yes, it's ugly. But we cannot distinguish the use of xterm
3001 * as a dumb terminal vs its use as in fullscreen programs such as vi.
3002 * Hint: do not try to use a proportional font in the icon.
3004 if (!IsIcon(screen) && !(flags & CHARBYCHAR) && screen->fnt_prop) {
3006 XTermFonts *font = ((flags & BOLDATTR(screen))
3007 ? WhichVFontData(screen, fnts[fBold])
3008 : WhichVFontData(screen, fnts[fNorm]));
3011 int cells = WideCells(*text);
3014 if (*text == HIDDEN_CHAR) {
3019 if (IsXtermMissingChar(screen, *text, font)) {
3024 if_WIDE_OR_NARROW(screen, {
3026 temp[0].byte2 = LO_BYTE(*text);
3027 temp[0].byte1 = HI_BYTE(*text);
3028 width = XTextWidth16(font->fs, temp, 1);
3032 temp[0] = (char) LO_BYTE(*text);
3033 width = XTextWidth(font->fs, temp, 1);
3035 adj = (FontWidth(screen) - width) / 2;
3039 xtermFillCells(xw, flags, gc, x, y, (Cardinal) cells);
3040 x = drawXtermText(xw,
3041 flags | NOBACKGROUND | CHARBYCHAR,
3042 gc, x + adj, y, chrset,
3043 text++, 1, on_wide) - adj;
3048 /* If the font is incomplete, draw some substitutions */
3050 && !(flags & NOTRANSLATION)
3051 && (!screen->fnt_boxes || screen->force_box_chars)) {
3052 /* Fill in missing box-characters.
3053 Find regions without missing characters, and draw
3054 them calling ourselves recursively. Draw missing
3055 characters via xtermDrawBoxChar(). */
3056 XTermFonts *font = ((flags & BOLDATTR(screen))
3057 ? WhichVFontData(screen, fnts[fBold])
3058 : WhichVFontData(screen, fnts[fNorm]));
3059 int last, first = 0;
3060 Bool drewBoxes = False;
3062 for (last = 0; last < (int) len; last++) {
3063 unsigned ch = (unsigned) text[last];
3068 if (ch == HIDDEN_CHAR) {
3070 x = drawXtermText(xw, flags | NOTRANSLATION, gc,
3072 chrset, text + first,
3073 (unsigned) (last - first), on_wide);
3079 ch_width = my_wcwidth((int) ch);
3081 IsXtermMissingChar(screen, ch,
3082 ((on_wide || ch_width > 1)
3083 && okFont(NormalWFont(screen)))
3084 ? WhichVFontData(screen, fnts[fWide])
3087 isMissing = IsXtermMissingChar(screen, ch, font);
3091 * If the character is not missing, but we're in wide-character
3092 * mode and the character happens to be a wide-character that
3093 * corresponds to the line-drawing set, allow the forceBoxChars
3094 * resource (or menu entry) to force it to display using our
3097 if_OPT_WIDE_CHARS(screen, {
3101 && TScreenOf(xw)->force_box_chars) {
3109 x = drawXtermText(xw, flags | NOTRANSLATION, gc,
3111 chrset, text + first,
3112 (unsigned) (last - first), on_wide);
3115 if (ucs_workaround(xw, ch, flags, gc,
3119 * if true, we drew at least one cell whether or not it is
3129 xtermDrawBoxChar(xw, ch, flags, gc,
3133 x += (ch_width * FontWidth(screen));
3138 if (last <= first) {
3142 len = (Cardinal) (last - first);
3143 flags |= NOTRANSLATION;
3145 return drawXtermText(xw,
3156 #endif /* OPT_BOX_CHARS */
3158 * Behave as if the font has (maybe Unicode-replacements for) drawing
3159 * characters in the range 1-31 (either we were not asked to ignore them,
3160 * or the caller made sure that there is none).
3162 TRACE(("drawtext%c[%4d,%4d] (%d) %d:%s\n",
3163 screen->cursor_state == OFF ? ' ' : '*',
3165 visibleIChars(text, len)));
3166 y += FontAscent(screen);
3170 if (screen->wide_chars || screen->unicode_font) {
3172 Bool needWide = False;
3173 int ascent_adjust = 0;
3176 BumpTypedBuffer(XChar2b, len);
3177 buffer = BfBuf(XChar2b);
3179 for (src = dst = 0; src < (int) len; src++) {
3180 IChar ch = text[src];
3182 if (ch == HIDDEN_CHAR)
3187 && ((on_wide || my_wcwidth((int) ch) > 1)
3188 && okFont(NormalWFont(screen)))) {
3193 * bitmap-fonts are limited to 16-bits.
3200 buffer[dst].byte2 = LO_BYTE(ch);
3201 buffer[dst].byte1 = HI_BYTE(ch);
3203 #define UCS2SBUF(value) buffer[dst].byte2 = LO_BYTE(value);\
3204 buffer[dst].byte1 = HI_BYTE(value)
3206 #define Map2Sbuf(from,to) (text[src] == from) { UCS2SBUF(to); }
3208 if (screen->latin9_mode && !screen->utf8_mode && text[src] < 256) {
3210 /* see http://www.cs.tut.fi/~jkorpela/latin9.html */
3212 if Map2Sbuf(0xa4, 0x20ac)
3213 else if Map2Sbuf(0xa6, 0x0160)
3214 else if Map2Sbuf(0xa8, 0x0161)
3215 else if Map2Sbuf(0xb4, 0x017d)
3216 else if Map2Sbuf(0xb8, 0x017e)
3217 else if Map2Sbuf(0xbc, 0x0152)
3218 else if Map2Sbuf(0xbd, 0x0153)
3219 else if Map2Sbuf(0xbe, 0x0178)
3223 if (screen->unicode_font
3224 && (text[src] == ANSI_DEL ||
3225 text[src] < ANSI_SPA)) {
3226 unsigned ni = dec2ucs((unsigned) ((text[src] == ANSI_DEL)
3231 #endif /* OPT_MINI_LUIT */
3234 /* FIXME This is probably wrong. But it works. */
3235 underline_len = len;
3237 /* Set the drawing font */
3238 if (!(flags & (DOUBLEHFONT | DOUBLEWFONT))) {
3239 VTwin *currentWin = WhichVWin(screen);
3242 Pixel fg = getCgsFore(xw, currentWin, gc);
3243 Pixel bg = getCgsBack(xw, currentWin, gc);
3246 && (okFont(NormalWFont(screen)) || okFont(BoldWFont(screen)))) {
3247 if ((flags & BOLDATTR(screen)) != 0
3248 && okFont(BoldWFont(screen))) {
3255 } else if ((flags & BOLDATTR(screen)) != 0
3256 && okFont(BoldFont(screen))) {
3264 setCgsFore(xw, currentWin, cgsId, fg);
3265 setCgsBack(xw, currentWin, cgsId, bg);
3266 gc = getCgsGC(xw, currentWin, cgsId);
3268 if (fntId != fNorm) {
3269 XFontStruct *thisFp = WhichVFont(screen, fnts[fntId].fs);
3270 ascent_adjust = (thisFp->ascent
3271 - NormalFont(screen)->ascent);
3272 if (thisFp->max_bounds.width ==
3273 NormalFont(screen)->max_bounds.width * 2) {
3274 underline_len = real_length = (Cardinal) (dst * 2);
3275 } else if (cgsId == gcWide || cgsId == gcWBold) {
3276 underline_len = real_length = (Cardinal) (dst * 2);
3287 if (flags & NOBACKGROUND) {
3288 XDrawString16(screen->display,
3289 VWindow(screen), gc,
3290 x, y + ascent_adjust,
3293 XDrawImageString16(screen->display,
3294 VWindow(screen), gc,
3295 x, y + ascent_adjust,
3299 if ((flags & BOLDATTR(screen)) && screen->enbolden) {
3300 beginClipping(screen, gc, (Cardinal) font_width, len);
3301 XDrawString16(screen->display, VWindow(screen), gc,
3305 endClipping(screen, gc);
3309 #endif /* OPT_WIDE_CHARS */
3311 int length = (int) len; /* X should have used unsigned */
3316 BumpTypedBuffer(char, len);
3317 buffer = BfBuf(char);
3319 for (dst = 0; dst < length; ++dst)
3320 buffer[dst] = (char) LO_BYTE(text[dst]);
3322 char *buffer = (char *) text;
3325 if (flags & NOBACKGROUND) {
3326 XDrawString(screen->display, VWindow(screen), gc,
3327 x, y, buffer, length);
3329 XDrawImageString(screen->display, VWindow(screen), gc,
3330 x, y, buffer, length);
3332 underline_len = (Cardinal) length;
3333 if ((flags & BOLDATTR(screen)) && screen->enbolden) {
3334 beginClipping(screen, gc, font_width, length);
3335 XDrawString(screen->display, VWindow(screen), gc,
3336 x + 1, y, buffer, length);
3337 endClipping(screen, gc);
3341 if ((flags & UNDERLINE) && screen->underline && !did_ul) {
3342 if (FontDescent(screen) > 1)
3344 XDrawLine(screen->display, VWindow(screen), gc,
3345 x, y, (x + (int) underline_len * font_width - 1), y);
3348 return x + (int) real_length *FontWidth(screen);
3353 * Allocate buffer - workaround for wide-character interfaces.
3356 allocXtermChars(ScrnPtr * buffer, Cardinal length)
3359 *buffer = (ScrnPtr) XtMalloc(length);
3361 *buffer = (ScrnPtr) XtRealloc((char *) *buffer, length);
3366 /* set up size hints for window manager; min 1 char by 1 char */
3368 xtermSizeHints(XtermWidget xw, int scrollbarWidth)
3370 TScreen *screen = TScreenOf(xw);
3372 TRACE(("xtermSizeHints\n"));
3373 TRACE((" border %d\n", xw->core.border_width));
3374 TRACE((" scrollbar %d\n", scrollbarWidth));
3376 xw->hints.base_width = 2 * screen->border + scrollbarWidth;
3377 xw->hints.base_height = 2 * screen->border;
3380 TRACE((" toolbar %d\n", ToolbarHeight(xw)));
3382 xw->hints.base_height += ToolbarHeight(xw);
3383 xw->hints.base_height += BorderWidth(xw) * 2;
3384 xw->hints.base_width += BorderWidth(xw) * 2;
3387 xw->hints.width_inc = FontWidth(screen);
3388 xw->hints.height_inc = FontHeight(screen);
3389 xw->hints.min_width = xw->hints.base_width + xw->hints.width_inc;
3390 xw->hints.min_height = xw->hints.base_height + xw->hints.height_inc;
3392 xw->hints.width = MaxCols(screen) * FontWidth(screen) + xw->hints.min_width;
3393 xw->hints.height = MaxRows(screen) * FontHeight(screen) + xw->hints.min_height;
3395 xw->hints.flags |= (PSize | PBaseSize | PMinSize | PResizeInc);
3397 TRACE_HINTS(&(xw->hints));
3401 getXtermSizeHints(XtermWidget xw)
3403 TScreen *screen = TScreenOf(xw);
3406 if (!XGetWMNormalHints(screen->display, VShellWindow(xw),
3408 memset(&xw->hints, 0, sizeof(xw->hints));
3409 TRACE_HINTS(&(xw->hints));
3413 * Returns a GC, selected according to the font (reverse/bold/normal) that is
3414 * required for the current position (implied). The GC is updated with the
3415 * current screen foreground and background colors.
3418 updatedXtermGC(XtermWidget xw, unsigned flags, unsigned fg_bg, Bool hilite)
3420 TScreen *screen = TScreenOf(xw);
3421 VTwin *win = WhichVWin(screen);
3422 CgsEnum cgsId = gcMAX;
3423 unsigned my_fg = extract_fg(xw, fg_bg, flags);
3424 unsigned my_bg = extract_bg(xw, fg_bg, flags);
3425 Pixel fg_pix = getXtermForeground(xw, flags, my_fg);
3426 Pixel bg_pix = getXtermBackground(xw, flags, my_bg);
3428 #if OPT_HIGHLIGHT_COLOR
3429 Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG);
3430 Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG);
3431 Boolean always = screen->hilite_color;
3432 Boolean use_selbg = (Boolean) (always ||
3433 isNotForeground(xw, fg_pix, bg_pix, selbg_pix));
3434 Boolean use_selfg = (Boolean) (always &&
3435 isNotBackground(xw, fg_pix, bg_pix, selfg_pix));
3443 * Discard video attributes overridden by colorXXXMode's.
3445 checkVeryBoldColors(flags, my_fg);
3447 if (ReverseOrHilite(screen, flags, hilite)) {
3448 if (flags & BOLDATTR(screen)) {
3449 cgsId = gcBoldReverse;
3451 cgsId = gcNormReverse;
3454 #if OPT_HIGHLIGHT_COLOR
3455 if (!screen->hilite_color) {
3456 if (selbg_pix != T_COLOR(screen, TEXT_FG)
3457 && selbg_pix != fg_pix
3458 && selbg_pix != bg_pix
3459 && selbg_pix != xw->dft_foreground) {
3465 EXCHANGE(fg_pix, bg_pix, xx_pix);
3466 #if OPT_HIGHLIGHT_COLOR
3467 if (screen->hilite_color) {
3468 if (screen->hilite_reverse) {
3483 if (flags & BOLDATTR(screen)) {
3489 #if OPT_HIGHLIGHT_COLOR
3490 if (!screen->hilite_color || !screen->hilite_reverse) {
3491 if (hilite && !screen->hilite_reverse) {
3501 if ((screen->blink_state == ON) && (!screen->blink_as_bold) && (flags & BLINK)) {
3506 setCgsFore(xw, win, cgsId, fg_pix);
3507 setCgsBack(xw, win, cgsId, bg_pix);
3508 return getCgsGC(xw, win, cgsId);
3512 * Resets the foreground/background of the GC returned by 'updatedXtermGC()'
3513 * to the values that would be set in SGR_Foreground and SGR_Background. This
3514 * duplicates some logic, but only modifies 1/4 as many GC's.
3517 resetXtermGC(XtermWidget xw, unsigned flags, Bool hilite)
3519 TScreen *screen = TScreenOf(xw);
3520 VTwin *win = WhichVWin(screen);
3521 CgsEnum cgsId = gcMAX;
3522 Pixel fg_pix = getXtermForeground(xw, flags, xw->cur_foreground);
3523 Pixel bg_pix = getXtermBackground(xw, flags, xw->cur_background);
3525 checkVeryBoldColors(flags, xw->cur_foreground);
3527 if (ReverseOrHilite(screen, flags, hilite)) {
3528 if (flags & BOLDATTR(screen)) {
3529 cgsId = gcBoldReverse;
3531 cgsId = gcNormReverse;
3534 setCgsFore(xw, win, cgsId, bg_pix);
3535 setCgsBack(xw, win, cgsId, fg_pix);
3538 if (flags & BOLDATTR(screen)) {
3544 setCgsFore(xw, win, cgsId, fg_pix);
3545 setCgsBack(xw, win, cgsId, bg_pix);
3551 * Extract the foreground-color index from a color pair.
3552 * If we've got BOLD or UNDERLINE color-mode active, those will be used.
3555 extract_fg(XtermWidget xw, unsigned color, unsigned flags)
3557 unsigned fg = ExtractForeground(color);
3559 if (TScreenOf(xw)->colorAttrMode
3560 || (fg == ExtractBackground(color))) {
3561 fg = MapToColorMode(fg, TScreenOf(xw), flags);
3567 * Extract the background-color index from a color pair.
3568 * If we've got INVERSE color-mode active, that will be used.
3571 extract_bg(XtermWidget xw, unsigned color, unsigned flags)
3573 unsigned bg = ExtractBackground(color);
3575 if (TScreenOf(xw)->colorAttrMode
3576 || (bg == ExtractForeground(color))) {
3577 if (TScreenOf(xw)->colorRVMode && (flags & INVERSE))
3584 * Combine the current foreground and background into a single 8-bit number.
3585 * Note that we're storing the SGR foreground, since cur_foreground may be set
3586 * to COLOR_UL, COLOR_BD or COLOR_BL, which would make the code larger than 8
3589 * This assumes that fg/bg are equal when we override with one of the special
3593 makeColorPair(int fg, int bg)
3595 unsigned my_bg = (bg >= 0) && (bg < NUM_ANSI_COLORS) ? (unsigned) bg : 0;
3596 unsigned my_fg = (fg >= 0) && (fg < NUM_ANSI_COLORS) ? (unsigned) fg : my_bg;
3598 return (CellColor) (my_fg | (my_bg << COLOR_BITS));
3602 * Using the "current" SGR background, clear a rectangle.
3605 ClearCurBackground(XtermWidget xw,
3611 TScreen *screen = TScreenOf(xw);
3613 TRACE(("ClearCurBackground(%d,%d,%d,%d) %d\n",
3614 top, left, height, width, xw->cur_background));
3616 if (VWindow(screen)) {
3617 set_background(xw, xw->cur_background);
3619 XClearArea(screen->display, VWindow(screen),
3620 left, top, width, height, False);
3622 set_background(xw, -1);
3625 #endif /* OPT_ISO_COLORS */
3628 * Returns a single base character for the given cell.
3631 getXtermCell(TScreen * screen, int row, int col)
3633 LineData *ld = getLineData(screen, row);
3635 assert(ld && (col < (int) ld->lineSize));
3636 return ((ld && (col < (int) ld->lineSize))
3642 * Sets a single base character for the given cell.
3645 putXtermCell(TScreen * screen, int row, int col, int ch)
3647 LineData *ld = getLineData(screen, row);
3649 assert(ld && (col < (int) ld->lineSize));
3650 if (ld && (col < (int) ld->lineSize)) {
3651 ld->charData[col] = (CharData) ch;
3652 if_OPT_WIDE_CHARS(screen, {
3654 for_each_combData(off, ld) {
3655 ld->combData[off][col] = 0;
3663 * Add a combining character for the given cell
3666 addXtermCombining(TScreen * screen, int row, int col, unsigned ch)
3669 LineData *ld = getLineData(screen, row);
3672 TRACE(("addXtermCombining %d,%d %#x (%d)\n",
3673 row, col, ch, my_wcwidth((wchar_t) ch)));
3675 for_each_combData(off, ld) {
3676 if (!ld->combData[off][col]) {
3677 ld->combData[off][col] = (CharData) ch;
3685 #ifdef HAVE_CONFIG_H
3686 #ifdef USE_MY_MEMMOVE
3688 my_memmove(void *s1, void *s2, size_t n)
3691 char *p1 = (char *) s1;
3692 char *p2 = (char *) s2;
3694 if ((p1 + n > p2) && (p2 + n > p1)) {
3696 static size_t length;
3699 length = (n * 3) / 2;
3701 ? TypeRealloc(char, length, bfr)
3702 : TypeMallocN(char, length));
3704 SysError(ERROR_MMALLOC);
3706 for (j = 0; j < n; j++)
3715 #endif /* USE_MY_MEMMOVE */
3717 #ifndef HAVE_STRERROR
3721 extern char *sys_errlist[];
3722 extern int sys_nerr;
3723 if (n > 0 && n < sys_nerr)
3724 return sys_errlist[n];
3731 update_keyboard_type(void)
3733 update_delete_del();
3734 update_tcap_fkeys();
3743 set_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set)
3745 xtermKeyboardType save = xw->keyboard.type;
3747 TRACE(("set_keyboard_type(%s, %s) currently %s\n",
3748 visibleKeyboardType(type),
3750 visibleKeyboardType(xw->keyboard.type)));
3752 xw->keyboard.type = type;
3754 xw->keyboard.type = keyboardIsDefault;
3757 if (save != xw->keyboard.type) {
3758 update_keyboard_type();
3763 toggle_keyboard_type(XtermWidget xw, xtermKeyboardType type)
3765 xtermKeyboardType save = xw->keyboard.type;
3767 TRACE(("toggle_keyboard_type(%s) currently %s\n",
3768 visibleKeyboardType(type),
3769 visibleKeyboardType(xw->keyboard.type)));
3770 if (xw->keyboard.type == type) {
3771 xw->keyboard.type = keyboardIsDefault;
3773 xw->keyboard.type = type;
3776 if (save != xw->keyboard.type) {
3777 update_keyboard_type();
3782 init_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set)
3784 static Bool wasSet = False;
3786 TRACE(("init_keyboard_type(%s, %s) currently %s\n",
3787 visibleKeyboardType(type),
3789 visibleKeyboardType(xw->keyboard.type)));
3792 fprintf(stderr, "Conflicting keyboard type option (%u/%u)\n",
3793 xw->keyboard.type, type);
3795 xw->keyboard.type = type;
3797 update_keyboard_type();
3802 * If the keyboardType resource is set, use that, overriding the individual
3803 * boolean resources for different keyboard types.
3806 decode_keyboard_type(XtermWidget xw, XTERM_RESOURCE * rp)
3808 #define DATA(n, t, f) { n, t, XtOffsetOf(XTERM_RESOURCE, f) }
3809 #define FLAG(n) *(Boolean *)(((char *)rp) + table[n].offset)
3812 xtermKeyboardType type;
3815 #if OPT_HP_FUNC_KEYS
3816 DATA(NAME_HP_KT, keyboardIsHP, hpFunctionKeys),
3818 #if OPT_SCO_FUNC_KEYS
3819 DATA(NAME_SCO_KT, keyboardIsSCO, scoFunctionKeys),
3821 #if OPT_SUN_FUNC_KEYS
3822 DATA(NAME_SUN_KT, keyboardIsSun, sunFunctionKeys),
3825 DATA(NAME_VT220_KT, keyboardIsVT220, sunKeyboard),
3828 DATA(NAME_TCAP_KT, keyboardIsTermcap, termcapKeys),
3833 TRACE(("decode_keyboard_type(%s)\n", rp->keyboardType));
3834 if (!x_strcasecmp(rp->keyboardType, "unknown")) {
3836 * Let the individual resources comprise the keyboard-type.
3838 for (n = 0; n < XtNumber(table); ++n)
3839 init_keyboard_type(xw, table[n].type, FLAG(n));
3840 } else if (!x_strcasecmp(rp->keyboardType, "default")) {
3842 * Set the keyboard-type to the Sun/PC type, allowing modified
3843 * function keys, etc.
3845 for (n = 0; n < XtNumber(table); ++n)
3846 init_keyboard_type(xw, table[n].type, False);
3851 * Choose an individual keyboard type.
3853 for (n = 0; n < XtNumber(table); ++n) {
3854 if (!x_strcasecmp(rp->keyboardType, table[n].name + 1)) {
3860 init_keyboard_type(xw, table[n].type, FLAG(n));
3864 "KeyboardType resource \"%s\" not found\n",
3873 #if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
3875 * If xterm is running in a UTF-8 locale, it is still possible to encounter
3876 * old runtime configurations which yield incomplete or inaccurate data.
3879 systemWcwidthOk(int samplesize, int samplepass)
3884 for (n = 21; n <= 25; ++n) {
3885 int code = (int) dec2ucs((unsigned) n);
3886 int system_code = wcwidth(code);
3887 int intern_code = mk_wcwidth(code);
3890 * Solaris 10 wcwidth() returns "2" for all of the line-drawing (page
3891 * 0x2500) and most of the geometric shapes (a few are excluded, just
3892 * to make it more difficult to use). Do a sanity check to avoid using
3895 if ((system_code < 0 && intern_code >= 1)
3896 || (system_code >= 0 && intern_code != system_code)) {
3897 TRACE(("systemWcwidthOk: broken system line-drawing wcwidth\n"));
3898 oops += (samplepass + 1);
3903 for (n = 0; n < (wchar_t) samplesize; ++n) {
3904 int system_code = wcwidth(n);
3905 int intern_code = mk_wcwidth(n);
3908 * Since mk_wcwidth() is designed to check for nonspacing characters,
3909 * and has rough range-checks for double-width characters, it will
3910 * generally not detect cases where a code has not been assigned.
3912 * Some experimentation with GNU libc suggests that up to 1/4 of the
3913 * codes would differ, simply because the runtime library would have a
3914 * table listing the unassigned codes, and return -1 for those. If
3915 * mk_wcwidth() has no information about a code, it returns 1. On the
3916 * other hand, if the runtime returns a positive number, the two should
3919 * The "up to" is measured for 4k, 8k, 16k of data. With only 1k, the
3920 * number of differences was only 77. However, that is only one
3921 * system, and this is only a sanity check to avoid using broken
3924 if ((system_code < 0 && intern_code >= 1)
3925 || (system_code >= 0 && intern_code != system_code)) {
3929 TRACE(("systemWcwidthOk: %d/%d mismatches, allowed %d\n",
3930 oops, samplesize, samplepass));
3931 return (oops <= samplepass);
3933 #endif /* HAVE_WCWIDTH */
3936 decode_wcwidth(XtermWidget xw)
3938 int mode = ((xw->misc.cjk_width ? 2 : 0)
3939 + (xw->misc.mk_width ? 1 : 0)
3944 #if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
3945 if (xtermEnvUTF8() &&
3946 systemWcwidthOk(xw->misc.mk_samplesize, xw->misc.mk_samplepass)) {
3947 my_wcwidth = wcwidth;
3948 TRACE(("using system wcwidth() function\n"));
3954 my_wcwidth = &mk_wcwidth;
3955 TRACE(("using MK wcwidth() function\n"));
3959 my_wcwidth = &mk_wcwidth_cjk;
3960 TRACE(("using MK-CJK wcwidth() function\n"));
3964 for (first_widechar = 128; first_widechar < 4500; ++first_widechar) {
3965 if (my_wcwidth((int) first_widechar) > 1) {
3966 TRACE(("first_widechar %#x\n", first_widechar));