aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/xterm/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/programs/xterm/util.c')
-rw-r--r--nx-X11/programs/xterm/util.c2951
1 files changed, 2951 insertions, 0 deletions
diff --git a/nx-X11/programs/xterm/util.c b/nx-X11/programs/xterm/util.c
new file mode 100644
index 000000000..84feac48f
--- /dev/null
+++ b/nx-X11/programs/xterm/util.c
@@ -0,0 +1,2951 @@
+/* $XTermId: util.c,v 1.255 2005/09/18 23:48:13 tom Exp $ */
+
+/*
+ * $Xorg: util.c,v 1.3 2000/08/17 19:55:10 cpqbld Exp $
+ */
+
+/* $XFree86: xc/programs/xterm/util.c,v 3.93 2005/09/18 23:48:13 dickey Exp $ */
+
+/*
+ * Copyright 1999-2004,2005 by Thomas E. Dickey
+ *
+ * All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name(s) of the above copyright
+ * holders shall not be used in advertising or otherwise to promote the
+ * sale, use or other dealings in this Software without prior written
+ * authorization.
+ *
+ *
+ * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital Equipment
+ * Corporation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ *
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/* util.c */
+
+#include <xterm.h>
+
+#include <data.h>
+#include <error.h>
+#include <menu.h>
+#include <fontutils.h>
+#include <xstrings.h>
+
+#if OPT_WIDE_CHARS
+#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
+#include <wchar.h>
+#endif
+#include <wcwidth.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+
+static int ClearInLine(TScreen * screen, int row, int col, unsigned len);
+static int handle_translated_exposure(TScreen * screen,
+ int rect_x,
+ int rect_y,
+ int rect_width,
+ int rect_height);
+static void ClearLeft(TScreen * screen);
+static void CopyWait(TScreen * screen);
+static void horizontal_copy_area(TScreen * screen,
+ int firstchar,
+ int nchars,
+ int amount);
+static void vertical_copy_area(TScreen * screen,
+ int firstline,
+ int nlines,
+ int amount);
+
+#if OPT_WIDE_CHARS
+int (*my_wcwidth) (wchar_t);
+#endif
+
+/*
+ * These routines are used for the jump scroll feature
+ */
+void
+FlushScroll(TScreen * screen)
+{
+ int i;
+ int shift = -screen->topline;
+ int bot = screen->max_row - shift;
+ int refreshtop;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+
+ if (screen->cursor_state)
+ HideCursor();
+ if (screen->scroll_amt > 0) {
+ refreshheight = screen->refresh_amt;
+ scrollheight = screen->bot_marg - screen->top_marg -
+ refreshheight + 1;
+ if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
+ (i = screen->max_row - screen->scroll_amt + 1))
+ refreshtop = i;
+ if (screen->scrollWidget && !screen->alternate
+ && screen->top_marg == 0) {
+ scrolltop = 0;
+ if ((scrollheight += shift) > i)
+ scrollheight = i;
+ if ((i = screen->bot_marg - bot) > 0 &&
+ (refreshheight -= i) < screen->scroll_amt)
+ refreshheight = screen->scroll_amt;
+ if ((i = screen->savedlines) < screen->savelines) {
+ if ((i += screen->scroll_amt) >
+ screen->savelines)
+ i = screen->savelines;
+ screen->savedlines = i;
+ ScrollBarDrawThumb(screen->scrollWidget);
+ }
+ } else {
+ scrolltop = screen->top_marg + shift;
+ if ((i = bot - (screen->bot_marg - screen->refresh_amt +
+ screen->scroll_amt)) > 0) {
+ if (bot < screen->bot_marg)
+ refreshheight = screen->scroll_amt + i;
+ } else {
+ scrollheight += i;
+ refreshheight = screen->scroll_amt;
+ if ((i = screen->top_marg + screen->scroll_amt -
+ 1 - bot) > 0) {
+ refreshtop += i;
+ refreshheight -= i;
+ }
+ }
+ }
+ } else {
+ refreshheight = -screen->refresh_amt;
+ scrollheight = screen->bot_marg - screen->top_marg -
+ refreshheight + 1;
+ refreshtop = screen->top_marg + shift;
+ scrolltop = refreshtop + refreshheight;
+ if ((i = screen->bot_marg - bot) > 0)
+ scrollheight -= i;
+ if ((i = screen->top_marg + refreshheight - 1 - bot) > 0)
+ refreshheight -= i;
+ }
+ scrolling_copy_area(screen, scrolltop + screen->scroll_amt,
+ scrollheight, screen->scroll_amt);
+ ScrollSelection(screen, -(screen->scroll_amt), False);
+ screen->scroll_amt = 0;
+ screen->refresh_amt = 0;
+ if (refreshheight > 0) {
+ ClearCurBackground(screen,
+ (int) refreshtop * FontHeight(screen) + screen->border,
+ (int) OriginX(screen),
+ (unsigned) refreshheight * FontHeight(screen),
+ (unsigned) Width(screen));
+ ScrnRefresh(screen, refreshtop, 0, refreshheight,
+ MaxCols(screen), False);
+ }
+ return;
+}
+
+int
+AddToRefresh(TScreen * screen)
+{
+ int amount = screen->refresh_amt;
+ int row = screen->cur_row;
+
+ if (amount == 0) {
+ return (0);
+ } else if (amount > 0) {
+ int bottom;
+
+ if (row == (bottom = screen->bot_marg) - amount) {
+ screen->refresh_amt++;
+ return (1);
+ }
+ return (row >= bottom - amount + 1 && row <= bottom);
+ } else {
+ int top;
+
+ amount = -amount;
+ if (row == (top = screen->top_marg) + amount) {
+ screen->refresh_amt--;
+ return (1);
+ }
+ return (row <= top + amount - 1 && row >= top);
+ }
+}
+
+/*
+ * If we're scrolling, leave the selection intact if possible.
+ * If it will bump into one of the extremes of the saved-lines, truncate that.
+ * If the selection is not contained within the scrolled region, clear it.
+ */
+static void
+adjustHiliteOnFwdScroll(TScreen * screen, int amount, Boolean all_lines)
+{
+ int lo_row = (all_lines
+ ? (screen->bot_marg - screen->savelines)
+ : screen->top_marg);
+ int hi_row = screen->bot_marg;
+
+ TRACE2(("adjustSelection FWD %s by %d (%s)\n",
+ screen->alternate ? "alternate" : "normal",
+ amount,
+ all_lines ? "all" : "visible"));
+ TRACE2((" before highlite %d.%d .. %d.%d\n",
+ screen->startHRow,
+ screen->startHCol,
+ screen->endHRow,
+ screen->endHCol));
+ TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg));
+ TRACE2((" limits %d..%d\n", lo_row, hi_row));
+
+ if (screen->startHRow >= lo_row
+ && screen->startHRow - amount < lo_row) {
+ /* truncate the selection because its start would move out of region */
+ if (lo_row + amount <= screen->endHRow) {
+ TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
+ screen->startHRow,
+ screen->startHCol,
+ lo_row + amount,
+ 0));
+ screen->startHRow = lo_row + amount;
+ screen->startHCol = 0;
+ } else {
+ TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
+ screen->startHRow,
+ screen->startHCol,
+ screen->endHRow,
+ screen->endHCol,
+ -amount,
+ lo_row,
+ hi_row));
+ ScrnDisownSelection(screen);
+ }
+ } else if (screen->startHRow <= hi_row && screen->endHRow > hi_row) {
+ ScrnDisownSelection(screen);
+ } else if (screen->startHRow < lo_row && screen->endHRow > lo_row) {
+ ScrnDisownSelection(screen);
+ }
+
+ TRACE2((" after highlite %d.%d .. %d.%d\n",
+ screen->startHRow,
+ screen->startHCol,
+ screen->endHRow,
+ screen->endHCol));
+}
+
+/*
+ * This is the same as adjustHiliteOnFwdScroll(), but reversed. In this case,
+ * only the visible lines are affected.
+ */
+static void
+adjustHiliteOnBakScroll(TScreen * screen, int amount)
+{
+ int lo_row = screen->top_marg;
+ int hi_row = screen->bot_marg;
+
+ TRACE2(("adjustSelection BAK %s by %d (%s)\n",
+ screen->alternate ? "alternate" : "normal",
+ amount,
+ "visible"));
+ TRACE2((" before highlite %d.%d .. %d.%d\n",
+ screen->startHRow,
+ screen->startHCol,
+ screen->endHRow,
+ screen->endHCol));
+ TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg));
+
+ if (screen->endHRow >= hi_row
+ && screen->endHRow + amount > hi_row) {
+ /* truncate the selection because its start would move out of region */
+ if (hi_row - amount >= screen->startHRow) {
+ TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
+ screen->startHRow,
+ screen->startHCol,
+ hi_row - amount,
+ 0));
+ screen->endHRow = hi_row - amount;
+ screen->endHCol = 0;
+ } else {
+ TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
+ screen->startHRow,
+ screen->startHCol,
+ screen->endHRow,
+ screen->endHCol,
+ amount,
+ lo_row,
+ hi_row));
+ ScrnDisownSelection(screen);
+ }
+ } else if (screen->endHRow >= lo_row && screen->startHRow < lo_row) {
+ ScrnDisownSelection(screen);
+ } else if (screen->endHRow > hi_row && screen->startHRow > hi_row) {
+ ScrnDisownSelection(screen);
+ }
+
+ TRACE2((" after highlite %d.%d .. %d.%d\n",
+ screen->startHRow,
+ screen->startHCol,
+ screen->endHRow,
+ screen->endHCol));
+}
+
+/*
+ * scrolls the screen by amount lines, erases bottom, doesn't alter
+ * cursor position (i.e. cursor moves down amount relative to text).
+ * All done within the scrolling region, of course.
+ * requires: amount > 0
+ */
+void
+xtermScroll(TScreen * screen, int amount)
+{
+ int i = screen->bot_marg - screen->top_marg + 1;
+ int shift;
+ int bot;
+ int refreshtop = 0;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+ Boolean scroll_all_lines = (screen->scrollWidget
+ && !screen->alternate
+ && screen->top_marg == 0);
+
+ TRACE(("xtermScroll count=%d\n", amount));
+
+ screen->cursor_busy += 1;
+ screen->cursor_moved = True;
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ if (amount > i)
+ amount = i;
+
+ if (ScrnHaveSelection(screen))
+ adjustHiliteOnFwdScroll(screen, amount, scroll_all_lines);
+
+ if (screen->jumpscroll) {
+ if (screen->scroll_amt > 0) {
+ if (screen->refresh_amt + amount > i)
+ FlushScroll(screen);
+ screen->scroll_amt += amount;
+ screen->refresh_amt += amount;
+ } else {
+ if (screen->scroll_amt < 0)
+ FlushScroll(screen);
+ screen->scroll_amt = amount;
+ screen->refresh_amt = amount;
+ }
+ refreshheight = 0;
+ } else {
+ ScrollSelection(screen, -(amount), False);
+ if (amount == i) {
+ ClearScreen(screen);
+ screen->cursor_busy -= 1;
+ return;
+ }
+
+ shift = -screen->topline;
+ bot = screen->max_row - shift;
+ scrollheight = i - amount;
+ refreshheight = amount;
+
+ if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
+ (i = screen->max_row - refreshheight + 1))
+ refreshtop = i;
+
+ if (scroll_all_lines) {
+ scrolltop = 0;
+ if ((scrollheight += shift) > i)
+ scrollheight = i;
+ if ((i = screen->savedlines) < screen->savelines) {
+ if ((i += amount) > screen->savelines)
+ i = screen->savelines;
+ screen->savedlines = i;
+ ScrollBarDrawThumb(screen->scrollWidget);
+ }
+ } else {
+ scrolltop = screen->top_marg + shift;
+ if ((i = screen->bot_marg - bot) > 0) {
+ scrollheight -= i;
+ if ((i = screen->top_marg + amount - 1 - bot) >= 0) {
+ refreshtop += i;
+ refreshheight -= i;
+ }
+ }
+ }
+
+ if (screen->multiscroll && amount == 1 &&
+ screen->topline == 0 && screen->top_marg == 0 &&
+ screen->bot_marg == screen->max_row) {
+ if (screen->incopy < 0 && screen->scrolls == 0)
+ CopyWait(screen);
+ screen->scrolls++;
+ }
+
+ scrolling_copy_area(screen, scrolltop + amount, scrollheight, amount);
+
+ if (refreshheight > 0) {
+ ClearCurBackground(screen,
+ (int) refreshtop * FontHeight(screen) + screen->border,
+ (int) OriginX(screen),
+ (unsigned) refreshheight * FontHeight(screen),
+ (unsigned) Width(screen));
+ if (refreshheight > shift)
+ refreshheight = shift;
+ }
+ }
+
+ if (amount > 0) {
+ if (scroll_all_lines) {
+ ScrnDeleteLine(screen,
+ screen->allbuf,
+ screen->bot_marg + screen->savelines,
+ 0,
+ (unsigned) amount,
+ (unsigned) MaxCols(screen));
+ } else {
+ ScrnDeleteLine(screen,
+ screen->visbuf,
+ screen->bot_marg,
+ screen->top_marg,
+ (unsigned) amount,
+ (unsigned) MaxCols(screen));
+ }
+ }
+
+ if (refreshheight > 0) {
+ ScrnRefresh(screen, refreshtop, 0, refreshheight,
+ MaxCols(screen), False);
+ }
+
+ screen->cursor_busy -= 1;
+ return;
+}
+
+/*
+ * Reverse scrolls the screen by amount lines, erases top, doesn't alter
+ * cursor position (i.e. cursor moves up amount relative to text).
+ * All done within the scrolling region, of course.
+ * Requires: amount > 0
+ */
+void
+RevScroll(TScreen * screen, int amount)
+{
+ int i = screen->bot_marg - screen->top_marg + 1;
+ int shift;
+ int bot;
+ int refreshtop;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+
+ TRACE(("RevScroll count=%d\n", amount));
+
+ screen->cursor_busy += 1;
+ screen->cursor_moved = True;
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ if (amount > i)
+ amount = i;
+
+ if (ScrnHaveSelection(screen))
+ adjustHiliteOnBakScroll(screen, amount);
+
+ if (screen->jumpscroll) {
+ if (screen->scroll_amt < 0) {
+ if (-screen->refresh_amt + amount > i)
+ FlushScroll(screen);
+ screen->scroll_amt -= amount;
+ screen->refresh_amt -= amount;
+ } else {
+ if (screen->scroll_amt > 0)
+ FlushScroll(screen);
+ screen->scroll_amt = -amount;
+ screen->refresh_amt = -amount;
+ }
+ } else {
+ shift = -screen->topline;
+ bot = screen->max_row - shift;
+ refreshheight = amount;
+ scrollheight = screen->bot_marg - screen->top_marg -
+ refreshheight + 1;
+ refreshtop = screen->top_marg + shift;
+ scrolltop = refreshtop + refreshheight;
+ if ((i = screen->bot_marg - bot) > 0)
+ scrollheight -= i;
+ if ((i = screen->top_marg + refreshheight - 1 - bot) > 0)
+ refreshheight -= i;
+
+ if (screen->multiscroll && amount == 1 &&
+ screen->topline == 0 && screen->top_marg == 0 &&
+ screen->bot_marg == screen->max_row) {
+ if (screen->incopy < 0 && screen->scrolls == 0)
+ CopyWait(screen);
+ screen->scrolls++;
+ }
+
+ scrolling_copy_area(screen, scrolltop - amount, scrollheight, -amount);
+
+ if (refreshheight > 0) {
+ ClearCurBackground(screen,
+ (int) refreshtop * FontHeight(screen) + screen->border,
+ (int) OriginX(screen),
+ (unsigned) refreshheight * FontHeight(screen),
+ (unsigned) Width(screen));
+ }
+ }
+ if (amount > 0) {
+ ScrnInsertLine(screen,
+ screen->visbuf,
+ screen->bot_marg,
+ screen->top_marg,
+ (unsigned) amount,
+ (unsigned) MaxCols(screen));
+ }
+ screen->cursor_busy -= 1;
+ return;
+}
+
+/*
+ * If cursor not in scrolling region, returns. Else,
+ * inserts n blank lines at the cursor's position. Lines above the
+ * bottom margin are lost.
+ */
+void
+InsertLine(TScreen * screen, int n)
+{
+ int i;
+ int shift;
+ int bot;
+ int refreshtop;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+
+ if (!ScrnIsLineInMargins(screen, screen->cur_row - screen->topline))
+ return;
+
+ TRACE(("InsertLine count=%d\n", n));
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ if (ScrnHaveSelection(screen)
+ && ScrnAreLinesInSelection(screen, screen->top_marg, screen->bot_marg)) {
+ ScrnDisownSelection(screen);
+ }
+
+ screen->do_wrap = 0;
+ if (n > (i = screen->bot_marg - screen->cur_row + 1))
+ n = i;
+ if (screen->jumpscroll) {
+ if (screen->scroll_amt <= 0 &&
+ screen->cur_row <= -screen->refresh_amt) {
+ if (-screen->refresh_amt + n > MaxRows(screen))
+ FlushScroll(screen);
+ screen->scroll_amt -= n;
+ screen->refresh_amt -= n;
+ } else if (screen->scroll_amt)
+ FlushScroll(screen);
+ }
+ if (!screen->scroll_amt) {
+ shift = -screen->topline;
+ bot = screen->max_row - shift;
+ refreshheight = n;
+ scrollheight = screen->bot_marg - screen->cur_row - refreshheight + 1;
+ refreshtop = screen->cur_row + shift;
+ scrolltop = refreshtop + refreshheight;
+ if ((i = screen->bot_marg - bot) > 0)
+ scrollheight -= i;
+ if ((i = screen->cur_row + refreshheight - 1 - bot) > 0)
+ refreshheight -= i;
+ vertical_copy_area(screen, scrolltop - n, scrollheight, -n);
+ if (refreshheight > 0) {
+ ClearCurBackground(screen,
+ (int) refreshtop * FontHeight(screen) + screen->border,
+ (int) OriginX(screen),
+ (unsigned) refreshheight * FontHeight(screen),
+ (unsigned) Width(screen));
+ }
+ }
+ if (n > 0) {
+ ScrnInsertLine(screen,
+ screen->visbuf,
+ screen->bot_marg,
+ screen->cur_row,
+ (unsigned) n,
+ (unsigned) MaxCols(screen));
+ }
+}
+
+/*
+ * If cursor not in scrolling region, returns. Else, deletes n lines
+ * at the cursor's position, lines added at bottom margin are blank.
+ */
+void
+DeleteLine(TScreen * screen, int n)
+{
+ int i;
+ int shift;
+ int bot;
+ int refreshtop;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+
+ if (!ScrnIsLineInMargins(screen, screen->cur_row - screen->topline))
+ return;
+
+ TRACE(("DeleteLine count=%d\n", n));
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ if (ScrnHaveSelection(screen)
+ && ScrnAreLinesInSelection(screen, screen->top_marg, screen->bot_marg)) {
+ ScrnDisownSelection(screen);
+ }
+
+ screen->do_wrap = 0;
+ if (n > (i = screen->bot_marg - screen->cur_row + 1))
+ n = i;
+ if (screen->jumpscroll) {
+ if (screen->scroll_amt >= 0 && screen->cur_row == screen->top_marg) {
+ if (screen->refresh_amt + n > MaxRows(screen))
+ FlushScroll(screen);
+ screen->scroll_amt += n;
+ screen->refresh_amt += n;
+ } else if (screen->scroll_amt)
+ FlushScroll(screen);
+ }
+ if (!screen->scroll_amt) {
+
+ shift = -screen->topline;
+ bot = screen->max_row - shift;
+ scrollheight = i - n;
+ refreshheight = n;
+ if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
+ (i = screen->max_row - refreshheight + 1))
+ refreshtop = i;
+ if (screen->scrollWidget && !screen->alternate && screen->cur_row == 0) {
+ scrolltop = 0;
+ if ((scrollheight += shift) > i)
+ scrollheight = i;
+ if ((i = screen->savedlines) < screen->savelines) {
+ if ((i += n) > screen->savelines)
+ i = screen->savelines;
+ screen->savedlines = i;
+ ScrollBarDrawThumb(screen->scrollWidget);
+ }
+ } else {
+ scrolltop = screen->cur_row + shift;
+ if ((i = screen->bot_marg - bot) > 0) {
+ scrollheight -= i;
+ if ((i = screen->cur_row + n - 1 - bot) >= 0) {
+ refreshheight -= i;
+ }
+ }
+ }
+ vertical_copy_area(screen, scrolltop + n, scrollheight, n);
+ if (refreshheight > 0) {
+ ClearCurBackground(screen,
+ (int) refreshtop * FontHeight(screen) + screen->border,
+ (int) OriginX(screen),
+ (unsigned) refreshheight * FontHeight(screen),
+ (unsigned) Width(screen));
+ }
+ }
+ /* adjust screen->buf */
+ if (n > 0) {
+ if (screen->scrollWidget
+ && !screen->alternate
+ && screen->cur_row == 0)
+ ScrnDeleteLine(screen,
+ screen->allbuf,
+ screen->bot_marg + screen->savelines,
+ 0,
+ (unsigned) n,
+ (unsigned) MaxCols(screen));
+ else
+ ScrnDeleteLine(screen,
+ screen->visbuf,
+ screen->bot_marg,
+ screen->cur_row,
+ (unsigned) n,
+ (unsigned) MaxCols(screen));
+ }
+}
+
+/*
+ * Insert n blanks at the cursor's position, no wraparound
+ */
+void
+InsertChar(TScreen * screen, unsigned n)
+{
+ unsigned limit;
+ int row = screen->cur_row - screen->topline;
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ TRACE(("InsertChar count=%d\n", n));
+
+ if (ScrnHaveSelection(screen)
+ && ScrnIsLineInSelection(screen, row)) {
+ ScrnDisownSelection(screen);
+ }
+ screen->do_wrap = 0;
+
+ assert(screen->cur_col <= screen->max_col);
+ limit = MaxCols(screen) - screen->cur_col;
+
+ if (n > limit)
+ n = limit;
+
+ assert(n != 0);
+ if (row <= screen->max_row) {
+ if (!AddToRefresh(screen)) {
+ int col = MaxCols(screen) - n;
+ if (screen->scroll_amt)
+ FlushScroll(screen);
+
+#if OPT_DEC_CHRSET
+ if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, screen->cur_row)[0])) {
+ col = MaxCols(screen) / 2 - n;
+ }
+#endif
+ /*
+ * prevent InsertChar from shifting the end of a line over
+ * if it is being appended to
+ */
+ if (non_blank_line(screen->visbuf, screen->cur_row,
+ screen->cur_col, MaxCols(screen)))
+ horizontal_copy_area(screen, screen->cur_col,
+ col - screen->cur_col,
+ (int) n);
+
+ ClearCurBackground(screen,
+ CursorY(screen, screen->cur_row),
+ CurCursorX(screen, screen->cur_row, screen->cur_col),
+ (unsigned) FontHeight(screen),
+ n * CurFontWidth(screen, screen->cur_row));
+ }
+ }
+ /* adjust screen->buf */
+ ScrnInsertChar(screen, n);
+}
+
+/*
+ * Deletes n chars at the cursor's position, no wraparound.
+ */
+void
+DeleteChar(TScreen * screen, unsigned n)
+{
+ unsigned limit;
+ int row = screen->cur_row - screen->topline;
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ TRACE(("DeleteChar count=%d\n", n));
+
+ if (ScrnHaveSelection(screen)
+ && ScrnIsLineInSelection(screen, row)) {
+ ScrnDisownSelection(screen);
+ }
+ screen->do_wrap = 0;
+
+ assert(screen->cur_col <= screen->max_col);
+ limit = MaxCols(screen) - screen->cur_col;
+
+ if (n > limit)
+ n = limit;
+
+ assert(n != 0);
+ if (row <= screen->max_row) {
+ if (!AddToRefresh(screen)) {
+ int col = MaxCols(screen) - n;
+ if (screen->scroll_amt)
+ FlushScroll(screen);
+
+#if OPT_DEC_CHRSET
+ if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, screen->cur_row)[0])) {
+ col = MaxCols(screen) / 2 - n;
+ }
+#endif
+ horizontal_copy_area(screen,
+ (int) (screen->cur_col + n),
+ col - screen->cur_col,
+ -((int) n));
+
+ ClearCurBackground(screen,
+ CursorY(screen, screen->cur_row),
+ CurCursorX(screen, screen->cur_row, col),
+ (unsigned) FontHeight(screen),
+ n * CurFontWidth(screen, screen->cur_row));
+ }
+ }
+ if (n > 0) {
+ /* adjust screen->buf */
+ ScrnDeleteChar(screen, (unsigned) n);
+ }
+}
+
+/*
+ * Clear from cursor position to beginning of display, inclusive.
+ */
+static void
+ClearAbove(TScreen * screen)
+{
+ if (screen->protected_mode != OFF_PROTECT) {
+ int row;
+ unsigned len = MaxCols(screen);
+
+ assert(screen->max_col >= 0);
+ for (row = 0; row <= screen->max_row; row++)
+ ClearInLine(screen, row, 0, len);
+ } else {
+ int top, height;
+
+ if (screen->cursor_state)
+ HideCursor();
+ if ((top = -screen->topline) <= screen->max_row) {
+ if (screen->scroll_amt)
+ FlushScroll(screen);
+ if ((height = screen->cur_row + top) > screen->max_row)
+ height = screen->max_row;
+ if ((height -= top) > 0) {
+ ClearCurBackground(screen,
+ top * FontHeight(screen) + screen->border,
+ OriginX(screen),
+ (unsigned) (height * FontHeight(screen)),
+ (unsigned) (Width(screen)));
+ }
+ }
+ ClearBufRows(screen, 0, screen->cur_row - 1);
+ }
+
+ if (screen->cur_row - screen->topline <= screen->max_row)
+ ClearLeft(screen);
+}
+
+/*
+ * Clear from cursor position to end of display, inclusive.
+ */
+static void
+ClearBelow(TScreen * screen)
+{
+ ClearRight(screen, -1);
+
+ if (screen->protected_mode != OFF_PROTECT) {
+ int row;
+ unsigned len = MaxCols(screen);
+
+ assert(screen->max_col >= 0);
+ for (row = screen->cur_row + 1; row <= screen->max_row; row++)
+ ClearInLine(screen, row, 0, len);
+ } else {
+ int top;
+
+ if ((top = screen->cur_row - screen->topline) <= screen->max_row) {
+ if (screen->scroll_amt)
+ FlushScroll(screen);
+ if (++top <= screen->max_row) {
+ ClearCurBackground(screen,
+ top * FontHeight(screen) + screen->border,
+ OriginX(screen),
+ (unsigned) ((screen->max_row - top + 1)
+ * FontHeight(screen)),
+ (unsigned) (Width(screen)));
+ }
+ }
+ ClearBufRows(screen, screen->cur_row + 1, screen->max_row);
+ }
+}
+
+/*
+ * Clear the given row, for the given range of columns, returning 1 if no
+ * protected characters were found, 0 otherwise.
+ */
+static int
+ClearInLine(TScreen * screen, int row, int col, unsigned len)
+{
+ int rc = 1;
+ int flags = TERM_COLOR_FLAGS(term);
+
+ TRACE(("ClearInLine(row=%d, col=%d, len=%d) vs %d..%d\n",
+ row, col, len,
+ screen->startHRow,
+ screen->startHCol));
+
+ if (ScrnHaveSelection(screen)
+ && ScrnIsLineInSelection(screen, row)) {
+ ScrnDisownSelection(screen);
+ }
+
+ /*
+ * If we're clearing to the end of the line, we won't count this as
+ * "drawn" characters. We'll only do cut/paste on "drawn" characters,
+ * so this has the effect of suppressing trailing blanks from a
+ * selection.
+ */
+ if (col + (int) len < MaxCols(screen)) {
+ flags |= CHARDRAWN;
+ } else {
+ len = MaxCols(screen) - col;
+ }
+
+ /* If we've marked protected text on the screen, we'll have to
+ * check each time we do an erase.
+ */
+ if (screen->protected_mode != OFF_PROTECT) {
+ unsigned n;
+ Char *attrs = SCRN_BUF_ATTRS(screen, row) + col;
+ int saved_mode = screen->protected_mode;
+ Bool done;
+
+ /* disable this branch during recursion */
+ screen->protected_mode = OFF_PROTECT;
+
+ do {
+ done = True;
+ for (n = 0; n < len; n++) {
+ if (attrs[n] & PROTECTED) {
+ rc = 0; /* found a protected segment */
+ if (n != 0)
+ ClearInLine(screen, row, col, n);
+ while ((n < len)
+ && (attrs[n] & PROTECTED))
+ n++;
+ done = False;
+ break;
+ }
+ }
+ /* setup for another segment, past the protected text */
+ if (!done) {
+ attrs += n;
+ col += n;
+ len -= n;
+ }
+ } while (!done);
+
+ screen->protected_mode = saved_mode;
+ if (len <= 0)
+ return 0;
+ }
+ /* fall through to the final non-protected segment */
+
+ if (screen->cursor_state)
+ HideCursor();
+ screen->do_wrap = 0;
+
+ if (row - screen->topline <= screen->max_row) {
+ if (!AddToRefresh(screen)) {
+ if (screen->scroll_amt)
+ FlushScroll(screen);
+ ClearCurBackground(screen,
+ CursorY(screen, row),
+ CurCursorX(screen, row, col),
+ (unsigned) FontHeight(screen),
+ len * CurFontWidth(screen, row));
+ }
+ }
+
+ memset(SCRN_BUF_CHARS(screen, row) + col, ' ', len);
+ memset(SCRN_BUF_ATTRS(screen, row) + col, flags, len);
+
+ if_OPT_EXT_COLORS(screen, {
+ memset(SCRN_BUF_FGRND(screen, row) + col, term->sgr_foreground, len);
+ memset(SCRN_BUF_BGRND(screen, row) + col, term->cur_background, len);
+ });
+ if_OPT_ISO_TRADITIONAL_COLORS(screen, {
+ memset(SCRN_BUF_COLOR(screen, row) + col, xtermColorPair(), len);
+ });
+ if_OPT_DEC_CHRSET({
+ memset(SCRN_BUF_CSETS(screen, row) + col,
+ curXtermChrSet(screen->cur_row), len);
+ });
+ if_OPT_WIDE_CHARS(screen, {
+ memset(SCRN_BUF_WIDEC(screen, row) + col, 0, len);
+ memset(SCRN_BUF_COM1L(screen, row) + col, 0, len);
+ memset(SCRN_BUF_COM1H(screen, row) + col, 0, len);
+ memset(SCRN_BUF_COM2L(screen, row) + col, 0, len);
+ memset(SCRN_BUF_COM2H(screen, row) + col, 0, len);
+ });
+
+ return rc;
+}
+
+/*
+ * Clear the next n characters on the cursor's line, including the cursor's
+ * position.
+ */
+void
+ClearRight(TScreen * screen, int n)
+{
+ unsigned len = (MaxCols(screen) - screen->cur_col);
+
+ assert(screen->max_col >= 0);
+ assert(screen->max_col >= screen->cur_col);
+
+ if (n < 0) /* the remainder of the line */
+ n = MaxCols(screen);
+ if (n == 0) /* default for 'ECH' */
+ n = 1;
+
+ if (len > (unsigned) n)
+ len = n;
+
+ (void) ClearInLine(screen, screen->cur_row, screen->cur_col, len);
+
+ /* with the right part cleared, we can't be wrapping */
+ ScrnClrWrapped(screen, screen->cur_row);
+}
+
+/*
+ * Clear first part of cursor's line, inclusive.
+ */
+static void
+ClearLeft(TScreen * screen)
+{
+ unsigned len = screen->cur_col + 1;
+ assert(screen->cur_col >= 0);
+
+ (void) ClearInLine(screen, screen->cur_row, 0, len);
+}
+
+/*
+ * Erase the cursor's line.
+ */
+static void
+ClearLine(TScreen * screen)
+{
+ unsigned len = MaxCols(screen);
+
+ assert(screen->max_col >= 0);
+ (void) ClearInLine(screen, screen->cur_row, 0, len);
+}
+
+void
+ClearScreen(TScreen * screen)
+{
+ int top;
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ ScrnDisownSelection(screen);
+ screen->do_wrap = 0;
+ if ((top = -screen->topline) <= screen->max_row) {
+ if (screen->scroll_amt)
+ FlushScroll(screen);
+ ClearCurBackground(screen,
+ top * FontHeight(screen) + screen->border,
+ OriginX(screen),
+ (unsigned) ((screen->max_row - top + 1)
+ * FontHeight(screen)),
+ (unsigned) Width(screen));
+ }
+ ClearBufRows(screen, 0, screen->max_row);
+}
+
+/*
+ * If we've written protected text DEC-style, and are issuing a non-DEC
+ * erase, temporarily reset the protected_mode flag so that the erase will
+ * ignore the protected flags.
+ */
+void
+do_erase_line(TScreen * screen, int param, int mode)
+{
+ int saved_mode = screen->protected_mode;
+
+ if (saved_mode == DEC_PROTECT
+ && saved_mode != mode)
+ screen->protected_mode = OFF_PROTECT;
+
+ switch (param) {
+ case -1: /* DEFAULT */
+ case 0:
+ ClearRight(screen, -1);
+ break;
+ case 1:
+ ClearLeft(screen);
+ break;
+ case 2:
+ ClearLine(screen);
+ break;
+ }
+ screen->protected_mode = saved_mode;
+}
+
+/*
+ * Just like 'do_erase_line()', except that this intercepts ED controls. If we
+ * clear the whole screen, we'll get the return-value from ClearInLine, and
+ * find if there were any protected characters left. If not, reset the
+ * protected mode flag in the screen data (it's slower).
+ */
+void
+do_erase_display(TScreen * screen, int param, int mode)
+{
+ int saved_mode = screen->protected_mode;
+
+ if (saved_mode == DEC_PROTECT
+ && saved_mode != mode)
+ screen->protected_mode = OFF_PROTECT;
+
+ switch (param) {
+ case -1: /* DEFAULT */
+ case 0:
+ if (screen->cur_row == 0
+ && screen->cur_col == 0) {
+ screen->protected_mode = saved_mode;
+ do_erase_display(screen, 2, mode);
+ saved_mode = screen->protected_mode;
+ } else
+ ClearBelow(screen);
+ break;
+
+ case 1:
+ if (screen->cur_row == screen->max_row
+ && screen->cur_col == screen->max_col) {
+ screen->protected_mode = saved_mode;
+ do_erase_display(screen, 2, mode);
+ saved_mode = screen->protected_mode;
+ } else
+ ClearAbove(screen);
+ break;
+
+ case 2:
+ /*
+ * We use 'ClearScreen()' throughout the remainder of the
+ * program for places where we don't care if the characters are
+ * protected or not. So we modify the logic around this call
+ * on 'ClearScreen()' to handle protected characters.
+ */
+ if (screen->protected_mode != OFF_PROTECT) {
+ int row;
+ int rc = 1;
+ unsigned len = MaxCols(screen);
+
+ assert(screen->max_col >= 0);
+ for (row = 0; row <= screen->max_row; row++)
+ rc &= ClearInLine(screen, row, 0, len);
+ if (rc != 0)
+ saved_mode = OFF_PROTECT;
+ } else {
+ ClearScreen(screen);
+ }
+ break;
+
+ case 3:
+ /* xterm addition - erase saved lines. */
+ screen->savedlines = 0;
+ ScrollBarDrawThumb(screen->scrollWidget);
+ break;
+ }
+ screen->protected_mode = saved_mode;
+}
+
+static void
+CopyWait(TScreen * screen)
+{
+ XEvent reply;
+ XEvent *rep = &reply;
+
+ while (1) {
+ XWindowEvent(screen->display, VWindow(screen),
+ ExposureMask, &reply);
+ switch (reply.type) {
+ case Expose:
+ HandleExposure(screen, &reply);
+ break;
+ case NoExpose:
+ case GraphicsExpose:
+ if (screen->incopy <= 0) {
+ screen->incopy = 1;
+ if (screen->scrolls > 0)
+ screen->scrolls--;
+ }
+ if (reply.type == GraphicsExpose)
+ HandleExposure(screen, &reply);
+
+ if ((reply.type == NoExpose) ||
+ ((XExposeEvent *) rep)->count == 0) {
+ if (screen->incopy <= 0 && screen->scrolls > 0)
+ screen->scrolls--;
+ if (screen->scrolls == 0) {
+ screen->incopy = 0;
+ return;
+ }
+ screen->incopy = -1;
+ }
+ break;
+ }
+ }
+}
+
+/*
+ * used by vertical_copy_area and and horizontal_copy_area
+ */
+static void
+copy_area(TScreen * screen,
+ int src_x,
+ int src_y,
+ unsigned width,
+ unsigned height,
+ int dest_x,
+ int dest_y)
+{
+ if (width != 0 && height != 0) {
+ /* wait for previous CopyArea to complete unless
+ multiscroll is enabled and active */
+ if (screen->incopy && screen->scrolls == 0)
+ CopyWait(screen);
+ screen->incopy = -1;
+
+ /* save for translating Expose events */
+ screen->copy_src_x = src_x;
+ screen->copy_src_y = src_y;
+ screen->copy_width = width;
+ screen->copy_height = height;
+ screen->copy_dest_x = dest_x;
+ screen->copy_dest_y = dest_y;
+
+ XCopyArea(screen->display,
+ VWindow(screen), VWindow(screen),
+ NormalGC(screen),
+ src_x, src_y, width, height, dest_x, dest_y);
+ }
+}
+
+/*
+ * use when inserting or deleting characters on the current line
+ */
+static void
+horizontal_copy_area(TScreen * screen,
+ int firstchar, /* char pos on screen to start copying at */
+ int nchars,
+ int amount) /* number of characters to move right */
+{
+ int src_x = CurCursorX(screen, screen->cur_row, firstchar);
+ int src_y = CursorY(screen, screen->cur_row);
+
+ copy_area(screen, src_x, src_y,
+ (unsigned) nchars * CurFontWidth(screen, screen->cur_row),
+ (unsigned) FontHeight(screen),
+ src_x + amount * CurFontWidth(screen, screen->cur_row), src_y);
+}
+
+/*
+ * use when inserting or deleting lines from the screen
+ */
+static void
+vertical_copy_area(TScreen * screen,
+ int firstline, /* line on screen to start copying at */
+ int nlines,
+ int amount) /* number of lines to move up (neg=down) */
+{
+ if (nlines > 0) {
+ int src_x = OriginX(screen);
+ int src_y = firstline * FontHeight(screen) + screen->border;
+
+ copy_area(screen, src_x, src_y,
+ (unsigned) Width(screen),
+ (unsigned) (nlines * FontHeight(screen)),
+ src_x, src_y - amount * FontHeight(screen));
+ }
+}
+
+/*
+ * use when scrolling the entire screen
+ */
+void
+scrolling_copy_area(TScreen * screen,
+ int firstline, /* line on screen to start copying at */
+ int nlines,
+ int amount) /* number of lines to move up (neg=down) */
+{
+
+ if (nlines > 0) {
+ vertical_copy_area(screen, firstline, nlines, amount);
+ }
+}
+
+/*
+ * Handler for Expose events on the VT widget.
+ * Returns 1 iff the area where the cursor was got refreshed.
+ */
+int
+HandleExposure(TScreen * screen, XEvent * event)
+{
+ XExposeEvent *reply = (XExposeEvent *) event;
+
+#ifndef NO_ACTIVE_ICON
+ if (reply->window == screen->iconVwin.window) {
+ WhichVWin(screen) = &screen->iconVwin;
+ TRACE(("HandleExposure - icon"));
+ } else {
+ WhichVWin(screen) = &screen->fullVwin;
+ TRACE(("HandleExposure - normal"));
+ }
+ TRACE((" event %d,%d %dx%d\n",
+ reply->y,
+ reply->x,
+ reply->height,
+ reply->width));
+#endif /* NO_ACTIVE_ICON */
+
+ /* if not doing CopyArea or if this is a GraphicsExpose, don't translate */
+ if (!screen->incopy || event->type != Expose)
+ return handle_translated_exposure(screen, reply->x, reply->y,
+ reply->width,
+ reply->height);
+ else {
+ /* compute intersection of area being copied with
+ area being exposed. */
+ int both_x1 = Max(screen->copy_src_x, reply->x);
+ int both_y1 = Max(screen->copy_src_y, reply->y);
+ int both_x2 = Min(screen->copy_src_x + screen->copy_width,
+ (unsigned) (reply->x + reply->width));
+ int both_y2 = Min(screen->copy_src_y + screen->copy_height,
+ (unsigned) (reply->y + reply->height));
+ int value = 0;
+
+ /* was anything copied affected? */
+ if (both_x2 > both_x1 && both_y2 > both_y1) {
+ /* do the copied area */
+ value = handle_translated_exposure
+ (screen, reply->x + screen->copy_dest_x - screen->copy_src_x,
+ reply->y + screen->copy_dest_y - screen->copy_src_y,
+ reply->width, reply->height);
+ }
+ /* was anything not copied affected? */
+ if (reply->x < both_x1 || reply->y < both_y1
+ || reply->x + reply->width > both_x2
+ || reply->y + reply->height > both_y2)
+ value = handle_translated_exposure(screen, reply->x, reply->y,
+ reply->width, reply->height);
+
+ return value;
+ }
+}
+
+/*
+ * Called by the ExposeHandler to do the actual repaint after the coordinates
+ * have been translated to allow for any CopyArea in progress.
+ * The rectangle passed in is pixel coordinates.
+ */
+static int
+handle_translated_exposure(TScreen * screen,
+ int rect_x,
+ int rect_y,
+ int rect_width,
+ int rect_height)
+{
+ int toprow, leftcol, nrows, ncols;
+ int x0, x1;
+ int y0, y1;
+
+ TRACE(("handle_translated_exposure at %d,%d size %dx%d\n",
+ rect_y, rect_x, rect_height, rect_width));
+
+ x0 = (rect_x - OriginX(screen));
+ x1 = (x0 + rect_width);
+
+ y0 = (rect_y - OriginY(screen));
+ y1 = (y0 + rect_height);
+
+ toprow = y0 / FontHeight(screen);
+ if (toprow < 0)
+ toprow = 0;
+
+ leftcol = x0 / CurFontWidth(screen, screen->cur_row);
+ if (leftcol < 0)
+ leftcol = 0;
+
+ nrows = (y1 - 1) / FontHeight(screen) - toprow + 1;
+ ncols = (x1 - 1) / FontWidth(screen) - leftcol + 1;
+ toprow -= screen->scrolls;
+ if (toprow < 0) {
+ nrows += toprow;
+ toprow = 0;
+ }
+ if (toprow + nrows > MaxRows(screen))
+ nrows = MaxRows(screen) - toprow;
+ if (leftcol + ncols > MaxCols(screen))
+ ncols = MaxCols(screen) - leftcol;
+
+ if (nrows > 0 && ncols > 0) {
+ ScrnRefresh(screen, toprow, leftcol, nrows, ncols, False);
+ if (waiting_for_initial_map) {
+ first_map_occurred();
+ }
+ if (screen->cur_row >= toprow &&
+ screen->cur_row < toprow + nrows &&
+ screen->cur_col >= leftcol &&
+ screen->cur_col < leftcol + ncols)
+ return (1);
+
+ }
+ return (0);
+}
+
+/***====================================================================***/
+
+void
+GetColors(XtermWidget tw, ScrnColors * pColors)
+{
+ TScreen *screen = &tw->screen;
+ int n;
+
+ pColors->which = 0;
+ for (n = 0; n < NCOLORS; ++n) {
+ SET_COLOR_VALUE(pColors, n, T_COLOR(screen, n));
+ }
+}
+
+void
+ChangeColors(XtermWidget tw, ScrnColors * pNew)
+{
+ TScreen *screen = &tw->screen;
+#if OPT_TEK4014
+ Window tek = TWindow(screen);
+#endif
+
+ TRACE(("ChangeColors\n"));
+
+ if (COLOR_DEFINED(pNew, TEXT_CURSOR)) {
+ T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_CURSOR);
+ TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR)));
+ } else if ((T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) &&
+ (COLOR_DEFINED(pNew, TEXT_FG))) {
+ T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_FG);
+ TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR)));
+ }
+
+ if (COLOR_DEFINED(pNew, TEXT_FG)) {
+ Pixel fg = COLOR_VALUE(pNew, TEXT_FG);
+ T_COLOR(screen, TEXT_FG) = fg;
+ TRACE(("... TEXT_FG: %#lx\n", T_COLOR(screen, TEXT_FG)));
+ XSetForeground(screen->display, NormalGC(screen), fg);
+ XSetBackground(screen->display, ReverseGC(screen), fg);
+ XSetForeground(screen->display, NormalBoldGC(screen), fg);
+ XSetBackground(screen->display, ReverseBoldGC(screen), fg);
+ }
+
+ if (COLOR_DEFINED(pNew, TEXT_BG)) {
+ Pixel bg = COLOR_VALUE(pNew, TEXT_BG);
+ T_COLOR(screen, TEXT_BG) = bg;
+ TRACE(("... TEXT_BG: %#lx\n", T_COLOR(screen, TEXT_BG)));
+ XSetBackground(screen->display, NormalGC(screen), bg);
+ XSetForeground(screen->display, ReverseGC(screen), bg);
+ XSetBackground(screen->display, NormalBoldGC(screen), bg);
+ XSetForeground(screen->display, ReverseBoldGC(screen), bg);
+ XSetWindowBackground(screen->display, VWindow(screen),
+ T_COLOR(screen, TEXT_BG));
+ }
+#if OPT_HIGHLIGHT_COLOR
+ if (COLOR_DEFINED(pNew, HIGHLIGHT_BG)) {
+ T_COLOR(screen, HIGHLIGHT_BG) = COLOR_VALUE(pNew, HIGHLIGHT_BG);
+ TRACE(("... HIGHLIGHT_BG: %#lx\n", T_COLOR(screen, HIGHLIGHT_BG)));
+ }
+#endif
+
+ if (COLOR_DEFINED(pNew, MOUSE_FG) || (COLOR_DEFINED(pNew, MOUSE_BG))) {
+ if (COLOR_DEFINED(pNew, MOUSE_FG)) {
+ T_COLOR(screen, MOUSE_FG) = COLOR_VALUE(pNew, MOUSE_FG);
+ TRACE(("... MOUSE_FG: %#lx\n", T_COLOR(screen, MOUSE_FG)));
+ }
+ if (COLOR_DEFINED(pNew, MOUSE_BG)) {
+ T_COLOR(screen, MOUSE_BG) = COLOR_VALUE(pNew, MOUSE_BG);
+ TRACE(("... MOUSE_BG: %#lx\n", T_COLOR(screen, MOUSE_BG)));
+ }
+
+ recolor_cursor(screen->pointer_cursor,
+ T_COLOR(screen, MOUSE_FG),
+ T_COLOR(screen, MOUSE_BG));
+ recolor_cursor(screen->arrow,
+ T_COLOR(screen, MOUSE_FG),
+ T_COLOR(screen, MOUSE_BG));
+ XDefineCursor(screen->display, VWindow(screen),
+ screen->pointer_cursor);
+
+#if OPT_TEK4014
+ if (tek)
+ XDefineCursor(screen->display, tek, screen->arrow);
+#endif
+ }
+#if OPT_TEK4014
+ if (COLOR_DEFINED(pNew, TEK_FG) ||
+ COLOR_DEFINED(pNew, TEK_BG) ||
+ COLOR_DEFINED(pNew, TEK_CURSOR)) {
+ ChangeTekColors(screen, pNew);
+ }
+#endif
+ set_cursor_gcs(screen);
+ XClearWindow(screen->display, VWindow(screen));
+ ScrnRefresh(screen, 0, 0, MaxRows(screen),
+ MaxCols(screen), False);
+#if OPT_TEK4014
+ if (screen->Tshow) {
+ XClearWindow(screen->display, tek);
+ TekExpose((Widget) NULL, (XEvent *) NULL, (Region) NULL);
+ }
+#endif
+}
+
+void
+ChangeAnsiColors(XtermWidget tw)
+{
+ TScreen *screen = &tw->screen;
+
+ XClearWindow(screen->display, VWindow(screen));
+ ScrnRefresh(screen, 0, 0,
+ MaxRows(screen),
+ MaxCols(screen), False);
+}
+
+/***====================================================================***/
+
+void
+ReverseVideo(XtermWidget termw)
+{
+ TScreen *screen = &termw->screen;
+ GC tmpGC;
+ Pixel tmp;
+#if OPT_TEK4014
+ Window tek = TWindow(screen);
+#endif
+
+ /*
+ * Swap SGR foreground and background colors. By convention, these are
+ * the colors assigned to "black" (SGR #0) and "white" (SGR #7). Also,
+ * SGR #8 and SGR #15 are the bold (or bright) versions of SGR #0 and
+ * #7, respectively.
+ *
+ * We don't swap colors that happen to match the screen's foreground
+ * and background because that tends to produce bizarre effects.
+ */
+ if_OPT_ISO_COLORS(screen, {
+ ColorRes tmp2;
+ EXCHANGE(screen->Acolors[0], screen->Acolors[7], tmp2);
+ EXCHANGE(screen->Acolors[8], screen->Acolors[15], tmp2);
+ });
+
+ tmp = T_COLOR(screen, TEXT_BG);
+ if (T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG))
+ T_COLOR(screen, TEXT_CURSOR) = tmp;
+ T_COLOR(screen, TEXT_BG) = T_COLOR(screen, TEXT_FG);
+ T_COLOR(screen, TEXT_FG) = tmp;
+
+ EXCHANGE(T_COLOR(screen, MOUSE_FG), T_COLOR(screen, MOUSE_BG), tmp);
+ EXCHANGE(NormalGC(screen), ReverseGC(screen), tmpGC);
+ EXCHANGE(NormalBoldGC(screen), ReverseBoldGC(screen), tmpGC);
+#ifndef NO_ACTIVE_ICON
+ tmpGC = screen->iconVwin.normalGC;
+ screen->iconVwin.normalGC = screen->iconVwin.reverseGC;
+ screen->iconVwin.reverseGC = tmpGC;
+
+ tmpGC = screen->iconVwin.normalboldGC;
+ screen->iconVwin.normalboldGC = screen->iconVwin.reverseboldGC;
+ screen->iconVwin.reverseboldGC = tmpGC;
+#endif /* NO_ACTIVE_ICON */
+
+ recolor_cursor(screen->pointer_cursor,
+ T_COLOR(screen, MOUSE_FG),
+ T_COLOR(screen, MOUSE_BG));
+ recolor_cursor(screen->arrow,
+ T_COLOR(screen, MOUSE_FG),
+ T_COLOR(screen, MOUSE_BG));
+
+ termw->misc.re_verse = !termw->misc.re_verse;
+
+ if (XtIsRealized((Widget) termw)) {
+ XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor);
+ }
+#if OPT_TEK4014
+ if (tek)
+ XDefineCursor(screen->display, tek, screen->arrow);
+#endif
+
+ if (screen->scrollWidget)
+ ScrollBarReverseVideo(screen->scrollWidget);
+
+ if (XtIsRealized((Widget) termw)) {
+ XSetWindowBackground(screen->display, VWindow(screen),
+ T_COLOR(screen, TEXT_BG));
+
+ /* the shell-window's background will be used in the first repainting
+ * on resizing
+ */
+ XSetWindowBackground(screen->display, VShellWindow,
+ T_COLOR(screen, TEXT_BG));
+ }
+#if OPT_TEK4014
+ TekReverseVideo(screen);
+#endif
+ if (XtIsRealized((Widget) termw)) {
+ XClearWindow(screen->display, VWindow(screen));
+ ScrnRefresh(screen, 0, 0, MaxRows(screen),
+ MaxCols(screen), False);
+ }
+#if OPT_TEK4014
+ if (screen->Tshow) {
+ XClearWindow(screen->display, tek);
+ TekExpose((Widget) NULL, (XEvent *) NULL, (Region) NULL);
+ }
+#endif
+ ReverseOldColors();
+ update_reversevideo();
+}
+
+void
+recolor_cursor(Cursor cursor, /* X cursor ID to set */
+ unsigned long fg, /* pixel indexes to look up */
+ unsigned long bg) /* pixel indexes to look up */
+{
+ TScreen *screen = &term->screen;
+ Display *dpy = screen->display;
+ XColor colordefs[2]; /* 0 is foreground, 1 is background */
+
+ colordefs[0].pixel = fg;
+ colordefs[1].pixel = bg;
+ XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),
+ colordefs, 2);
+ XRecolorCursor(dpy, cursor, colordefs, colordefs + 1);
+ return;
+}
+
+#if OPT_RENDERFONT
+static XftColor *
+getColor(Pixel pixel)
+{
+#define CACHE_SIZE 4
+ static struct {
+ XftColor color;
+ int use;
+ } cache[CACHE_SIZE];
+ static int use;
+ int i;
+ int oldest, oldestuse;
+ XColor color;
+
+ oldestuse = 0x7fffffff;
+ oldest = 0;
+ for (i = 0; i < CACHE_SIZE; i++) {
+ if (cache[i].use) {
+ if (cache[i].color.pixel == pixel) {
+ cache[i].use = ++use;
+ return &cache[i].color;
+ }
+ }
+ if (cache[i].use < oldestuse) {
+ oldestuse = cache[i].use;
+ oldest = i;
+ }
+ }
+ i = oldest;
+ color.pixel = pixel;
+ XQueryColor(term->screen.display, term->core.colormap, &color);
+ cache[i].color.color.red = color.red;
+ cache[i].color.color.green = color.green;
+ cache[i].color.color.blue = color.blue;
+ cache[i].color.color.alpha = 0xffff;
+ cache[i].color.pixel = pixel;
+ cache[i].use = ++use;
+ return &cache[i].color;
+}
+
+/*
+ * fontconfig/Xft combination prior to 2.2 has a problem with
+ * CJK truetype 'double-width' (bi-width/monospace) fonts leading
+ * to the 's p a c e d o u t' rendering. Consequently, we can't
+ * rely on XftDrawString8/16 when one of those fonts is used.
+ * Instead, we need to roll out our own using XftDrawCharSpec.
+ * A patch in the same spirit (but in a rather different form)
+ * was applied to gnome vte and gtk2 port of vim.
+ * See http://bugzilla.mozilla.org/show_bug.cgi?id=196312
+ */
+static void
+xtermXftDrawString(TScreen * screen,
+ unsigned flags GCC_UNUSED,
+ XftColor * color,
+ XftFont * font,
+ int x,
+ int y,
+ PAIRED_CHARS(Char * text, Char * text2),
+ int len,
+ int fwidth,
+ int *deltax)
+{
+#if OPT_RENDERWIDE
+ XftFont *wfont;
+ int n;
+ int ncells = 0; /* # of 'half-width' charcells */
+ static XftCharSpec *sbuf;
+ static int slen = 0;
+ XftFont *lastFont = 0;
+ XftFont *currFont = 0;
+ int start = 0;
+ int charWidth;
+ FcChar32 wc;
+ int fontnum = screen->menu_font_number;
+
+ if (len == 0 || !(*text || *text2)) {
+ return;
+ }
+#if OPT_ISO_COLORS
+ if ((flags & UNDERLINE)
+ && screen->italicULMode
+ && screen->renderWideItal[fontnum]) {
+ wfont = screen->renderWideItal[fontnum];
+ } else
+#endif
+ if ((flags & BOLDATTR(screen))
+ && screen->renderWideBold[fontnum]) {
+ wfont = screen->renderWideBold[fontnum];
+ } else {
+ wfont = screen->renderWideNorm[fontnum];
+ }
+
+ if ((int) slen < len) {
+ slen = (len + 1) * 2;
+ sbuf = (XftCharSpec *) XtRealloc((char *) sbuf,
+ slen * sizeof(XftCharSpec));
+ }
+
+ for (n = 0; n < len; n++) {
+ if (text2)
+ wc = *text++ | (*text2++ << 8);
+ else
+ wc = *text++;
+ sbuf[n].ucs4 = wc;
+ sbuf[n].x = x + fwidth * ncells;
+ sbuf[n].y = y;
+ charWidth = my_wcwidth((int) wc);
+ currFont = (charWidth == 2 && wfont != 0) ? wfont : font;
+ ncells += charWidth;
+ if (lastFont != currFont) {
+ if (lastFont != 0) {
+ XftDrawCharSpec(screen->renderDraw,
+ color,
+ lastFont,
+ sbuf + start,
+ n - start);
+ }
+ start = n;
+ lastFont = currFont;
+ }
+ }
+ XftDrawCharSpec(screen->renderDraw,
+ color,
+ lastFont,
+ sbuf + start,
+ n - start);
+
+ if (deltax)
+ *deltax = ncells * fwidth;
+#else
+
+ XftDrawString8(screen->renderDraw,
+ color,
+ font,
+ x, y, (unsigned char *) text, len);
+ if (deltax)
+ *deltax = len * fwidth;
+#endif
+}
+#endif /* OPT_RENDERFONT */
+
+#define DrawX(col) x + (col * (font_width))
+#define DrawSegment(first,last) (void)drawXtermText(screen, flags|NOTRANSLATION, gc, DrawX(first), y, chrset, PAIRED_CHARS(text+first, text2+first), (unsigned)(last - first), on_wide)
+
+#if OPT_WIDE_CHARS
+/*
+ * Actually this should be called "groff_workaround()" - for the places where
+ * groff stomps on compatibility. Still, if enough people get used to it,
+ * this might someday become a quasi-standard.
+ */
+static int
+ucs_workaround(TScreen * screen,
+ unsigned ch,
+ unsigned flags,
+ GC gc,
+ int x,
+ int y,
+ int chrset,
+ int on_wide)
+{
+ int fixed = False;
+
+ if (screen->wide_chars && screen->utf8_mode && ch > 256) {
+ switch (ch) {
+ case 0x2010: /* groff "-" */
+ case 0x2011:
+ case 0x2012:
+ case 0x2013:
+ case 0x2014:
+ case 0x2015:
+ case 0x2212: /* groff "\-" */
+ ch = '-';
+ fixed = True;
+ break;
+ case 0x2018: /* groff "`" */
+ ch = '`';
+ fixed = True;
+ break;
+ case 0x2019: /* groff ' */
+ ch = '\'';
+ fixed = True;
+ break;
+ case 0x201C: /* groff lq */
+ case 0x201D: /* groff rq */
+ ch = '"';
+ fixed = True;
+ break;
+ }
+ if (fixed) {
+ Char text[2];
+ Char text2[2];
+
+ text[0] = ch;
+ text2[0] = 0;
+ drawXtermText(screen,
+ flags,
+ gc,
+ x,
+ y,
+ chrset,
+ PAIRED_CHARS(text, text2),
+ 1,
+ on_wide);
+ }
+ }
+ return fixed;
+}
+#endif
+
+#if OPT_CLIP_BOLD
+/*
+ * This special case is a couple of percent slower, but avoids a lot of pixel
+ * trash in rxcurses' hanoi.cmd demo (e.g., 10x20 font).
+ */
+#define beginClipping(screen,gc,pwidth,plength) \
+ if (pwidth > 2) { \
+ XRectangle clip; \
+ int clip_x = x; \
+ int clip_y = y - FontHeight(screen) + FontDescent(screen); \
+ clip.x = 0; \
+ clip.y = 0; \
+ clip.height = FontHeight(screen); \
+ clip.width = pwidth * plength; \
+ XSetClipRectangles(screen->display, gc, \
+ clip_x, clip_y, \
+ &clip, 1, Unsorted); \
+ }
+#define endClipping(screen,gc) \
+ XSetClipMask(screen->display, gc, None)
+#else
+#define beginClipping(screen,gc,pwidth,plength) /* nothing */
+#define endClipping(screen,gc) /* nothing */
+#endif /* OPT_CLIP_BOLD */
+
+/*
+ * Draws text with the specified combination of bold/underline. The return
+ * value is the updated x position.
+ */
+int
+drawXtermText(TScreen * screen,
+ unsigned flags,
+ GC gc,
+ int x,
+ int y,
+ int chrset,
+ PAIRED_CHARS(Char * text, Char * text2),
+ Cardinal len,
+ int on_wide)
+{
+ int real_length = len;
+ int underline_len;
+ /* Intended width of the font to draw (as opposed to the actual width of
+ the X font, and the width of the default font) */
+ int font_width = ((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide;
+ Bool did_ul = False;
+
+#if OPT_WIDE_CHARS
+ /*
+ * It's simpler to pass in a null pointer for text2 in places where
+ * we only use codes through 255. Fix text2 here so we can increment
+ * it, etc.
+ */
+ if (text2 == 0) {
+ static Char *dbuf;
+ static unsigned dlen;
+ if (dlen <= len) {
+ dlen = (len + 1) * 2;
+ dbuf = (Char *) XtRealloc((char *) dbuf, dlen);
+ memset(dbuf, 0, dlen);
+ }
+ text2 = dbuf;
+ }
+#endif
+#if OPT_DEC_CHRSET
+ if (CSET_DOUBLE(chrset)) {
+ /* We could try drawing double-size characters in the icon, but
+ * given that the icon font is usually nil or nil2, there
+ * doesn't seem to be much point.
+ */
+ GC gc2 = ((!IsIcon(screen) && screen->font_doublesize)
+ ? xterm_DoubleGC((unsigned) chrset, flags, gc)
+ : 0);
+
+ TRACE(("DRAWTEXT%c[%4d,%4d] (%d) %d:%.*s\n",
+ screen->cursor_state == OFF ? ' ' : '*',
+ y, x, chrset, len, (int) len, text));
+
+ if (gc2 != 0) { /* draw actual double-sized characters */
+ /* Update the last-used cache of double-sized fonts */
+ int inx = xterm_Double_index((unsigned) chrset, flags);
+ XFontStruct *fs = screen->double_fonts[inx].fs;
+ XRectangle rect, *rp = &rect;
+ int nr = 1;
+ int adjust;
+
+ font_width *= 2;
+ flags |= DOUBLEWFONT;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = len * font_width;
+ rect.height = FontHeight(screen);
+
+ switch (chrset) {
+ case CSET_DHL_TOP:
+ rect.y = -(rect.height / 2);
+ y -= rect.y;
+ flags |= DOUBLEHFONT;
+ break;
+ case CSET_DHL_BOT:
+ rect.y = (rect.height / 2);
+ y -= rect.y;
+ flags |= DOUBLEHFONT;
+ break;
+ default:
+ nr = 0;
+ break;
+ }
+
+ /*
+ * Though it is the right "size", a given bold font may
+ * be shifted up by a pixel or two. Shift it back into
+ * the clipping rectangle.
+ */
+ if (nr != 0) {
+ adjust = fs->ascent
+ + fs->descent
+ - (2 * FontHeight(screen));
+ rect.y -= adjust;
+ y += adjust;
+ }
+
+ if (nr)
+ XSetClipRectangles(screen->display, gc2,
+ x, y, rp, nr, YXBanded);
+ else
+ XSetClipMask(screen->display, gc2, None);
+
+ /* Call ourselves recursively with the new gc */
+
+ /*
+ * If we're trying to use proportional font, or if the
+ * font server didn't give us what we asked for wrt
+ * width, position each character independently.
+ */
+ if (screen->fnt_prop
+ || (fs->min_bounds.width != fs->max_bounds.width)
+ || (fs->min_bounds.width != 2 * FontWidth(screen))) {
+ /* It is hard to fall-through to the main
+ branch: in a lot of places the check
+ for the cached font info is for
+ normal/bold fonts only. */
+ while (len--) {
+ x = drawXtermText(screen, flags, gc2,
+ x, y, 0,
+ PAIRED_CHARS(text++, text2++),
+ 1, on_wide);
+ x += FontWidth(screen);
+ }
+ } else {
+ x = drawXtermText(screen, flags, gc2,
+ x, y, 0,
+ PAIRED_CHARS(text, text2),
+ len, on_wide);
+ x += len * FontWidth(screen);
+ }
+
+ TRACE(("drawtext [%4d,%4d]\n", y, x));
+ } else { /* simulate double-sized characters */
+#if OPT_WIDE_CHARS
+ Char *wide = 0;
+#endif
+ unsigned need = 2 * len;
+ Char *temp = TypeMallocN(Char, need);
+ unsigned n = 0;
+ if_OPT_WIDE_CHARS(screen, {
+ wide = TypeMallocN(Char, need);
+ });
+ while (len--) {
+ if_OPT_WIDE_CHARS(screen, {
+ wide[n] = *text2++;
+ wide[n + 1] = 0;
+ });
+ temp[n++] = *text++;
+ temp[n++] = ' ';
+ }
+ x = drawXtermText(screen,
+ flags,
+ gc,
+ x, y,
+ 0,
+ PAIRED_CHARS(temp, wide),
+ n,
+ on_wide);
+ free(temp);
+ if_OPT_WIDE_CHARS(screen, {
+ free(wide);
+ });
+ }
+ return x;
+ }
+#endif
+#if OPT_RENDERFONT
+ if (UsingRenderFont(term)) {
+ Display *dpy = screen->display;
+ XftFont *font;
+ XGCValues values;
+ int fontnum = screen->menu_font_number;
+
+ if (!screen->renderDraw) {
+ int scr;
+ Drawable draw = VWindow(screen);
+ Visual *visual;
+
+ scr = DefaultScreen(dpy);
+ visual = DefaultVisual(dpy, scr);
+ screen->renderDraw = XftDrawCreate(dpy, draw, visual,
+ DefaultColormap(dpy, scr));
+ }
+#if OPT_ISO_COLORS
+ if ((flags & UNDERLINE)
+ && screen->italicULMode
+ && screen->renderFontItal[fontnum]) {
+ font = screen->renderFontItal[fontnum];
+ did_ul = True;
+ } else
+#endif
+ if ((flags & BOLDATTR(screen))
+ && screen->renderFontBold[fontnum]) {
+ font = screen->renderFontBold[fontnum];
+ } else {
+ font = screen->renderFontNorm[fontnum];
+ }
+ XGetGCValues(dpy, gc, GCForeground | GCBackground, &values);
+ if (!(flags & NOBACKGROUND))
+ XftDrawRect(screen->renderDraw,
+ getColor(values.background),
+ x, y,
+ len * FontWidth(screen),
+ (unsigned) FontHeight(screen));
+
+ y += font->ascent;
+#if OPT_BOX_CHARS
+ if (!screen->force_box_chars) {
+ /* adding code to substitute simulated line-drawing characters */
+ int last, first = 0;
+ Dimension old_wide, old_high = 0;
+ int curX = x;
+
+ for (last = 0; last < (int) len; last++) {
+ unsigned ch = text[last];
+ int deltax = 0;
+
+ /*
+ * If we're reading UTF-8 from the client, we may have a
+ * line-drawing character. Translate it back to our box-code
+ * if it is really a line-drawing character (since the
+ * fonts used by Xft generally do not have correct glyphs),
+ * or if Xft can tell us that the glyph is really missing.
+ */
+ if_OPT_WIDE_CHARS(screen, {
+ unsigned full = (ch | (text2[last] << 8));
+ unsigned part = ucs2dec(full);
+ if (xtermIsDecGraphic(part) &&
+ (xtermIsLineDrawing(part)
+ || xtermXftMissing(term, font, full)))
+ ch = part;
+ else
+ ch = full;
+ });
+ /*
+ * If we have one of our box-codes, draw it directly.
+ */
+ if (xtermIsDecGraphic(ch)) {
+ /* line drawing character time */
+ if (last > first) {
+ xtermXftDrawString(screen, flags,
+ getColor(values.foreground),
+ font, curX, y,
+ PAIRED_CHARS(text + first,
+ text2 + first),
+ last - first,
+ FontWidth(screen),
+ &deltax);
+ curX += deltax;
+ }
+ old_wide = screen->fnt_wide;
+ old_high = screen->fnt_high;
+ screen->fnt_wide = FontWidth(screen);
+ screen->fnt_high = FontHeight(screen);
+ xtermDrawBoxChar(term, ch, flags, gc,
+ curX, y - FontAscent(screen));
+ curX += FontWidth(screen);
+ screen->fnt_wide = old_wide;
+ screen->fnt_high = old_high;
+ first = last + 1;
+ }
+ }
+ if (last > first) {
+ xtermXftDrawString(screen, flags,
+ getColor(values.foreground),
+ font, curX, y,
+ PAIRED_CHARS(text + first, text2 + first),
+ last - first,
+ FontWidth(screen),
+ NULL);
+ }
+ } else
+#endif /* OPT_BOX_CHARS */
+ {
+ xtermXftDrawString(screen, flags,
+ getColor(values.foreground),
+ font, x, y, PAIRED_CHARS(text, text2),
+ (int) len, FontWidth(screen), NULL);
+ }
+
+ if ((flags & UNDERLINE) && screen->underline && !did_ul) {
+ if (FontDescent(screen) > 1)
+ y++;
+ XDrawLine(screen->display, VWindow(screen), gc,
+ x, y,
+ x + (int) len * FontWidth(screen) - 1,
+ y);
+ }
+ return x + len * FontWidth(screen);
+ }
+#endif /* OPT_RENDERFONT */
+ /*
+ * If we're asked to display a proportional font, do this with a fixed
+ * pitch. Yes, it's ugly. But we cannot distinguish the use of xterm
+ * as a dumb terminal vs its use as in fullscreen programs such as vi.
+ * Hint: do not try to use a proportional font in the icon.
+ */
+ if (!IsIcon(screen) && !(flags & CHARBYCHAR) && screen->fnt_prop) {
+ int adj, width;
+ GC fillGC = gc; /* might be cursorGC */
+ XFontStruct *fs = ((flags & BOLDATTR(screen))
+ ? BoldFont(screen)
+ : NormalFont(screen));
+
+#define GC_PAIRS(a,b) \
+ if (gc == a) fillGC = b; \
+ if (gc == b) fillGC = a
+
+ /*
+ * Fill the area where we'll write the characters, otherwise
+ * we'll get gaps between them. The cursor is a special case,
+ * because the XFillRectangle call only uses the foreground,
+ * while we've set the cursor color in the background. So we
+ * need a special GC for that.
+ */
+ if (gc == screen->cursorGC
+ || gc == screen->reversecursorGC)
+ fillGC = screen->fillCursorGC;
+ GC_PAIRS(NormalGC(screen), ReverseGC(screen));
+ GC_PAIRS(NormalBoldGC(screen), ReverseBoldGC(screen));
+
+ if (!(flags & NOBACKGROUND))
+ XFillRectangle(screen->display, VWindow(screen), fillGC,
+ x, y,
+ len * FontWidth(screen),
+ (unsigned) FontHeight(screen));
+
+ while (len--) {
+ width = XTextWidth(fs, (char *) text, 1);
+ adj = (FontWidth(screen) - width) / 2;
+ (void) drawXtermText(screen, flags | NOBACKGROUND | CHARBYCHAR,
+ gc, x + adj, y, chrset,
+ PAIRED_CHARS(text++, text2++), 1, on_wide);
+ x += FontWidth(screen);
+ }
+ return x;
+ }
+#if OPT_BOX_CHARS
+ /* If the font is incomplete, draw some substitutions */
+ if (!IsIcon(screen)
+ && !(flags & NOTRANSLATION)
+ && (!screen->fnt_boxes || screen->force_box_chars)) {
+ /* Fill in missing box-characters.
+ Find regions without missing characters, and draw
+ them calling ourselves recursively. Draw missing
+ characters via xtermDrawBoxChar(). */
+ XFontStruct *font = ((flags & BOLD)
+ ? BoldFont(screen)
+ : NormalFont(screen));
+ int last, first = 0;
+ for (last = 0; last < (int) len; last++) {
+ unsigned ch = text[last];
+ Bool isMissing;
+#if OPT_WIDE_CHARS
+ if (text2 != 0)
+ ch |= (text2[last] << 8);
+ isMissing = (ch != HIDDEN_CHAR)
+ && (xtermMissingChar(term, ch,
+ ((on_wide || iswide((int) ch))
+ && screen->fnt_dwd)
+ ? screen->fnt_dwd
+ : font));
+#else
+ isMissing = xtermMissingChar(term, ch, font);
+#endif
+ if (isMissing) {
+ if (last > first)
+ DrawSegment(first, last);
+#if OPT_WIDE_CHARS
+ if (!ucs_workaround(screen, ch, flags, gc, DrawX(last), y,
+ chrset, on_wide))
+#endif
+ xtermDrawBoxChar(term, ch, flags, gc, DrawX(last), y);
+ first = last + 1;
+ }
+ }
+ if (last <= first) {
+ return x + real_length * FontWidth(screen);
+ }
+ text += first;
+#if OPT_WIDE_CHARS
+ text2 += first;
+#endif
+ len = last - first;
+ flags |= NOTRANSLATION;
+ if (DrawX(first) != x) {
+ return drawXtermText(screen,
+ flags,
+ gc,
+ DrawX(first),
+ y,
+ chrset,
+ PAIRED_CHARS(text, text2),
+ len,
+ on_wide);
+ }
+ }
+#endif /* OPT_BOX_CHARS */
+ /*
+ * Behave as if the font has (maybe Unicode-replacements for) drawing
+ * characters in the range 1-31 (either we were not asked to ignore them,
+ * or the caller made sure that there is none). The only translation we do
+ * in this branch is the removal of HIDDEN_CHAR (for the wide-char case).
+ */
+ TRACE(("drawtext%c[%4d,%4d] (%d) %d:%s\n",
+ screen->cursor_state == OFF ? ' ' : '*',
+ y, x, chrset, len,
+ visibleChars(PAIRED_CHARS(text, text2), len)));
+ y += FontAscent(screen);
+
+#if OPT_WIDE_CHARS
+ if (screen->wide_chars || screen->unicode_font) {
+ int ascent_adjust = 0;
+ static XChar2b *sbuf;
+ static Cardinal slen;
+ int n;
+ unsigned ch = text[0] | (text2[0] << 8);
+ int wideness = (!IsIcon(screen)
+ && ((on_wide || iswide((int) ch) != 0)
+ && (screen->fnt_dwd != NULL)));
+ unsigned char *endtext = text + len;
+ if (slen < len) {
+ slen = (len + 1) * 2;
+ sbuf = (XChar2b *) XtRealloc((char *) sbuf, slen * sizeof(*sbuf));
+ }
+ for (n = 0; n < (int) len; n++) {
+ sbuf[n].byte2 = *text;
+ sbuf[n].byte1 = *text2;
+#if OPT_MINI_LUIT
+#define UCS2SBUF(n,value) sbuf[n].byte2 = (value & 0xff);\
+ sbuf[n].byte1 = (value >> 8)
+#define Map2Sbuf(n,from,to) (*text == from) { UCS2SBUF(n,to); }
+ if (screen->latin9_mode && !screen->utf8_mode && *text2 == 0) {
+
+ /* see http://www.cs.tut.fi/~jkorpela/latin9.html */
+ /* *INDENT-OFF* */
+ if Map2Sbuf(n, 0xa4, 0x20ac)
+ else if Map2Sbuf(n, 0xa6, 0x0160)
+ else if Map2Sbuf(n, 0xa8, 0x0161)
+ else if Map2Sbuf(n, 0xb4, 0x017d)
+ else if Map2Sbuf(n, 0xb8, 0x017e)
+ else if Map2Sbuf(n, 0xbc, 0x0152)
+ else if Map2Sbuf(n, 0xbd, 0x0153)
+ else if Map2Sbuf(n, 0xbe, 0x0178)
+ /* *INDENT-ON* */
+
+ }
+ if (screen->unicode_font
+ && *text2 == 0
+ && (*text == 0x7f || *text < 0x20)) {
+ int ni = dec2ucs(*text == 0x7f ? 0 : *text);
+ UCS2SBUF(n, ni);
+ }
+#endif /* OPT_MINI_LUIT */
+ text++;
+ text2++;
+ if (wideness) {
+ /* filter out those pesky fake characters. */
+ while (text < endtext
+ && *text == HIDDEN_HI
+ && *text2 == HIDDEN_LO) {
+ text++;
+ text2++;
+ len--;
+ }
+ }
+ }
+ /* This is probably wrong. But it works. */
+ underline_len = len;
+
+ /* Set the drawing font */
+ if (flags & (DOUBLEHFONT | DOUBLEWFONT)) {
+ ; /* Do nothing: font is already set */
+ } else if (wideness
+ && (screen->fnt_dwd->fid || screen->fnt_dwdb->fid)) {
+ underline_len = real_length = len * 2;
+ if ((flags & BOLDATTR(screen)) != 0
+ && screen->fnt_dwdb->fid) {
+ XSetFont(screen->display, gc, screen->fnt_dwdb->fid);
+ ascent_adjust = (screen->fnt_dwdb->ascent
+ - NormalFont(screen)->ascent);
+ } else {
+ XSetFont(screen->display, gc, screen->fnt_dwd->fid);
+ ascent_adjust = (screen->fnt_dwd->ascent
+ - NormalFont(screen)->ascent);
+ }
+ /* fix ascent */
+ } else if ((flags & BOLDATTR(screen)) != 0
+ && BoldFont(screen)->fid) {
+ XSetFont(screen->display, gc, BoldFont(screen)->fid);
+ } else {
+ XSetFont(screen->display, gc, NormalFont(screen)->fid);
+ }
+
+ if (flags & NOBACKGROUND)
+ XDrawString16(screen->display,
+ VWindow(screen), gc,
+ x, y + ascent_adjust,
+ sbuf, n);
+ else
+ XDrawImageString16(screen->display,
+ VWindow(screen), gc,
+ x, y + ascent_adjust,
+ sbuf, n);
+
+ if ((flags & BOLDATTR(screen)) && screen->enbolden) {
+ beginClipping(screen, gc, font_width, len);
+ XDrawString16(screen->display, VWindow(screen), gc,
+ x + 1, y + ascent_adjust, sbuf, n);
+ endClipping(screen, gc);
+ }
+
+ } else
+#endif /* OPT_WIDE_CHARS */
+ {
+ int length = len; /* X should have used unsigned */
+
+ if (flags & NOBACKGROUND)
+ XDrawString(screen->display, VWindow(screen), gc,
+ x, y, (char *) text, length);
+ else
+ XDrawImageString(screen->display, VWindow(screen), gc,
+ x, y, (char *) text, length);
+ underline_len = length;
+ if ((flags & BOLDATTR(screen)) && screen->enbolden) {
+ beginClipping(screen, gc, font_width, length);
+ XDrawString(screen->display, VWindow(screen), gc,
+ x + 1, y, (char *) text, length);
+ endClipping(screen, gc);
+ }
+ }
+
+ if ((flags & UNDERLINE) && screen->underline && !did_ul) {
+ if (FontDescent(screen) > 1)
+ y++;
+ XDrawLine(screen->display, VWindow(screen), gc,
+ x, y, x + underline_len * font_width - 1, y);
+ }
+
+ return x + real_length * FontWidth(screen);
+}
+
+/* set up size hints for window manager; min 1 char by 1 char */
+void
+xtermSizeHints(XtermWidget xw, XSizeHints * sizehints, int scrollbarWidth)
+{
+ TScreen *screen = &xw->screen;
+
+ TRACE(("xtermSizeHints\n"));
+ TRACE((" border %d\n", xw->core.border_width));
+ TRACE((" scrollbar %d\n", scrollbarWidth));
+
+ sizehints->base_width = 2 * screen->border + scrollbarWidth;
+ sizehints->base_height = 2 * screen->border;
+
+#if OPT_TOOLBAR
+ TRACE((" toolbar %d\n", ToolbarHeight(xw)));
+
+ sizehints->base_height += ToolbarHeight(xw);
+ sizehints->base_height += xw->core.border_width * 2;
+ sizehints->base_width += xw->core.border_width * 2;
+#endif
+
+ sizehints->width_inc = FontWidth(screen);
+ sizehints->height_inc = FontHeight(screen);
+ sizehints->min_width = sizehints->base_width + sizehints->width_inc;
+ sizehints->min_height = sizehints->base_height + sizehints->height_inc;
+
+ sizehints->width = MaxCols(screen) * FontWidth(screen) + sizehints->min_width;
+ sizehints->height = MaxRows(screen) * FontHeight(screen) + sizehints->min_height;
+
+ sizehints->flags |= (PSize | PBaseSize | PMinSize | PResizeInc);
+
+ TRACE_HINTS(sizehints);
+}
+
+/*
+ * Returns a GC, selected according to the font (reverse/bold/normal) that is
+ * required for the current position (implied). The GC is updated with the
+ * current screen foreground and background colors.
+ */
+GC
+updatedXtermGC(TScreen * screen, unsigned flags, unsigned fg_bg, Bool hilite)
+{
+ int my_fg = extract_fg(fg_bg, flags);
+ int my_bg = extract_bg(fg_bg, flags);
+ Pixel fg_pix = getXtermForeground(flags, my_fg);
+ Pixel bg_pix = getXtermBackground(flags, my_bg);
+ Pixel xx_pix;
+#if OPT_HIGHLIGHT_COLOR
+ Pixel hi_pix = T_COLOR(screen, HIGHLIGHT_BG);
+#endif
+ GC gc;
+
+ checkVeryBoldColors(flags, my_fg);
+
+ if (ReverseOrHilite(screen, flags, hilite)) {
+ if (flags & BOLDATTR(screen))
+ gc = ReverseBoldGC(screen);
+ else
+ gc = ReverseGC(screen);
+
+#if OPT_HIGHLIGHT_COLOR
+ if (hi_pix != T_COLOR(screen, TEXT_FG)
+ && hi_pix != fg_pix
+ && hi_pix != bg_pix
+ && hi_pix != term->dft_foreground) {
+ bg_pix = fg_pix;
+ fg_pix = hi_pix;
+ }
+#endif
+ xx_pix = bg_pix;
+ bg_pix = fg_pix;
+ fg_pix = xx_pix;
+ } else {
+ if (flags & BOLDATTR(screen))
+ gc = NormalBoldGC(screen);
+ else
+ gc = NormalGC(screen);
+
+ }
+
+#if OPT_BLINK_TEXT
+ if ((screen->blink_state == ON) && (!screen->blink_as_bold) && (flags & BLINK)) {
+ fg_pix = bg_pix;
+ }
+#endif
+
+ XSetForeground(screen->display, gc, fg_pix);
+ XSetBackground(screen->display, gc, bg_pix);
+ return gc;
+}
+
+/*
+ * Resets the foreground/background of the GC returned by 'updatedXtermGC()'
+ * to the values that would be set in SGR_Foreground and SGR_Background. This
+ * duplicates some logic, but only modifies 1/4 as many GC's.
+ */
+void
+resetXtermGC(TScreen * screen, unsigned flags, Bool hilite)
+{
+ Pixel fg_pix = getXtermForeground(flags, term->cur_foreground);
+ Pixel bg_pix = getXtermBackground(flags, term->cur_background);
+ GC gc;
+
+ checkVeryBoldColors(flags, term->cur_foreground);
+
+ if (ReverseOrHilite(screen, flags, hilite)) {
+ if (flags & BOLDATTR(screen))
+ gc = ReverseBoldGC(screen);
+ else
+ gc = ReverseGC(screen);
+
+ XSetForeground(screen->display, gc, bg_pix);
+ XSetBackground(screen->display, gc, fg_pix);
+
+ } else {
+ if (flags & BOLDATTR(screen))
+ gc = NormalBoldGC(screen);
+ else
+ gc = NormalGC(screen);
+
+ XSetForeground(screen->display, gc, fg_pix);
+ XSetBackground(screen->display, gc, bg_pix);
+ }
+}
+
+#if OPT_ISO_COLORS
+/*
+ * Extract the foreground-color index from a one-byte color pair. If we've got
+ * BOLD or UNDERLINE color-mode active, those will be used.
+ */
+unsigned
+extract_fg(unsigned color, unsigned flags)
+{
+ unsigned fg = ExtractForeground(color);
+
+ if (term->screen.colorAttrMode
+ || (fg == ExtractBackground(color))) {
+ if (term->screen.colorULMode && (flags & UNDERLINE))
+ fg = COLOR_UL;
+ if (term->screen.colorBDMode && (flags & BOLD))
+ fg = COLOR_BD;
+ if (term->screen.colorBLMode && (flags & BLINK))
+ fg = COLOR_BL;
+ }
+ return fg;
+}
+
+/*
+ * Extract the background-color index from a one-byte color pair.
+ * If we've got INVERSE color-mode active, that will be used.
+ */
+unsigned
+extract_bg(unsigned color, unsigned flags)
+{
+ unsigned bg = ExtractBackground(color);
+
+ if (term->screen.colorAttrMode
+ || (bg == ExtractForeground(color))) {
+ if (term->screen.colorRVMode && (flags & INVERSE))
+ bg = COLOR_RV;
+ }
+ return bg;
+}
+
+/*
+ * Combine the current foreground and background into a single 8-bit number.
+ * Note that we're storing the SGR foreground, since cur_foreground may be set
+ * to COLOR_UL, COLOR_BD or COLOR_BL, which would make the code larger than 8
+ * bits.
+ *
+ * This assumes that fg/bg are equal when we override with one of the special
+ * attribute colors.
+ */
+unsigned
+makeColorPair(int fg, int bg)
+{
+ unsigned my_bg = (bg >= 0) && (bg < NUM_ANSI_COLORS) ? (unsigned) bg : 0;
+ unsigned my_fg = (fg >= 0) && (fg < NUM_ANSI_COLORS) ? (unsigned) fg : my_bg;
+#if OPT_EXT_COLORS
+ return (my_fg << 8) | my_bg;
+#else
+ return (my_fg << 4) | my_bg;
+#endif
+}
+
+/*
+ * Using the "current" SGR background, clear a rectangle.
+ */
+void
+ClearCurBackground(TScreen * screen,
+ int top,
+ int left,
+ unsigned height,
+ unsigned width)
+{
+ XSetWindowBackground(screen->display,
+ VWindow(screen),
+ getXtermBackground(term->flags, term->cur_background));
+
+ XClearArea(screen->display, VWindow(screen),
+ left, top, width, height, False);
+
+ XSetWindowBackground(screen->display,
+ VWindow(screen),
+ getXtermBackground(term->flags, MAXCOLORS));
+}
+#endif /* OPT_ISO_COLORS */
+
+/*
+ * Returns a single 8/16-bit number for the given cell
+ */
+unsigned
+getXtermCell(TScreen * screen, int row, int col)
+{
+ unsigned ch = SCRN_BUF_CHARS(screen, row)[col];
+ if_OPT_WIDE_CHARS(screen, {
+ ch |= (SCRN_BUF_WIDEC(screen, row)[col] << 8);
+ });
+ return ch;
+}
+
+/*
+ * Sets a single 8/16-bit number for the given cell
+ */
+void
+putXtermCell(TScreen * screen, int row, int col, int ch)
+{
+ SCRN_BUF_CHARS(screen, row)[col] = ch;
+ if_OPT_WIDE_CHARS(screen, {
+ SCRN_BUF_WIDEC(screen, row)[col] = (ch >> 8);
+ SCRN_BUF_COM1L(screen, row)[col] = 0;
+ SCRN_BUF_COM1H(screen, row)[col] = 0;
+ SCRN_BUF_COM2L(screen, row)[col] = 0;
+ SCRN_BUF_COM2H(screen, row)[col] = 0;
+ });
+}
+
+#if OPT_WIDE_CHARS
+unsigned
+getXtermCellComb1(TScreen * screen, int row, int col)
+{
+ unsigned ch = SCRN_BUF_COM1L(screen, row)[col];
+ ch |= (SCRN_BUF_COM1H(screen, row)[col] << 8);
+ return ch;
+}
+
+unsigned
+getXtermCellComb2(TScreen * screen, int row, int col)
+{
+ unsigned ch = SCRN_BUF_COM2L(screen, row)[col];
+ ch |= (SCRN_BUF_COM2H(screen, row)[col] << 8);
+ return ch;
+}
+
+/*
+ * Add a combining character for the given cell
+ */
+void
+addXtermCombining(TScreen * screen, int row, int col, unsigned ch)
+{
+ if (!SCRN_BUF_COM1L(screen, row)[col]
+ && !SCRN_BUF_COM1H(screen, row)[col]) {
+ SCRN_BUF_COM1L(screen, row)[col] = ch & 0xff;
+ SCRN_BUF_COM1H(screen, row)[col] = ch >> 8;
+ } else if (!SCRN_BUF_COM2H(screen, row)[col]) {
+ SCRN_BUF_COM2L(screen, row)[col] = ch & 0xff;
+ SCRN_BUF_COM2H(screen, row)[col] = ch >> 8;
+ }
+}
+#endif
+
+#ifdef HAVE_CONFIG_H
+#ifdef USE_MY_MEMMOVE
+char *
+my_memmove(char *s1, char *s2, size_t n)
+{
+ if (n != 0) {
+ if ((s1 + n > s2) && (s2 + n > s1)) {
+ static char *bfr;
+ static size_t length;
+ size_t j;
+ if (length < n) {
+ length = (n * 3) / 2;
+ bfr = ((bfr != 0)
+ ? TypeRealloc(char, length, bfr)
+ : TypeMallocN(char, length));
+ if (bfr == NULL)
+ SysError(ERROR_MMALLOC);
+ }
+ for (j = 0; j < n; j++)
+ bfr[j] = s2[j];
+ s2 = bfr;
+ }
+ while (n-- != 0)
+ s1[n] = s2[n];
+ }
+ return s1;
+}
+#endif /* USE_MY_MEMMOVE */
+
+#ifndef HAVE_STRERROR
+char *
+my_strerror(int n)
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ if (n > 0 && n < sys_nerr)
+ return sys_errlist[n];
+ return "?";
+}
+#endif
+#endif
+
+int
+char2lower(int ch)
+{
+ if (isascii(ch) && isupper(ch)) { /* lowercasify */
+#ifdef _tolower
+ ch = _tolower(ch);
+#else
+ ch = tolower(ch);
+#endif
+ }
+ return ch;
+}
+
+void
+update_keyboard_type(void)
+{
+ update_delete_del();
+ update_old_fkeys();
+ update_hp_fkeys();
+ update_sco_fkeys();
+ update_sun_fkeys();
+ update_sun_kbd();
+}
+
+void
+set_keyboard_type(xtermKeyboardType type, Bool set)
+{
+ xtermKeyboardType save = term->keyboard.type;
+
+ TRACE(("set_keyboard_type(%s, %s) currently %s\n",
+ visibleKeyboardType(type),
+ BtoS(set),
+ visibleKeyboardType(term->keyboard.type)));
+ if (set) {
+ term->keyboard.type = type;
+ } else {
+ term->keyboard.type = keyboardIsDefault;
+ }
+
+ if (save != term->keyboard.type) {
+ update_keyboard_type();
+ }
+}
+
+void
+toggle_keyboard_type(xtermKeyboardType type)
+{
+ xtermKeyboardType save = term->keyboard.type;
+
+ TRACE(("toggle_keyboard_type(%s) currently %s\n",
+ visibleKeyboardType(type),
+ visibleKeyboardType(term->keyboard.type)));
+ if (term->keyboard.type == type) {
+ term->keyboard.type = keyboardIsDefault;
+ } else {
+ term->keyboard.type = type;
+ }
+
+ if (save != term->keyboard.type) {
+ update_keyboard_type();
+ }
+}
+
+void
+init_keyboard_type(xtermKeyboardType type, Bool set)
+{
+ static Bool wasSet = False;
+
+ TRACE(("init_keyboard_type(%s, %s) currently %s\n",
+ visibleKeyboardType(type),
+ BtoS(set),
+ visibleKeyboardType(term->keyboard.type)));
+ if (set) {
+ if (wasSet) {
+ fprintf(stderr, "Conflicting keyboard type option (%u/%u)\n",
+ term->keyboard.type, type);
+ }
+ term->keyboard.type = type;
+ wasSet = True;
+ update_keyboard_type();
+ }
+}
+
+/*
+ * If the keyboardType resource is set, use that, overriding the individual
+ * boolean resources for different keyboard types.
+ */
+void
+decode_keyboard_type(XTERM_RESOURCE * rp)
+{
+#define DATA(n, t, f) { n, t, XtOffsetOf(XTERM_RESOURCE, f) }
+#define FLAG(n) *(Boolean *)(((char *)rp) + table[n].offset)
+ static struct {
+ const char *name;
+ xtermKeyboardType type;
+ unsigned offset;
+ } table[] = {
+#if OPT_HP_FUNC_KEYS
+ DATA(NAME_HP_KT, keyboardIsHP, hpFunctionKeys),
+#endif
+#if OPT_SCO_FUNC_KEYS
+ DATA(NAME_SCO_KT, keyboardIsSCO, scoFunctionKeys),
+#endif
+ DATA(NAME_SUN_KT, keyboardIsSun, sunFunctionKeys),
+#if OPT_SUNPC_KBD
+ DATA(NAME_VT220_KT, keyboardIsVT220, sunKeyboard),
+#endif
+ };
+ Cardinal n;
+
+ if (x_strcasecmp(rp->keyboardType, "unknown")) {
+ Bool found = False;
+ for (n = 0; n < XtNumber(table); ++n) {
+ if (!x_strcasecmp(rp->keyboardType, table[n].name + 1)) {
+ FLAG(n) = True;
+ found = True;
+ init_keyboard_type(table[n].type, FLAG(n));
+ } else {
+ FLAG(n) = False;
+ }
+ }
+ if (!found) {
+ fprintf(stderr,
+ "KeyboardType resource \"%s\" not found\n",
+ rp->keyboardType);
+ }
+ } else {
+ for (n = 0; n < XtNumber(table); ++n)
+ init_keyboard_type(table[n].type, FLAG(n));
+ }
+#undef DATA
+#undef FLAG
+}
+
+#if OPT_WIDE_CHARS
+#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
+/*
+ * If xterm is running in a UTF-8 locale, it is still possible to encounter
+ * old runtime configurations which yield incomplete or inaccurate data.
+ */
+static Bool
+systemWcwidthOk(void)
+{
+ wchar_t n;
+ int oops = 0;
+ int last = 1024;
+
+ for (n = 0; n < last; ++n) {
+ int system_code = wcwidth(n);
+ int intern_code = mk_wcwidth(n);
+
+ /*
+ * Since mk_wcwidth() is designed to check for nonspacing characters,
+ * and has rough range-checks for double-width characters, it will
+ * generally not detect cases where a code has not been assigned.
+ *
+ * Some experimentation with GNU libc suggests that up to 1/4 of the
+ * codes would differ, simply because the runtime library would have a
+ * table listing the unassigned codes, and return -1 for those. If
+ * mk_wcwidth() has no information about a code, it returns 1. On the
+ * other hand, if the runtime returns a positive number, the two should
+ * agree.
+ *
+ * The "up to" is measured for 4k, 8k, 16k of data. With only 1k, the
+ * number of differences was only 77. However, that is only one
+ * system, and this is only a sanity check to avoid using broken
+ * libraries.
+ */
+ if ((system_code < 0 && intern_code >= 1)
+ || (system_code >= 0 && intern_code != system_code)) {
+ ++oops;
+ }
+ }
+ TRACE(("systemWcwidthOk: %d/%d mismatches\n", oops, last));
+ return (oops < (last / 4));
+}
+#endif /* HAVE_WCWIDTH */
+
+void
+decode_wcwidth(int mode)
+{
+ switch (mode) {
+ default:
+#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
+ if (xtermEnvUTF8() && systemWcwidthOk()) {
+ my_wcwidth = wcwidth;
+ TRACE(("using system wcwidth() function\n"));
+ break;
+ }
+ /* FALLTHRU */
+ case 2:
+#endif
+ my_wcwidth = &mk_wcwidth;
+ TRACE(("using MK wcwidth() function\n"));
+ break;
+ case 3:
+ case 4:
+ my_wcwidth = &mk_wcwidth_cjk;
+ TRACE(("using MK-CJK wcwidth() function\n"));
+ break;
+ }
+}
+#endif