summaryrefslogtreecommitdiff
path: root/util.c
diff options
context:
space:
mode:
authorLorry <lorry@roadtrain.codethink.co.uk>2012-07-10 15:54:41 +0100
committerLorry <lorry@roadtrain.codethink.co.uk>2012-07-10 15:54:41 +0100
commit18853b9e7f177a39aa228c812169b0f1e95324a0 (patch)
tree47af94eeac283b1fd9183d6133fb1b3fe4758eb1 /util.c
downloadxterm-18853b9e7f177a39aa228c812169b0f1e95324a0.tar.gz
Tarball conversion
Diffstat (limited to 'util.c')
-rw-r--r--util.c4398
1 files changed, 4398 insertions, 0 deletions
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..b1d1496
--- /dev/null
+++ b/util.c
@@ -0,0 +1,4398 @@
+/* $XTermId: util.c,v 1.588 2012/06/03 18:45:04 tom Exp $ */
+
+/*
+ * Copyright 1999-2011,2012 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>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+
+#if OPT_WIDE_CHARS
+#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
+#include <wchar.h>
+#endif
+#include <wcwidth.h>
+#endif
+
+static int handle_translated_exposure(XtermWidget xw,
+ int rect_x,
+ int rect_y,
+ int rect_width,
+ int rect_height);
+static void ClearLeft(XtermWidget xw);
+static void CopyWait(XtermWidget xw);
+static void horizontal_copy_area(XtermWidget xw,
+ int firstchar,
+ int nchars,
+ int amount);
+static void vertical_copy_area(XtermWidget xw,
+ int firstline,
+ int nlines,
+ int amount,
+ int left,
+ int right);
+
+#if OPT_WIDE_CHARS
+unsigned first_widechar;
+int (*my_wcwidth) (wchar_t);
+#endif
+
+#if OPT_WIDE_CHARS
+/*
+ * We will modify the 'n' cells beginning at the current position.
+ * Some of those cells may be part of multi-column characters, including
+ * carryover from the left. Find the limits of the multi-column characters
+ * that we should fill with blanks, return true if filling is needed.
+ */
+int
+DamagedCells(TScreen * screen, unsigned n, int *klp, int *krp, int row, int col)
+{
+ LineData *ld = getLineData(screen, row);
+ int result = False;
+
+ assert(ld);
+ if (col < (int) ld->lineSize) {
+ int nn = (int) n;
+ int kl = col;
+ int kr = col + nn;
+
+ if (kr >= (int) ld->lineSize) {
+ nn = (ld->lineSize - col - 1);
+ kr = col + nn;
+ }
+
+ if (nn > 0) {
+ assert(kl < (int) ld->lineSize);
+ if (ld->charData[kl] == HIDDEN_CHAR) {
+ while (kl > 0) {
+ if (ld->charData[--kl] != HIDDEN_CHAR) {
+ break;
+ }
+ }
+ } else {
+ kl = col + 1;
+ }
+
+ assert(kr < (int) ld->lineSize);
+ if (ld->charData[kr] == HIDDEN_CHAR) {
+ while (kr < screen->max_col) {
+ assert((kr + 1) < (int) ld->lineSize);
+ if (ld->charData[++kr] != HIDDEN_CHAR) {
+ --kr;
+ break;
+ }
+ }
+ } else {
+ kr = col - 1;
+ }
+
+ if (klp)
+ *klp = kl;
+ if (krp)
+ *krp = kr;
+ result = (kr >= kl);
+ }
+ }
+
+ return result;
+}
+
+int
+DamagedCurCells(TScreen * screen, unsigned n, int *klp, int *krp)
+{
+ return DamagedCells(screen, n, klp, krp, screen->cur_row, screen->cur_col);
+}
+#endif /* OPT_WIDE_CHARS */
+
+/*
+ * These routines are used for the jump scroll feature
+ */
+void
+FlushScroll(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+ int i;
+ int shift = INX2ROW(screen, 0);
+ int bot = screen->max_row - shift;
+ int refreshtop;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+ int left = ScrnLeftMargin(xw);
+ int right = ScrnRightMargin(xw);
+ Boolean full_lines = (Boolean) ((left == 0) && (right == screen->max_col));
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ TRACE(("FlushScroll %s-lines scroll:%d refresh %d\n",
+ full_lines ? "full" : "partial",
+ screen->scroll_amt,
+ screen->refresh_amt));
+
+ if (screen->scroll_amt > 0) {
+ /*
+ * Lines will be scrolled "up".
+ */
+ refreshheight = screen->refresh_amt;
+ scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1;
+ refreshtop = screen->bot_marg - refreshheight + 1 + shift;
+ i = screen->max_row - screen->scroll_amt + 1;
+ if (refreshtop > i) {
+ refreshtop = i;
+ }
+
+ /*
+ * If this is the normal (not alternate) screen, and the top margin is
+ * at the top of the screen, then we will shift full lines scrolled out
+ * of the scrolling region into the saved-lines.
+ */
+ if (screen->scrollWidget
+ && !screen->whichBuf
+ && full_lines
+ && screen->top_marg == 0) {
+ scrolltop = 0;
+ scrollheight += shift;
+ if (scrollheight > i)
+ scrollheight = i;
+ i = screen->bot_marg - bot;
+ if (i > 0) {
+ refreshheight -= i;
+ if (refreshheight < screen->scroll_amt) {
+ refreshheight = screen->scroll_amt;
+ }
+ }
+ i = screen->savedlines;
+ if (i < screen->savelines) {
+ i += screen->scroll_amt;
+ if (i > screen->savelines) {
+ i = screen->savelines;
+ }
+ screen->savedlines = i;
+ ScrollBarDrawThumb(screen->scrollWidget);
+ }
+ } else {
+ scrolltop = screen->top_marg + shift;
+ i = bot - (screen->bot_marg - screen->refresh_amt + screen->scroll_amt);
+ if (i > 0) {
+ if (bot < screen->bot_marg) {
+ refreshheight = screen->scroll_amt + i;
+ }
+ } else {
+ scrollheight += i;
+ refreshheight = screen->scroll_amt;
+ i = screen->top_marg + screen->scroll_amt - 1 - bot;
+ if (i > 0) {
+ refreshtop += i;
+ refreshheight -= i;
+ }
+ }
+ }
+ } else {
+ /*
+ * Lines will be scrolled "down".
+ */
+ refreshheight = -screen->refresh_amt;
+ scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1;
+ refreshtop = screen->top_marg + shift;
+ scrolltop = refreshtop + refreshheight;
+ i = screen->bot_marg - bot;
+ if (i > 0) {
+ scrollheight -= i;
+ }
+ i = screen->top_marg + refreshheight - 1 - bot;
+ if (i > 0) {
+ refreshheight -= i;
+ }
+ }
+
+ vertical_copy_area(xw,
+ scrolltop + screen->scroll_amt,
+ scrollheight,
+ screen->scroll_amt,
+ left,
+ right);
+ ScrollSelection(screen, -(screen->scroll_amt), False);
+ screen->scroll_amt = 0;
+ screen->refresh_amt = 0;
+
+ if (refreshheight > 0) {
+ ClearCurBackground(xw,
+ refreshtop,
+ left,
+ (unsigned) refreshheight,
+ (unsigned) (right + 1 - left),
+ (unsigned) FontWidth(screen));
+ ScrnRefresh(xw,
+ refreshtop,
+ 0,
+ refreshheight,
+ MaxCols(screen),
+ False);
+ }
+ return;
+}
+
+/*
+ * Returns true if there are lines off-screen due to scrolling which should
+ * include the current line. If false, the line is visible and we should
+ * paint it now rather than waiting for the line to become visible.
+ */
+static Bool
+AddToRefresh(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+ int amount = screen->refresh_amt;
+ int row = screen->cur_row;
+ Bool result;
+
+ if (amount == 0) {
+ result = False;
+ } else if (amount > 0) {
+ int bottom;
+
+ if (row == (bottom = screen->bot_marg) - amount) {
+ screen->refresh_amt++;
+ result = True;
+ } else {
+ result = (row >= bottom - amount + 1 && row <= bottom);
+ }
+ } else {
+ int top;
+
+ amount = -amount;
+ if (row == (top = screen->top_marg) + amount) {
+ screen->refresh_amt--;
+ result = True;
+ } else {
+ result = (row <= top + amount - 1 && row >= top);
+ }
+ }
+
+ /*
+ * If this line is visible, and there are scrolled-off lines, flush out
+ * those which are now visible.
+ */
+ if (!result && screen->scroll_amt)
+ FlushScroll(xw);
+
+ return result;
+}
+
+/*
+ * Returns true if the current row is in the visible area (it should be for
+ * screen operations) and incidentally flush the scrolled-in lines which
+ * have newly become visible.
+ */
+static Bool
+AddToVisible(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+ Bool result = False;
+
+ if (INX2ROW(screen, screen->cur_row) <= screen->max_row) {
+ if (!AddToRefresh(xw)) {
+ result = True;
+ }
+ }
+ return result;
+}
+
+/*
+ * 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 entirely contained within the margins and not
+ * entirely outside the margins, clear it.
+ */
+static void
+adjustHiliteOnFwdScroll(XtermWidget xw, int amount, Bool all_lines)
+{
+ TScreen *screen = TScreenOf(xw);
+ int lo_row = (all_lines
+ ? (screen->bot_marg - screen->savelines)
+ : screen->top_marg);
+ int hi_row = screen->bot_marg;
+ int left = ScrnLeftMargin(xw);
+ int right = ScrnRightMargin(xw);
+
+ TRACE2(("adjustSelection FWD %s by %d (%s)\n",
+ screen->whichBuf ? "alternate" : "normal",
+ amount,
+ all_lines ? "all" : "visible"));
+ TRACE2((" before highlite %d.%d .. %d.%d\n",
+ screen->startH.row,
+ screen->startH.col,
+ screen->endH.row,
+ screen->endH.col));
+ TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg));
+ TRACE2((" limits %d..%d\n", lo_row, hi_row));
+
+ if ((left > 0 || right < screen->max_col) &&
+ ((screen->startH.row >= lo_row &&
+ screen->startH.row - amount <= hi_row) ||
+ (screen->endH.row >= lo_row &&
+ screen->endH.row - amount <= hi_row))) {
+ /*
+ * This could be improved slightly by excluding the special case where
+ * the selection is on a single line outside left/right margins.
+ */
+ TRACE2(("deselect because selection overlaps with scrolled partial-line\n"));
+ ScrnDisownSelection(xw);
+ } else if (screen->startH.row >= lo_row
+ && screen->startH.row - amount < lo_row) {
+ /* truncate the selection because its start would move out of region */
+ if (lo_row + amount <= screen->endH.row) {
+ TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
+ screen->startH.row,
+ screen->startH.col,
+ lo_row + amount,
+ 0));
+ screen->startH.row = lo_row + amount;
+ screen->startH.col = 0;
+ } else {
+ TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
+ screen->startH.row,
+ screen->startH.col,
+ screen->endH.row,
+ screen->endH.col,
+ -amount,
+ lo_row,
+ hi_row));
+ ScrnDisownSelection(xw);
+ }
+ } else if (screen->startH.row <= hi_row && screen->endH.row > hi_row) {
+ TRACE2(("deselect because selection straddles top-margin\n"));
+ ScrnDisownSelection(xw);
+ } else if (screen->startH.row < lo_row && screen->endH.row > lo_row) {
+ TRACE2(("deselect because selection straddles bottom-margin\n"));
+ ScrnDisownSelection(xw);
+ }
+
+ TRACE2((" after highlite %d.%d .. %d.%d\n",
+ screen->startH.row,
+ screen->startH.col,
+ screen->endH.row,
+ screen->endH.col));
+}
+
+/*
+ * This is the same as adjustHiliteOnFwdScroll(), but reversed. In this case,
+ * only the visible lines are affected.
+ */
+static void
+adjustHiliteOnBakScroll(XtermWidget xw, int amount)
+{
+ TScreen *screen = TScreenOf(xw);
+ int lo_row = screen->top_marg;
+ int hi_row = screen->bot_marg;
+
+ TRACE2(("adjustSelection BAK %s by %d (%s)\n",
+ screen->whichBuf ? "alternate" : "normal",
+ amount,
+ "visible"));
+ TRACE2((" before highlite %d.%d .. %d.%d\n",
+ screen->startH.row,
+ screen->startH.col,
+ screen->endH.row,
+ screen->endH.col));
+ TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg));
+
+ if (screen->endH.row >= hi_row
+ && screen->endH.row + amount > hi_row) {
+ /* truncate the selection because its start would move out of region */
+ if (hi_row - amount >= screen->startH.row) {
+ TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
+ screen->startH.row,
+ screen->startH.col,
+ hi_row - amount,
+ 0));
+ screen->endH.row = hi_row - amount;
+ screen->endH.col = 0;
+ } else {
+ TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
+ screen->startH.row,
+ screen->startH.col,
+ screen->endH.row,
+ screen->endH.col,
+ amount,
+ lo_row,
+ hi_row));
+ ScrnDisownSelection(xw);
+ }
+ } else if (screen->endH.row >= lo_row && screen->startH.row < lo_row) {
+ ScrnDisownSelection(xw);
+ } else if (screen->endH.row > hi_row && screen->startH.row > hi_row) {
+ ScrnDisownSelection(xw);
+ }
+
+ TRACE2((" after highlite %d.%d .. %d.%d\n",
+ screen->startH.row,
+ screen->startH.col,
+ screen->endH.row,
+ screen->endH.col));
+}
+
+/*
+ * Move cells in LineData's on the current screen to simulate scrolling by the
+ * given amount of lines.
+ */
+static void
+scrollInMargins(XtermWidget xw, int amount, int top)
+{
+ TScreen *screen = TScreenOf(xw);
+ LineData *src;
+ LineData *dst;
+ int row;
+ int left = ScrnLeftMargin(xw);
+ int right = ScrnRightMargin(xw);
+ int length = right + 1 - left;
+
+ if (amount > 0) {
+ for (row = top; row <= screen->bot_marg - amount; ++row) {
+ if ((src = getLineData(screen, row + amount)) != 0
+ && (dst = getLineData(screen, row)) != 0) {
+ CopyCells(screen, src, dst, left, length);
+ }
+ }
+ while (row <= screen->bot_marg) {
+ ClearCells(xw, 0, (unsigned) length, row, left);
+ ++row;
+ }
+ } else if (amount < 0) {
+ for (row = screen->bot_marg; row >= top - amount; --row) {
+ if ((src = getLineData(screen, row + amount)) != 0
+ && (dst = getLineData(screen, row)) != 0) {
+ CopyCells(screen, src, dst, left, length);
+ }
+ }
+ while (row >= top) {
+ ClearCells(xw, 0, (unsigned) length, row, left);
+ --row;
+ }
+ }
+}
+
+/*
+ * 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(XtermWidget xw, int amount)
+{
+ TScreen *screen = TScreenOf(xw);
+ int i;
+ int shift;
+ int bot;
+ int refreshtop = 0;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+ int left = ScrnLeftMargin(xw);
+ int right = ScrnRightMargin(xw);
+ Boolean scroll_all_lines = (Boolean) (screen->scrollWidget
+ && !screen->whichBuf
+ && screen->top_marg == 0);
+
+ TRACE(("xtermScroll count=%d\n", amount));
+
+ screen->cursor_busy += 1;
+ screen->cursor_moved = True;
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ i = screen->bot_marg - screen->top_marg + 1;
+ if (amount > i)
+ amount = i;
+
+#if OPT_SCROLL_LOCK
+ if (screen->allowScrollLock && screen->scroll_lock) {
+ refreshheight = 0;
+ screen->scroll_amt = 0;
+ screen->refresh_amt = 0;
+ if (--(screen->topline) < -screen->savelines) {
+ screen->topline = -screen->savelines;
+ screen->scroll_dirty = True;
+ }
+ if (++(screen->savedlines) > screen->savelines) {
+ screen->savedlines = screen->savelines;
+ }
+ } else
+#endif
+ {
+ if (ScrnHaveSelection(screen))
+ adjustHiliteOnFwdScroll(xw, amount, scroll_all_lines);
+
+ if (screen->jumpscroll) {
+ if (screen->scroll_amt > 0) {
+ if (!screen->fastscroll) {
+ if (screen->refresh_amt + amount > i)
+ FlushScroll(xw);
+ }
+ screen->scroll_amt += amount;
+ screen->refresh_amt += amount;
+ } else {
+ if (!screen->fastscroll) {
+ if (screen->scroll_amt < 0)
+ FlushScroll(xw);
+ }
+ screen->scroll_amt = amount;
+ screen->refresh_amt = amount;
+ }
+ refreshheight = 0;
+ } else {
+ ScrollSelection(screen, -(amount), False);
+ if (amount == i) {
+ ClearScreen(xw);
+ screen->cursor_busy -= 1;
+ return;
+ }
+
+ shift = INX2ROW(screen, 0);
+ 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(xw);
+ screen->scrolls++;
+ }
+
+ vertical_copy_area(xw,
+ scrolltop + amount,
+ scrollheight,
+ amount,
+ left,
+ right);
+
+ if (refreshheight > 0) {
+ ClearCurBackground(xw,
+ refreshtop,
+ left,
+ (unsigned) refreshheight,
+ (unsigned) (right + 1 - left),
+ (unsigned) FontWidth(screen));
+ if (refreshheight > shift)
+ refreshheight = shift;
+ }
+ }
+ }
+
+ if (amount > 0) {
+ if (left > 0 || right < screen->max_col) {
+ scrollInMargins(xw, amount, screen->top_marg);
+ } else if (scroll_all_lines) {
+ ScrnDeleteLine(xw,
+ screen->saveBuf_index,
+ screen->bot_marg + screen->savelines,
+ 0,
+ (unsigned) amount);
+ } else {
+ ScrnDeleteLine(xw,
+ screen->visbuf,
+ screen->bot_marg,
+ screen->top_marg,
+ (unsigned) amount);
+ }
+ }
+
+ if (refreshheight > 0) {
+ ScrnRefresh(xw,
+ refreshtop,
+ left,
+ refreshheight,
+ right + 1 - left,
+ False);
+ }
+
+ screen->cursor_busy -= 1;
+ return;
+}
+
+/*
+ * This is from ISO 6429, not found in any of DEC's terminals.
+ */
+void
+xtermScrollLR(XtermWidget xw, int amount, Bool toLeft)
+{
+ if (amount > 0) {
+ xtermColScroll(xw, amount, toLeft, 0);
+ }
+}
+
+/*
+ * Implement DECBI/DECFI (back/forward column index)
+ */
+void
+xtermColIndex(XtermWidget xw, Bool toLeft)
+{
+ TScreen *screen = TScreenOf(xw);
+ int margin;
+
+ if (toLeft) {
+ margin = ScrnLeftMargin(xw);
+ if (screen->cur_col > margin) {
+ CursorBack(xw, 1);
+ } else if (screen->cur_col == margin) {
+ xtermColScroll(xw, 1, False, screen->cur_col);
+ }
+ } else {
+ margin = ScrnRightMargin(xw);
+ if (screen->cur_col < margin) {
+ CursorForward(xw, 1);
+ } else if (screen->cur_col == margin) {
+ xtermColScroll(xw, 1, True, ScrnLeftMargin(xw));
+ }
+ }
+}
+
+/*
+ * Implement DECDC/DECIC (delete/insert column)
+ */
+void
+xtermColScroll(XtermWidget xw, int amount, Bool toLeft, int at_col)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ if (amount > 0) {
+ int min_row;
+ int max_row;
+
+ if (ScrnHaveRowMargins(screen)) {
+ min_row = screen->top_marg;
+ max_row = screen->bot_marg;
+ } else {
+ min_row = 0;
+ max_row = screen->max_row;
+ }
+
+ if (screen->cur_row >= min_row
+ && screen->cur_row <= max_row
+ && screen->cur_col >= screen->lft_marg
+ && screen->cur_col <= screen->rgt_marg) {
+ int save_row = screen->cur_row;
+ int save_col = screen->cur_col;
+ int row;
+
+ screen->cur_col = at_col;
+ if (toLeft) {
+ for (row = min_row; row <= max_row; row++) {
+ screen->cur_row = row;
+ ScrnDeleteChar(xw, (unsigned) amount);
+ }
+ } else {
+ for (row = min_row; row <= max_row; row++) {
+ screen->cur_row = row;
+ ScrnInsertChar(xw, (unsigned) amount);
+ }
+ }
+ screen->cur_row = save_row;
+ screen->cur_col = save_col;
+ xtermRepaint(xw);
+ }
+ }
+}
+
+/*
+ * 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(XtermWidget xw, int amount)
+{
+ TScreen *screen = TScreenOf(xw);
+ int i = screen->bot_marg - screen->top_marg + 1;
+ int shift;
+ int bot;
+ int refreshtop;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+ int left = ScrnLeftMargin(xw);
+ int right = ScrnRightMargin(xw);
+
+ 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(xw, amount);
+
+ if (screen->jumpscroll) {
+ if (screen->scroll_amt < 0) {
+ if (-screen->refresh_amt + amount > i)
+ FlushScroll(xw);
+ screen->scroll_amt -= amount;
+ screen->refresh_amt -= amount;
+ } else {
+ if (screen->scroll_amt > 0)
+ FlushScroll(xw);
+ screen->scroll_amt = -amount;
+ screen->refresh_amt = -amount;
+ }
+ } else {
+ shift = INX2ROW(screen, 0);
+ 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(xw);
+ screen->scrolls++;
+ }
+
+ vertical_copy_area(xw,
+ scrolltop - amount,
+ scrollheight,
+ -amount,
+ left,
+ right);
+
+ if (refreshheight > 0) {
+ ClearCurBackground(xw,
+ refreshtop,
+ left,
+ (unsigned) refreshheight,
+ (unsigned) (right + 1 - left),
+ (unsigned) FontWidth(screen));
+ }
+ }
+ if (amount > 0) {
+ if (left > 0 || right < screen->max_col) {
+ scrollInMargins(xw, -amount, screen->top_marg);
+ } else {
+ ScrnInsertLine(xw,
+ screen->visbuf,
+ screen->bot_marg,
+ screen->top_marg,
+ (unsigned) amount);
+ }
+ }
+ screen->cursor_busy -= 1;
+ return;
+}
+
+#if OPT_ZICONBEEP
+void
+initZIconBeep(void)
+{
+ if (resource.zIconBeep > 100 || resource.zIconBeep < -100) {
+ resource.zIconBeep = 0; /* was 100, but I prefer to defaulting off. */
+ xtermWarning("a number between -100 and 100 is required for zIconBeep. 0 used by default\n");
+ }
+}
+
+static void
+setZIconBeep(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ /* Flag icon name with "***" on window output when iconified.
+ */
+ if (resource.zIconBeep && mapstate == IsUnmapped && !screen->zIconBeep_flagged) {
+ static char *icon_name;
+ static Arg args[] =
+ {
+ {XtNiconName, (XtArgVal) & icon_name}
+ };
+
+ icon_name = NULL;
+ XtGetValues(toplevel, args, XtNumber(args));
+
+ if (icon_name != NULL) {
+ screen->zIconBeep_flagged = True;
+ ChangeIconName(xw, icon_name);
+ }
+ xtermBell(xw, XkbBI_Info, 0);
+ }
+ mapstate = -1;
+}
+
+/*
+ * If warning should be given then give it
+ */
+Boolean
+showZIconBeep(XtermWidget xw, char *name)
+{
+ Boolean code = False;
+
+ if (resource.zIconBeep && TScreenOf(xw)->zIconBeep_flagged) {
+ char *format = resource.zIconFormat;
+ char *newname = CastMallocN(char, strlen(name) + strlen(format) + 1);
+ if (!newname) {
+ xtermWarning("malloc failed in showZIconBeep\n");
+ } else {
+ char *marker = strstr(format, "%s");
+ char *result = newname;
+ if (marker != 0) {
+ size_t skip = (size_t) (marker - format);
+ if (skip) {
+ strncpy(result, format, skip);
+ result += skip;
+ }
+ strcpy(result, name);
+ strcat(result, marker + 2);
+ } else {
+ strcpy(result, format);
+ strcat(result, name);
+ }
+ ChangeGroup(xw, XtNiconName, newname);
+ free(newname);
+ }
+ code = True;
+ }
+ return code;
+}
+
+/*
+ * Restore the icon name, resetting the state for zIconBeep.
+ */
+void
+resetZIconBeep(XtermWidget xw)
+{
+ static char *icon_name;
+ static Arg args[] =
+ {
+ {XtNiconName, (XtArgVal) & icon_name}
+ };
+ TScreen *screen = TScreenOf(xw);
+
+ if (screen->zIconBeep_flagged) {
+ screen->zIconBeep_flagged = False;
+ icon_name = NULL;
+ XtGetValues(toplevel, args, XtNumber(args));
+ if (icon_name != NULL) {
+ char *buf = CastMallocN(char, strlen(icon_name));
+ if (buf == NULL) {
+ screen->zIconBeep_flagged = True;
+ } else {
+ char *format = resource.zIconFormat;
+ char *marker = strstr(format, "%s");
+ Boolean found = False;
+
+ if (marker != 0) {
+ if (marker == format
+ || !strncmp(icon_name, format, (size_t) (marker - format))) {
+ found = True;
+ strcpy(buf, icon_name + (marker - format));
+ marker += 2;
+ if (*marker != '\0') {
+ size_t len_m = strlen(marker);
+ size_t len_b = strlen(buf);
+ if (len_m < len_b
+ && !strcmp(buf + len_b - len_m, marker)) {
+ buf[len_b - len_m] = '\0';
+ }
+ }
+ }
+ } else if (!strncmp(icon_name, format, strlen(format))) {
+ strcpy(buf, icon_name + strlen(format));
+ found = True;
+ }
+ if (found)
+ ChangeIconName(xw, buf);
+ free(buf);
+ }
+ }
+ }
+}
+#else
+#define setZIconBeep(xw) /* nothing */
+#endif /* OPT_ZICONBEEP */
+
+/*
+ * write a string str of length len onto the screen at
+ * the current cursor position. update cursor position.
+ */
+void
+WriteText(XtermWidget xw, IChar * str, Cardinal len)
+{
+ TScreen *screen = TScreenOf(xw);
+ LineData *ld = 0;
+ int fg;
+ unsigned test;
+ unsigned flags = xw->flags;
+ CellColor fg_bg = makeColorPair(xw->cur_foreground, xw->cur_background);
+ unsigned cells = visual_width(str, len);
+ GC currentGC;
+
+ TRACE(("WriteText %d (%2d,%2d) %3d:%s\n",
+ screen->topline,
+ screen->cur_row,
+ screen->cur_col,
+ len, visibleIChar(str, len)));
+
+ if (cells + (unsigned) screen->cur_col > (unsigned) MaxCols(screen)) {
+ cells = (unsigned) (MaxCols(screen) - screen->cur_col);
+ }
+
+ if (ScrnHaveSelection(screen)
+ && ScrnIsRowInSelection(screen, INX2ROW(screen, screen->cur_row))) {
+ ScrnDisownSelection(xw);
+ }
+
+ /* if we are in insert-mode, reserve space for the new cells */
+ if (flags & INSERT) {
+ InsertChar(xw, cells);
+ }
+
+ if (AddToVisible(xw)
+ && ((ld = getLineData(screen, screen->cur_row))) != 0) {
+ if (screen->cursor_state)
+ HideCursor();
+
+ /*
+ * If we overwrite part of a multi-column character, fill the rest
+ * of it with blanks.
+ */
+ if_OPT_WIDE_CHARS(screen, {
+ int kl;
+ int kr;
+ if (DamagedCurCells(screen, cells, &kl, &kr))
+ ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
+ });
+
+ if (flags & INVISIBLE) {
+ Cardinal n;
+ for (n = 0; n < cells; ++n)
+ str[n] = ' ';
+ }
+
+ TRACE(("WriteText calling drawXtermText (%d) (%d,%d)\n",
+ LineCharSet(screen, ld),
+ screen->cur_col,
+ screen->cur_row));
+
+ test = flags;
+#if OPT_ISO_COLORS
+ if (screen->colorAttrMode) {
+ fg = MapToColorMode(xw->cur_foreground, screen, flags);
+ } else {
+ fg = xw->cur_foreground;
+ }
+ checkVeryBoldColors(test, fg);
+#endif
+
+ /* make sure that the correct GC is current */
+ currentGC = updatedXtermGC(xw, flags, fg_bg, False);
+
+ drawXtermText(xw, test & DRAWX_MASK, currentGC,
+ LineCursorX(screen, ld, screen->cur_col),
+ CursorY(screen, screen->cur_row),
+ LineCharSet(screen, ld),
+ str, len, 0);
+
+ resetXtermGC(xw, flags, False);
+ }
+
+ ScrnWriteText(xw, str, flags, fg_bg, len);
+ CursorForward(xw, (int) cells);
+ setZIconBeep(xw);
+ 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(XtermWidget xw, int n)
+{
+ TScreen *screen = TScreenOf(xw);
+ int i;
+ int shift;
+ int bot;
+ int refreshtop;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+ int left = ScrnLeftMargin(xw);
+ int right = ScrnRightMargin(xw);
+
+ if (!ScrnIsRowInMargins(screen, screen->cur_row)
+ || screen->cur_col < left
+ || screen->cur_col > right)
+ return;
+
+ TRACE(("InsertLine count=%d\n", n));
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ if (ScrnHaveSelection(screen)
+ && ScrnAreRowsInSelection(screen,
+ INX2ROW(screen, screen->top_marg),
+ INX2ROW(screen, screen->cur_row - 1))
+ && ScrnAreRowsInSelection(screen,
+ INX2ROW(screen, screen->cur_row),
+ INX2ROW(screen, screen->bot_marg))) {
+ ScrnDisownSelection(xw);
+ }
+
+ ResetWrap(screen);
+ 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(xw);
+ screen->scroll_amt -= n;
+ screen->refresh_amt -= n;
+ } else {
+ if (screen->scroll_amt)
+ FlushScroll(xw);
+ }
+ }
+ if (!screen->scroll_amt) {
+ shift = INX2ROW(screen, 0);
+ 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(xw, scrolltop - n, scrollheight, -n, left, right);
+ if (refreshheight > 0) {
+ ClearCurBackground(xw,
+ refreshtop,
+ left,
+ (unsigned) refreshheight,
+ (unsigned) (right + 1 - left),
+ (unsigned) FontWidth(screen));
+ }
+ }
+ if (n > 0) {
+ if (left > 0 || right < screen->max_col) {
+ scrollInMargins(xw, -n, screen->cur_row);
+ } else {
+ ScrnInsertLine(xw,
+ screen->visbuf,
+ screen->bot_marg,
+ screen->cur_row,
+ (unsigned) n);
+ }
+ }
+}
+
+/*
+ * 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(XtermWidget xw, int n)
+{
+ TScreen *screen = TScreenOf(xw);
+ int i;
+ int shift;
+ int bot;
+ int refreshtop;
+ int refreshheight;
+ int scrolltop;
+ int scrollheight;
+ int left = ScrnLeftMargin(xw);
+ int right = ScrnRightMargin(xw);
+ Boolean scroll_all_lines = (Boolean) (screen->scrollWidget
+ && !screen->whichBuf
+ && screen->cur_row == 0);
+
+ if (!ScrnIsRowInMargins(screen, screen->cur_row)
+ || screen->cur_col < left
+ || screen->cur_col > right)
+ return;
+
+ TRACE(("DeleteLine count=%d\n", n));
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ if (n > (i = screen->bot_marg - screen->cur_row + 1)) {
+ n = i;
+ }
+ if (ScrnHaveSelection(screen)
+ && ScrnAreRowsInSelection(screen,
+ INX2ROW(screen, screen->cur_row),
+ INX2ROW(screen, screen->cur_row + n - 1))) {
+ ScrnDisownSelection(xw);
+ }
+
+ ResetWrap(screen);
+ if (screen->jumpscroll) {
+ if (screen->scroll_amt >= 0 && screen->cur_row == screen->top_marg) {
+ if (screen->refresh_amt + n > MaxRows(screen))
+ FlushScroll(xw);
+ screen->scroll_amt += n;
+ screen->refresh_amt += n;
+ } else {
+ if (screen->scroll_amt)
+ FlushScroll(xw);
+ }
+ }
+
+ /* adjust screen->buf */
+ if (n > 0) {
+ if (left > 0 || right < screen->max_col) {
+ scrollInMargins(xw, n, screen->cur_row);
+ } else if (scroll_all_lines) {
+ ScrnDeleteLine(xw,
+ screen->saveBuf_index,
+ screen->bot_marg + screen->savelines,
+ 0,
+ (unsigned) n);
+ } else {
+ ScrnDeleteLine(xw,
+ screen->visbuf,
+ screen->bot_marg,
+ screen->cur_row,
+ (unsigned) n);
+ }
+ }
+
+ /* repaint the screen, as needed */
+ if (!screen->scroll_amt) {
+ shift = INX2ROW(screen, 0);
+ 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 (scroll_all_lines) {
+ 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(xw, scrolltop + n, scrollheight, n, left, right);
+ if (shift > 0 && refreshheight > 0) {
+ int rows = refreshheight;
+ if (rows > shift)
+ rows = shift;
+ ScrnUpdate(xw, refreshtop, 0, rows, MaxCols(screen), True);
+ refreshtop += shift;
+ refreshheight -= shift;
+ }
+ if (refreshheight > 0) {
+ ClearCurBackground(xw,
+ refreshtop,
+ left,
+ (unsigned) refreshheight,
+ (unsigned) (right + 1 - left),
+ (unsigned) FontWidth(screen));
+ }
+ }
+}
+
+/*
+ * Insert n blanks at the cursor's position, no wraparound
+ */
+void
+InsertChar(XtermWidget xw, unsigned n)
+{
+ TScreen *screen = TScreenOf(xw);
+ LineData *ld;
+ unsigned limit;
+ int row = INX2ROW(screen, screen->cur_row);
+ int left = ScrnLeftMargin(xw);
+ int right = ScrnRightMargin(xw);
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ TRACE(("InsertChar count=%d\n", n));
+
+ if (ScrnHaveSelection(screen)
+ && ScrnIsRowInSelection(screen, row)) {
+ ScrnDisownSelection(xw);
+ }
+ ResetWrap(screen);
+
+ limit = (unsigned) (right + 1 - screen->cur_col);
+
+ if (n > limit)
+ n = limit;
+
+ if (screen->cur_col < left || screen->cur_col > right) {
+ n = 0;
+ } else if (AddToVisible(xw)
+ && (ld = getLineData(screen, screen->cur_row)) != 0) {
+ int col = right + 1 - (int) n;
+
+ /*
+ * If we shift part of a multi-column character, fill the rest
+ * of it with blanks. Do similar repair for the text which will
+ * be shifted into the right-margin.
+ */
+ if_OPT_WIDE_CHARS(screen, {
+ int kl;
+ int kr = screen->cur_col;
+ if (DamagedCurCells(screen, n, &kl, (int *) 0) && kr > kl) {
+ ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
+ }
+ kr = screen->max_col - (int) n + 1;
+ if (DamagedCells(screen, n, &kl, (int *) 0,
+ screen->cur_row,
+ kr) && kr > kl) {
+ ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
+ }
+ });
+
+#if OPT_DEC_CHRSET
+ if (CSET_DOUBLE(GetLineDblCS(ld))) {
+ col = MaxCols(screen) / 2 - (int) n;
+ }
+#endif
+ /*
+ * prevent InsertChar from shifting the end of a line over
+ * if it is being appended to
+ */
+ if (non_blank_line(screen, screen->cur_row,
+ screen->cur_col, MaxCols(screen))) {
+ horizontal_copy_area(xw, screen->cur_col,
+ col - screen->cur_col,
+ (int) n);
+ }
+
+ ClearCurBackground(xw,
+ screen->cur_row,
+ screen->cur_col,
+ 1,
+ n,
+ (unsigned) LineFontWidth(screen, ld));
+ }
+ if (n != 0) {
+ /* adjust screen->buf */
+ ScrnInsertChar(xw, n);
+ }
+}
+
+/*
+ * Deletes n chars at the cursor's position, no wraparound.
+ */
+void
+DeleteChar(XtermWidget xw, unsigned n)
+{
+ TScreen *screen = TScreenOf(xw);
+ LineData *ld;
+ unsigned limit;
+ int row = INX2ROW(screen, screen->cur_row);
+ int left = ScrnLeftMargin(xw);
+ int right = ScrnRightMargin(xw);
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ TRACE(("DeleteChar count=%d\n", n));
+
+ if (ScrnHaveSelection(screen)
+ && ScrnIsRowInSelection(screen, row)) {
+ ScrnDisownSelection(xw);
+ }
+ ResetWrap(screen);
+
+ limit = (unsigned) (right + 1 - screen->cur_col);
+
+ if (n > limit)
+ n = limit;
+
+ if (screen->cur_col < left || screen->cur_col > right) {
+ n = 0;
+ } else if (AddToVisible(xw)
+ && (ld = getLineData(screen, screen->cur_row)) != 0) {
+ int col = right + 1 - (int) n;
+
+ /*
+ * If we delete part of a multi-column character, fill the rest
+ * of it with blanks.
+ */
+ if_OPT_WIDE_CHARS(screen, {
+ int kl;
+ int kr;
+ if (DamagedCurCells(screen, n, &kl, &kr))
+ ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
+ });
+
+#if OPT_DEC_CHRSET
+ if (CSET_DOUBLE(GetLineDblCS(ld))) {
+ col = MaxCols(screen) / 2 - (int) n;
+ }
+#endif
+ horizontal_copy_area(xw,
+ (screen->cur_col + (int) n),
+ col - screen->cur_col,
+ -((int) n));
+
+ ClearCurBackground(xw,
+ screen->cur_row,
+ col,
+ 1,
+ n,
+ (unsigned) LineFontWidth(screen, ld));
+ }
+ if (n != 0) {
+ /* adjust screen->buf */
+ ScrnDeleteChar(xw, n);
+ }
+}
+
+/*
+ * Clear from cursor position to beginning of display, inclusive.
+ */
+static void
+ClearAbove(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ if (screen->protected_mode != OFF_PROTECT) {
+ int row;
+ unsigned len = (unsigned) MaxCols(screen);
+
+ assert(screen->max_col >= 0);
+ for (row = 0; row <= screen->max_row; row++)
+ ClearInLine(xw, row, 0, len);
+ } else {
+ int top, height;
+
+ if (screen->cursor_state)
+ HideCursor();
+ if ((top = INX2ROW(screen, 0)) <= screen->max_row) {
+ if (screen->scroll_amt)
+ FlushScroll(xw);
+ if ((height = screen->cur_row + top) > screen->max_row)
+ height = screen->max_row + 1;
+ if ((height -= top) > 0) {
+ ClearCurBackground(xw,
+ top,
+ 0,
+ (unsigned) height,
+ (unsigned) MaxCols(screen),
+ (unsigned) FontWidth(screen));
+ }
+ }
+ ClearBufRows(xw, 0, screen->cur_row - 1);
+ }
+
+ ClearLeft(xw);
+}
+
+/*
+ * Clear from cursor position to end of display, inclusive.
+ */
+static void
+ClearBelow(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ ClearRight(xw, -1);
+
+ if (screen->protected_mode != OFF_PROTECT) {
+ int row;
+ unsigned len = (unsigned) MaxCols(screen);
+
+ assert(screen->max_col >= 0);
+ for (row = screen->cur_row + 1; row <= screen->max_row; row++)
+ ClearInLine(xw, row, 0, len);
+ } else {
+ int top;
+
+ if ((top = INX2ROW(screen, screen->cur_row)) <= screen->max_row) {
+ if (screen->scroll_amt)
+ FlushScroll(xw);
+ if (++top <= screen->max_row) {
+ ClearCurBackground(xw,
+ top,
+ 0,
+ (unsigned) (screen->max_row - top + 1),
+ (unsigned) MaxCols(screen),
+ (unsigned) FontWidth(screen));
+ }
+ }
+ ClearBufRows(xw, 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
+ClearInLine2(XtermWidget xw, int flags, int row, int col, unsigned len)
+{
+ TScreen *screen = TScreenOf(xw);
+ LineData *ld;
+ int rc = 1;
+
+ TRACE(("ClearInLine(row=%d, col=%d, len=%d) vs %d..%d\n",
+ row, col, len,
+ screen->startH.row,
+ screen->startH.col));
+
+ if (ScrnHaveSelection(screen)
+ && ScrnIsRowInSelection(screen, row)) {
+ ScrnDisownSelection(xw);
+ }
+
+ if (col + (int) len >= MaxCols(screen)) {
+ len = (unsigned) (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 = getLineData(screen, row)->attribs + 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(xw, 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 += (int) n;
+ len -= n;
+ }
+ } while (!done);
+
+ screen->protected_mode = saved_mode;
+ if ((int) len <= 0) {
+ return 0;
+ }
+ }
+ /* fall through to the final non-protected segment */
+
+ if (screen->cursor_state)
+ HideCursor();
+ ResetWrap(screen);
+
+ if (AddToVisible(xw)
+ && (ld = getLineData(screen, row)) != 0) {
+
+ ClearCurBackground(xw,
+ row,
+ col,
+ 1,
+ len,
+ (unsigned) LineFontWidth(screen, ld));
+ }
+
+ if (len != 0) {
+ ClearCells(xw, flags, len, row, col);
+ }
+
+ return rc;
+}
+
+int
+ClearInLine(XtermWidget xw, int row, int col, unsigned len)
+{
+ TScreen *screen = TScreenOf(xw);
+ int flags = 0;
+
+ /*
+ * 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;
+ }
+ return ClearInLine2(xw, flags, row, col, len);
+}
+
+/*
+ * Clear the next n characters on the cursor's line, including the cursor's
+ * position.
+ */
+void
+ClearRight(XtermWidget xw, int n)
+{
+ TScreen *screen = TScreenOf(xw);
+ LineData *ld;
+ unsigned len = (unsigned) (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 = (unsigned) n;
+
+ ld = getLineData(screen, screen->cur_row);
+ if (AddToVisible(xw)) {
+ if_OPT_WIDE_CHARS(screen, {
+ int col = screen->cur_col;
+ int row = screen->cur_row;
+ int kl;
+ int kr;
+ int xx;
+ if (DamagedCurCells(screen, len, &kl, &kr) && kr >= kl) {
+ xx = col;
+ if (kl < xx) {
+ ClearInLine2(xw, 0, row, kl, (unsigned) (xx - kl));
+ }
+ xx = col + (int) len - 1;
+ if (kr > xx) {
+ ClearInLine2(xw, 0, row, xx + 1, (unsigned) (kr - xx));
+ }
+ }
+ });
+ (void) ClearInLine(xw, screen->cur_row, screen->cur_col, len);
+ } else {
+ ScrnClearCells(xw, screen->cur_row, screen->cur_col, len);
+ }
+
+ /* with the right part cleared, we can't be wrapping */
+ LineClrWrapped(ld);
+ if (screen->show_wrap_marks) {
+ ShowWrapMarks(xw, screen->cur_row, ld);
+ }
+ ResetWrap(screen);
+}
+
+/*
+ * Clear first part of cursor's line, inclusive.
+ */
+static void
+ClearLeft(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+ unsigned len = (unsigned) screen->cur_col + 1;
+
+ assert(screen->cur_col >= 0);
+ if (AddToVisible(xw)) {
+ if_OPT_WIDE_CHARS(screen, {
+ int row = screen->cur_row;
+ int kl;
+ int kr;
+ if (DamagedCurCells(screen, 1, &kl, &kr) && kr >= kl) {
+ ClearInLine2(xw, 0, row, kl, (unsigned) (kr - kl + 1));
+ }
+ });
+ (void) ClearInLine(xw, screen->cur_row, 0, len);
+ } else {
+ ScrnClearCells(xw, screen->cur_row, 0, len);
+ }
+}
+
+/*
+ * Erase the cursor's line.
+ */
+static void
+ClearLine(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+ unsigned len = (unsigned) MaxCols(screen);
+
+ assert(screen->max_col >= 0);
+ (void) ClearInLine(xw, screen->cur_row, 0, len);
+}
+
+void
+ClearScreen(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+ int top;
+
+ if (screen->cursor_state)
+ HideCursor();
+
+ ScrnDisownSelection(xw);
+ ResetWrap(screen);
+ if ((top = INX2ROW(screen, 0)) <= screen->max_row) {
+ if (screen->scroll_amt)
+ FlushScroll(xw);
+ ClearCurBackground(xw,
+ top,
+ 0,
+ (unsigned) (screen->max_row - top + 1),
+ (unsigned) MaxCols(screen),
+ (unsigned) FontWidth(screen));
+ }
+ ClearBufRows(xw, 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(XtermWidget xw, int param, int mode)
+{
+ TScreen *screen = TScreenOf(xw);
+ 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(xw, -1);
+ break;
+ case 1:
+ ClearLeft(xw);
+ break;
+ case 2:
+ ClearLine(xw);
+ 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(XtermWidget xw, int param, int mode)
+{
+ TScreen *screen = TScreenOf(xw);
+ 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(xw, 2, mode);
+ saved_mode = screen->protected_mode;
+ } else
+ ClearBelow(xw);
+ break;
+
+ case 1:
+ if (screen->cur_row == screen->max_row
+ && screen->cur_col == screen->max_col) {
+ screen->protected_mode = saved_mode;
+ do_erase_display(xw, 2, mode);
+ saved_mode = screen->protected_mode;
+ } else
+ ClearAbove(xw);
+ 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 = (unsigned) MaxCols(screen);
+
+ assert(screen->max_col >= 0);
+ for (row = 0; row <= screen->max_row; row++)
+ rc &= ClearInLine(xw, row, 0, len);
+ if (rc != 0)
+ saved_mode = OFF_PROTECT;
+ } else {
+ ClearScreen(xw);
+ }
+ break;
+
+ case 3:
+ /* xterm addition - erase saved lines. */
+ screen->savedlines = 0;
+ ScrollBarDrawThumb(screen->scrollWidget);
+ break;
+ }
+ screen->protected_mode = saved_mode;
+}
+
+static void
+CopyWait(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+ XEvent reply;
+ XEvent *rep = &reply;
+
+ for (;;) {
+ XWindowEvent(screen->display, VWindow(screen),
+ ExposureMask, &reply);
+ switch (reply.type) {
+ case Expose:
+ HandleExposure(xw, &reply);
+ break;
+ case NoExpose:
+ case GraphicsExpose:
+ if (screen->incopy <= 0) {
+ screen->incopy = 1;
+ if (screen->scrolls > 0)
+ screen->scrolls--;
+ }
+ if (reply.type == GraphicsExpose)
+ HandleExposure(xw, &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(XtermWidget xw,
+ int src_x,
+ int src_y,
+ unsigned width,
+ unsigned height,
+ int dest_x,
+ int dest_y)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ if (width != 0 && height != 0) {
+ /* wait for previous CopyArea to complete unless
+ multiscroll is enabled and active */
+ if (screen->incopy && screen->scrolls == 0)
+ CopyWait(xw);
+ 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(xw, 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(XtermWidget xw,
+ int firstchar, /* char pos on screen to start copying at */
+ int nchars,
+ int amount) /* number of characters to move right */
+{
+ TScreen *screen = TScreenOf(xw);
+ LineData *ld;
+
+ if ((ld = getLineData(screen, screen->cur_row)) != 0) {
+ int src_x = LineCursorX(screen, ld, firstchar);
+ int src_y = CursorY(screen, screen->cur_row);
+
+ copy_area(xw, src_x, src_y,
+ (unsigned) (nchars * LineFontWidth(screen, ld)),
+ (unsigned) FontHeight(screen),
+ src_x + amount * LineFontWidth(screen, ld), src_y);
+ }
+}
+
+/*
+ * use when inserting or deleting lines from the screen
+ */
+static void
+vertical_copy_area(XtermWidget xw,
+ int firstline, /* line on screen to start copying at */
+ int nlines,
+ int amount, /* number of lines to move up (neg=down) */
+ int left,
+ int right)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ if (nlines > 0) {
+ int src_x = CursorX(screen, left);
+ int src_y = firstline * FontHeight(screen) + screen->border;
+
+ copy_area(xw, src_x, src_y,
+ (unsigned) ((right + 1 - left) * FontWidth(screen)),
+ (unsigned) (nlines * FontHeight(screen)),
+ src_x, src_y - amount * FontHeight(screen));
+
+ if (screen->show_wrap_marks) {
+ LineData *ld;
+ int row;
+ for (row = firstline; row < firstline + nlines; ++row) {
+ if ((ld = getLineData(screen, row)) != 0) {
+ ShowWrapMarks(xw, row, ld);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * use when scrolling the entire screen
+ */
+void
+scrolling_copy_area(XtermWidget xw,
+ 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(xw, firstline, nlines, amount, 0, TScreenOf(xw)->max_col);
+ }
+}
+
+/*
+ * Handler for Expose events on the VT widget.
+ * Returns 1 iff the area where the cursor was got refreshed.
+ */
+int
+HandleExposure(XtermWidget xw, XEvent * event)
+{
+ TScreen *screen = TScreenOf(xw);
+ 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(xw, 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 + (int) screen->copy_width,
+ (reply->x + (int) reply->width));
+ int both_y2 = Min(screen->copy_src_y + (int) screen->copy_height,
+ (reply->y + (int) 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
+ (xw, 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(xw, reply->x, reply->y,
+ reply->width, reply->height);
+
+ return value;
+ }
+}
+
+static void
+set_background(XtermWidget xw, int color GCC_UNUSED)
+{
+ TScreen *screen = TScreenOf(xw);
+ Pixel c = getXtermBackground(xw, xw->flags, color);
+
+ TRACE(("set_background(%d) %#lx\n", color, c));
+ XSetWindowBackground(screen->display, VShellWindow(xw), c);
+ XSetWindowBackground(screen->display, VWindow(screen), c);
+}
+
+/*
+ * 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(XtermWidget xw,
+ int rect_x,
+ int rect_y,
+ int rect_width,
+ int rect_height)
+{
+ TScreen *screen = TScreenOf(xw);
+ int toprow, leftcol, nrows, ncols;
+ int x0, x1;
+ int y0, y1;
+ int result = 0;
+
+ 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);
+
+ if ((x0 < 0 ||
+ y0 < 0 ||
+ x1 > Width(screen) ||
+ y1 > Height(screen))) {
+ set_background(xw, -1);
+ XClearArea(screen->display, VWindow(screen),
+ rect_x,
+ rect_y,
+ (unsigned) rect_width,
+ (unsigned) rect_height, False);
+ }
+ toprow = y0 / FontHeight(screen);
+ if (toprow < 0)
+ toprow = 0;
+
+ leftcol = x0 / FontWidth(screen);
+ 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(xw, toprow, leftcol, nrows, ncols, True);
+ first_map_occurred();
+ if (screen->cur_row >= toprow &&
+ screen->cur_row < toprow + nrows &&
+ screen->cur_col >= leftcol &&
+ screen->cur_col < leftcol + ncols) {
+ result = 1;
+ }
+
+ }
+ TRACE(("...handle_translated_exposure %d\n", result));
+ return (result);
+}
+
+/***====================================================================***/
+
+void
+GetColors(XtermWidget xw, ScrnColors * pColors)
+{
+ TScreen *screen = TScreenOf(xw);
+ int n;
+
+ pColors->which = 0;
+ for (n = 0; n < NCOLORS; ++n) {
+ SET_COLOR_VALUE(pColors, n, T_COLOR(screen, n));
+ }
+}
+
+void
+ChangeColors(XtermWidget xw, ScrnColors * pNew)
+{
+ Bool repaint = False;
+ TScreen *screen = TScreenOf(xw);
+ VTwin *win = WhichVWin(screen);
+
+ 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)));
+ /* no repaint needed */
+ } else if ((T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) &&
+ (COLOR_DEFINED(pNew, TEXT_FG))) {
+ if (T_COLOR(screen, TEXT_CURSOR) != COLOR_VALUE(pNew, TEXT_FG)) {
+ T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_FG);
+ TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR)));
+ if (screen->Vshow)
+ repaint = True;
+ }
+ }
+
+ 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)));
+ if (screen->Vshow) {
+ setCgsFore(xw, win, gcNorm, fg);
+ setCgsBack(xw, win, gcNormReverse, fg);
+ setCgsFore(xw, win, gcBold, fg);
+ setCgsBack(xw, win, gcBoldReverse, fg);
+ repaint = True;
+ }
+ }
+
+ 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)));
+ if (screen->Vshow) {
+ setCgsBack(xw, win, gcNorm, bg);
+ setCgsFore(xw, win, gcNormReverse, bg);
+ setCgsBack(xw, win, gcBold, bg);
+ setCgsFore(xw, win, gcBoldReverse, bg);
+ set_background(xw, -1);
+ repaint = True;
+ }
+ }
+#if OPT_HIGHLIGHT_COLOR
+ if (COLOR_DEFINED(pNew, HIGHLIGHT_BG)) {
+ if (T_COLOR(screen, HIGHLIGHT_BG) != COLOR_VALUE(pNew, HIGHLIGHT_BG)) {
+ T_COLOR(screen, HIGHLIGHT_BG) = COLOR_VALUE(pNew, HIGHLIGHT_BG);
+ TRACE(("... HIGHLIGHT_BG: %#lx\n", T_COLOR(screen, HIGHLIGHT_BG)));
+ if (screen->Vshow)
+ repaint = True;
+ }
+ }
+ if (COLOR_DEFINED(pNew, HIGHLIGHT_FG)) {
+ if (T_COLOR(screen, HIGHLIGHT_FG) != COLOR_VALUE(pNew, HIGHLIGHT_FG)) {
+ T_COLOR(screen, HIGHLIGHT_FG) = COLOR_VALUE(pNew, HIGHLIGHT_FG);
+ TRACE(("... HIGHLIGHT_FG: %#lx\n", T_COLOR(screen, HIGHLIGHT_FG)));
+ if (screen->Vshow)
+ repaint = True;
+ }
+ }
+#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)));
+ }
+
+ if (screen->Vshow) {
+ recolor_cursor(screen,
+ screen->pointer_cursor,
+ T_COLOR(screen, MOUSE_FG),
+ T_COLOR(screen, MOUSE_BG));
+ XDefineCursor(screen->display, VWindow(screen),
+ screen->pointer_cursor);
+ }
+#if OPT_TEK4014
+ if (TEK4014_SHOWN(xw)) {
+ TekScreen *tekscr = TekScreenOf(tekWidget);
+ Window tekwin = TWindow(tekscr);
+ if (tekwin) {
+ recolor_cursor(screen,
+ tekscr->arrow,
+ T_COLOR(screen, MOUSE_FG),
+ T_COLOR(screen, MOUSE_BG));
+ XDefineCursor(screen->display, tekwin, tekscr->arrow);
+ }
+ }
+#endif
+ /* no repaint needed */
+ }
+
+ if (COLOR_DEFINED(pNew, TEXT_FG) ||
+ COLOR_DEFINED(pNew, TEXT_BG) ||
+ COLOR_DEFINED(pNew, TEXT_CURSOR)) {
+ if (set_cursor_gcs(xw) && screen->Vshow) {
+ repaint = True;
+ }
+ }
+#if OPT_TEK4014
+ if (COLOR_DEFINED(pNew, TEK_FG) ||
+ COLOR_DEFINED(pNew, TEK_BG)) {
+ ChangeTekColors(tekWidget, screen, pNew);
+ if (TEK4014_SHOWN(xw)) {
+ TekRepaint(tekWidget);
+ }
+ } else if (COLOR_DEFINED(pNew, TEK_CURSOR)) {
+ ChangeTekColors(tekWidget, screen, pNew);
+ }
+#endif
+ if (repaint)
+ xtermRepaint(xw);
+}
+
+void
+xtermClear(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ TRACE(("xtermClear\n"));
+ XClearWindow(screen->display, VWindow(screen));
+}
+
+void
+xtermRepaint(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ TRACE(("xtermRepaint\n"));
+ xtermClear(xw);
+ ScrnRefresh(xw, 0, 0, MaxRows(screen), MaxCols(screen), True);
+}
+
+/***====================================================================***/
+
+Boolean
+isDefaultForeground(const char *name)
+{
+ return (Boolean) ! x_strcasecmp(name, XtDefaultForeground);
+}
+
+Boolean
+isDefaultBackground(const char *name)
+{
+ return (Boolean) ! x_strcasecmp(name, XtDefaultBackground);
+}
+
+#if OPT_WIDE_CHARS
+/*
+ * Check for Unicode BIDI control characters, which may be miscategorized via
+ * wcwidth() and iswprint() as zero-width printable characters.
+ */
+Boolean
+isWideControl(unsigned ch)
+{
+ Boolean result;
+
+ switch (ch) {
+ case 0x200E:
+ case 0x200F:
+ case 0x202A:
+ case 0x202B:
+ case 0x202C:
+ case 0x202D:
+ case 0x202E:
+ result = True;
+ break;
+ default:
+ result = False;
+ break;
+ }
+ return result;
+}
+#endif
+
+/***====================================================================***/
+
+typedef struct {
+ Pixel fg;
+ Pixel bg;
+} ToSwap;
+
+#if OPT_HIGHLIGHT_COLOR
+#define hc_param ,Bool hilite_color
+#define hc_value ,screen->hilite_color
+#else
+#define hc_param /* nothing */
+#define hc_value /* nothing */
+#endif
+
+/*
+ * Use this to swap the foreground/background color values in the resource
+ * data, and to build up a list of the pairs which must be swapped in the
+ * GC cache.
+ */
+static void
+swapLocally(ToSwap * list, int *count, ColorRes * fg, ColorRes * bg hc_param)
+{
+ ColorRes tmp;
+ int n;
+ Boolean found = False;
+
+#if OPT_COLOR_RES
+ Pixel fg_color = fg->value;
+ Pixel bg_color = bg->value;
+#else
+ Pixel fg_color = *fg;
+ Pixel bg_color = *bg;
+#endif
+
+#if OPT_HIGHLIGHT_COLOR
+ if ((fg_color != bg_color) || !hilite_color)
+#endif
+ {
+ EXCHANGE(*fg, *bg, tmp);
+ for (n = 0; n < *count; ++n) {
+ if ((list[n].fg == fg_color && list[n].bg == bg_color)
+ || (list[n].fg == bg_color && list[n].bg == fg_color)) {
+ found = True;
+ break;
+ }
+ }
+ if (!found) {
+ list[*count].fg = fg_color;
+ list[*count].bg = bg_color;
+ *count = *count + 1;
+ TRACE(("swapLocally fg %#lx, bg %#lx ->%d\n",
+ fg_color, bg_color, *count));
+ }
+ }
+}
+
+static void
+reallySwapColors(XtermWidget xw, ToSwap * list, int count)
+{
+ int j, k;
+
+ TRACE(("reallySwapColors\n"));
+ for (j = 0; j < count; ++j) {
+ for_each_text_gc(k) {
+ redoCgs(xw, list[j].fg, list[j].bg, (CgsEnum) k);
+ }
+ }
+}
+
+static void
+swapVTwinGCs(XtermWidget xw, VTwin * win)
+{
+ swapCgs(xw, win, gcNorm, gcNormReverse);
+ swapCgs(xw, win, gcBold, gcBoldReverse);
+}
+
+void
+ReverseVideo(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+ ToSwap listToSwap[5];
+ int numToSwap = 0;
+
+ TRACE(("ReverseVideo\n"));
+
+ /*
+ * 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.
+ */
+#define swapAnyColor(name,a,b) swapLocally(listToSwap, &numToSwap, &(screen->name[a]), &(screen->name[b]) hc_value)
+#define swapAColor(a,b) swapAnyColor(Acolors, a, b)
+ if_OPT_ISO_COLORS(screen, {
+ swapAColor(0, 7);
+ swapAColor(8, 15);
+ });
+
+ if (T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG))
+ T_COLOR(screen, TEXT_CURSOR) = T_COLOR(screen, TEXT_BG);
+
+#define swapTColor(a,b) swapAnyColor(Tcolors, a, b)
+ swapTColor(TEXT_FG, TEXT_BG);
+ swapTColor(MOUSE_FG, MOUSE_BG);
+
+ reallySwapColors(xw, listToSwap, numToSwap);
+
+ swapVTwinGCs(xw, &(screen->fullVwin));
+#ifndef NO_ACTIVE_ICON
+ swapVTwinGCs(xw, &(screen->iconVwin));
+#endif /* NO_ACTIVE_ICON */
+
+ xw->misc.re_verse = (Boolean) ! xw->misc.re_verse;
+
+ if (XtIsRealized((Widget) xw)) {
+ xtermDisplayCursor(xw);
+ }
+#if OPT_TEK4014
+ if (TEK4014_SHOWN(xw)) {
+ TekScreen *tekscr = TekScreenOf(tekWidget);
+ Window tekwin = TWindow(tekscr);
+ recolor_cursor(screen,
+ tekscr->arrow,
+ T_COLOR(screen, MOUSE_FG),
+ T_COLOR(screen, MOUSE_BG));
+ XDefineCursor(screen->display, tekwin, tekscr->arrow);
+ }
+#endif
+
+ if (screen->scrollWidget)
+ ScrollBarReverseVideo(screen->scrollWidget);
+
+ if (XtIsRealized((Widget) xw)) {
+ set_background(xw, -1);
+ }
+#if OPT_TEK4014
+ TekReverseVideo(tekWidget);
+#endif
+ if (XtIsRealized((Widget) xw)) {
+ xtermRepaint(xw);
+ }
+#if OPT_TEK4014
+ if (TEK4014_SHOWN(xw)) {
+ TekRepaint(tekWidget);
+ }
+#endif
+ ReverseOldColors();
+ set_cursor_gcs(xw);
+ update_reversevideo();
+ TRACE(("...ReverseVideo\n"));
+}
+
+void
+recolor_cursor(TScreen * screen,
+ Cursor cursor, /* X cursor ID to set */
+ unsigned long fg, /* pixel indexes to look up */
+ unsigned long bg) /* pixel indexes to look up */
+{
+ 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 *
+getXftColor(XtermWidget xw, 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(TScreenOf(xw)->display, xw->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;
+}
+
+/*
+ * The cell-width is related to, but not the same as the wide-character width.
+ * We will only get useful values from wcwidth() for codes above 255.
+ * Otherwise, interpret according to internal data.
+ */
+#if OPT_RENDERWIDE
+
+#if OPT_C1_PRINT
+#define XtermCellWidth(xw, ch) \
+ (((ch) == 0 || (ch) == 127) \
+ ? 0 \
+ : (((ch) < 256) \
+ ? (((ch) >= 128 && (ch) < 160) \
+ ? (TScreenOf(xw)->c1_printable ? 1 : 0) \
+ : 1) \
+ : my_wcwidth(ch)))
+#else
+#define XtermCellWidth(xw, ch) \
+ (((ch) == 0 || (ch) == 127) \
+ ? 0 \
+ : (((ch) < 256) \
+ ? 1 \
+ : my_wcwidth(ch)))
+#endif
+
+#endif /* OPT_RENDERWIDE */
+
+#define XFT_FONT(name) screen->name.font
+
+#if OPT_ISO_COLORS
+#define UseBoldFont(screen) (!(screen)->colorBDMode || ((screen)->veryBoldColors & BOLD))
+#else
+#define UseBoldFont(screen) 1
+#endif
+/*
+ * 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 int
+xtermXftDrawString(XtermWidget xw,
+ unsigned flags GCC_UNUSED,
+ XftColor * color,
+ XftFont * font,
+ int x,
+ int y,
+ IChar * text,
+ Cardinal len,
+ Bool really)
+{
+ TScreen *screen = TScreenOf(xw);
+ int ncells = 0;
+
+ if (len != 0) {
+#if OPT_RENDERWIDE
+ XftCharSpec *sbuf;
+ XftFont *wfont;
+ Cardinal src, dst;
+ XftFont *lastFont = 0;
+ XftFont *currFont = 0;
+ Cardinal start = 0;
+ int charWidth;
+ int fontnum = screen->menu_font_number;
+ int fwidth = FontWidth(screen);
+
+#if OPT_ISO_COLORS
+ if ((flags & UNDERLINE)
+ && !screen->colorULMode
+ && screen->italicULMode
+ && XFT_FONT(renderWideItal[fontnum])) {
+ wfont = XFT_FONT(renderWideItal[fontnum]);
+ } else
+#endif
+ if ((flags & BOLDATTR(screen))
+ && UseBoldFont(screen)
+ && XFT_FONT(renderWideBold[fontnum])) {
+ wfont = XFT_FONT(renderWideBold[fontnum]);
+ } else {
+ wfont = XFT_FONT(renderWideNorm[fontnum]);
+ }
+
+ BumpTypedBuffer(XftCharSpec, len);
+ sbuf = BfBuf(XftCharSpec);
+
+ for (src = dst = 0; src < len; src++) {
+ FcChar32 wc = *text++;
+
+ charWidth = XtermCellWidth(xw, (wchar_t) wc);
+ if (charWidth < 0)
+ continue;
+
+ sbuf[dst].ucs4 = wc;
+ sbuf[dst].x = (short) (x + fwidth * ncells);
+ sbuf[dst].y = (short) (y);
+
+ currFont = (charWidth == 2 && wfont != 0) ? wfont : font;
+ ncells += charWidth;
+
+ if (lastFont != currFont) {
+ if ((lastFont != 0) && really) {
+ XftDrawCharSpec(screen->renderDraw,
+ color,
+ lastFont,
+ sbuf + start,
+ (int) (dst - start));
+ }
+ start = dst;
+ lastFont = currFont;
+ }
+ ++dst;
+ }
+ if ((dst != start) && really) {
+ XftDrawCharSpec(screen->renderDraw,
+ color,
+ lastFont,
+ sbuf + start,
+ (int) (dst - start));
+ }
+#else /* !OPT_RENDERWIDE */
+ if (really) {
+ XftChar8 *buffer;
+ int dst;
+
+ BumpTypedBuffer(XftChar8, len);
+ buffer = BfBuf(XftChar8);
+
+ for (dst = 0; dst < (int) len; ++dst)
+ buffer[dst] = CharOf(text[dst]);
+
+ XftDrawString8(screen->renderDraw,
+ color,
+ font,
+ x, y, buffer, (int) len);
+ }
+ ncells = (int) len;
+#endif
+ }
+ return ncells;
+}
+#define xtermXftWidth(xw, flags, color, font, x, y, chars, len) \
+ xtermXftDrawString(xw, flags, color, font, x, y, chars, len, False)
+#endif /* OPT_RENDERFONT */
+
+#if OPT_WIDE_CHARS
+/*
+ * Map characters commonly "fixed" by groff back to their ASCII equivalents.
+ * Also map other useful equivalents.
+ */
+unsigned
+AsciiEquivs(unsigned ch)
+{
+ switch (ch) {
+ case 0x2010: /* groff "-" */
+ case 0x2011:
+ case 0x2012:
+ case 0x2013:
+ case 0x2014:
+ case 0x2015:
+ case 0x2212: /* groff "\-" */
+ ch = '-';
+ break;
+ case 0x2018: /* groff "`" */
+ ch = '`';
+ break;
+ case 0x2019: /* groff ' */
+ ch = '\'';
+ break;
+ case 0x201C: /* groff lq */
+ case 0x201D: /* groff rq */
+ ch = '"';
+ break;
+ case 0x2329: /* groff ".URL" */
+ ch = '<';
+ break;
+ case 0x232a: /* groff ".URL" */
+ ch = '>';
+ break;
+ default:
+ if (ch >= 0xff01 && ch <= 0xff5e) {
+ /* "Fullwidth" codes (actually double-width) */
+ ch -= 0xff00;
+ ch += ANSI_SPA;
+ break;
+ }
+ }
+ return ch;
+}
+
+/*
+ * 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(XtermWidget xw,
+ unsigned ch,
+ unsigned flags,
+ GC gc,
+ int x,
+ int y,
+ int chrset,
+ int on_wide)
+{
+ TScreen *screen = TScreenOf(xw);
+ int fixed = False;
+
+ if (screen->wide_chars && screen->utf8_mode && ch > 256) {
+ IChar eqv = (IChar) AsciiEquivs(ch);
+
+ if (eqv != (IChar) ch) {
+ int width = my_wcwidth((int) ch);
+
+ do {
+ drawXtermText(xw,
+ flags,
+ gc,
+ x,
+ y,
+ chrset,
+ &eqv,
+ 1,
+ on_wide);
+ x += FontWidth(screen);
+ eqv = '?';
+ } while (width-- > 1);
+
+ fixed = True;
+ } else if (ch == HIDDEN_CHAR) {
+ fixed = True;
+ }
+ }
+ return fixed;
+}
+#endif
+
+/*
+ * Use this when the characters will not fill the cell area properly. Fill the
+ * area where we'll write the characters, otherwise we'll get gaps between
+ * them, e.g., in the original background color.
+ *
+ * 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.
+ */
+static void
+xtermFillCells(XtermWidget xw,
+ unsigned flags,
+ GC gc,
+ int x,
+ int y,
+ Cardinal len)
+{
+ TScreen *screen = TScreenOf(xw);
+ VTwin *currentWin = WhichVWin(screen);
+
+ if (!(flags & NOBACKGROUND)) {
+ CgsEnum srcId = getCgsId(xw, currentWin, gc);
+ CgsEnum dstId = gcMAX;
+ Pixel fg = getCgsFore(xw, currentWin, gc);
+ Pixel bg = getCgsBack(xw, currentWin, gc);
+
+ switch (srcId) {
+ case gcVTcursNormal:
+ case gcVTcursReverse:
+ dstId = gcVTcursOutline;
+ break;
+ case gcVTcursFilled:
+ case gcVTcursOutline:
+ /* FIXME */
+ break;
+ case gcNorm:
+ dstId = gcNormReverse;
+ break;
+ case gcNormReverse:
+ dstId = gcNorm;
+ break;
+ case gcBold:
+ dstId = gcBoldReverse;
+ break;
+ case gcBoldReverse:
+ dstId = gcBold;
+ break;
+#if OPT_BOX_CHARS
+ case gcLine:
+ case gcDots:
+ /* FIXME */
+ break;
+#endif
+#if OPT_DEC_CHRSET
+ case gcCNorm:
+ case gcCBold:
+ /* FIXME */
+ break;
+#endif
+#if OPT_WIDE_CHARS
+ case gcWide:
+ dstId = gcWideReverse;
+ break;
+ case gcWBold:
+ dstId = gcBoldReverse;
+ break;
+ case gcWideReverse:
+ case gcWBoldReverse:
+ /* FIXME */
+ break;
+#endif
+#if OPT_TEK4014
+ case gcTKcurs:
+ /* FIXME */
+ break;
+#endif
+ case gcMAX:
+ break;
+ }
+
+ if (dstId != gcMAX) {
+ setCgsFore(xw, currentWin, dstId, bg);
+ setCgsBack(xw, currentWin, dstId, fg);
+
+ XFillRectangle(screen->display, VWindow(screen),
+ getCgsGC(xw, currentWin, dstId),
+ x, y,
+ len * (Cardinal) FontWidth(screen),
+ (unsigned) FontHeight(screen));
+ }
+ }
+}
+
+#if OPT_TRACE
+static void
+xtermSetClipRectangles(Display * dpy,
+ GC gc,
+ int x,
+ int y,
+ XRectangle * rp,
+ Cardinal nr,
+ int order)
+{
+#if 0
+ TScreen *screen = TScreenOf(term);
+ Drawable draw = VWindow(screen);
+
+ XSetClipMask(dpy, gc, None);
+ XDrawRectangle(screen->display, draw, gc,
+ x + rp->x - 1,
+ y + rp->y - 1,
+ rp->width,
+ rp->height);
+#endif
+
+ XSetClipRectangles(dpy, gc,
+ x, y, rp, (int) nr, order);
+ TRACE(("clipping @(%3d,%3d) (%3d,%3d)..(%3d,%3d)\n",
+ y, x,
+ rp->y, rp->x, rp->height, rp->width));
+}
+
+#else
+#define xtermSetClipRectangles(dpy, gc, x, y, rp, nr, order) \
+ XSetClipRectangles(dpy, gc, x, y, rp, (int) nr, order)
+#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 (screen->use_clipping && (pwidth > 2)) { \
+ XRectangle clip; \
+ int clip_x = x; \
+ int clip_y = y - FontHeight(screen) + FontDescent(screen); \
+ clip.x = 0; \
+ clip.y = 0; \
+ clip.height = (unsigned short) FontHeight(screen); \
+ clip.width = (unsigned short) (pwidth * plength); \
+ xtermSetClipRectangles(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 */
+
+#if OPT_CLIP_BOLD && OPT_RENDERFONT && defined(HAVE_XFTDRAWSETCLIP) && defined(HAVE_XFTDRAWSETCLIPRECTANGLES)
+#define beginXftClipping(screen,px,py,plength) \
+ if (screen->use_clipping && (FontWidth(screen) > 2)) { \
+ XRectangle clip; \
+ double adds = (screen->scale_height - 1.0) * FontHeight(screen); \
+ int height = dimRound(adds + FontHeight(screen)); \
+ int descnt = dimRound(adds / 2.0) + FontDescent(screen); \
+ int clip_x = px; \
+ int clip_y = py - height + descnt; \
+ clip.x = 0; \
+ clip.y = 0; \
+ clip.height = (unsigned short) height; \
+ clip.width = (unsigned short) (FontWidth(screen) * plength); \
+ XftDrawSetClipRectangles (screen->renderDraw, \
+ clip_x, clip_y, \
+ &clip, 1); \
+ }
+#define endXftClipping(screen) \
+ XftDrawSetClip (screen->renderDraw, 0)
+#else
+#define beginXftClipping(screen,px,py,plength) /* nothing */
+#define endXftClipping(screen) /* nothing */
+#endif /* OPT_CLIP_BOLD */
+
+#if OPT_RENDERFONT
+static int
+drawClippedXftString(XtermWidget xw,
+ unsigned flags,
+ XftFont * font,
+ XftColor * fg_color,
+ int x,
+ int y,
+ IChar * text,
+ Cardinal len)
+{
+ int ncells = xtermXftWidth(xw, flags,
+ fg_color,
+ font, x, y,
+ text,
+ len);
+ TScreen *screen = TScreenOf(xw);
+
+ beginXftClipping(screen, x, y, ncells);
+ xtermXftDrawString(xw, flags,
+ fg_color,
+ font, x, y,
+ text,
+ len,
+ True);
+ endXftClipping(screen);
+ return ncells;
+}
+#endif
+
+#ifndef NO_ACTIVE_ICON
+#define WhichVFontData(screen,name) \
+ (IsIcon(screen) ? &((screen)->fnt_icon) \
+ : &((screen)->name))
+#else
+#define WhichVFontData(screen,name) \
+ (&((screen)->name))
+#endif
+
+/*
+ * Draws text with the specified combination of bold/underline. The return
+ * value is the updated x position.
+ */
+int
+drawXtermText(XtermWidget xw,
+ unsigned flags,
+ GC gc,
+ int x,
+ int y,
+ int chrset,
+ IChar * text,
+ Cardinal len,
+ int on_wide)
+{
+ TScreen *screen = TScreenOf(xw);
+ Cardinal real_length = len;
+ Cardinal underline_len = 0;
+ /* 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
+ if (text == 0)
+ return 0;
+#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.
+ */
+ int inx = 0;
+ GC gc2 = ((!IsIcon(screen) && screen->font_doublesize)
+ ? xterm_DoubleGC(xw, (unsigned) chrset, flags, gc, &inx)
+ : 0);
+
+ TRACE(("DRAWTEXT%c[%4d,%4d] (%d)%3d:%s\n",
+ screen->cursor_state == OFF ? ' ' : '*',
+ y, x, chrset, len,
+ visibleIChars(text, len)));
+
+ if (gc2 != 0) { /* draw actual double-sized characters */
+ XFontStruct *fs = screen->double_fonts[inx].fs;
+
+#if OPT_RENDERFONT
+ if (!UsingRenderFont(xw))
+#endif
+ {
+ XRectangle rect, *rp = &rect;
+ Cardinal nr = 1;
+
+ font_width *= 2;
+ flags |= DOUBLEWFONT;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = (unsigned short) ((int) len * font_width);
+ rect.height = (unsigned short) (FontHeight(screen));
+
+ TRACE(("drawing %s\n", visibleChrsetName((unsigned) chrset)));
+ switch (chrset) {
+ case CSET_DHL_TOP:
+ rect.y = (short) -(fs->ascent / 2);
+ y -= rect.y;
+ flags |= DOUBLEHFONT;
+ break;
+ case CSET_DHL_BOT:
+ rect.y = (short) (rect.height - (fs->ascent / 2));
+ y -= rect.y;
+ flags |= DOUBLEHFONT;
+ break;
+ default:
+ nr = 0;
+ break;
+ }
+
+ if (nr) {
+ xtermSetClipRectangles(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(xw, flags, gc2,
+ x, y, 0,
+ text++,
+ 1, on_wide);
+ x += FontWidth(screen);
+ }
+ } else {
+ x = drawXtermText(xw, flags, gc2,
+ x, y, 0,
+ text,
+ len, on_wide);
+ x += (int) len *FontWidth(screen);
+ }
+
+ TRACE(("drawtext [%4d,%4d]\n", y, x));
+ } else { /* simulate double-sized characters */
+ unsigned need = 2 * len;
+ IChar *temp = TypeMallocN(IChar, need);
+ unsigned n = 0;
+
+ while (len--) {
+ temp[n++] = *text++;
+ temp[n++] = ' ';
+ }
+ x = drawXtermText(xw,
+ flags,
+ gc,
+ x, y,
+ 0,
+ temp,
+ n,
+ on_wide);
+ free(temp);
+ }
+ return x;
+ }
+#endif
+#if OPT_RENDERFONT
+ if (UsingRenderFont(xw)) {
+ VTwin *currentWin = WhichVWin(screen);
+ Display *dpy = screen->display;
+ XftFont *font;
+ XGCValues values;
+ int fontnum = screen->menu_font_number;
+ int ncells;
+
+ 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->colorULMode
+ && screen->italicULMode
+ && XFT_FONT(renderFontItal[fontnum])) {
+ font = XFT_FONT(renderFontItal[fontnum]);
+ did_ul = True;
+ } else
+#endif
+ if ((flags & BOLDATTR(screen))
+ && UseBoldFont(screen)
+ && XFT_FONT(renderFontBold[fontnum])) {
+ font = XFT_FONT(renderFontBold[fontnum]);
+ } else {
+ font = XFT_FONT(renderFontNorm[fontnum]);
+ }
+ values.foreground = getCgsFore(xw, currentWin, gc);
+ values.background = getCgsBack(xw, currentWin, gc);
+
+ if (!(flags & NOBACKGROUND)) {
+ XftColor *bg_color = getXftColor(xw, values.background);
+ ncells = xtermXftWidth(xw, flags,
+ bg_color,
+ font, x, y,
+ text,
+ len);
+ XftDrawRect(screen->renderDraw,
+ bg_color,
+ x, y,
+ (unsigned) (ncells * FontWidth(screen)),
+ (unsigned) FontHeight(screen));
+ }
+
+ y += font->ascent;
+#if OPT_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++) {
+ Boolean replace = False;
+ Boolean missing = False;
+ unsigned ch = (unsigned) text[last];
+ int nc;
+#if OPT_WIDE_CHARS
+
+ if (xtermIsDecGraphic(ch)) {
+ /*
+ * Xft generally does not have the line-drawing characters
+ * in cells 1-31. Assume this (we cannot inspect the
+ * picture easily...), and attempt to fill in from real
+ * line-drawing character in the font at the Unicode
+ * position. Failing that, use our own box-characters.
+ */
+ if (screen->force_box_chars
+ || xtermXftMissing(xw, font, dec2ucs(ch))) {
+ missing = 1;
+ } else {
+ ch = dec2ucs(ch);
+ replace = True;
+ }
+ } else if (ch >= 256) {
+ /*
+ * If we're reading UTF-8 from the client, we may have a
+ * line-drawing character. Translate it back to our
+ * box-code if Xft tells us that the glyph is missing.
+ */
+ if_OPT_WIDE_CHARS(screen, {
+ unsigned part = ucs2dec(ch);
+ if (xtermIsDecGraphic(part) &&
+ (screen->force_box_chars
+ || xtermXftMissing(xw, font, ch))) {
+ ch = part;
+ missing = True;
+ }
+ });
+ }
+#else
+ if (xtermIsDecGraphic(ch)) {
+ /*
+ * Xft generally does not have the line-drawing characters
+ * in cells 1-31. Check for this, and attempt to fill in
+ * from real line-drawing character in the font at the
+ * Unicode position. Failing that, use our own
+ * box-characters.
+ */
+ if (xtermXftMissing(xw, font, ch)) {
+ missing = 1;
+ }
+ }
+#endif
+
+ /*
+ * If we now have one of our box-codes, draw it directly.
+ */
+ if (missing || replace) {
+ /* line drawing character time */
+ if (last > first) {
+ nc = drawClippedXftString(xw,
+ flags,
+ font,
+ getXftColor(xw, values.foreground),
+ curX,
+ y,
+ text + first,
+ (Cardinal) (last - first));
+ curX += nc * FontWidth(screen);
+ underline_len += (Cardinal) nc;
+ }
+ if (missing) {
+ old_wide = screen->fnt_wide;
+ old_high = screen->fnt_high;
+ screen->fnt_wide = (Dimension) FontWidth(screen);
+ screen->fnt_high = (Dimension) FontHeight(screen);
+ xtermDrawBoxChar(xw, ch, flags, gc,
+ curX, y - FontAscent(screen), 1);
+ curX += FontWidth(screen);
+ underline_len += 1;
+ screen->fnt_wide = old_wide;
+ screen->fnt_high = old_high;
+ } else {
+ IChar ch2 = (IChar) ch;
+ nc = drawClippedXftString(xw,
+ flags,
+ font,
+ getXftColor(xw, values.foreground),
+ curX,
+ y,
+ &ch2,
+ 1);
+ curX += nc * FontWidth(screen);
+ underline_len += (Cardinal) nc;
+ }
+ first = last + 1;
+ }
+ }
+ if (last > first) {
+ underline_len += (Cardinal)
+ drawClippedXftString(xw,
+ flags,
+ font,
+ getXftColor(xw, values.foreground),
+ curX,
+ y,
+ text + first,
+ (Cardinal) (last - first));
+ }
+ }
+#else
+ {
+ underline_len += (Cardinal)
+ drawClippedXftString(xw,
+ flags,
+ font,
+ getXftColor(xw, values.foreground),
+ x,
+ y,
+ text,
+ len);
+ }
+#endif /* OPT_BOX_CHARS */
+
+ if ((flags & UNDERLINE) && screen->underline && !did_ul) {
+ if (FontDescent(screen) > 1)
+ y++;
+ XDrawLine(screen->display, VWindow(screen), gc,
+ x, y,
+ x + (int) underline_len * FontWidth(screen) - 1,
+ y);
+ }
+ return x + (int) 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;
+ XTermFonts *font = ((flags & BOLDATTR(screen))
+ ? WhichVFontData(screen, fnts[fBold])
+ : WhichVFontData(screen, fnts[fNorm]));
+
+ while (len--) {
+ int cells = WideCells(*text);
+#if OPT_BOX_CHARS
+#if OPT_WIDE_CHARS
+ if (*text == HIDDEN_CHAR) {
+ ++text;
+ continue;
+ } else
+#endif
+ if (IsXtermMissingChar(screen, *text, font)) {
+ adj = 0;
+ } else
+#endif
+ {
+ if_WIDE_OR_NARROW(screen, {
+ XChar2b temp[1];
+ temp[0].byte2 = LO_BYTE(*text);
+ temp[0].byte1 = HI_BYTE(*text);
+ width = XTextWidth16(font->fs, temp, 1);
+ }
+ , {
+ char temp[1];
+ temp[0] = (char) LO_BYTE(*text);
+ width = XTextWidth(font->fs, temp, 1);
+ });
+ adj = (FontWidth(screen) - width) / 2;
+ if (adj < 0)
+ adj = 0;
+ }
+ xtermFillCells(xw, flags, gc, x, y, (Cardinal) cells);
+ x = drawXtermText(xw,
+ flags | NOBACKGROUND | CHARBYCHAR,
+ gc, x + adj, y, chrset,
+ text++, 1, on_wide) - adj;
+ }
+ 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(). */
+ XTermFonts *font = ((flags & BOLDATTR(screen))
+ ? WhichVFontData(screen, fnts[fBold])
+ : WhichVFontData(screen, fnts[fNorm]));
+ int last, first = 0;
+ Bool drewBoxes = False;
+
+ for (last = 0; last < (int) len; last++) {
+ unsigned ch = (unsigned) text[last];
+ Bool isMissing;
+ int ch_width;
+#if OPT_WIDE_CHARS
+
+ if (ch == HIDDEN_CHAR) {
+ if (last > first) {
+ x = drawXtermText(xw, flags | NOTRANSLATION, gc,
+ x, y,
+ chrset, text + first,
+ (unsigned) (last - first), on_wide);
+ }
+ first = last + 1;
+ drewBoxes = True;
+ continue;
+ }
+ ch_width = my_wcwidth((int) ch);
+ isMissing =
+ IsXtermMissingChar(screen, ch,
+ ((on_wide || ch_width > 1)
+ && okFont(NormalWFont(screen)))
+ ? WhichVFontData(screen, fnts[fWide])
+ : font);
+#else
+ isMissing = IsXtermMissingChar(screen, ch, font);
+ ch_width = 1;
+#endif
+ /*
+ * If the character is not missing, but we're in wide-character
+ * mode and the character happens to be a wide-character that
+ * corresponds to the line-drawing set, allow the forceBoxChars
+ * resource (or menu entry) to force it to display using our
+ * tables.
+ */
+ if_OPT_WIDE_CHARS(screen, {
+ if (!isMissing
+ && ch > 255
+ && ucs2dec(ch) < 32
+ && TScreenOf(xw)->force_box_chars) {
+ ch = ucs2dec(ch);
+ isMissing = True;
+ }
+ });
+
+ if (isMissing) {
+ if (last > first) {
+ x = drawXtermText(xw, flags | NOTRANSLATION, gc,
+ x, y,
+ chrset, text + first,
+ (unsigned) (last - first), on_wide);
+ }
+#if OPT_WIDE_CHARS
+ if (ucs_workaround(xw, ch, flags, gc,
+ x, y,
+ chrset, on_wide)) {
+ /*
+ * if true, we drew at least one cell whether or not it is
+ * printable
+ */
+ if (ch_width <= 0)
+ ch_width = 1;
+ } else
+#endif
+ {
+ if (ch_width <= 0)
+ ch_width = 1;
+ xtermDrawBoxChar(xw, ch, flags, gc,
+ x, y,
+ ch_width);
+ }
+ x += (ch_width * FontWidth(screen));
+ first = last + 1;
+ drewBoxes = True;
+ }
+ }
+ if (last <= first) {
+ return x;
+ }
+ text += first;
+ len = (Cardinal) (last - first);
+ flags |= NOTRANSLATION;
+ if (drewBoxes) {
+ return drawXtermText(xw,
+ flags,
+ gc,
+ x,
+ y,
+ chrset,
+ text,
+ 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).
+ */
+ TRACE(("drawtext%c[%4d,%4d] (%d) %d:%s\n",
+ screen->cursor_state == OFF ? ' ' : '*',
+ y, x, chrset, len,
+ visibleIChars(text, len)));
+ if (screen->scale_height != 1.0) {
+ xtermFillCells(xw, flags, gc, x, y, (Cardinal) len);
+ }
+ y += FontAscent(screen);
+
+#if OPT_WIDE_CHARS
+
+ if (screen->wide_chars || screen->unicode_font) {
+ XChar2b *buffer;
+ Bool needWide = False;
+ int ascent_adjust = 0;
+ int src, dst;
+
+ BumpTypedBuffer(XChar2b, len);
+ buffer = BfBuf(XChar2b);
+
+ for (src = dst = 0; src < (int) len; src++) {
+ IChar ch = text[src];
+
+ if (ch == HIDDEN_CHAR)
+ continue;
+
+ if (!needWide
+ && !IsIcon(screen)
+ && ((on_wide || my_wcwidth((int) ch) > 1)
+ && okFont(NormalWFont(screen)))) {
+ needWide = True;
+ }
+
+ /*
+ * bitmap-fonts are limited to 16-bits.
+ */
+#if OPT_WIDER_ICHAR
+ if (ch > 0xffff) {
+ ch = UCS_REPL;
+ }
+#endif
+ buffer[dst].byte2 = LO_BYTE(ch);
+ buffer[dst].byte1 = HI_BYTE(ch);
+#if OPT_MINI_LUIT
+#define UCS2SBUF(value) buffer[dst].byte2 = LO_BYTE(value);\
+ buffer[dst].byte1 = HI_BYTE(value)
+
+#define Map2Sbuf(from,to) (text[src] == from) { UCS2SBUF(to); }
+
+ if (screen->latin9_mode && !screen->utf8_mode && text[src] < 256) {
+
+ /* see http://www.cs.tut.fi/~jkorpela/latin9.html */
+ /* *INDENT-OFF* */
+ if Map2Sbuf(0xa4, 0x20ac)
+ else if Map2Sbuf(0xa6, 0x0160)
+ else if Map2Sbuf(0xa8, 0x0161)
+ else if Map2Sbuf(0xb4, 0x017d)
+ else if Map2Sbuf(0xb8, 0x017e)
+ else if Map2Sbuf(0xbc, 0x0152)
+ else if Map2Sbuf(0xbd, 0x0153)
+ else if Map2Sbuf(0xbe, 0x0178)
+ /* *INDENT-ON* */
+
+ }
+ if (screen->unicode_font
+ && (text[src] == ANSI_DEL ||
+ text[src] < ANSI_SPA)) {
+ unsigned ni = dec2ucs((unsigned) ((text[src] == ANSI_DEL)
+ ? 0
+ : text[src]));
+ UCS2SBUF(ni);
+ }
+#endif /* OPT_MINI_LUIT */
+ ++dst;
+ }
+ /* FIXME This is probably wrong. But it works. */
+ underline_len = len;
+
+ /* Set the drawing font */
+ if (!(flags & (DOUBLEHFONT | DOUBLEWFONT))) {
+ VTwin *currentWin = WhichVWin(screen);
+ VTFontEnum fntId;
+ CgsEnum cgsId;
+ Pixel fg = getCgsFore(xw, currentWin, gc);
+ Pixel bg = getCgsBack(xw, currentWin, gc);
+
+ if (needWide
+ && (okFont(NormalWFont(screen)) || okFont(BoldWFont(screen)))) {
+ if ((flags & BOLDATTR(screen)) != 0
+ && okFont(BoldWFont(screen))) {
+ fntId = fWBold;
+ cgsId = gcWBold;
+ } else {
+ fntId = fWide;
+ cgsId = gcWide;
+ }
+ } else if ((flags & BOLDATTR(screen)) != 0
+ && okFont(BoldFont(screen))) {
+ fntId = fBold;
+ cgsId = gcBold;
+ } else {
+ fntId = fNorm;
+ cgsId = gcNorm;
+ }
+
+ setCgsFore(xw, currentWin, cgsId, fg);
+ setCgsBack(xw, currentWin, cgsId, bg);
+ gc = getCgsGC(xw, currentWin, cgsId);
+
+ if (fntId != fNorm) {
+ XFontStruct *thisFp = WhichVFont(screen, fnts[fntId].fs);
+ ascent_adjust = (thisFp->ascent
+ - NormalFont(screen)->ascent);
+ if (thisFp->max_bounds.width ==
+ NormalFont(screen)->max_bounds.width * 2) {
+ underline_len = real_length = (Cardinal) (dst * 2);
+ } else if (cgsId == gcWide || cgsId == gcWBold) {
+ underline_len = real_length = (Cardinal) (dst * 2);
+ xtermFillCells(xw,
+ flags,
+ gc,
+ x,
+ y - thisFp->ascent,
+ real_length);
+ }
+ }
+ }
+
+ if (flags & NOBACKGROUND) {
+ XDrawString16(screen->display,
+ VWindow(screen), gc,
+ x, y + ascent_adjust,
+ buffer, dst);
+ } else {
+ XDrawImageString16(screen->display,
+ VWindow(screen), gc,
+ x, y + ascent_adjust,
+ buffer, dst);
+ }
+
+ if ((flags & BOLDATTR(screen)) && screen->enbolden) {
+ beginClipping(screen, gc, (Cardinal) font_width, len);
+ XDrawString16(screen->display, VWindow(screen), gc,
+ x + 1,
+ y + ascent_adjust,
+ buffer, dst);
+ endClipping(screen, gc);
+ }
+
+ } else
+#endif /* OPT_WIDE_CHARS */
+ {
+ int length = (int) len; /* X should have used unsigned */
+#if OPT_WIDE_CHARS
+ char *buffer;
+ int dst;
+
+ BumpTypedBuffer(char, len);
+ buffer = BfBuf(char);
+
+ for (dst = 0; dst < length; ++dst)
+ buffer[dst] = (char) LO_BYTE(text[dst]);
+#else
+ char *buffer = (char *) text;
+#endif
+
+ if (flags & NOBACKGROUND) {
+ XDrawString(screen->display, VWindow(screen), gc,
+ x, y, buffer, length);
+ } else {
+ XDrawImageString(screen->display, VWindow(screen), gc,
+ x, y, buffer, length);
+ }
+ underline_len = (Cardinal) length;
+ if ((flags & BOLDATTR(screen)) && screen->enbolden) {
+ beginClipping(screen, gc, font_width, length);
+ XDrawString(screen->display, VWindow(screen), gc,
+ x + 1, y, buffer, 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 + (int) underline_len * font_width - 1), y);
+ }
+
+ return x + (int) real_length *FontWidth(screen);
+}
+
+#if OPT_WIDE_CHARS
+/*
+ * Allocate buffer - workaround for wide-character interfaces.
+ */
+void
+allocXtermChars(ScrnPtr * buffer, Cardinal length)
+{
+ if (*buffer == 0) {
+ *buffer = (ScrnPtr) XtMalloc(length);
+ } else {
+ *buffer = (ScrnPtr) XtRealloc((char *) *buffer, length);
+ }
+}
+#endif
+
+/* set up size hints for window manager; min 1 char by 1 char */
+void
+xtermSizeHints(XtermWidget xw, int scrollbarWidth)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ TRACE(("xtermSizeHints\n"));
+ TRACE((" border %d\n", xw->core.border_width));
+ TRACE((" scrollbar %d\n", scrollbarWidth));
+
+ xw->hints.base_width = 2 * screen->border + scrollbarWidth;
+ xw->hints.base_height = 2 * screen->border;
+
+#if OPT_TOOLBAR
+ TRACE((" toolbar %d\n", ToolbarHeight(xw)));
+
+ xw->hints.base_height += ToolbarHeight(xw);
+ xw->hints.base_height += BorderWidth(xw) * 2;
+ xw->hints.base_width += BorderWidth(xw) * 2;
+#endif
+
+ xw->hints.width_inc = FontWidth(screen);
+ xw->hints.height_inc = FontHeight(screen);
+ xw->hints.min_width = xw->hints.base_width + xw->hints.width_inc;
+ xw->hints.min_height = xw->hints.base_height + xw->hints.height_inc;
+
+ xw->hints.width = MaxCols(screen) * FontWidth(screen) + xw->hints.min_width;
+ xw->hints.height = MaxRows(screen) * FontHeight(screen) + xw->hints.min_height;
+
+ xw->hints.flags |= (PSize | PBaseSize | PMinSize | PResizeInc);
+
+ TRACE_HINTS(&(xw->hints));
+}
+
+void
+getXtermSizeHints(XtermWidget xw)
+{
+ TScreen *screen = TScreenOf(xw);
+ long supp;
+
+ if (!XGetWMNormalHints(screen->display, VShellWindow(xw),
+ &xw->hints, &supp))
+ memset(&xw->hints, 0, sizeof(xw->hints));
+ TRACE_HINTS(&(xw->hints));
+}
+
+/*
+ * 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(XtermWidget xw, unsigned flags, unsigned fg_bg, Bool hilite)
+{
+ TScreen *screen = TScreenOf(xw);
+ VTwin *win = WhichVWin(screen);
+ CgsEnum cgsId = gcMAX;
+ unsigned my_fg = extract_fg(xw, fg_bg, flags);
+ unsigned my_bg = extract_bg(xw, fg_bg, flags);
+ Pixel fg_pix = getXtermForeground(xw, flags, my_fg);
+ Pixel bg_pix = getXtermBackground(xw, flags, my_bg);
+ Pixel xx_pix;
+#if OPT_HIGHLIGHT_COLOR
+ Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG);
+ Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG);
+ Boolean always = screen->hilite_color;
+ Boolean use_selbg = (Boolean) (always ||
+ isNotForeground(xw, fg_pix, bg_pix, selbg_pix));
+ Boolean use_selfg = (Boolean) (always &&
+ isNotBackground(xw, fg_pix, bg_pix, selfg_pix));
+#endif
+
+ (void) fg_bg;
+ (void) my_bg;
+ (void) my_fg;
+
+ /*
+ * Discard video attributes overridden by colorXXXMode's.
+ */
+ checkVeryBoldColors(flags, my_fg);
+
+ if (ReverseOrHilite(screen, flags, hilite)) {
+ if (flags & BOLDATTR(screen)) {
+ cgsId = gcBoldReverse;
+ } else {
+ cgsId = gcNormReverse;
+ }
+
+#if OPT_HIGHLIGHT_COLOR
+ if (!screen->hilite_color) {
+ if (selbg_pix != T_COLOR(screen, TEXT_FG)
+ && selbg_pix != fg_pix
+ && selbg_pix != bg_pix
+ && selbg_pix != xw->dft_foreground) {
+ bg_pix = fg_pix;
+ fg_pix = selbg_pix;
+ }
+ }
+#endif
+ EXCHANGE(fg_pix, bg_pix, xx_pix);
+#if OPT_HIGHLIGHT_COLOR
+ if (screen->hilite_color) {
+ if (screen->hilite_reverse) {
+ if (use_selbg) {
+ if (use_selfg)
+ bg_pix = fg_pix;
+ else
+ fg_pix = bg_pix;
+ }
+ if (use_selbg)
+ bg_pix = selbg_pix;
+ if (use_selfg)
+ fg_pix = selfg_pix;
+ }
+ }
+#endif
+ } else {
+ if (flags & BOLDATTR(screen)) {
+ cgsId = gcBold;
+ } else {
+ cgsId = gcNorm;
+ }
+ }
+#if OPT_HIGHLIGHT_COLOR
+ if (!screen->hilite_color || !screen->hilite_reverse) {
+ if (hilite && !screen->hilite_reverse) {
+ if (use_selbg)
+ bg_pix = selbg_pix;
+ if (use_selfg)
+ fg_pix = selfg_pix;
+ }
+ }
+#endif
+
+#if OPT_BLINK_TEXT
+ if ((screen->blink_state == ON) && (!screen->blink_as_bold) && (flags & BLINK)) {
+ fg_pix = bg_pix;
+ }
+#endif
+
+ setCgsFore(xw, win, cgsId, fg_pix);
+ setCgsBack(xw, win, cgsId, bg_pix);
+ return getCgsGC(xw, win, cgsId);
+}
+
+/*
+ * 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(XtermWidget xw, unsigned flags, Bool hilite)
+{
+ TScreen *screen = TScreenOf(xw);
+ VTwin *win = WhichVWin(screen);
+ CgsEnum cgsId = gcMAX;
+ Pixel fg_pix = getXtermForeground(xw, flags, xw->cur_foreground);
+ Pixel bg_pix = getXtermBackground(xw, flags, xw->cur_background);
+
+ checkVeryBoldColors(flags, xw->cur_foreground);
+
+ if (ReverseOrHilite(screen, flags, hilite)) {
+ if (flags & BOLDATTR(screen)) {
+ cgsId = gcBoldReverse;
+ } else {
+ cgsId = gcNormReverse;
+ }
+
+ setCgsFore(xw, win, cgsId, bg_pix);
+ setCgsBack(xw, win, cgsId, fg_pix);
+
+ } else {
+ if (flags & BOLDATTR(screen)) {
+ cgsId = gcBold;
+ } else {
+ cgsId = gcNorm;
+ }
+
+ setCgsFore(xw, win, cgsId, fg_pix);
+ setCgsBack(xw, win, cgsId, bg_pix);
+ }
+}
+
+#if OPT_ISO_COLORS
+/*
+ * Extract the foreground-color index from a color pair.
+ * If we've got BOLD or UNDERLINE color-mode active, those will be used.
+ */
+unsigned
+extract_fg(XtermWidget xw, unsigned color, unsigned flags)
+{
+ unsigned fg = ExtractForeground(color);
+
+ if (TScreenOf(xw)->colorAttrMode
+ || (fg == ExtractBackground(color))) {
+ fg = MapToColorMode(fg, TScreenOf(xw), flags);
+ }
+ return fg;
+}
+
+/*
+ * Extract the background-color index from a color pair.
+ * If we've got INVERSE color-mode active, that will be used.
+ */
+unsigned
+extract_bg(XtermWidget xw, unsigned color, unsigned flags)
+{
+ unsigned bg = ExtractBackground(color);
+
+ if (TScreenOf(xw)->colorAttrMode
+ || (bg == ExtractForeground(color))) {
+ if (TScreenOf(xw)->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.
+ */
+CellColor
+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;
+
+ return (CellColor) (my_fg | (my_bg << COLOR_BITS));
+}
+
+/*
+ * Using the "current" SGR background, clear a rectangle.
+ */
+void
+ClearCurBackground(XtermWidget xw,
+ int top,
+ int left,
+ unsigned height,
+ unsigned width,
+ unsigned fw)
+{
+ TScreen *screen = TScreenOf(xw);
+
+ TRACE(("ClearCurBackground %d,%d %dx%d with %d\n",
+ top, left, height, width, xw->cur_background));
+
+ assert((int) width > 0);
+ assert((left + (int) width) <= screen->max_col + 1);
+ assert((int) height <= screen->max_row + 1);
+
+ if (VWindow(screen)) {
+ set_background(xw, xw->cur_background);
+
+ XClearArea(screen->display, VWindow(screen),
+ CursorX2(screen, left, fw),
+ CursorY(screen, top),
+ (width * fw),
+ (height * (unsigned) FontHeight(screen)),
+ False);
+
+ set_background(xw, -1);
+ }
+}
+#endif /* OPT_ISO_COLORS */
+
+/*
+ * Returns a single base character for the given cell.
+ */
+unsigned
+getXtermCell(TScreen * screen, int row, int col)
+{
+ LineData *ld = getLineData(screen, row);
+
+ assert(ld && (col < (int) ld->lineSize));
+ return ((ld && (col < (int) ld->lineSize))
+ ? ld->charData[col]
+ : (unsigned) ' ');
+}
+
+/*
+ * Sets a single base character for the given cell.
+ */
+void
+putXtermCell(TScreen * screen, int row, int col, int ch)
+{
+ LineData *ld = getLineData(screen, row);
+
+ assert(ld && (col < (int) ld->lineSize));
+ if (ld && (col < (int) ld->lineSize)) {
+ ld->charData[col] = (CharData) ch;
+ if_OPT_WIDE_CHARS(screen, {
+ size_t off;
+ for_each_combData(off, ld) {
+ ld->combData[off][col] = 0;
+ }
+ });
+ }
+}
+
+#if OPT_WIDE_CHARS
+/*
+ * Add a combining character for the given cell
+ */
+void
+addXtermCombining(TScreen * screen, int row, int col, unsigned ch)
+{
+ if (ch != 0) {
+ LineData *ld = getLineData(screen, row);
+ size_t off;
+
+ TRACE(("addXtermCombining %d,%d %#x (%d)\n",
+ row, col, ch, my_wcwidth((wchar_t) ch)));
+
+ for_each_combData(off, ld) {
+ if (!ld->combData[off][col]) {
+ ld->combData[off][col] = (CharData) ch;
+ break;
+ }
+ }
+ }
+}
+
+unsigned
+getXtermCombining(TScreen * screen, int row, int col, int off)
+{
+ LineData *ld = getLineData(screen, row);
+ return ld->combData[off][col];
+}
+#endif
+
+#ifdef HAVE_CONFIG_H
+#ifdef USE_MY_MEMMOVE
+void *
+my_memmove(void *s1, void *s2, size_t n)
+{
+ if (n != 0) {
+ char *p1 = (char *) s1;
+ char *p2 = (char *) s2;
+
+ if ((p1 + n > p2) && (p2 + n > p1)) {
+ 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] = p2[j];
+ p2 = bfr;
+ }
+ while (n-- != 0)
+ p1[n] = p2[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
+
+void
+update_keyboard_type(void)
+{
+ update_delete_del();
+ update_tcap_fkeys();
+ update_old_fkeys();
+ update_hp_fkeys();
+ update_sco_fkeys();
+ update_sun_fkeys();
+ update_sun_kbd();
+}
+
+void
+set_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set)
+{
+ xtermKeyboardType save = xw->keyboard.type;
+
+ TRACE(("set_keyboard_type(%s, %s) currently %s\n",
+ visibleKeyboardType(type),
+ BtoS(set),
+ visibleKeyboardType(xw->keyboard.type)));
+ if (set) {
+ xw->keyboard.type = type;
+ } else {
+ xw->keyboard.type = keyboardIsDefault;
+ }
+
+ if (save != xw->keyboard.type) {
+ update_keyboard_type();
+ }
+}
+
+void
+toggle_keyboard_type(XtermWidget xw, xtermKeyboardType type)
+{
+ xtermKeyboardType save = xw->keyboard.type;
+
+ TRACE(("toggle_keyboard_type(%s) currently %s\n",
+ visibleKeyboardType(type),
+ visibleKeyboardType(xw->keyboard.type)));
+ if (xw->keyboard.type == type) {
+ xw->keyboard.type = keyboardIsDefault;
+ } else {
+ xw->keyboard.type = type;
+ }
+
+ if (save != xw->keyboard.type) {
+ update_keyboard_type();
+ }
+}
+
+void
+init_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set)
+{
+ static Bool wasSet = False;
+
+ TRACE(("init_keyboard_type(%s, %s) currently %s\n",
+ visibleKeyboardType(type),
+ BtoS(set),
+ visibleKeyboardType(xw->keyboard.type)));
+ if (set) {
+ if (wasSet) {
+ xtermWarning("Conflicting keyboard type option (%u/%u)\n",
+ xw->keyboard.type, type);
+ }
+ xw->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(XtermWidget xw, 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
+#if OPT_SUN_FUNC_KEYS
+ DATA(NAME_SUN_KT, keyboardIsSun, sunFunctionKeys),
+#endif
+#if OPT_SUNPC_KBD
+ DATA(NAME_VT220_KT, keyboardIsVT220, sunKeyboard),
+#endif
+#if OPT_TCAP_FKEYS
+ DATA(NAME_TCAP_KT, keyboardIsTermcap, termcapKeys),
+#endif
+ };
+ Cardinal n;
+
+ TRACE(("decode_keyboard_type(%s)\n", rp->keyboardType));
+ if (!x_strcasecmp(rp->keyboardType, "unknown")) {
+ /*
+ * Let the individual resources comprise the keyboard-type.
+ */
+ for (n = 0; n < XtNumber(table); ++n)
+ init_keyboard_type(xw, table[n].type, FLAG(n));
+ } else if (!x_strcasecmp(rp->keyboardType, "default")) {
+ /*
+ * Set the keyboard-type to the Sun/PC type, allowing modified
+ * function keys, etc.
+ */
+ for (n = 0; n < XtNumber(table); ++n)
+ init_keyboard_type(xw, table[n].type, False);
+ } else {
+ Bool found = False;
+
+ /*
+ * Choose an individual keyboard type.
+ */
+ for (n = 0; n < XtNumber(table); ++n) {
+ if (!x_strcasecmp(rp->keyboardType, table[n].name + 1)) {
+ FLAG(n) = True;
+ found = True;
+ } else {
+ FLAG(n) = False;
+ }
+ init_keyboard_type(xw, table[n].type, FLAG(n));
+ }
+ if (!found) {
+ xtermWarning("KeyboardType resource \"%s\" not found\n",
+ rp->keyboardType);
+ }
+ }
+#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(int samplesize, int samplepass)
+{
+ wchar_t n;
+ int oops = 0;
+
+ for (n = 21; n <= 25; ++n) {
+ int code = (int) dec2ucs((unsigned) n);
+ int system_code = wcwidth(code);
+ int intern_code = mk_wcwidth(code);
+
+ /*
+ * Solaris 10 wcwidth() returns "2" for all of the line-drawing (page
+ * 0x2500) and most of the geometric shapes (a few are excluded, just
+ * to make it more difficult to use). Do a sanity check to avoid using
+ * it.
+ */
+ if ((system_code < 0 && intern_code >= 1)
+ || (system_code >= 0 && intern_code != system_code)) {
+ TRACE(("systemWcwidthOk: broken system line-drawing wcwidth\n"));
+ oops += (samplepass + 1);
+ break;
+ }
+ }
+
+ for (n = 0; n < (wchar_t) samplesize; ++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, allowed %d\n",
+ oops, samplesize, samplepass));
+ return (oops <= samplepass);
+}
+#endif /* HAVE_WCWIDTH */
+
+void
+decode_wcwidth(XtermWidget xw)
+{
+ int mode = ((xw->misc.cjk_width ? 2 : 0)
+ + (xw->misc.mk_width ? 1 : 0)
+ + 1);
+
+ switch (mode) {
+ default:
+#if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
+ if (xtermEnvUTF8() &&
+ systemWcwidthOk(xw->misc.mk_samplesize, xw->misc.mk_samplepass)) {
+ my_wcwidth = wcwidth;
+ TRACE(("using system wcwidth() function\n"));
+ break;
+ }
+ /* FALLTHRU */
+#endif
+ case 2:
+ 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;
+ }
+
+ for (first_widechar = 128; first_widechar < 4500; ++first_widechar) {
+ if (my_wcwidth((int) first_widechar) > 1) {
+ TRACE(("first_widechar %#x\n", first_widechar));
+ break;
+ }
+ }
+}
+#endif
+
+/*
+ * Extend a (normally) boolean resource value by checking for additional values
+ * which will be mapped into true/false.
+ */
+int
+extendedBoolean(const char *value, FlagList * table, Cardinal limit)
+{
+ int result = -1;
+ long check;
+ char *next;
+ Cardinal n;
+
+ if ((x_strcasecmp(value, "true") == 0)
+ || (x_strcasecmp(value, "yes") == 0)
+ || (x_strcasecmp(value, "on") == 0)) {
+ result = True;
+ } else if ((x_strcasecmp(value, "false") == 0)
+ || (x_strcasecmp(value, "no") == 0)
+ || (x_strcasecmp(value, "off") == 0)) {
+ result = False;
+ } else if ((check = strtol(value, &next, 0)) >= 0 && *next == '\0') {
+ if (check >= (long) limit)
+ check = True;
+ result = (int) check;
+ } else {
+ for (n = 0; n < limit; ++n) {
+ if (x_strcasecmp(value, table[n].name) == 0) {
+ result = table[n].code;
+ break;
+ }
+ }
+ }
+
+ if (result < 0) {
+ xtermWarning("Unrecognized keyword: %s\n", value);
+ result = False;
+ }
+
+ TRACE(("extendedBoolean(%s) = %d\n", value, result));
+ return result;
+}
+
+/*
+ * Something like round() from math library, but round() is less widely-used
+ * than xterm. Also, there are no negative numbers to complicate this.
+ */
+int
+dimRound(double value)
+{
+ int result = (int) value;
+ if (result < value)
+ ++result;
+ return result;
+}