"Fossies" - the Fresh Open Source Software Archive

Member "xterm-368/util.c" (6 Jun 2021, 139949 Bytes) of package /linux/misc/xterm-368.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "util.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 367_vs_368.

    1 /* $XTermId: util.c,v 1.878 2021/06/06 23:14:52 Stelios.Bounanos Exp $ */
    2 
    3 /*
    4  * Copyright 1999-2020,2021 by Thomas E. Dickey
    5  *
    6  *                         All Rights Reserved
    7  *
    8  * Permission is hereby granted, free of charge, to any person obtaining a
    9  * copy of this software and associated documentation files (the
   10  * "Software"), to deal in the Software without restriction, including
   11  * without limitation the rights to use, copy, modify, merge, publish,
   12  * distribute, sublicense, and/or sell copies of the Software, and to
   13  * permit persons to whom the Software is furnished to do so, subject to
   14  * the following conditions:
   15  *
   16  * The above copyright notice and this permission notice shall be included
   17  * in all copies or substantial portions of the Software.
   18  *
   19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   22  * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
   23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   26  *
   27  * Except as contained in this notice, the name(s) of the above copyright
   28  * holders shall not be used in advertising or otherwise to promote the
   29  * sale, use or other dealings in this Software without prior written
   30  * authorization.
   31  *
   32  *
   33  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
   34  *
   35  *                         All Rights Reserved
   36  *
   37  * Permission to use, copy, modify, and distribute this software and its
   38  * documentation for any purpose and without fee is hereby granted,
   39  * provided that the above copyright notice appear in all copies and that
   40  * both that copyright notice and this permission notice appear in
   41  * supporting documentation, and that the name of Digital Equipment
   42  * Corporation not be used in advertising or publicity pertaining to
   43  * distribution of the software without specific, written prior permission.
   44  *
   45  *
   46  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   47  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
   48  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   49  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
   50  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
   51  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   52  * SOFTWARE.
   53  */
   54 
   55 /* util.c */
   56 
   57 #include <xterm.h>
   58 
   59 #include <data.h>
   60 #include <error.h>
   61 #include <menu.h>
   62 #include <fontutils.h>
   63 #include <xstrings.h>
   64 
   65 #include <stdio.h>
   66 #include <string.h>
   67 #include <ctype.h>
   68 #include <assert.h>
   69 
   70 #if OPT_WIDE_CHARS
   71 #if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
   72 #include <wchar.h>
   73 #endif
   74 #include <wcwidth.h>
   75 #endif
   76 
   77 #ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
   78 #include <X11/extensions/Xinerama.h>
   79 #endif /* HAVE_X11_EXTENSIONS_XINERAMA_H */
   80 
   81 #include <graphics.h>
   82 
   83 static int handle_translated_exposure(XtermWidget xw,
   84                       int rect_x,
   85                       int rect_y,
   86                       int rect_width,
   87                       int rect_height);
   88 static void ClearLeft(XtermWidget xw);
   89 static void CopyWait(XtermWidget xw);
   90 static void horizontal_copy_area(XtermWidget xw,
   91                  int firstchar,
   92                  int nchars,
   93                  int amount);
   94 static void vertical_copy_area(XtermWidget xw,
   95                    int firstline,
   96                    int nlines,
   97                    int amount,
   98                    int left,
   99                    int right);
  100 
  101 #if OPT_WIDE_CHARS
  102 unsigned first_widechar;
  103 int (*my_wcwidth) (wchar_t);
  104 #endif
  105 
  106 #if OPT_WIDE_CHARS
  107 /*
  108  * We will modify the 'n' cells beginning at the current position.
  109  * Some of those cells may be part of multi-column characters, including
  110  * carryover from the left.  Find the limits of the multi-column characters
  111  * that we should fill with blanks, return true if filling is needed.
  112  */
  113 int
  114 DamagedCells(TScreen *screen, unsigned n, int *klp, int *krp, int row, int col)
  115 {
  116     CLineData *ld = getLineData(screen, row);
  117     int result = False;
  118 
  119     assert(ld);
  120     if (col < (int) ld->lineSize) {
  121     int nn = (int) n;
  122     int kl = col;
  123     int kr = col + nn;
  124 
  125     if (kr >= (int) ld->lineSize) {
  126         nn = (ld->lineSize - col - 1);
  127         kr = col + nn;
  128     }
  129 
  130     if (nn > 0) {
  131         assert(kl < (int) ld->lineSize);
  132         if (ld->charData[kl] == HIDDEN_CHAR) {
  133         while (kl > 0) {
  134             if (ld->charData[--kl] != HIDDEN_CHAR) {
  135             break;
  136             }
  137         }
  138         } else {
  139         kl = col + 1;
  140         }
  141 
  142         assert(kr < (int) ld->lineSize);
  143         if (ld->charData[kr] == HIDDEN_CHAR) {
  144         while (kr < screen->max_col) {
  145             assert((kr + 1) < (int) ld->lineSize);
  146             if (ld->charData[++kr] != HIDDEN_CHAR) {
  147             --kr;
  148             break;
  149             }
  150         }
  151         } else {
  152         kr = col - 1;
  153         }
  154 
  155         if (klp)
  156         *klp = kl;
  157         if (krp)
  158         *krp = kr;
  159         result = (kr >= kl);
  160     }
  161     }
  162 
  163     return result;
  164 }
  165 
  166 int
  167 DamagedCurCells(TScreen *screen, unsigned n, int *klp, int *krp)
  168 {
  169     return DamagedCells(screen, n, klp, krp, screen->cur_row, screen->cur_col);
  170 }
  171 #endif /* OPT_WIDE_CHARS */
  172 
  173 /*
  174  * These routines are used for the jump scroll feature
  175  */
  176 void
  177 FlushScroll(XtermWidget xw)
  178 {
  179     TScreen *screen = TScreenOf(xw);
  180     int i;
  181     int shift = INX2ROW(screen, 0);
  182     int bot = screen->max_row - shift;
  183     int refreshtop;
  184     int refreshheight;
  185     int scrolltop;
  186     int scrollheight;
  187     int left = ScrnLeftMargin(xw);
  188     int right = ScrnRightMargin(xw);
  189     Boolean full_lines = (Boolean) ((left == 0) && (right == screen->max_col));
  190 
  191     if (screen->cursor_state)
  192     HideCursor(xw);
  193 
  194     TRACE(("FlushScroll %s-lines scroll:%d refresh %d\n",
  195        full_lines ? "full" : "partial",
  196        screen->scroll_amt,
  197        screen->refresh_amt));
  198 
  199     if (screen->scroll_amt > 0) {
  200     /*
  201      * Lines will be scrolled "up".
  202      */
  203     refreshheight = screen->refresh_amt;
  204     scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1;
  205     refreshtop = screen->bot_marg - refreshheight + 1 + shift;
  206     i = screen->max_row - screen->scroll_amt + 1;
  207     if (refreshtop > i) {
  208         refreshtop = i;
  209     }
  210 
  211     /*
  212      * If this is the normal (not alternate) screen, and the top margin is
  213      * at the top of the screen, then we will shift full lines scrolled out
  214      * of the scrolling region into the saved-lines.
  215      */
  216     if (screen->scrollWidget
  217         && !screen->whichBuf
  218         && full_lines
  219         && screen->top_marg == 0) {
  220         scrolltop = 0;
  221         scrollheight += shift;
  222         if (scrollheight > i)
  223         scrollheight = i;
  224         i = screen->bot_marg - bot;
  225         if (i > 0) {
  226         refreshheight -= i;
  227         if (refreshheight < screen->scroll_amt) {
  228             refreshheight = screen->scroll_amt;
  229         }
  230         }
  231         i = screen->savedlines;
  232         if (i < screen->savelines) {
  233         i += screen->scroll_amt;
  234         if (i > screen->savelines) {
  235             i = screen->savelines;
  236         }
  237         screen->savedlines = i;
  238         ScrollBarDrawThumb(xw, 1);
  239         }
  240     } else {
  241         scrolltop = screen->top_marg + shift;
  242         i = bot - (screen->bot_marg - screen->refresh_amt + screen->scroll_amt);
  243         if (i > 0) {
  244         if (bot < screen->bot_marg) {
  245             refreshheight = screen->scroll_amt + i;
  246         }
  247         } else {
  248         scrollheight += i;
  249         refreshheight = screen->scroll_amt;
  250         i = screen->top_marg + screen->scroll_amt - 1 - bot;
  251         if (i > 0) {
  252             refreshtop += i;
  253             refreshheight -= i;
  254         }
  255         }
  256     }
  257     } else {
  258     /*
  259      * Lines will be scrolled "down".
  260      */
  261     refreshheight = -screen->refresh_amt;
  262     scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1;
  263     refreshtop = screen->top_marg + shift;
  264     scrolltop = refreshtop + refreshheight;
  265     i = screen->bot_marg - bot;
  266     if (i > 0) {
  267         scrollheight -= i;
  268     }
  269     i = screen->top_marg + refreshheight - 1 - bot;
  270     if (i > 0) {
  271         refreshheight -= i;
  272     }
  273     }
  274 
  275     vertical_copy_area(xw,
  276                scrolltop + screen->scroll_amt,
  277                scrollheight,
  278                screen->scroll_amt,
  279                left,
  280                right);
  281     ScrollSelection(screen, -(screen->scroll_amt), False);
  282     screen->scroll_amt = 0;
  283     screen->refresh_amt = 0;
  284 
  285     if (refreshheight > 0) {
  286     ClearCurBackground(xw,
  287                refreshtop,
  288                left,
  289                (unsigned) refreshheight,
  290                (unsigned) (right + 1 - left),
  291                (unsigned) FontWidth(screen));
  292     ScrnRefresh(xw,
  293             refreshtop,
  294             0,
  295             refreshheight,
  296             MaxCols(screen),
  297             False);
  298     }
  299     xtermTimedDbe(xw);
  300     return;
  301 }
  302 
  303 /*
  304  * Returns true if there are lines off-screen due to scrolling which should
  305  * include the current line.  If false, the line is visible and we should
  306  * paint it now rather than waiting for the line to become visible.
  307  */
  308 static Bool
  309 AddToRefresh(XtermWidget xw)
  310 {
  311     TScreen *screen = TScreenOf(xw);
  312     int amount = screen->refresh_amt;
  313     int row = screen->cur_row;
  314     Bool result;
  315 
  316     if (amount == 0) {
  317     result = False;
  318     } else if (amount > 0) {
  319     int bottom;
  320 
  321     if (row == (bottom = screen->bot_marg) - amount) {
  322         screen->refresh_amt++;
  323         result = True;
  324     } else {
  325         result = (row >= bottom - amount + 1 && row <= bottom);
  326     }
  327     } else {
  328     int top;
  329 
  330     amount = -amount;
  331     if (row == (top = screen->top_marg) + amount) {
  332         screen->refresh_amt--;
  333         result = True;
  334     } else {
  335         result = (row <= top + amount - 1 && row >= top);
  336     }
  337     }
  338 
  339     /*
  340      * If this line is visible, and there are scrolled-off lines, flush out
  341      * those which are now visible.
  342      */
  343     if (!result && screen->scroll_amt)
  344     FlushScroll(xw);
  345 
  346     return result;
  347 }
  348 
  349 /*
  350  * Returns true if the current row is in the visible area (it should be for
  351  * screen operations) and incidentally flush the scrolled-in lines which
  352  * have newly become visible.
  353  */
  354 static Bool
  355 AddToVisible(XtermWidget xw)
  356 {
  357     TScreen *screen = TScreenOf(xw);
  358     Bool result = False;
  359 
  360     if (INX2ROW(screen, screen->cur_row) <= screen->max_row) {
  361     if (!AddToRefresh(xw)) {
  362         result = True;
  363     }
  364     }
  365     return result;
  366 }
  367 
  368 /*
  369  * If we're scrolling, leave the selection intact if possible.
  370  * If it will bump into one of the extremes of the saved-lines, truncate that.
  371  * If the selection is not entirely contained within the margins and not
  372  * entirely outside the margins, clear it.
  373  */
  374 static void
  375 adjustHiliteOnFwdScroll(XtermWidget xw, int amount, Bool all_lines)
  376 {
  377     TScreen *screen = TScreenOf(xw);
  378     int lo_row = (all_lines
  379           ? (screen->bot_marg - screen->savelines)
  380           : screen->top_marg);
  381     int hi_row = screen->bot_marg;
  382     int left = ScrnLeftMargin(xw);
  383     int right = ScrnRightMargin(xw);
  384 
  385     TRACE2(("adjustSelection FWD %s by %d (%s)\n",
  386         screen->whichBuf ? "alternate" : "normal",
  387         amount,
  388         all_lines ? "all" : "visible"));
  389     TRACE2(("  before highlite %d.%d .. %d.%d\n",
  390         screen->startH.row,
  391         screen->startH.col,
  392         screen->endH.row,
  393         screen->endH.col));
  394     TRACE2(("  margins %d..%d\n", screen->top_marg, screen->bot_marg));
  395     TRACE2(("  limits  %d..%d\n", lo_row, hi_row));
  396 
  397     if ((left > 0 || right < screen->max_col) &&
  398     ((screen->startH.row >= lo_row &&
  399       screen->startH.row - amount <= hi_row) ||
  400      (screen->endH.row >= lo_row &&
  401       screen->endH.row - amount <= hi_row))) {
  402     /*
  403      * This could be improved slightly by excluding the special case where
  404      * the selection is on a single line outside left/right margins.
  405      */
  406     TRACE2(("deselect because selection overlaps with scrolled partial-line\n"));
  407     ScrnDisownSelection(xw);
  408     } else if (screen->startH.row >= lo_row
  409            && screen->startH.row - amount < lo_row) {
  410     /* truncate the selection because its start would move out of region */
  411     if (lo_row + amount <= screen->endH.row) {
  412         TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
  413             screen->startH.row,
  414             screen->startH.col,
  415             lo_row + amount,
  416             0));
  417         screen->startH.row = lo_row + amount;
  418         screen->startH.col = 0;
  419     } else {
  420         TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
  421             screen->startH.row,
  422             screen->startH.col,
  423             screen->endH.row,
  424             screen->endH.col,
  425             -amount,
  426             lo_row,
  427             hi_row));
  428         ScrnDisownSelection(xw);
  429     }
  430     } else if (screen->startH.row <= hi_row && screen->endH.row > hi_row) {
  431     TRACE2(("deselect because selection straddles top-margin\n"));
  432     ScrnDisownSelection(xw);
  433     } else if (screen->startH.row < lo_row && screen->endH.row > lo_row) {
  434     TRACE2(("deselect because selection straddles bottom-margin\n"));
  435     ScrnDisownSelection(xw);
  436     }
  437 
  438     TRACE2(("  after highlite %d.%d .. %d.%d\n",
  439         screen->startH.row,
  440         screen->startH.col,
  441         screen->endH.row,
  442         screen->endH.col));
  443 }
  444 
  445 /*
  446  * This is the same as adjustHiliteOnFwdScroll(), but reversed.  In this case,
  447  * only the visible lines are affected.
  448  */
  449 static void
  450 adjustHiliteOnBakScroll(XtermWidget xw, int amount)
  451 {
  452     TScreen *screen = TScreenOf(xw);
  453     int lo_row = screen->top_marg;
  454     int hi_row = screen->bot_marg;
  455 
  456     TRACE2(("adjustSelection BAK %s by %d (%s)\n",
  457         screen->whichBuf ? "alternate" : "normal",
  458         amount,
  459         "visible"));
  460     TRACE2(("  before highlite %d.%d .. %d.%d\n",
  461         screen->startH.row,
  462         screen->startH.col,
  463         screen->endH.row,
  464         screen->endH.col));
  465     TRACE2(("  margins %d..%d\n", screen->top_marg, screen->bot_marg));
  466 
  467     if (screen->endH.row >= hi_row
  468     && screen->endH.row + amount > hi_row) {
  469     /* truncate the selection because its start would move out of region */
  470     if (hi_row - amount >= screen->startH.row) {
  471         TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
  472             screen->startH.row,
  473             screen->startH.col,
  474             hi_row - amount,
  475             0));
  476         screen->endH.row = hi_row - amount;
  477         screen->endH.col = 0;
  478     } else {
  479         TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
  480             screen->startH.row,
  481             screen->startH.col,
  482             screen->endH.row,
  483             screen->endH.col,
  484             amount,
  485             lo_row,
  486             hi_row));
  487         ScrnDisownSelection(xw);
  488     }
  489     } else if (screen->endH.row >= lo_row && screen->startH.row < lo_row) {
  490     ScrnDisownSelection(xw);
  491     } else if (screen->endH.row > hi_row && screen->startH.row > hi_row) {
  492     ScrnDisownSelection(xw);
  493     }
  494 
  495     TRACE2(("  after highlite %d.%d .. %d.%d\n",
  496         screen->startH.row,
  497         screen->startH.col,
  498         screen->endH.row,
  499         screen->endH.col));
  500 }
  501 
  502 /*
  503  * Move cells in LineData's on the current screen to simulate scrolling by the
  504  * given amount of lines.
  505  */
  506 static void
  507 scrollInMargins(XtermWidget xw, int amount, int top)
  508 {
  509     TScreen *screen = TScreenOf(xw);
  510     LineData *src;
  511     LineData *dst;
  512     int row;
  513     int left = ScrnLeftMargin(xw);
  514     int right = ScrnRightMargin(xw);
  515     int length = right + 1 - left;
  516 
  517     if_OPT_WIDE_CHARS(screen, {
  518     if (amount != 0) {
  519         for (row = top; row <= screen->bot_marg; ++row) {
  520         LineData *ld;
  521         if ((ld = getLineData(screen, row + amount)) != 0) {
  522             if (left > 0) {
  523             if (ld->charData[left] == HIDDEN_CHAR) {
  524                 Clear1Cell(ld, left - 1);
  525                 Clear1Cell(ld, left);
  526             }
  527             }
  528             if (right + 1 < (int) ld->lineSize) {
  529             if (ld->charData[right + 1] == HIDDEN_CHAR) {
  530                 Clear1Cell(ld, right);
  531                 Clear1Cell(ld, right + 1);
  532             }
  533             }
  534         }
  535         }
  536     }
  537     });
  538 
  539     if (amount > 0) {
  540     for (row = top; row <= screen->bot_marg - amount; ++row) {
  541         if ((src = getLineData(screen, row + amount)) != 0
  542         && (dst = getLineData(screen, row)) != 0) {
  543         CopyCells(screen, src, dst, left, length, False);
  544         }
  545     }
  546     while (row <= screen->bot_marg) {
  547         ClearCells(xw, 0, (unsigned) length, row, left);
  548         ++row;
  549     }
  550     } else if (amount < 0) {
  551     for (row = screen->bot_marg; row >= top - amount; --row) {
  552         if ((src = getLineData(screen, row + amount)) != 0
  553         && (dst = getLineData(screen, row)) != 0) {
  554         CopyCells(screen, src, dst, left, length, True);
  555         }
  556     }
  557     while (row >= top) {
  558         ClearCells(xw, 0, (unsigned) length, row, left);
  559         --row;
  560     }
  561     }
  562 }
  563 
  564 #if OPT_WIDE_CHARS
  565 /*
  566  * If we're repainting a section of wide-characters that, e.g., ClearCells has
  567  * repaired when finding double-cell characters, then we should account for
  568  * that in the repaint.
  569  */
  570 static void
  571 ScrnUpdate2(XtermWidget xw,
  572         int toprow,
  573         int leftcol,
  574         int nrows,
  575         int ncols,
  576         Bool force)
  577 {
  578     if_OPT_WIDE_CHARS(TScreenOf(xw), {
  579     if (leftcol + ncols <= TScreenOf(xw)->max_col)
  580         ncols++;
  581     if (leftcol > 0) {
  582         leftcol--;
  583         ncols++;
  584     }
  585     });
  586     ScrnUpdate(xw, toprow, leftcol, nrows, ncols, force);
  587 }
  588 #else
  589 #define ScrnUpdate2(xw, toprow, leftcol, nrows, ncols, force) \
  590     ScrnUpdate(xw, toprow, leftcol, nrows, ncols, force)
  591 #endif
  592 
  593 /*
  594  * scrolls the screen by amount lines, erases bottom, doesn't alter
  595  * cursor position (i.e. cursor moves down amount relative to text).
  596  * All done within the scrolling region, of course.
  597  * requires: amount > 0
  598  */
  599 void
  600 xtermScroll(XtermWidget xw, int amount)
  601 {
  602     TScreen *screen = TScreenOf(xw);
  603     int i;
  604     int refreshtop = 0;
  605     int refreshheight;
  606     Boolean save_wrap = screen->do_wrap;
  607     int left = ScrnLeftMargin(xw);
  608     int right = ScrnRightMargin(xw);
  609     Boolean scroll_all_lines = (Boolean) (screen->scrollWidget
  610                       && !screen->whichBuf
  611                       && screen->top_marg == 0);
  612     Boolean scroll_full_line = ((left == 0) && (right == screen->max_col));
  613 
  614     TRACE(("xtermScroll count=%d\n", amount));
  615 
  616     screen->cursor_busy += 1;
  617     screen->cursor_moved = True;
  618 
  619     if (screen->cursor_state)
  620     HideCursor(xw);
  621 
  622     i = screen->bot_marg - screen->top_marg + 1;
  623     if (amount > i)
  624     amount = i;
  625 
  626     if (!scroll_full_line) {
  627     refreshheight = 0;
  628     } else
  629 #if OPT_SCROLL_LOCK
  630     if ((screen->allowScrollLock && screen->scroll_lock)
  631         || (screen->autoScrollLock && screen->topline < 0)) {
  632     refreshheight = 0;
  633     screen->scroll_amt = 0;
  634     screen->refresh_amt = 0;
  635     if (--(screen->topline) < -screen->savelines) {
  636         screen->topline = -screen->savelines;
  637         screen->scroll_dirty = True;
  638     }
  639     if (++(screen->savedlines) > screen->savelines) {
  640         screen->savedlines = screen->savelines;
  641     }
  642     } else
  643 #endif
  644     {
  645     if (ScrnHaveSelection(screen))
  646         adjustHiliteOnFwdScroll(xw, amount, scroll_all_lines);
  647 
  648     if (screen->jumpscroll) {
  649         if (screen->scroll_amt > 0) {
  650         if (!screen->fastscroll) {
  651             if (screen->refresh_amt + amount > i)
  652             FlushScroll(xw);
  653         }
  654         screen->scroll_amt += amount;
  655         screen->refresh_amt += amount;
  656         } else {
  657         if (!screen->fastscroll) {
  658             if (screen->scroll_amt < 0)
  659             FlushScroll(xw);
  660         }
  661         screen->scroll_amt = amount;
  662         screen->refresh_amt = amount;
  663         }
  664         refreshheight = 0;
  665     } else {
  666         int scrolltop;
  667         int scrollheight;
  668         int shift;
  669         int bot;
  670 
  671         ScrollSelection(screen, -(amount), False);
  672         if (amount == i) {
  673         ClearScreen(xw);
  674         goto done;
  675         }
  676 
  677         shift = INX2ROW(screen, 0);
  678         bot = screen->max_row - shift;
  679         scrollheight = i - amount;
  680         refreshheight = amount;
  681 
  682         if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
  683         (i = screen->max_row - refreshheight + 1))
  684         refreshtop = i;
  685 
  686         if (scroll_all_lines) {
  687         scrolltop = 0;
  688         if ((scrollheight += shift) > i)
  689             scrollheight = i;
  690         if ((i = screen->savedlines) < screen->savelines) {
  691             if ((i += amount) > screen->savelines)
  692             i = screen->savelines;
  693             screen->savedlines = i;
  694             ScrollBarDrawThumb(xw, 1);
  695         }
  696         } else {
  697         scrolltop = screen->top_marg + shift;
  698         if ((i = screen->bot_marg - bot) > 0) {
  699             scrollheight -= i;
  700             if ((i = screen->top_marg + amount - 1 - bot) >= 0) {
  701             refreshtop += i;
  702             refreshheight -= i;
  703             }
  704         }
  705         }
  706 
  707         if (screen->multiscroll && amount == 1 &&
  708         screen->topline == 0 && screen->top_marg == 0 &&
  709         screen->bot_marg == screen->max_row) {
  710         if (screen->incopy < 0 && screen->scrolls == 0)
  711             CopyWait(xw);
  712         screen->scrolls++;
  713         }
  714 
  715         vertical_copy_area(xw,
  716                    scrolltop + amount,
  717                    scrollheight,
  718                    amount,
  719                    left,
  720                    right);
  721 
  722         if (refreshheight > 0) {
  723         ClearCurBackground(xw,
  724                    refreshtop,
  725                    left,
  726                    (unsigned) refreshheight,
  727                    (unsigned) (right + 1 - left),
  728                    (unsigned) FontWidth(screen));
  729         if (refreshheight > shift)
  730             refreshheight = shift;
  731         }
  732     }
  733     }
  734 
  735     if (amount > 0) {
  736     if (left > 0 || right < screen->max_col) {
  737         scrollInMargins(xw, amount, screen->top_marg);
  738         ScrnUpdate2(xw,
  739             screen->top_marg,
  740             left,
  741             screen->bot_marg + 1 - screen->top_marg,
  742             right + 1 - left,
  743             True);
  744     } else if (scroll_all_lines) {
  745         ScrnDeleteLine(xw,
  746                screen->saveBuf_index,
  747                screen->bot_marg + screen->savelines,
  748                0,
  749                (unsigned) amount);
  750     } else {
  751         ScrnDeleteLine(xw,
  752                screen->visbuf,
  753                screen->bot_marg,
  754                screen->top_marg,
  755                (unsigned) amount);
  756     }
  757     }
  758 
  759     scroll_displayed_graphics(xw, amount);
  760 
  761     if (refreshheight > 0) {
  762     ScrnRefresh(xw,
  763             refreshtop,
  764             left,
  765             refreshheight,
  766             right + 1 - left,
  767             False);
  768     }
  769 
  770   done:
  771     screen->do_wrap = save_wrap;
  772     screen->cursor_busy -= 1;
  773     return;
  774 }
  775 
  776 /*
  777  * This is from ISO 6429, not found in any of DEC's terminals.
  778  */
  779 void
  780 xtermScrollLR(XtermWidget xw, int amount, Bool toLeft)
  781 {
  782     if (amount > 0) {
  783     xtermColScroll(xw, amount, toLeft, ScrnLeftMargin(xw));
  784     }
  785 }
  786 
  787 /*
  788  * Implement DECBI/DECFI (back/forward column index)
  789  */
  790 void
  791 xtermColIndex(XtermWidget xw, Bool toLeft)
  792 {
  793     TScreen *screen = TScreenOf(xw);
  794 
  795     if (toLeft) {
  796     if (ScrnIsColInMargins(screen, screen->cur_col)) {
  797         if (screen->cur_col == ScrnLeftMargin(xw)) {
  798         xtermColScroll(xw, 1, False, screen->cur_col);
  799         } else {
  800         CursorBack(xw, 1);
  801         }
  802     } else {
  803         CursorBack(xw, 1);
  804     }
  805     } else {
  806     if (ScrnIsColInMargins(screen, screen->cur_col)) {
  807         if (screen->cur_col == ScrnRightMargin(xw)) {
  808         xtermColScroll(xw, 1, True, ScrnLeftMargin(xw));
  809         } else {
  810         CursorForward(xw, 1);
  811         }
  812     } else {
  813         CursorForward(xw, 1);
  814     }
  815     }
  816 }
  817 
  818 /*
  819  * Implement DECDC/DECIC (delete/insert column)
  820  */
  821 void
  822 xtermColScroll(XtermWidget xw, int amount, Bool toLeft, int at_col)
  823 {
  824     TScreen *screen = TScreenOf(xw);
  825 
  826     if (amount > 0) {
  827     int min_row;
  828     int max_row;
  829 
  830     if (ScrnHaveRowMargins(screen)) {
  831         min_row = screen->top_marg;
  832         max_row = screen->bot_marg;
  833     } else {
  834         min_row = 0;
  835         max_row = screen->max_row;
  836     }
  837 
  838     if (screen->cur_row >= min_row
  839         && screen->cur_row <= max_row
  840         && screen->cur_col >= screen->lft_marg
  841         && screen->cur_col <= screen->rgt_marg) {
  842         int save_row = screen->cur_row;
  843         int save_col = screen->cur_col;
  844         int row;
  845 
  846         screen->cur_col = at_col;
  847         if (toLeft) {
  848         for (row = min_row; row <= max_row; row++) {
  849             screen->cur_row = row;
  850             ScrnDeleteChar(xw, (unsigned) amount);
  851         }
  852         } else {
  853         for (row = min_row; row <= max_row; row++) {
  854             screen->cur_row = row;
  855             ScrnInsertChar(xw, (unsigned) amount);
  856         }
  857         }
  858         screen->cur_row = save_row;
  859         screen->cur_col = save_col;
  860         xtermRepaint(xw);
  861     }
  862     }
  863 }
  864 
  865 /*
  866  * Reverse scrolls the screen by amount lines, erases top, doesn't alter
  867  * cursor position (i.e. cursor moves up amount relative to text).
  868  * All done within the scrolling region, of course.
  869  * Requires: amount > 0
  870  */
  871 void
  872 RevScroll(XtermWidget xw, int amount)
  873 {
  874     TScreen *screen = TScreenOf(xw);
  875     int i = screen->bot_marg - screen->top_marg + 1;
  876     int left = ScrnLeftMargin(xw);
  877     int right = ScrnRightMargin(xw);
  878     Boolean scroll_full_line = ((left == 0) && (right == screen->max_col));
  879 
  880     TRACE(("RevScroll count=%d\n", amount));
  881 
  882     screen->cursor_busy += 1;
  883     screen->cursor_moved = True;
  884 
  885     if (screen->cursor_state)
  886     HideCursor(xw);
  887 
  888     if (amount > i)
  889     amount = i;
  890 
  891     if (ScrnHaveSelection(screen))
  892     adjustHiliteOnBakScroll(xw, amount);
  893 
  894     if (!scroll_full_line) {
  895     ;
  896     } else if (screen->jumpscroll) {
  897     if (screen->scroll_amt < 0) {
  898         if (-screen->refresh_amt + amount > i)
  899         FlushScroll(xw);
  900         screen->scroll_amt -= amount;
  901         screen->refresh_amt -= amount;
  902     } else {
  903         if (screen->scroll_amt > 0)
  904         FlushScroll(xw);
  905         screen->scroll_amt = -amount;
  906         screen->refresh_amt = -amount;
  907     }
  908     } else {
  909     int shift = INX2ROW(screen, 0);
  910     int bot = screen->max_row - shift;
  911     int refreshheight = amount;
  912     int refreshtop = screen->top_marg + shift;
  913     int scrollheight = (screen->bot_marg
  914                 - screen->top_marg - refreshheight + 1);
  915     int scrolltop = refreshtop + refreshheight;
  916 
  917     if ((i = screen->bot_marg - bot) > 0)
  918         scrollheight -= i;
  919     if ((i = screen->top_marg + refreshheight - 1 - bot) > 0)
  920         refreshheight -= i;
  921 
  922     if (screen->multiscroll && amount == 1 &&
  923         screen->topline == 0 && screen->top_marg == 0 &&
  924         screen->bot_marg == screen->max_row) {
  925         if (screen->incopy < 0 && screen->scrolls == 0)
  926         CopyWait(xw);
  927         screen->scrolls++;
  928     }
  929 
  930     vertical_copy_area(xw,
  931                scrolltop - amount,
  932                scrollheight,
  933                -amount,
  934                left,
  935                right);
  936 
  937     if (refreshheight > 0) {
  938         ClearCurBackground(xw,
  939                    refreshtop,
  940                    left,
  941                    (unsigned) refreshheight,
  942                    (unsigned) (right + 1 - left),
  943                    (unsigned) FontWidth(screen));
  944     }
  945     }
  946     if (amount > 0) {
  947     if (left > 0 || right < screen->max_col) {
  948         scrollInMargins(xw, -amount, screen->top_marg);
  949         ScrnUpdate2(xw,
  950             screen->top_marg,
  951             left,
  952             screen->bot_marg + 1 - screen->top_marg,
  953             right + 1 - left,
  954             True);
  955     } else {
  956         ScrnInsertLine(xw,
  957                screen->visbuf,
  958                screen->bot_marg,
  959                screen->top_marg,
  960                (unsigned) amount);
  961     }
  962     }
  963     screen->cursor_busy -= 1;
  964     return;
  965 }
  966 
  967 #if OPT_ZICONBEEP
  968 void
  969 initZIconBeep(void)
  970 {
  971     if (resource.zIconBeep > 100 || resource.zIconBeep < -100) {
  972     resource.zIconBeep = 0; /* was 100, but I prefer to defaulting off. */
  973     xtermWarning("a number between -100 and 100 is required for zIconBeep.  0 used by default\n");
  974     }
  975 }
  976 
  977 static char *
  978 getIconName(void)
  979 {
  980     static char *icon_name;
  981     static Arg args[] =
  982     {
  983     {XtNiconName, (XtArgVal) & icon_name}
  984     };
  985 
  986     icon_name = NULL;
  987     XtGetValues(toplevel, args, XtNumber(args));
  988     return icon_name;
  989 }
  990 
  991 static void
  992 setZIconBeep(XtermWidget xw)
  993 {
  994     TScreen *screen = TScreenOf(xw);
  995 
  996     /* Flag icon name with "***"  on window output when iconified.
  997      */
  998     if (resource.zIconBeep && mapstate == IsUnmapped && !screen->zIconBeep_flagged) {
  999     char *icon_name = getIconName();
 1000     if (icon_name != NULL) {
 1001         screen->zIconBeep_flagged = True;
 1002         ChangeIconName(xw, icon_name);
 1003     }
 1004     xtermBell(xw, XkbBI_Info, 0);
 1005     }
 1006     mapstate = -1;
 1007 }
 1008 
 1009 /*
 1010  * If warning should be given then give it
 1011  */
 1012 Boolean
 1013 showZIconBeep(XtermWidget xw, char *name)
 1014 {
 1015     Boolean code = False;
 1016 
 1017     if (resource.zIconBeep && TScreenOf(xw)->zIconBeep_flagged) {
 1018     char *format = resource.zIconFormat;
 1019     char *newname = malloc(strlen(name) + strlen(format) + 2);
 1020     if (!newname) {
 1021         xtermWarning("malloc failed in showZIconBeep\n");
 1022     } else {
 1023         char *marker = strstr(format, "%s");
 1024         char *result = newname;
 1025         if (marker != 0) {
 1026         size_t skip = (size_t) (marker - format);
 1027         if (skip) {
 1028             strncpy(result, format, skip);
 1029             result += skip;
 1030         }
 1031         strcpy(result, name);
 1032         strcat(result, marker + 2);
 1033         } else {
 1034         strcpy(result, format);
 1035         strcat(result, name);
 1036         }
 1037         ChangeGroup(xw, XtNiconName, newname);
 1038         free(newname);
 1039     }
 1040     code = True;
 1041     }
 1042     return code;
 1043 }
 1044 
 1045 /*
 1046  * Restore the icon name, resetting the state for zIconBeep.
 1047  */
 1048 void
 1049 resetZIconBeep(XtermWidget xw)
 1050 {
 1051     TScreen *screen = TScreenOf(xw);
 1052 
 1053     if (screen->zIconBeep_flagged) {
 1054     char *icon_name = getIconName();
 1055     screen->zIconBeep_flagged = False;
 1056     if (icon_name != NULL) {
 1057         char *buf = malloc(strlen(icon_name) + 1);
 1058         if (buf == NULL) {
 1059         screen->zIconBeep_flagged = True;
 1060         } else {
 1061         char *format = resource.zIconFormat;
 1062         char *marker = strstr(format, "%s");
 1063         Boolean found = False;
 1064 
 1065         if (marker != 0) {
 1066             if (marker == format
 1067             || !strncmp(icon_name, format, (size_t) (marker - format))) {
 1068             found = True;
 1069             strcpy(buf, icon_name + (marker - format));
 1070             marker += 2;
 1071             if (*marker != '\0') {
 1072                 size_t len_m = strlen(marker);
 1073                 size_t len_b = strlen(buf);
 1074                 if (len_m < len_b
 1075                 && !strcmp(buf + len_b - len_m, marker)) {
 1076                 buf[len_b - len_m] = '\0';
 1077                 }
 1078             }
 1079             }
 1080         } else if (!strncmp(icon_name, format, strlen(format))) {
 1081             strcpy(buf, icon_name + strlen(format));
 1082             found = True;
 1083         }
 1084         if (found)
 1085             ChangeIconName(xw, buf);
 1086         free(buf);
 1087         }
 1088     }
 1089     }
 1090 }
 1091 #else
 1092 #define setZIconBeep(xw)    /* nothing */
 1093 #endif /* OPT_ZICONBEEP */
 1094 
 1095 /*
 1096  * write a string str of length len onto the screen at
 1097  * the current cursor position.  update cursor position.
 1098  */
 1099 void
 1100 WriteText(XtermWidget xw, IChar *str, Cardinal len)
 1101 {
 1102     TScreen *screen = TScreenOf(xw);
 1103     XTermDraw params;
 1104     CLineData *ld = 0;
 1105     unsigned attr_flags = xw->flags;
 1106     CellColor fg_bg = xtermColorPair(xw);
 1107     unsigned cells = visual_width(str, len);
 1108     GC currentGC;
 1109 
 1110     TRACE(("WriteText %d (%2d,%2d) %3d:%s\n",
 1111        screen->topline,
 1112        screen->cur_row,
 1113        screen->cur_col,
 1114        len, visibleIChars(str, len)));
 1115 
 1116     if (cells + (unsigned) screen->cur_col > (unsigned) MaxCols(screen)) {
 1117     cells = (unsigned) (MaxCols(screen) - screen->cur_col);
 1118     }
 1119 
 1120     if (ScrnHaveSelection(screen)
 1121     && ScrnIsRowInSelection(screen, INX2ROW(screen, screen->cur_row))) {
 1122     ScrnDisownSelection(xw);
 1123     }
 1124 #if OPT_ISO_COLORS
 1125     /* if colorBDMode is set, and enabled */
 1126     if (screen->colorBDMode &&
 1127     screen->boldColors &&
 1128     !hasDirectFG(attr_flags) &&
 1129     /* and bold foreground color on bold background color */
 1130     GetCellColorFG(fg_bg) > COLOR_7 &&
 1131     GetCellColorFG(fg_bg) < MIN_ANSI_COLORS &&
 1132     /* and both colors are the same */
 1133     GetCellColorFG(fg_bg) == GetCellColorBG(fg_bg))
 1134     /* clear BOLD flag, else it will be colorBD on bold background color */
 1135     UIntClr(attr_flags, BOLD);
 1136 #endif
 1137 
 1138     /* if we are in insert-mode, reserve space for the new cells */
 1139     if (attr_flags & INSERT) {
 1140     InsertChar(xw, cells);
 1141     }
 1142 
 1143     if (AddToVisible(xw)
 1144     && ((ld = getLineData(screen, screen->cur_row))) != 0) {
 1145     unsigned test;
 1146 
 1147     if (screen->cursor_state)
 1148         HideCursor(xw);
 1149 
 1150     /*
 1151      * If we overwrite part of a multi-column character, fill the rest
 1152      * of it with blanks.
 1153      */
 1154     if_OPT_WIDE_CHARS(screen, {
 1155         int kl;
 1156         int kr;
 1157         if (DamagedCurCells(screen, cells, &kl, &kr))
 1158         ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
 1159     });
 1160 
 1161     if (attr_flags & INVISIBLE) {
 1162         Cardinal n;
 1163         for (n = 0; n < cells; ++n)
 1164         str[n] = ' ';
 1165     }
 1166 
 1167     TRACE(("WriteText calling drawXtermText (%d) (%d,%d)\n",
 1168            LineCharSet(screen, ld),
 1169            screen->cur_row,
 1170            screen->cur_col));
 1171 
 1172     test = attr_flags;
 1173 #if OPT_ISO_COLORS
 1174     {
 1175         int fg;
 1176         if (screen->colorAttrMode) {
 1177         fg = MapToColorMode(xw->cur_foreground, screen, attr_flags);
 1178         } else {
 1179         fg = xw->cur_foreground;
 1180         }
 1181         checkVeryBoldColors(test, fg);
 1182     }
 1183 #endif
 1184 
 1185     /* make sure that the correct GC is current */
 1186     currentGC = updatedXtermGC(xw, attr_flags, fg_bg, False);
 1187 
 1188     /* *INDENT-EQLS* */
 1189     params.xw          = xw;
 1190     params.attr_flags  = (test & DRAWX_MASK);
 1191     params.draw_flags  = 0;
 1192     params.this_chrset = LineCharSet(screen, ld);
 1193     params.real_chrset = CSET_SWL;
 1194     params.on_wide     = 0;
 1195 
 1196     drawXtermText(&params,
 1197               currentGC,
 1198               LineCursorX(screen, ld, screen->cur_col),
 1199               CursorY(screen, screen->cur_row),
 1200               str, len);
 1201 
 1202     resetXtermGC(xw, attr_flags, False);
 1203     }
 1204 
 1205     ScrnWriteText(xw, str, attr_flags, fg_bg, len);
 1206     CursorForward(xw, (int) cells);
 1207     setZIconBeep(xw);
 1208     return;
 1209 }
 1210 
 1211 /*
 1212  * If cursor not in scrolling region, returns.  Else,
 1213  * inserts n blank lines at the cursor's position.  Lines above the
 1214  * bottom margin are lost.
 1215  */
 1216 void
 1217 InsertLine(XtermWidget xw, int n)
 1218 {
 1219     TScreen *screen = TScreenOf(xw);
 1220     int i;
 1221     int left = ScrnLeftMargin(xw);
 1222     int right = ScrnRightMargin(xw);
 1223     Boolean scroll_full_line = ((left == 0) && (right == screen->max_col));
 1224 
 1225     if (!ScrnIsRowInMargins(screen, screen->cur_row)
 1226     || screen->cur_col < left
 1227     || screen->cur_col > right)
 1228     return;
 1229 
 1230     TRACE(("InsertLine count=%d\n", n));
 1231 
 1232     set_cur_col(screen, ScrnLeftMargin(xw));
 1233     if (screen->cursor_state)
 1234     HideCursor(xw);
 1235 
 1236     if (ScrnHaveSelection(screen)
 1237     && ScrnAreRowsInSelection(screen,
 1238                   INX2ROW(screen, screen->top_marg),
 1239                   INX2ROW(screen, screen->cur_row - 1))
 1240     && ScrnAreRowsInSelection(screen,
 1241                   INX2ROW(screen, screen->cur_row),
 1242                   INX2ROW(screen, screen->bot_marg))) {
 1243     ScrnDisownSelection(xw);
 1244     }
 1245 
 1246     ResetWrap(screen);
 1247     if (n > (i = screen->bot_marg - screen->cur_row + 1))
 1248     n = i;
 1249     if (screen->jumpscroll && scroll_full_line) {
 1250     if (screen->scroll_amt <= 0 &&
 1251         screen->cur_row <= -screen->refresh_amt) {
 1252         if (-screen->refresh_amt + n > MaxRows(screen))
 1253         FlushScroll(xw);
 1254         screen->scroll_amt -= n;
 1255         screen->refresh_amt -= n;
 1256     } else {
 1257         if (screen->scroll_amt)
 1258         FlushScroll(xw);
 1259     }
 1260     }
 1261     if (!screen->scroll_amt && scroll_full_line) {
 1262     int shift = INX2ROW(screen, 0);
 1263     int bot = screen->max_row - shift;
 1264     int refreshheight = n;
 1265     int refreshtop = screen->cur_row + shift;
 1266     int scrolltop = refreshtop + refreshheight;
 1267     int scrollheight = (screen->bot_marg
 1268                 - screen->cur_row - refreshheight + 1);
 1269 
 1270     if ((i = screen->bot_marg - bot) > 0)
 1271         scrollheight -= i;
 1272     if ((i = screen->cur_row + refreshheight - 1 - bot) > 0)
 1273         refreshheight -= i;
 1274     vertical_copy_area(xw, scrolltop - n, scrollheight, -n, left, right);
 1275     if (refreshheight > 0) {
 1276         ClearCurBackground(xw,
 1277                    refreshtop,
 1278                    left,
 1279                    (unsigned) refreshheight,
 1280                    (unsigned) (right + 1 - left),
 1281                    (unsigned) FontWidth(screen));
 1282     }
 1283     }
 1284     if (n > 0) {
 1285     if (scroll_full_line) {
 1286         ScrnInsertLine(xw,
 1287                screen->visbuf,
 1288                screen->bot_marg,
 1289                screen->cur_row,
 1290                (unsigned) n);
 1291     } else {
 1292         scrollInMargins(xw, -n, screen->cur_row);
 1293         ScrnUpdate2(xw,
 1294             screen->cur_row,
 1295             left,
 1296             screen->bot_marg + 1 - screen->cur_row,
 1297             right + 1 - left,
 1298             True);
 1299     }
 1300     }
 1301 }
 1302 
 1303 /*
 1304  * If cursor not in scrolling region, returns.  Else, deletes n lines
 1305  * at the cursor's position, lines added at bottom margin are blank.
 1306  */
 1307 void
 1308 DeleteLine(XtermWidget xw, int n)
 1309 {
 1310     TScreen *screen = TScreenOf(xw);
 1311     int i;
 1312     int left = ScrnLeftMargin(xw);
 1313     int right = ScrnRightMargin(xw);
 1314     Boolean scroll_all_lines = (Boolean) (screen->scrollWidget
 1315                       && !screen->whichBuf
 1316                       && screen->cur_row == 0);
 1317     Boolean scroll_full_line = ((left == 0) && (right == screen->max_col));
 1318 
 1319     if (!ScrnIsRowInMargins(screen, screen->cur_row) ||
 1320     !ScrnIsColInMargins(screen, screen->cur_col))
 1321     return;
 1322 
 1323     TRACE(("DeleteLine count=%d\n", n));
 1324 
 1325     set_cur_col(screen, ScrnLeftMargin(xw));
 1326     if (screen->cursor_state)
 1327     HideCursor(xw);
 1328 
 1329     if (n > (i = screen->bot_marg - screen->cur_row + 1)) {
 1330     n = i;
 1331     }
 1332     if (ScrnHaveSelection(screen)
 1333     && ScrnAreRowsInSelection(screen,
 1334                   INX2ROW(screen, screen->cur_row),
 1335                   INX2ROW(screen, screen->cur_row + n - 1))) {
 1336     ScrnDisownSelection(xw);
 1337     }
 1338 
 1339     ResetWrap(screen);
 1340     if (screen->jumpscroll && scroll_full_line) {
 1341     if (screen->scroll_amt >= 0 && screen->cur_row == screen->top_marg) {
 1342         if (screen->refresh_amt + n > MaxRows(screen))
 1343         FlushScroll(xw);
 1344         screen->scroll_amt += n;
 1345         screen->refresh_amt += n;
 1346     } else {
 1347         if (screen->scroll_amt)
 1348         FlushScroll(xw);
 1349     }
 1350     }
 1351 
 1352     /* adjust screen->buf */
 1353     if (n > 0) {
 1354     if (left > 0 || right < screen->max_col) {
 1355         scrollInMargins(xw, n, screen->cur_row);
 1356     } else if (scroll_all_lines) {
 1357         ScrnDeleteLine(xw,
 1358                screen->saveBuf_index,
 1359                screen->bot_marg + screen->savelines,
 1360                0,
 1361                (unsigned) n);
 1362     } else {
 1363         ScrnDeleteLine(xw,
 1364                screen->visbuf,
 1365                screen->bot_marg,
 1366                screen->cur_row,
 1367                (unsigned) n);
 1368     }
 1369     }
 1370 
 1371     /* repaint the screen, as needed */
 1372     if (!scroll_full_line) {
 1373     ScrnUpdate2(xw,
 1374             screen->cur_row,
 1375             left,
 1376             screen->bot_marg + 1 - screen->cur_row,
 1377             right + 1 - left,
 1378             True);
 1379     } else if (!screen->scroll_amt) {
 1380     int shift = INX2ROW(screen, 0);
 1381     int bot = screen->max_row - shift;
 1382     int refreshtop;
 1383     int refreshheight = n;
 1384     int scrolltop;
 1385     int scrollheight = i - n;
 1386 
 1387     if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
 1388         (i = screen->max_row - refreshheight + 1))
 1389         refreshtop = i;
 1390     if (scroll_all_lines) {
 1391         scrolltop = 0;
 1392         if ((scrollheight += shift) > i)
 1393         scrollheight = i;
 1394         if ((i = screen->savedlines) < screen->savelines) {
 1395         if ((i += n) > screen->savelines)
 1396             i = screen->savelines;
 1397         screen->savedlines = i;
 1398         ScrollBarDrawThumb(xw, 1);
 1399         }
 1400     } else {
 1401         scrolltop = screen->cur_row + shift;
 1402         if ((i = screen->bot_marg - bot) > 0) {
 1403         scrollheight -= i;
 1404         if ((i = screen->cur_row + n - 1 - bot) >= 0) {
 1405             refreshheight -= i;
 1406         }
 1407         }
 1408     }
 1409     vertical_copy_area(xw, scrolltop + n, scrollheight, n, left, right);
 1410     if (shift > 0 && refreshheight > 0) {
 1411         int rows = refreshheight;
 1412         if (rows > shift)
 1413         rows = shift;
 1414         ScrnUpdate(xw, refreshtop, 0, rows, MaxCols(screen), True);
 1415         refreshtop += shift;
 1416         refreshheight -= shift;
 1417     }
 1418     if (refreshheight > 0) {
 1419         ClearCurBackground(xw,
 1420                    refreshtop,
 1421                    left,
 1422                    (unsigned) refreshheight,
 1423                    (unsigned) (right + 1 - left),
 1424                    (unsigned) FontWidth(screen));
 1425     }
 1426     }
 1427 }
 1428 
 1429 /*
 1430  * Insert n blanks at the cursor's position, no wraparound
 1431  */
 1432 void
 1433 InsertChar(XtermWidget xw, unsigned n)
 1434 {
 1435     TScreen *screen = TScreenOf(xw);
 1436     CLineData *ld;
 1437     unsigned limit;
 1438     int row = INX2ROW(screen, screen->cur_row);
 1439     int left = ScrnLeftMargin(xw);
 1440     int right = ScrnRightMargin(xw);
 1441 
 1442     if (screen->cursor_state)
 1443     HideCursor(xw);
 1444 
 1445     TRACE(("InsertChar count=%d\n", n));
 1446 
 1447     if (ScrnHaveSelection(screen)
 1448     && ScrnIsRowInSelection(screen, row)) {
 1449     ScrnDisownSelection(xw);
 1450     }
 1451     ResetWrap(screen);
 1452 
 1453     limit = (unsigned) (right + 1 - screen->cur_col);
 1454 
 1455     if (n > limit)
 1456     n = limit;
 1457 
 1458     if (screen->cur_col < left || screen->cur_col > right) {
 1459     n = 0;
 1460     } else if (AddToVisible(xw)
 1461            && (ld = getLineData(screen, screen->cur_row)) != 0) {
 1462     int col = right + 1 - (int) n;
 1463 
 1464     /*
 1465      * If we shift part of a multi-column character, fill the rest
 1466      * of it with blanks.  Do similar repair for the text which will
 1467      * be shifted into the right-margin.
 1468      */
 1469     if_OPT_WIDE_CHARS(screen, {
 1470         int kl;
 1471         int kr = screen->cur_col;
 1472         if (DamagedCurCells(screen, n, &kl, (int *) 0) && kr > kl) {
 1473         ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
 1474         }
 1475         kr = screen->max_col - (int) n + 1;
 1476         if (DamagedCells(screen, n, &kl, (int *) 0,
 1477                  screen->cur_row,
 1478                  kr) && kr > kl) {
 1479         ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
 1480         }
 1481     });
 1482 
 1483 #if OPT_DEC_CHRSET
 1484     if (CSET_DOUBLE(GetLineDblCS(ld))) {
 1485         col = MaxCols(screen) / 2 - (int) n;
 1486     }
 1487 #endif
 1488     /*
 1489      * prevent InsertChar from shifting the end of a line over
 1490      * if it is being appended to
 1491      */
 1492     if (non_blank_line(screen, screen->cur_row,
 1493                screen->cur_col, MaxCols(screen))) {
 1494         horizontal_copy_area(xw, screen->cur_col,
 1495                  col - screen->cur_col,
 1496                  (int) n);
 1497     }
 1498 
 1499     ClearCurBackground(xw,
 1500                INX2ROW(screen, screen->cur_row),
 1501                screen->cur_col,
 1502                1U,
 1503                n,
 1504                (unsigned) LineFontWidth(screen, ld));
 1505     }
 1506     if (n != 0) {
 1507     /* adjust screen->buf */
 1508     ScrnInsertChar(xw, n);
 1509     }
 1510 }
 1511 
 1512 /*
 1513  * Deletes n chars at the cursor's position, no wraparound.
 1514  */
 1515 void
 1516 DeleteChar(XtermWidget xw, unsigned n)
 1517 {
 1518     TScreen *screen = TScreenOf(xw);
 1519     CLineData *ld;
 1520     unsigned limit;
 1521     int row = INX2ROW(screen, screen->cur_row);
 1522     int right = ScrnRightMargin(xw);
 1523 
 1524     if (screen->cursor_state)
 1525     HideCursor(xw);
 1526 
 1527     if (!ScrnIsColInMargins(screen, screen->cur_col))
 1528     return;
 1529 
 1530     TRACE(("DeleteChar count=%d\n", n));
 1531 
 1532     if (ScrnHaveSelection(screen)
 1533     && ScrnIsRowInSelection(screen, row)) {
 1534     ScrnDisownSelection(xw);
 1535     }
 1536     ResetWrap(screen);
 1537 
 1538     limit = (unsigned) (right + 1 - screen->cur_col);
 1539 
 1540     if (n > limit)
 1541     n = limit;
 1542 
 1543     if (AddToVisible(xw)
 1544     && (ld = getLineData(screen, screen->cur_row)) != 0) {
 1545     int col = right + 1 - (int) n;
 1546 
 1547     /*
 1548      * If we delete part of a multi-column character, fill the rest
 1549      * of it with blanks.
 1550      */
 1551     if_OPT_WIDE_CHARS(screen, {
 1552         int kl;
 1553         int kr;
 1554         if (DamagedCurCells(screen, n, &kl, &kr))
 1555         ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
 1556     });
 1557 
 1558 #if OPT_DEC_CHRSET
 1559     if (CSET_DOUBLE(GetLineDblCS(ld))) {
 1560         col = MaxCols(screen) / 2 - (int) n;
 1561     }
 1562 #endif
 1563     horizontal_copy_area(xw,
 1564                  (screen->cur_col + (int) n),
 1565                  col - screen->cur_col,
 1566                  -((int) n));
 1567 
 1568     ClearCurBackground(xw,
 1569                INX2ROW(screen, screen->cur_row),
 1570                col,
 1571                1U,
 1572                n,
 1573                (unsigned) LineFontWidth(screen, ld));
 1574     }
 1575     if (n != 0) {
 1576     /* adjust screen->buf */
 1577     ScrnDeleteChar(xw, n);
 1578     }
 1579 }
 1580 
 1581 /*
 1582  * Clear from cursor position to beginning of display, inclusive.
 1583  */
 1584 static void
 1585 ClearAbove(XtermWidget xw)
 1586 {
 1587     TScreen *screen = TScreenOf(xw);
 1588 
 1589     if (screen->protected_mode != OFF_PROTECT) {
 1590     int row;
 1591     unsigned len = (unsigned) MaxCols(screen);
 1592 
 1593     assert(screen->max_col >= 0);
 1594     for (row = 0; row < screen->cur_row; row++)
 1595         ClearInLine(xw, row, 0, len);
 1596     ClearInLine(xw, screen->cur_row, 0, (unsigned) screen->cur_col);
 1597     } else {
 1598     int top;
 1599 
 1600     if (screen->cursor_state)
 1601         HideCursor(xw);
 1602     if ((top = INX2ROW(screen, 0)) <= screen->max_row) {
 1603         int height;
 1604 
 1605         if (screen->scroll_amt)
 1606         FlushScroll(xw);
 1607         if ((height = screen->cur_row + top) > screen->max_row)
 1608         height = screen->max_row + 1;
 1609         if ((height -= top) > 0) {
 1610         chararea_clear_displayed_graphics(screen,
 1611                           0,
 1612                           top,
 1613                           MaxCols(screen),
 1614                           height);
 1615 
 1616         ClearCurBackground(xw,
 1617                    top,
 1618                    0,
 1619                    (unsigned) height,
 1620                    (unsigned) MaxCols(screen),
 1621                    (unsigned) FontWidth(screen));
 1622         }
 1623     }
 1624     ClearBufRows(xw, 0, screen->cur_row - 1);
 1625     }
 1626 
 1627     ClearLeft(xw);
 1628 }
 1629 
 1630 /*
 1631  * Clear from cursor position to end of display, inclusive.
 1632  */
 1633 static void
 1634 ClearBelow(XtermWidget xw)
 1635 {
 1636     TScreen *screen = TScreenOf(xw);
 1637 
 1638     ClearRight(xw, -1);
 1639 
 1640     if (screen->protected_mode != OFF_PROTECT) {
 1641     int row;
 1642     unsigned len = (unsigned) MaxCols(screen);
 1643 
 1644     assert(screen->max_col >= 0);
 1645     for (row = screen->cur_row + 1; row <= screen->max_row; row++)
 1646         ClearInLine(xw, row, 0, len);
 1647     } else {
 1648     int top;
 1649 
 1650     if ((top = INX2ROW(screen, screen->cur_row)) <= screen->max_row) {
 1651         if (screen->scroll_amt)
 1652         FlushScroll(xw);
 1653         if (++top <= screen->max_row) {
 1654         chararea_clear_displayed_graphics(screen,
 1655                           0,
 1656                           top,
 1657                           MaxCols(screen),
 1658                           (screen->max_row - top + 1));
 1659         ClearCurBackground(xw,
 1660                    top,
 1661                    0,
 1662                    (unsigned) (screen->max_row - top + 1),
 1663                    (unsigned) MaxCols(screen),
 1664                    (unsigned) FontWidth(screen));
 1665         }
 1666     }
 1667     ClearBufRows(xw, screen->cur_row + 1, screen->max_row);
 1668     }
 1669 }
 1670 
 1671 /*
 1672  * Clear the given row, for the given range of columns, returning 1 if no
 1673  * protected characters were found, 0 otherwise.
 1674  */
 1675 static int
 1676 ClearInLine2(XtermWidget xw, int flags, int row, int col, unsigned len)
 1677 {
 1678     TScreen *screen = TScreenOf(xw);
 1679     CLineData *ld;
 1680     int rc = 1;
 1681 
 1682     TRACE(("ClearInLine(row=%d, col=%d, len=%d) vs %d..%d\n",
 1683        row, col, len,
 1684        screen->startH.row,
 1685        screen->startH.col));
 1686 
 1687     if (ScrnHaveSelection(screen)
 1688     && ScrnIsRowInSelection(screen, row)) {
 1689     ScrnDisownSelection(xw);
 1690     }
 1691 
 1692     if (col + (int) len >= MaxCols(screen)) {
 1693     len = (unsigned) (MaxCols(screen) - col);
 1694     }
 1695 
 1696     /* If we've marked protected text on the screen, we'll have to
 1697      * check each time we do an erase.
 1698      */
 1699     if (screen->protected_mode != OFF_PROTECT) {
 1700     unsigned n;
 1701     IAttr *attrs = getLineData(screen, row)->attribs + col;
 1702     int saved_mode = screen->protected_mode;
 1703     Bool done;
 1704 
 1705     /* disable this branch during recursion */
 1706     screen->protected_mode = OFF_PROTECT;
 1707 
 1708     do {
 1709         done = True;
 1710         for (n = 0; n < len; n++) {
 1711         if (attrs[n] & PROTECTED) {
 1712             rc = 0; /* found a protected segment */
 1713             if (n != 0) {
 1714             ClearInLine(xw, row, col, n);
 1715             }
 1716             while ((n < len)
 1717                && (attrs[n] & PROTECTED)) {
 1718             n++;
 1719             }
 1720             done = False;
 1721             break;
 1722         }
 1723         }
 1724         /* setup for another segment, past the protected text */
 1725         if (!done) {
 1726         attrs += n;
 1727         col += (int) n;
 1728         len -= n;
 1729         }
 1730     } while (!done);
 1731 
 1732     screen->protected_mode = saved_mode;
 1733     if ((int) len <= 0) {
 1734         return 0;
 1735     }
 1736     }
 1737     /* fall through to the final non-protected segment */
 1738 
 1739     if (screen->cursor_state)
 1740     HideCursor(xw);
 1741     ResetWrap(screen);
 1742 
 1743     if (AddToVisible(xw)
 1744     && (ld = getLineData(screen, row)) != 0) {
 1745 
 1746     ClearCurBackground(xw,
 1747                INX2ROW(screen, row),
 1748                col,
 1749                1U,
 1750                len,
 1751                (unsigned) LineFontWidth(screen, ld));
 1752     }
 1753 
 1754     if (len != 0) {
 1755     ClearCells(xw, flags, len, row, col);
 1756     }
 1757 
 1758     return rc;
 1759 }
 1760 
 1761 int
 1762 ClearInLine(XtermWidget xw, int row, int col, unsigned len)
 1763 {
 1764     TScreen *screen = TScreenOf(xw);
 1765     int flags = 0;
 1766 
 1767     /*
 1768      * If we're clearing to the end of the line, we won't count this as
 1769      * "drawn" characters.  We'll only do cut/paste on "drawn" characters,
 1770      * so this has the effect of suppressing trailing blanks from a
 1771      * selection.
 1772      */
 1773     if (col + (int) len < MaxCols(screen)) {
 1774     flags |= CHARDRAWN;
 1775     }
 1776     return ClearInLine2(xw, flags, row, col, len);
 1777 }
 1778 
 1779 /*
 1780  * Clear the next n characters on the cursor's line, including the cursor's
 1781  * position.
 1782  */
 1783 void
 1784 ClearRight(XtermWidget xw, int n)
 1785 {
 1786     TScreen *screen = TScreenOf(xw);
 1787     LineData *ld;
 1788     unsigned len = (unsigned) (MaxCols(screen) - screen->cur_col);
 1789 
 1790     assert(screen->max_col >= 0);
 1791     assert(screen->max_col >= screen->cur_col);
 1792 
 1793     if (n < 0)          /* the remainder of the line */
 1794     n = MaxCols(screen);
 1795     if (n == 0)         /* default for 'ECH' */
 1796     n = 1;
 1797 
 1798     if (len > (unsigned) n)
 1799     len = (unsigned) n;
 1800 
 1801     ld = getLineData(screen, screen->cur_row);
 1802     if (AddToVisible(xw)) {
 1803     if_OPT_WIDE_CHARS(screen, {
 1804         int col = screen->cur_col;
 1805         int row = screen->cur_row;
 1806         int kl;
 1807         int kr;
 1808         if (DamagedCurCells(screen, len, &kl, &kr) && kr >= kl) {
 1809         int xx = col;
 1810         if (kl < xx) {
 1811             ClearInLine2(xw, 0, row, kl, (unsigned) (xx - kl));
 1812         }
 1813         xx = col + (int) len - 1;
 1814         if (kr > xx) {
 1815             ClearInLine2(xw, 0, row, xx + 1, (unsigned) (kr - xx));
 1816         }
 1817         }
 1818     });
 1819     (void) ClearInLine(xw, screen->cur_row, screen->cur_col, len);
 1820     } else {
 1821     ScrnClearCells(xw, screen->cur_row, screen->cur_col, len);
 1822     }
 1823 
 1824     /* with the right part cleared, we can't be wrapping */
 1825     LineClrWrapped(ld);
 1826     ShowWrapMarks(xw, screen->cur_row, ld);
 1827     ResetWrap(screen);
 1828 }
 1829 
 1830 /*
 1831  * Clear first part of cursor's line, inclusive.
 1832  */
 1833 static void
 1834 ClearLeft(XtermWidget xw)
 1835 {
 1836     TScreen *screen = TScreenOf(xw);
 1837     unsigned len = (unsigned) screen->cur_col + 1;
 1838 
 1839     assert(screen->cur_col >= 0);
 1840     if (AddToVisible(xw)) {
 1841     if_OPT_WIDE_CHARS(screen, {
 1842         int row = screen->cur_row;
 1843         int kl;
 1844         int kr;
 1845         if (DamagedCurCells(screen, 1, &kl, &kr) && kr >= kl) {
 1846         ClearInLine2(xw, 0, row, kl, (unsigned) (kr - kl + 1));
 1847         }
 1848     });
 1849     (void) ClearInLine(xw, screen->cur_row, 0, len);
 1850     } else {
 1851     ScrnClearCells(xw, screen->cur_row, 0, len);
 1852     }
 1853 }
 1854 
 1855 /*
 1856  * Erase the cursor's line.
 1857  */
 1858 static void
 1859 ClearLine(XtermWidget xw)
 1860 {
 1861     TScreen *screen = TScreenOf(xw);
 1862     unsigned len = (unsigned) MaxCols(screen);
 1863 
 1864     assert(screen->max_col >= 0);
 1865     (void) ClearInLine(xw, screen->cur_row, 0, len);
 1866 }
 1867 
 1868 void
 1869 ClearScreen(XtermWidget xw)
 1870 {
 1871     TScreen *screen = TScreenOf(xw);
 1872     int top;
 1873 
 1874     TRACE(("ClearScreen\n"));
 1875 
 1876     if (screen->cursor_state)
 1877     HideCursor(xw);
 1878 
 1879     ScrnDisownSelection(xw);
 1880     ResetWrap(screen);
 1881     if ((top = INX2ROW(screen, 0)) <= screen->max_row) {
 1882     if (screen->scroll_amt)
 1883         FlushScroll(xw);
 1884     chararea_clear_displayed_graphics(screen,
 1885                       0,
 1886                       top,
 1887                       MaxCols(screen),
 1888                       (screen->max_row - top + 1));
 1889     ClearCurBackground(xw,
 1890                top,
 1891                0,
 1892                (unsigned) (screen->max_row - top + 1),
 1893                (unsigned) MaxCols(screen),
 1894                (unsigned) FontWidth(screen));
 1895     }
 1896     ClearBufRows(xw, 0, screen->max_row);
 1897 }
 1898 
 1899 /*
 1900  * If we've written protected text DEC-style, and are issuing a non-DEC
 1901  * erase, temporarily reset the protected_mode flag so that the erase will
 1902  * ignore the protected flags.
 1903  */
 1904 void
 1905 do_erase_char(XtermWidget xw, int param, int mode)
 1906 {
 1907     TScreen *screen = TScreenOf(xw);
 1908     int saved_mode = screen->protected_mode;
 1909 
 1910     if (saved_mode == DEC_PROTECT
 1911     && saved_mode != mode) {
 1912     screen->protected_mode = OFF_PROTECT;
 1913     }
 1914 
 1915     ClearRight(xw, param);
 1916     screen->protected_mode = saved_mode;
 1917 }
 1918 
 1919 void
 1920 do_erase_line(XtermWidget xw, int param, int mode)
 1921 {
 1922     TScreen *screen = TScreenOf(xw);
 1923     int saved_mode = screen->protected_mode;
 1924 
 1925     if (saved_mode == DEC_PROTECT
 1926     && saved_mode != mode) {
 1927     screen->protected_mode = OFF_PROTECT;
 1928     }
 1929 
 1930     switch (param) {
 1931     case -1:            /* DEFAULT */
 1932     case 0:
 1933     ClearRight(xw, -1);
 1934     break;
 1935     case 1:
 1936     ClearLeft(xw);
 1937     break;
 1938     case 2:
 1939     ClearLine(xw);
 1940     break;
 1941     }
 1942     screen->protected_mode = saved_mode;
 1943 }
 1944 
 1945 /*
 1946  * Just like 'do_erase_line()', except that this intercepts ED controls.  If we
 1947  * clear the whole screen, we'll get the return-value from ClearInLine, and
 1948  * find if there were any protected characters left.  If not, reset the
 1949  * protected mode flag in the screen data (it's slower).
 1950  */
 1951 void
 1952 do_erase_display(XtermWidget xw, int param, int mode)
 1953 {
 1954     TScreen *screen = TScreenOf(xw);
 1955     int saved_mode = screen->protected_mode;
 1956 
 1957     if (saved_mode == DEC_PROTECT
 1958     && saved_mode != mode)
 1959     screen->protected_mode = OFF_PROTECT;
 1960 
 1961     switch (param) {
 1962     case -1:            /* DEFAULT */
 1963     case 0:
 1964     if (screen->cur_row == 0
 1965         && screen->cur_col == 0) {
 1966         screen->protected_mode = saved_mode;
 1967         do_erase_display(xw, 2, mode);
 1968         saved_mode = screen->protected_mode;
 1969     } else
 1970         ClearBelow(xw);
 1971     break;
 1972 
 1973     case 1:
 1974     if (screen->cur_row == screen->max_row
 1975         && screen->cur_col == screen->max_col) {
 1976         screen->protected_mode = saved_mode;
 1977         do_erase_display(xw, 2, mode);
 1978         saved_mode = screen->protected_mode;
 1979     } else
 1980         ClearAbove(xw);
 1981     break;
 1982 
 1983     case 2:
 1984     /*
 1985      * We use 'ClearScreen()' throughout the remainder of the
 1986      * program for places where we don't care if the characters are
 1987      * protected or not.  So we modify the logic around this call
 1988      * on 'ClearScreen()' to handle protected characters.
 1989      */
 1990     if (screen->protected_mode != OFF_PROTECT) {
 1991         int row;
 1992         int rc = 1;
 1993         unsigned len = (unsigned) MaxCols(screen);
 1994 
 1995         assert(screen->max_col >= 0);
 1996         for (row = 0; row <= screen->max_row; row++)
 1997         rc &= ClearInLine(xw, row, 0, len);
 1998         if (rc != 0)
 1999         saved_mode = OFF_PROTECT;
 2000     } else {
 2001         ClearScreen(xw);
 2002     }
 2003     break;
 2004 
 2005     case 3:
 2006     /* xterm addition - erase saved lines. */
 2007     if (screen->eraseSavedLines) {
 2008         screen->savedlines = 0;
 2009         ScrollBarDrawThumb(xw, 1);
 2010     }
 2011     break;
 2012     }
 2013     screen->protected_mode = saved_mode;
 2014 }
 2015 
 2016 static Boolean
 2017 screen_has_data(XtermWidget xw)
 2018 {
 2019     TScreen *screen = TScreenOf(xw);
 2020     Boolean result = False;
 2021     int row;
 2022 
 2023     for (row = 0; row < screen->max_row; ++row) {
 2024     CLineData *ld;
 2025 
 2026     if ((ld = getLineData(screen, row)) != 0) {
 2027         int col;
 2028 
 2029         for (col = 0; col < screen->max_col; ++col) {
 2030         if (ld->attribs[col] & CHARDRAWN) {
 2031             result = True;
 2032             break;
 2033         }
 2034         }
 2035     }
 2036     if (result)
 2037         break;
 2038     }
 2039     return result;
 2040 }
 2041 
 2042 /*
 2043  * Like tiXtraScroll, perform a scroll up of the page contents.  In this case,
 2044  * it happens for the special case when erasing the whole display starting from
 2045  * the upper-left corner of the screen.
 2046  */
 2047 void
 2048 do_cd_xtra_scroll(XtermWidget xw)
 2049 {
 2050     TScreen *screen = TScreenOf(xw);
 2051 
 2052     if (xw->misc.cdXtraScroll
 2053     && screen->cur_col == 0
 2054     && screen->cur_row == 0
 2055     && screen_has_data(xw)) {
 2056     xtermScroll(xw, screen->max_row);
 2057     }
 2058 }
 2059 
 2060 /*
 2061  * Scroll the page up (saving it).  This is called when doing terminal
 2062  * initialization (ti) or exiting from that (te).
 2063  */
 2064 void
 2065 do_ti_xtra_scroll(XtermWidget xw)
 2066 {
 2067     TScreen *screen = TScreenOf(xw);
 2068 
 2069     if (xw->misc.tiXtraScroll) {
 2070     xtermScroll(xw, screen->max_row);
 2071     }
 2072 }
 2073 
 2074 static void
 2075 CopyWait(XtermWidget xw)
 2076 {
 2077     TScreen *screen = TScreenOf(xw);
 2078     XEvent reply;
 2079     XEvent *rep = &reply;
 2080 #ifndef NO_ACTIVE_ICON
 2081     int retries = 0;
 2082 #endif
 2083 
 2084 #if USE_DOUBLE_BUFFER
 2085     if (resource.buffered)
 2086     return;
 2087 #endif
 2088 
 2089     for (;;) {
 2090 #ifndef NO_ACTIVE_ICON
 2091     if (xw->work.active_icon != eiFalse) {
 2092         /*
 2093          * The XWindowEvent call blocks until an event is available.  That
 2094          * can hang when using active-icon and iconifying/deiconifying
 2095          * while the terminal is receiving lots of output.  Checking with
 2096          * this call on the other hand may lose exposure events which
 2097          * arrive too late.  As a compromise, try several times with a
 2098          * time-delay before assuming no more events are available.
 2099          */
 2100         if (XCheckWindowEvent(screen->display,
 2101                   VWindow(screen),
 2102                   ExposureMask,
 2103                   &reply)) {
 2104         retries = 0;
 2105         } else {
 2106         if (++retries >= 1000)
 2107             return;
 2108         usleep(100U);   /* wait 0.1msec */
 2109         continue;
 2110         }
 2111     } else
 2112 #endif
 2113         XWindowEvent(screen->display, VWindow(screen), ExposureMask, &reply);
 2114     switch (reply.type) {
 2115     case Expose:
 2116         HandleExposure(xw, &reply);
 2117         break;
 2118     case NoExpose:
 2119     case GraphicsExpose:
 2120         if (screen->incopy <= 0) {
 2121         screen->incopy = 1;
 2122         if (screen->scrolls > 0)
 2123             screen->scrolls--;
 2124         }
 2125         if (reply.type == GraphicsExpose)
 2126         HandleExposure(xw, &reply);
 2127 
 2128         if ((reply.type == NoExpose) ||
 2129         ((XExposeEvent *) rep)->count == 0) {
 2130         if (screen->incopy <= 0 && screen->scrolls > 0)
 2131             screen->scrolls--;
 2132         if (screen->scrolls == 0) {
 2133             screen->incopy = 0;
 2134             return;
 2135         }
 2136         screen->incopy = -1;
 2137         }
 2138         break;
 2139     }
 2140     }
 2141 }
 2142 
 2143 /*
 2144  * used by vertical_copy_area and and horizontal_copy_area
 2145  */
 2146 static void
 2147 copy_area(XtermWidget xw,
 2148       int src_x,
 2149       int src_y,
 2150       unsigned width,
 2151       unsigned height,
 2152       int dest_x,
 2153       int dest_y)
 2154 {
 2155     TScreen *screen = TScreenOf(xw);
 2156 
 2157     if (width != 0 && height != 0) {
 2158     /* wait for previous CopyArea to complete unless
 2159        multiscroll is enabled and active */
 2160     if (screen->incopy && screen->scrolls == 0)
 2161         CopyWait(xw);
 2162     screen->incopy = -1;
 2163 
 2164     /* save for translating Expose events */
 2165     screen->copy_src_x = src_x;
 2166     screen->copy_src_y = src_y;
 2167     screen->copy_width = width;
 2168     screen->copy_height = height;
 2169     screen->copy_dest_x = dest_x;
 2170     screen->copy_dest_y = dest_y;
 2171 
 2172     XCopyArea(screen->display,
 2173           VDrawable(screen), VDrawable(screen),
 2174           NormalGC(xw, screen),
 2175           src_x, src_y, width, height, dest_x, dest_y);
 2176     }
 2177 }
 2178 
 2179 /*
 2180  * use when inserting or deleting characters on the current line
 2181  */
 2182 static void
 2183 horizontal_copy_area(XtermWidget xw,
 2184              int firstchar, /* char pos on screen to start copying at */
 2185              int nchars,
 2186              int amount)    /* number of characters to move right */
 2187 {
 2188     TScreen *screen = TScreenOf(xw);
 2189     CLineData *ld;
 2190 
 2191     if ((ld = getLineData(screen, screen->cur_row)) != 0) {
 2192     int src_x = LineCursorX(screen, ld, firstchar);
 2193     int src_y = CursorY(screen, screen->cur_row);
 2194 
 2195     copy_area(xw, src_x, src_y,
 2196           (unsigned) (nchars * LineFontWidth(screen, ld)),
 2197           (unsigned) FontHeight(screen),
 2198           src_x + amount * LineFontWidth(screen, ld), src_y);
 2199     }
 2200 }
 2201 
 2202 /*
 2203  * use when inserting or deleting lines from the screen
 2204  */
 2205 static void
 2206 vertical_copy_area(XtermWidget xw,
 2207            int firstline,   /* line on screen to start copying at */
 2208            int nlines,
 2209            int amount,  /* number of lines to move up (neg=down) */
 2210            int left,
 2211            int right)
 2212 {
 2213     TScreen *screen = TScreenOf(xw);
 2214 
 2215     TRACE(("vertical_copy_area - firstline=%d nlines=%d left=%d right=%d amount=%d\n",
 2216        firstline, nlines, left, right, amount));
 2217 
 2218     if (nlines > 0) {
 2219     int src_x = CursorX(screen, left);
 2220     int src_y = firstline * FontHeight(screen) + screen->border;
 2221     unsigned int w = (unsigned) ((right + 1 - left) * FontWidth(screen));
 2222     unsigned int h = (unsigned) (nlines * FontHeight(screen));
 2223     int dst_x = src_x;
 2224     int dst_y = src_y - amount * FontHeight(screen);
 2225 
 2226     copy_area(xw, src_x, src_y, w, h, dst_x, dst_y);
 2227 
 2228     if (screen->show_wrap_marks) {
 2229         int row;
 2230         int first = firstline - amount;
 2231         int last = firstline + nlines + amount;
 2232 
 2233         for (row = first; row < last; ++row) {
 2234         CLineData *ld;
 2235         int mapped = amount + row + screen->topline;
 2236 
 2237         if ((ld = getLineData(screen, mapped)) != 0) {
 2238             ShowWrapMarks(xw, row, ld);
 2239         }
 2240         }
 2241     }
 2242     }
 2243 }
 2244 
 2245 /*
 2246  * use when scrolling the entire screen
 2247  */
 2248 void
 2249 scrolling_copy_area(XtermWidget xw,
 2250             int firstline,  /* line on screen to start copying at */
 2251             int nlines,
 2252             int amount) /* number of lines to move up (neg=down) */
 2253 {
 2254 
 2255     if (nlines > 0) {
 2256     vertical_copy_area(xw, firstline, nlines, amount, 0, TScreenOf(xw)->max_col);
 2257     }
 2258 }
 2259 
 2260 /*
 2261  * Handler for Expose events on the VT widget.
 2262  * Returns 1 iff the area where the cursor was got refreshed.
 2263  */
 2264 int
 2265 HandleExposure(XtermWidget xw, XEvent *event)
 2266 {
 2267     TScreen *screen = TScreenOf(xw);
 2268     XExposeEvent *reply = (XExposeEvent *) event;
 2269 
 2270 #ifndef NO_ACTIVE_ICON
 2271     if (reply->window == screen->iconVwin.window) {
 2272     WhichVWin(screen) = &screen->iconVwin;
 2273     TRACE(("HandleExposure - icon\n"));
 2274     } else {
 2275     WhichVWin(screen) = &screen->fullVwin;
 2276     TRACE(("HandleExposure - normal\n"));
 2277     }
 2278     TRACE((" event %d,%d %dx%d\n",
 2279        reply->y,
 2280        reply->x,
 2281        reply->height,
 2282        reply->width));
 2283 #endif /* NO_ACTIVE_ICON */
 2284 
 2285     /* if not doing CopyArea or if this is a GraphicsExpose, don't translate */
 2286     if (!screen->incopy || event->type != Expose) {
 2287     return handle_translated_exposure(xw, reply->x, reply->y,
 2288                       reply->width,
 2289                       reply->height);
 2290     } else {
 2291     /* compute intersection of area being copied with
 2292        area being exposed. */
 2293     int both_x1 = Max(screen->copy_src_x, reply->x);
 2294     int both_y1 = Max(screen->copy_src_y, reply->y);
 2295     int both_x2 = Min(screen->copy_src_x + (int) screen->copy_width,
 2296               (reply->x + (int) reply->width));
 2297     int both_y2 = Min(screen->copy_src_y + (int) screen->copy_height,
 2298               (reply->y + (int) reply->height));
 2299     int value = 0;
 2300 
 2301     /* was anything copied affected? */
 2302     if (both_x2 > both_x1 && both_y2 > both_y1) {
 2303         /* do the copied area */
 2304         value = handle_translated_exposure
 2305         (xw, reply->x + screen->copy_dest_x - screen->copy_src_x,
 2306          reply->y + screen->copy_dest_y - screen->copy_src_y,
 2307          reply->width, reply->height);
 2308     }
 2309     /* was anything not copied affected? */
 2310     if (reply->x < both_x1 || reply->y < both_y1
 2311         || reply->x + reply->width > both_x2
 2312         || reply->y + reply->height > both_y2)
 2313         value = handle_translated_exposure(xw, reply->x, reply->y,
 2314                            reply->width, reply->height);
 2315 
 2316     return value;
 2317     }
 2318 }
 2319 
 2320 static void
 2321 set_background(XtermWidget xw, int color)
 2322 {
 2323     TScreen *screen = TScreenOf(xw);
 2324     Pixel c = getXtermBG(xw, xw->flags, color);
 2325 
 2326 #if OPT_WIDE_ATTRS
 2327     TRACE(("set_background(%d) %#lx %s\n", color, c,
 2328        ((xw->flags & ATR_DIRECT_BG)
 2329         ? "direct"
 2330         : "indexed")));
 2331 #else
 2332     TRACE(("set_background(%d) %#lx\n", color, c));
 2333 #endif
 2334     XSetWindowBackground(screen->display, VShellWindow(xw), c);
 2335     XSetWindowBackground(screen->display, VWindow(screen), c);
 2336     initBorderGC(xw, WhichVWin(screen));
 2337 }
 2338 
 2339 void
 2340 xtermClear2(XtermWidget xw, int x, int y, unsigned width, unsigned height)
 2341 {
 2342     TScreen *screen = TScreenOf(xw);
 2343     VTwin *vwin = WhichVWin(screen);
 2344     Drawable draw = VDrawable(screen);
 2345     GC gc;
 2346 
 2347     if ((gc = vwin->border_gc) != 0) {
 2348     int vmark1 = screen->border;
 2349     int vmark2 = vwin->height + vmark1;
 2350     int hmark1 = OriginX(screen);
 2351     int hmark2 = vwin->width + hmark1;
 2352     if (y < vmark1) {
 2353         int yy = y + (int) height;
 2354         int h1 = (yy <= vmark1) ? (yy - y) : (vmark1 - y);
 2355         XFillRectangle(screen->display, draw, gc,
 2356                x, y, width, (unsigned) h1);
 2357         if (yy > vmark1) {
 2358         xtermClear2(xw, x, vmark1, width, (unsigned) (yy - vmark1));
 2359         }
 2360     } else if (y < vmark2) {
 2361         int yy = y + (int) height;
 2362         int h2 = (yy <= vmark2) ? (yy - y) : (vmark2 - y);
 2363         int xb = x;
 2364         int xx = x + (int) width;
 2365         int ww = (int) width;
 2366         if (x < hmark1) {
 2367         int w1 = (xx <= hmark1) ? (xx - x) : (hmark1 - x);
 2368         XFillRectangle(screen->display, draw, gc,
 2369                    x, y, (unsigned) w1, (unsigned) h2);
 2370         x += w1;
 2371         ww -= w1;
 2372         }
 2373         if ((ww > 0) && (x < hmark2)) {
 2374         int w2 = (xx <= hmark2) ? (xx - x) : (hmark2 - x);
 2375 #if USE_DOUBLE_BUFFER
 2376         if (resource.buffered) {
 2377             XFillRectangle(screen->display, draw,
 2378                    FillerGC(xw, screen),
 2379                    x, y, (unsigned) w2, (unsigned) h2);
 2380         } else
 2381 #endif
 2382             XClearArea(screen->display, VWindow(screen),
 2383                    x, y, (unsigned) w2, (unsigned) h2, False);
 2384         x += w2;
 2385         ww -= w2;
 2386         }
 2387         if (ww > 0) {
 2388         XFillRectangle(screen->display, draw, gc,
 2389                    x, y, (unsigned) ww, (unsigned) h2);
 2390         }
 2391         if (yy > vmark2) {
 2392         xtermClear2(xw, xb, vmark2, width, (unsigned) (yy - vmark2));
 2393         }
 2394     } else {
 2395         XFillRectangle(screen->display, draw, gc, x, y, width, height);
 2396     }
 2397     } else {
 2398 #if USE_DOUBLE_BUFFER
 2399     if (resource.buffered) {
 2400         gc = FillerGC(xw, screen);
 2401         XFillRectangle(screen->display, draw, gc,
 2402                x, y, width, height);
 2403     } else
 2404 #endif
 2405         XClearArea(screen->display,
 2406                VWindow(screen),
 2407                x, y, width, height, False);
 2408     }
 2409 }
 2410 
 2411 /*
 2412  * Called by the ExposeHandler to do the actual repaint after the coordinates
 2413  * have been translated to allow for any CopyArea in progress.
 2414  * The rectangle passed in is pixel coordinates.
 2415  */
 2416 static int
 2417 handle_translated_exposure(XtermWidget xw,
 2418                int rect_x,
 2419                int rect_y,
 2420                int rect_width,
 2421                int rect_height)
 2422 {
 2423     TScreen *screen = TScreenOf(xw);
 2424     int toprow, leftcol, nrows, ncols;
 2425     int x0, x1;
 2426     int y0, y1;
 2427     int result = 0;
 2428 
 2429     TRACE(("handle_translated_exposure at %d,%d size %dx%d\n",
 2430        rect_y, rect_x, rect_height, rect_width));
 2431 
 2432     x0 = (rect_x - OriginX(screen));
 2433     x1 = (x0 + rect_width);
 2434 
 2435     y0 = (rect_y - OriginY(screen));
 2436     y1 = (y0 + rect_height);
 2437 
 2438     if ((x0 < 0 ||
 2439      y0 < 0 ||
 2440      x1 > Width(screen) ||
 2441      y1 > Height(screen))) {
 2442     set_background(xw, -1);
 2443     xtermClear2(xw,
 2444             rect_x,
 2445             rect_y,
 2446             (unsigned) rect_width,
 2447             (unsigned) rect_height);
 2448     }
 2449     toprow = y0 / FontHeight(screen);
 2450     if (toprow < 0)
 2451     toprow = 0;
 2452 
 2453     leftcol = x0 / FontWidth(screen);
 2454     if (leftcol < 0)
 2455     leftcol = 0;
 2456 
 2457     nrows = (y1 - 1) / FontHeight(screen) - toprow + 1;
 2458     ncols = (x1 - 1) / FontWidth(screen) - leftcol + 1;
 2459     toprow -= screen->scrolls;
 2460     if (toprow < 0) {
 2461     nrows += toprow;
 2462     toprow = 0;
 2463     }
 2464     if (toprow + nrows > MaxRows(screen))
 2465     nrows = MaxRows(screen) - toprow;
 2466     if (leftcol + ncols > MaxCols(screen))
 2467     ncols = MaxCols(screen) - leftcol;
 2468 
 2469     if (nrows > 0 && ncols > 0) {
 2470     ScrnRefresh(xw, toprow, leftcol, nrows, ncols, True);
 2471     first_map_occurred();
 2472     if (screen->cur_row >= toprow &&
 2473         screen->cur_row < toprow + nrows &&
 2474         screen->cur_col >= leftcol &&
 2475         screen->cur_col < leftcol + ncols) {
 2476         result = 1;
 2477     }
 2478 
 2479     }
 2480     TRACE(("...handle_translated_exposure %d\n", result));
 2481     return (result);
 2482 }
 2483 
 2484 /***====================================================================***/
 2485 
 2486 void
 2487 GetColors(XtermWidget xw, ScrnColors * pColors)
 2488 {
 2489     TScreen *screen = TScreenOf(xw);
 2490     int n;
 2491 
 2492     pColors->which = 0;
 2493     for (n = 0; n < NCOLORS; ++n) {
 2494     SET_COLOR_VALUE(pColors, n, T_COLOR(screen, n));
 2495     }
 2496 }
 2497 
 2498 void
 2499 ChangeColors(XtermWidget xw, ScrnColors * pNew)
 2500 {
 2501     Bool repaint = False;
 2502     TScreen *screen = TScreenOf(xw);
 2503     VTwin *win = WhichVWin(screen);
 2504 
 2505     TRACE(("ChangeColors\n"));
 2506 
 2507     if (COLOR_DEFINED(pNew, TEXT_CURSOR)) {
 2508     T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_CURSOR);
 2509     TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR)));
 2510     FreeMarkGCs(xw);
 2511     /* no repaint needed */
 2512     } else if ((T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) &&
 2513            (COLOR_DEFINED(pNew, TEXT_FG))) {
 2514     if (T_COLOR(screen, TEXT_CURSOR) != COLOR_VALUE(pNew, TEXT_FG)) {
 2515         T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_FG);
 2516         TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR)));
 2517         if (screen->Vshow)
 2518         repaint = True;
 2519     }
 2520     FreeMarkGCs(xw);
 2521     }
 2522 
 2523     if (COLOR_DEFINED(pNew, TEXT_FG)) {
 2524     Pixel fg = COLOR_VALUE(pNew, TEXT_FG);
 2525     T_COLOR(screen, TEXT_FG) = fg;
 2526     TRACE(("... TEXT_FG: %#lx\n", T_COLOR(screen, TEXT_FG)));
 2527     if (screen->Vshow) {
 2528         setCgsFore(xw, win, gcNorm, fg);
 2529         setCgsBack(xw, win, gcNormReverse, fg);
 2530         setCgsFore(xw, win, gcBold, fg);
 2531         setCgsBack(xw, win, gcBoldReverse, fg);
 2532         repaint = True;
 2533     }
 2534     FreeMarkGCs(xw);
 2535     }
 2536 
 2537     if (COLOR_DEFINED(pNew, TEXT_BG)) {
 2538     Pixel bg = COLOR_VALUE(pNew, TEXT_BG);
 2539     T_COLOR(screen, TEXT_BG) = bg;
 2540     TRACE(("... TEXT_BG: %#lx\n", T_COLOR(screen, TEXT_BG)));
 2541     if (screen->Vshow) {
 2542         setCgsBack(xw, win, gcNorm, bg);
 2543         setCgsFore(xw, win, gcNormReverse, bg);
 2544         setCgsBack(xw, win, gcBold, bg);
 2545         setCgsFore(xw, win, gcBoldReverse, bg);
 2546         set_background(xw, -1);
 2547         repaint = True;
 2548     }
 2549     }
 2550 #if OPT_HIGHLIGHT_COLOR
 2551     if (COLOR_DEFINED(pNew, HIGHLIGHT_BG)) {
 2552     if (T_COLOR(screen, HIGHLIGHT_BG) != COLOR_VALUE(pNew, HIGHLIGHT_BG)) {
 2553         T_COLOR(screen, HIGHLIGHT_BG) = COLOR_VALUE(pNew, HIGHLIGHT_BG);
 2554         TRACE(("... HIGHLIGHT_BG: %#lx\n", T_COLOR(screen, HIGHLIGHT_BG)));
 2555         if (screen->Vshow)
 2556         repaint = True;
 2557     }
 2558     }
 2559     if (COLOR_DEFINED(pNew, HIGHLIGHT_FG)) {
 2560     if (T_COLOR(screen, HIGHLIGHT_FG) != COLOR_VALUE(pNew, HIGHLIGHT_FG)) {
 2561         T_COLOR(screen, HIGHLIGHT_FG) = COLOR_VALUE(pNew, HIGHLIGHT_FG);
 2562         TRACE(("... HIGHLIGHT_FG: %#lx\n", T_COLOR(screen, HIGHLIGHT_FG)));
 2563         if (screen->Vshow)
 2564         repaint = True;
 2565     }
 2566     }
 2567 #endif
 2568 
 2569     if (COLOR_DEFINED(pNew, MOUSE_FG) || (COLOR_DEFINED(pNew, MOUSE_BG))) {
 2570     if (COLOR_DEFINED(pNew, MOUSE_FG)) {
 2571         T_COLOR(screen, MOUSE_FG) = COLOR_VALUE(pNew, MOUSE_FG);
 2572         TRACE(("... MOUSE_FG: %#lx\n", T_COLOR(screen, MOUSE_FG)));
 2573     }
 2574     if (COLOR_DEFINED(pNew, MOUSE_BG)) {
 2575         T_COLOR(screen, MOUSE_BG) = COLOR_VALUE(pNew, MOUSE_BG);
 2576         TRACE(("... MOUSE_BG: %#lx\n", T_COLOR(screen, MOUSE_BG)));
 2577     }
 2578 
 2579     if (screen->Vshow) {
 2580         recolor_cursor(screen,
 2581                screen->pointer_cursor,
 2582                T_COLOR(screen, MOUSE_FG),
 2583                T_COLOR(screen, MOUSE_BG));
 2584         XDefineCursor(screen->display, VWindow(screen),
 2585               screen->pointer_cursor);
 2586     }
 2587 #if OPT_TEK4014
 2588     if (TEK4014_SHOWN(xw)) {
 2589         TekScreen *tekscr = TekScreenOf(tekWidget);
 2590         Window tekwin = TWindow(tekscr);
 2591         if (tekwin) {
 2592         recolor_cursor(screen,
 2593                    tekscr->arrow,
 2594                    T_COLOR(screen, MOUSE_FG),
 2595                    T_COLOR(screen, MOUSE_BG));
 2596         XDefineCursor(screen->display, tekwin, tekscr->arrow);
 2597         }
 2598     }
 2599 #endif
 2600     /* no repaint needed */
 2601     }
 2602 
 2603     if (COLOR_DEFINED(pNew, TEXT_FG) ||
 2604     COLOR_DEFINED(pNew, TEXT_BG) ||
 2605     COLOR_DEFINED(pNew, TEXT_CURSOR)) {
 2606     if (set_cursor_gcs(xw) && screen->Vshow) {
 2607         repaint = True;
 2608     }
 2609     }
 2610 #if OPT_TEK4014
 2611     if (COLOR_DEFINED(pNew, TEK_FG) ||
 2612     COLOR_DEFINED(pNew, TEK_BG)) {
 2613     ChangeTekColors(tekWidget, screen, pNew);
 2614     if (TEK4014_SHOWN(xw)) {
 2615         TekRepaint(tekWidget);
 2616     }
 2617     } else if (COLOR_DEFINED(pNew, TEK_CURSOR)) {
 2618     ChangeTekColors(tekWidget, screen, pNew);
 2619     }
 2620 #endif
 2621     if (repaint)
 2622     xtermRepaint(xw);
 2623 }
 2624 
 2625 void
 2626 xtermClear(XtermWidget xw)
 2627 {
 2628     TScreen *screen = TScreenOf(xw);
 2629 
 2630     TRACE(("xtermClear\n"));
 2631     xtermClear2(xw, 0, 0, FullWidth(screen), FullHeight(screen));
 2632 }
 2633 
 2634 void
 2635 xtermRepaint(XtermWidget xw)
 2636 {
 2637     TScreen *screen = TScreenOf(xw);
 2638 
 2639     TRACE(("xtermRepaint\n"));
 2640     xtermClear(xw);
 2641     ScrnRefresh(xw, 0, 0, MaxRows(screen), MaxCols(screen), True);
 2642 }
 2643 
 2644 /***====================================================================***/
 2645 
 2646 Boolean
 2647 isDefaultForeground(const char *name)
 2648 {
 2649     return (Boolean) !x_strcasecmp(name, XtDefaultForeground);
 2650 }
 2651 
 2652 Boolean
 2653 isDefaultBackground(const char *name)
 2654 {
 2655     return (Boolean) !x_strcasecmp(name, XtDefaultBackground);
 2656 }
 2657 
 2658 #if OPT_WIDE_CHARS
 2659 /*
 2660  * Check for Unicode BIDI control characters, which may be miscategorized via
 2661  * wcwidth() and iswprint() as zero-width printable characters.
 2662  */
 2663 Boolean
 2664 isWideControl(unsigned ch)
 2665 {
 2666     Boolean result;
 2667 
 2668     switch (ch) {
 2669     case 0x200E:
 2670     case 0x200F:
 2671     case 0x202A:
 2672     case 0x202B:
 2673     case 0x202C:
 2674     case 0x202D:
 2675     case 0x202E:
 2676     result = True;
 2677     break;
 2678     default:
 2679     result = False;
 2680     break;
 2681     }
 2682     return result;
 2683 }
 2684 #endif
 2685 
 2686 /***====================================================================***/
 2687 
 2688 typedef struct {
 2689     Pixel fg;
 2690     Pixel bg;
 2691 } ToSwap;
 2692 
 2693 #if OPT_HIGHLIGHT_COLOR
 2694 #define hc_param ,Bool hilite_color
 2695 #define hc_value ,screen->hilite_color
 2696 #else
 2697 #define hc_param        /* nothing */
 2698 #define hc_value        /* nothing */
 2699 #endif
 2700 
 2701 /*
 2702  * Use this to swap the foreground/background color values in the resource
 2703  * data, and to build up a list of the pairs which must be swapped in the
 2704  * GC cache.
 2705  */
 2706 static void
 2707 swapLocally(ToSwap * list, int *count, ColorRes * fg, ColorRes * bg hc_param)
 2708 {
 2709     ColorRes tmp;
 2710     Boolean found = False;
 2711 
 2712 #if OPT_COLOR_RES
 2713     Pixel fg_color = fg->value;
 2714     Pixel bg_color = bg->value;
 2715 #else
 2716     Pixel fg_color = *fg;
 2717     Pixel bg_color = *bg;
 2718 #endif
 2719 
 2720 #if OPT_HIGHLIGHT_COLOR
 2721     if ((fg_color != bg_color) || !hilite_color)
 2722 #endif
 2723     {
 2724     int n;
 2725 
 2726     EXCHANGE(*fg, *bg, tmp);
 2727     for (n = 0; n < *count; ++n) {
 2728         if ((list[n].fg == fg_color && list[n].bg == bg_color)
 2729         || (list[n].fg == bg_color && list[n].bg == fg_color)) {
 2730         found = True;
 2731         break;
 2732         }
 2733     }
 2734     if (!found) {
 2735         list[*count].fg = fg_color;
 2736         list[*count].bg = bg_color;
 2737         *count = *count + 1;
 2738         TRACE(("swapLocally fg %#lx, bg %#lx ->%d\n",
 2739            fg_color, bg_color, *count));
 2740     }
 2741     }
 2742 }
 2743 
 2744 static void
 2745 reallySwapColors(XtermWidget xw, ToSwap * list, int count)
 2746 {
 2747     int j, k;
 2748 
 2749     TRACE(("reallySwapColors\n"));
 2750     for (j = 0; j < count; ++j) {
 2751     for_each_text_gc(k) {
 2752         redoCgs(xw, list[j].fg, list[j].bg, (CgsEnum) k);
 2753     }
 2754     }
 2755     FreeMarkGCs(xw);
 2756 }
 2757 
 2758 static void
 2759 swapVTwinGCs(XtermWidget xw, VTwin *win)
 2760 {
 2761     swapCgs(xw, win, gcNorm, gcNormReverse);
 2762     swapCgs(xw, win, gcBold, gcBoldReverse);
 2763 }
 2764 
 2765 void
 2766 ReverseVideo(XtermWidget xw)
 2767 {
 2768     TScreen *screen = TScreenOf(xw);
 2769     ToSwap listToSwap[5];
 2770     int numToSwap = 0;
 2771 
 2772     TRACE(("ReverseVideo now %s\n", BtoS(xw->misc.re_verse)));
 2773 
 2774     /*
 2775      * Swap SGR foreground and background colors.  By convention, these are
 2776      * the colors assigned to "black" (SGR #0) and "white" (SGR #7).  Also,
 2777      * SGR #8 and SGR #15 are the bold (or bright) versions of SGR #0 and
 2778      * #7, respectively.
 2779      *
 2780      * We don't swap colors that happen to match the screen's foreground
 2781      * and background because that tends to produce bizarre effects.
 2782      */
 2783 #define swapAnyColor(name,a,b) swapLocally(listToSwap, &numToSwap, &(screen->name[a]), &(screen->name[b]) hc_value)
 2784 #define swapAColor(a,b) swapAnyColor(Acolors, a, b)
 2785     if_OPT_ISO_COLORS(screen, {
 2786     swapAColor(0, 7);
 2787     swapAColor(8, 15);
 2788     });
 2789 
 2790     if (T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) {
 2791     T_COLOR(screen, TEXT_CURSOR) = T_COLOR(screen, TEXT_BG);
 2792     }
 2793 #define swapTColor(a,b) swapAnyColor(Tcolors, a, b)
 2794     swapTColor(TEXT_FG, TEXT_BG);
 2795     swapTColor(MOUSE_FG, MOUSE_BG);
 2796 
 2797     reallySwapColors(xw, listToSwap, numToSwap);
 2798 
 2799     swapVTwinGCs(xw, &(screen->fullVwin));
 2800 #ifndef NO_ACTIVE_ICON
 2801     swapVTwinGCs(xw, &(screen->iconVwin));
 2802 #endif /* NO_ACTIVE_ICON */
 2803 
 2804     xw->misc.re_verse = (Boolean) !xw->misc.re_verse;
 2805     TRACE(("...swapping done, set ReverseVideo %s\n", BtoS(xw->misc.re_verse)));
 2806 
 2807     if (XtIsRealized((Widget) xw)) {
 2808     xtermDisplayPointer(xw);
 2809     }
 2810 #if OPT_TEK4014
 2811     if (TEK4014_SHOWN(xw)) {
 2812     TekScreen *tekscr = TekScreenOf(tekWidget);
 2813     Window tekwin = TWindow(tekscr);
 2814     recolor_cursor(screen,
 2815                tekscr->arrow,
 2816                T_COLOR(screen, MOUSE_FG),
 2817                T_COLOR(screen, MOUSE_BG));
 2818     XDefineCursor(screen->display, tekwin, tekscr->arrow);
 2819     }
 2820 #endif
 2821 
 2822     if (screen->scrollWidget)
 2823     ScrollBarReverseVideo(screen->scrollWidget);
 2824 
 2825     if (XtIsRealized((Widget) xw)) {
 2826     set_background(xw, -1);
 2827     }
 2828 #if OPT_TEK4014
 2829     TekReverseVideo(xw, tekWidget);
 2830 #endif
 2831     if (XtIsRealized((Widget) xw)) {
 2832     xtermRepaint(xw);
 2833     }
 2834 #if OPT_TEK4014
 2835     if (TEK4014_SHOWN(xw)) {
 2836     TekRepaint(tekWidget);
 2837     }
 2838 #endif
 2839     ReverseOldColors(xw);
 2840     set_cursor_gcs(xw);
 2841     update_reversevideo();
 2842     TRACE(("...ReverseVideo now %s\n", BtoS(xw->misc.re_verse)));
 2843 }
 2844 
 2845 void
 2846 recolor_cursor(TScreen *screen,
 2847            Cursor cursor,   /* X cursor ID to set */
 2848            unsigned long fg,    /* pixel indexes to look up */
 2849            unsigned long bg)    /* pixel indexes to look up */
 2850 {
 2851     Display *dpy = screen->display;
 2852     XColor colordefs[2];    /* 0 is foreground, 1 is background */
 2853 
 2854     colordefs[0].pixel = fg;
 2855     colordefs[1].pixel = bg;
 2856     XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),
 2857          colordefs, 2);
 2858     XRecolorCursor(dpy, cursor, colordefs, colordefs + 1);
 2859     cleanup_colored_cursor();
 2860     return;
 2861 }
 2862 
 2863 #if OPT_RENDERFONT
 2864 #define XFT_CACHE_LIMIT ((unsigned)(~0) >> 1)
 2865 #define XFT_CACHE_SIZE  16
 2866 typedef struct {
 2867     XftColor color;
 2868     unsigned use;
 2869 } XftColorCache;
 2870 
 2871 static int
 2872 compare_xft_color_cache(const void *a, const void *b)
 2873 {
 2874     return (int) (((const XftColorCache *) a)->use -
 2875           ((const XftColorCache *) b)->use);
 2876 }
 2877 
 2878 static XftColor *
 2879 getXftColor(XtermWidget xw, Pixel pixel)
 2880 {
 2881     static XftColorCache cache[XFT_CACHE_SIZE + 1];
 2882     static unsigned latest_use;
 2883     int i;
 2884     int oldest;
 2885     unsigned oldest_use;
 2886     XColor color;
 2887     Boolean found = False;
 2888 
 2889     oldest_use = XFT_CACHE_LIMIT;
 2890     oldest = 0;
 2891     if (latest_use == XFT_CACHE_LIMIT) {
 2892     latest_use = 0;
 2893     qsort(cache, (size_t) XFT_CACHE_SIZE, sizeof(XftColorCache), compare_xft_color_cache);
 2894     for (i = 0; i < XFT_CACHE_SIZE; i++) {
 2895         if (cache[i].use) {
 2896         cache[i].use = ++latest_use;
 2897         }
 2898     }
 2899     }
 2900     for (i = 0; i < XFT_CACHE_SIZE; i++) {
 2901     if (cache[i].use) {
 2902         if (cache[i].color.pixel == pixel) {
 2903         found = True;
 2904         break;
 2905         }
 2906     }
 2907     if (cache[i].use < oldest_use) {
 2908         oldest_use = cache[i].use;
 2909         oldest = i;
 2910     }
 2911     }
 2912     if (!found) {
 2913     i = oldest;
 2914     color.pixel = pixel;
 2915     XQueryColor(TScreenOf(xw)->display, xw->core.colormap, &color);
 2916     cache[i].color.color.red = color.red;
 2917     cache[i].color.color.green = color.green;
 2918     cache[i].color.color.blue = color.blue;
 2919     cache[i].color.color.alpha = 0xffff;
 2920     cache[i].color.pixel = pixel;
 2921     }
 2922     cache[i].use = ++latest_use;
 2923     return &cache[i].color;
 2924 }
 2925 
 2926 /*
 2927  * The cell-width is related to, but not the same as the wide-character width.
 2928  * We will only get useful values from wcwidth() for codes above 255.
 2929  * Otherwise, interpret according to internal data.
 2930  */
 2931 #if OPT_RENDERWIDE
 2932 
 2933 #if OPT_C1_PRINT
 2934 #define XtermCellWidth(xw, ch) \
 2935     (((ch) == 0 || (ch) == 127) \
 2936       ? 0 \
 2937       : (((ch) < 256) \
 2938           ? (((ch) >= 128 && (ch) < 160) \
 2939           ? (TScreenOf(xw)->c1_printable ? 1 : 0) \
 2940           : 1) \
 2941           : CharWidth(ch)))
 2942 #else
 2943 #define XtermCellWidth(xw, ch) \
 2944     (((ch) == 0 || (ch) == 127) \
 2945       ? 0 \
 2946       : (((ch) < 256) \
 2947           ? 1 \
 2948           : CharWidth(ch)))
 2949 #endif
 2950 
 2951 #endif /* OPT_RENDERWIDE */
 2952 
 2953 #define XFT_FONT(which) getXftFont(params->xw, which, fontnum)
 2954 
 2955 #if OPT_ISO_COLORS
 2956 #define UseBoldFont(screen) (!(screen)->colorBDMode || ((screen)->veryBoldColors & BOLD))
 2957 #else
 2958 #define UseBoldFont(screen) 1
 2959 #endif
 2960 
 2961 #if OPT_RENDERWIDE
 2962 /*
 2963  * Find Xft (truetype) double-width font for the given normal/bold attributes.
 2964  */
 2965 static XftFont *
 2966 getWideXftFont(XTermDraw * params,
 2967            unsigned attr_flags)
 2968 {
 2969     TScreen *screen = TScreenOf(params->xw);
 2970     int fontnum = screen->menu_font_number;
 2971     XftFont *wfont = 0;
 2972 
 2973 #if OPT_WIDE_ATTRS
 2974     if ((attr_flags & ATR_ITALIC)
 2975 #if OPT_ISO_COLORS
 2976     && !screen->colorITMode
 2977 #endif
 2978     ) {
 2979     if ((attr_flags & BOLDATTR(screen))
 2980         && UseBoldFont(screen)
 2981         && XFT_FONT(fWBtal)) {
 2982         wfont = XFT_FONT(fWBtal);
 2983     } else if (XFT_FONT(fWItal)) {
 2984         wfont = XFT_FONT(fWItal);
 2985     }
 2986     }
 2987     if (wfont != 0) {
 2988     ;           /* skip the other tests */
 2989     } else
 2990 #endif
 2991 #if OPT_ISO_COLORS
 2992     if ((attr_flags & UNDERLINE)
 2993         && !screen->colorULMode
 2994         && screen->italicULMode
 2995         && XFT_FONT(fWItal)) {
 2996     wfont = XFT_FONT(fWItal);
 2997     } else
 2998 #endif
 2999     if ((attr_flags & BOLDATTR(screen))
 3000         && UseBoldFont(screen)
 3001         && XFT_FONT(fWBold)) {
 3002     wfont = XFT_FONT(fWBold);
 3003     } else {
 3004     wfont = XFT_FONT(fWide);
 3005     }
 3006     return wfont;
 3007 }
 3008 #endif /* OPT_RENDERWIDE */
 3009 
 3010 /*
 3011  * Find Xft (truetype) single-width font for the given normal/bold attributes.
 3012  */
 3013 static XftFont *
 3014 getNormXftFont(XTermDraw * params,
 3015            unsigned attr_flags,
 3016            Bool *did_ul)
 3017 {
 3018     TScreen *screen = TScreenOf(params->xw);
 3019     int fontnum = screen->menu_font_number;
 3020     XftFont *font = 0;
 3021 
 3022     (void) did_ul;
 3023 #if OPT_DEC_CHRSET
 3024     if (CSET_DOUBLE(params->real_chrset)) {
 3025     font = xterm_DoubleFT(params, params->real_chrset, attr_flags);
 3026     }
 3027     if (font != 0) {
 3028     ;           /* found a usable double-sized font */
 3029     } else
 3030 #endif
 3031 #if OPT_WIDE_ATTRS
 3032     if ((attr_flags & ATR_ITALIC)
 3033 #if OPT_ISO_COLORS
 3034         && !screen->colorITMode
 3035 #endif
 3036     ) {
 3037     if ((attr_flags & BOLDATTR(screen))
 3038         && UseBoldFont(screen)
 3039         && XFT_FONT(fBtal)) {
 3040         font = XFT_FONT(fBtal);
 3041     } else if (XFT_FONT(fItal)) {
 3042         font = XFT_FONT(fItal);
 3043     }
 3044     }
 3045     if (font != 0) {
 3046     ;           /* skip the other tests */
 3047     } else
 3048 #endif
 3049 #if OPT_ISO_COLORS
 3050     if ((attr_flags & UNDERLINE)
 3051         && !screen->colorULMode
 3052         && screen->italicULMode
 3053         && XFT_FONT(fItal)) {
 3054     font = XFT_FONT(fItal);
 3055     *did_ul = True;
 3056     } else
 3057 #endif
 3058     if ((attr_flags & BOLDATTR(screen))
 3059         && UseBoldFont(screen)
 3060         && XFT_FONT(fBold)) {
 3061     font = XFT_FONT(fBold);
 3062     } else {
 3063     font = XFT_FONT(fNorm);
 3064     }
 3065     return font;
 3066 }
 3067 
 3068 #if OPT_RENDERWIDE
 3069 #define pickXftFont(width, nf, wf) ((width == 2 && wf != 0) ? wf : nf)
 3070 #else
 3071 #define pickXftFont(width, nf, wf) (nf)
 3072 #endif
 3073 
 3074 /*
 3075  * fontconfig/Xft combination prior to 2.2 has a problem with
 3076  * CJK truetype 'double-width' (bi-width/monospace) fonts leading
 3077  * to the 's p a c e d o u t' rendering. Consequently, we can't
 3078  * rely on XftDrawString8/16 when one of those fonts is used.
 3079  * Instead, we need to roll out our own using XftDrawCharSpec.
 3080  * A patch in the same spirit (but in a rather different form)
 3081  * was applied to gnome vte and gtk2 port of vim.
 3082  * See http://bugzilla.mozilla.org/show_bug.cgi?id=196312
 3083  */
 3084 static int
 3085 xtermXftDrawString(XTermDraw * params,
 3086            unsigned attr_flags,
 3087            XftColor *color,
 3088            XftFont *font,
 3089            int x,
 3090            int y,
 3091            const IChar *text,
 3092            Cardinal len,
 3093            Bool really)
 3094 {
 3095     TScreen *screen = TScreenOf(params->xw);
 3096     int ncells = 0;
 3097 
 3098     (void) attr_flags;
 3099     if (len != 0) {
 3100 #if OPT_RENDERWIDE
 3101     XftCharSpec *sbuf;
 3102     XftFont *wfont = getWideXftFont(params, attr_flags);
 3103     Cardinal src, dst;
 3104     XftFont *lastFont = 0;
 3105     XftFont *currFont = 0;
 3106     Cardinal start = 0;
 3107     int charWidth;
 3108     int fwidth = FontWidth(screen);
 3109 #if OPT_DEC_CHRSET
 3110     Boolean forceDbl = CSET_DOUBLE(params->real_chrset);
 3111 #else
 3112     Boolean forceDbl = False;
 3113 #endif
 3114 
 3115     BumpTypedBuffer(XftCharSpec, 2 * len);
 3116     sbuf = BfBuf(XftCharSpec);
 3117 
 3118     for (src = dst = 0; src < len; src++) {
 3119         FcChar32 wc = *text++;
 3120 
 3121         charWidth = XtermCellWidth(params->xw, (wchar_t) wc);
 3122         if (charWidth < 0)
 3123         continue;
 3124 
 3125         sbuf[dst].ucs4 = wc;
 3126         sbuf[dst].x = (short) (x + fwidth * ncells);
 3127         sbuf[dst].y = (short) (y);
 3128 
 3129         currFont = pickXftFont(charWidth, font, wfont);
 3130         ncells += charWidth;
 3131 
 3132         if (lastFont != currFont) {
 3133         if ((lastFont != 0) && really) {
 3134             XftDrawCharSpec(screen->renderDraw,
 3135                     color,
 3136                     lastFont,
 3137                     sbuf + start,
 3138                     (int) (dst - start));
 3139         }
 3140         start = dst;
 3141         lastFont = currFont;
 3142         }
 3143         ++dst;
 3144 
 3145         if (forceDbl && charWidth < 2) {
 3146         sbuf[dst].ucs4 = ' ';
 3147         sbuf[dst].x = (short) (x + fwidth * ncells);
 3148         sbuf[dst].y = (short) (y);
 3149         ++dst;
 3150         ncells += charWidth;
 3151         }
 3152     }
 3153     if ((dst != start) && really) {
 3154         XftDrawCharSpec(screen->renderDraw,
 3155                 color,
 3156                 lastFont,
 3157                 sbuf + start,
 3158                 (int) (dst - start));
 3159     }
 3160 #else /* !OPT_RENDERWIDE */
 3161     if (really) {
 3162         XftChar8 *buffer;
 3163         int dst;
 3164 
 3165         BumpTypedBuffer(XftChar8, len);
 3166         buffer = BfBuf(XftChar8);
 3167 
 3168         for (dst = 0; dst < (int) len; ++dst)
 3169         buffer[dst] = CharOf(text[dst]);
 3170 
 3171         XftDrawString8(screen->renderDraw,
 3172                color,
 3173                font,
 3174                x, y, buffer, (int) len);
 3175     }
 3176     ncells = (int) len;
 3177 #endif
 3178     xtermNeedSwap(params->xw, 1);
 3179     }
 3180     return ncells;
 3181 }
 3182 #define xtermXftWidth(params, attr_flags, color, font, x, y, chars, len) \
 3183    xtermXftDrawString(params, attr_flags, color, font, x, y, chars, len, False)
 3184 #endif /* OPT_RENDERFONT */
 3185 
 3186 #if OPT_WIDE_CHARS
 3187 /*
 3188  * Map characters commonly "fixed" by groff back to their ASCII equivalents.
 3189  * Also map other useful equivalents.
 3190  */
 3191 unsigned
 3192 AsciiEquivs(unsigned ch)
 3193 {
 3194     switch (ch) {
 3195     case 0x2010:        /* groff "-" */
 3196     case 0x2011:
 3197     case 0x2012:
 3198     case 0x2013:
 3199     case 0x2014:
 3200     case 0x2015:
 3201     case 0x2212:        /* groff "\-" */
 3202     ch = '-';
 3203     break;
 3204     case 0x2018:        /* groff "`" */
 3205     ch = '`';
 3206     break;
 3207     case 0x2019:        /* groff ' */
 3208     ch = '\'';
 3209     break;
 3210     case 0x201C:        /* groff lq */
 3211     case 0x201D:        /* groff rq */
 3212     ch = '"';
 3213     break;
 3214     case 0x2329:        /* groff ".URL" */
 3215     ch = '<';
 3216     break;
 3217     case 0x232a:        /* groff ".URL" */
 3218     ch = '>';
 3219     break;
 3220     default:
 3221     if (ch >= 0xff01 && ch <= 0xff5e) {
 3222         /* "Fullwidth" codes (actually double-width) */
 3223         ch -= 0xff00;
 3224         ch += ANSI_SPA;
 3225         break;
 3226     }
 3227     }
 3228     return ch;
 3229 }
 3230 
 3231 /*
 3232  * Actually this should be called "groff_workaround()" - for the places where
 3233  * groff stomps on compatibility.  Still, if enough people get used to it,
 3234  * this might someday become a quasi-standard.
 3235  */
 3236 #if OPT_BOX_CHARS
 3237 static int
 3238 ucs_workaround(XTermDraw * params,
 3239            unsigned ch,
 3240            GC gc,
 3241            int x,
 3242            int y)
 3243 {
 3244     TScreen *screen = TScreenOf(params->xw);
 3245     int fixed = False;
 3246 
 3247     if (screen->wide_chars && screen->utf8_mode && ch > 256) {
 3248     IChar eqv = (IChar) AsciiEquivs(ch);
 3249 
 3250     if (eqv != (IChar) ch) {
 3251         int width = CharWidth(ch);
 3252 
 3253         do {
 3254         drawXtermText(params,
 3255                   gc,
 3256                   x,
 3257                   y,
 3258                   &eqv,
 3259                   1);
 3260         x += FontWidth(screen);
 3261         eqv = BAD_ASCII;
 3262         } while (width-- > 1);
 3263 
 3264         fixed = True;
 3265     } else if (ch == HIDDEN_CHAR) {
 3266         fixed = True;
 3267     }
 3268     }
 3269     return fixed;
 3270 }
 3271 #endif /* OPT_BOX_CHARS */
 3272 #endif /* OPT_WIDE_CHARS */
 3273 
 3274 /*
 3275  * Use this when the characters will not fill the cell area properly.  Fill the
 3276  * area where we'll write the characters, otherwise we'll get gaps between
 3277  * them, e.g., in the original background color.
 3278  *
 3279  * The cursor is a special case, because the XFillRectangle call only uses the
 3280  * foreground, while we've set the cursor color in the background.  So we need
 3281  * a special GC for that.
 3282  */
 3283 static void
 3284 xtermFillCells(XTermDraw * params,
 3285            GC gc,
 3286            int x,
 3287            int y,
 3288            Cardinal len)
 3289 {
 3290     TScreen *screen = TScreenOf(params->xw);
 3291     VTwin *currentWin = WhichVWin(screen);
 3292 
 3293     if (!(params->draw_flags & NOBACKGROUND)) {
 3294     CgsEnum srcId = getCgsId(params->xw, currentWin, gc);
 3295     CgsEnum dstId = gcMAX;
 3296     Pixel fg = getCgsFore(params->xw, currentWin, gc);
 3297     Pixel bg = getCgsBack(params->xw, currentWin, gc);
 3298 
 3299     switch (srcId) {
 3300     case gcVTcursNormal:
 3301     case gcVTcursReverse:
 3302         dstId = gcVTcursOutline;
 3303         break;
 3304     case gcVTcursFilled:
 3305     case gcVTcursOutline:
 3306         /* FIXME */
 3307         break;
 3308     case gcNorm:
 3309         dstId = gcNormReverse;
 3310         break;
 3311     case gcNormReverse:
 3312         dstId = gcNorm;
 3313         break;
 3314     case gcBold:
 3315         dstId = gcBoldReverse;
 3316         break;
 3317     case gcBoldReverse:
 3318         dstId = gcBold;
 3319         break;
 3320     case gcBorder:
 3321     case gcFiller:
 3322         dstId = srcId;
 3323         break;
 3324 #if OPT_BOX_CHARS
 3325     case gcLine:
 3326     case gcDots:
 3327         /* FIXME */
 3328         break;
 3329 #endif
 3330 #if OPT_DEC_CHRSET
 3331     case gcCNorm:
 3332     case gcCBold:
 3333         /* FIXME */
 3334         break;
 3335 #endif
 3336 #if OPT_WIDE_CHARS
 3337     case gcWide:
 3338         dstId = gcWideReverse;
 3339         break;
 3340     case gcWBold:
 3341         dstId = gcBoldReverse;
 3342         break;
 3343     case gcWideReverse:
 3344     case gcWBoldReverse:
 3345         /* FIXME */
 3346         break;
 3347 #endif
 3348 #if OPT_TEK4014
 3349     case gcTKcurs:
 3350         /* FIXME */
 3351         break;
 3352 #endif
 3353     case gcMAX:
 3354         break;
 3355     }
 3356 
 3357     if (dstId != gcMAX) {
 3358         setCgsFore(params->xw, currentWin, dstId, bg);
 3359         setCgsBack(params->xw, currentWin, dstId, fg);
 3360 
 3361         XFillRectangle(screen->display, VDrawable(screen),
 3362                getCgsGC(params->xw, currentWin, dstId),
 3363                x, y,
 3364                len * (Cardinal) FontWidth(screen),
 3365                (unsigned) FontHeight(screen));
 3366     }
 3367     }
 3368 }
 3369 
 3370 #if OPT_TRACE
 3371 static void
 3372 xtermSetClipRectangles(Display *dpy,
 3373                GC gc,
 3374                int x,
 3375                int y,
 3376                XRectangle * rp,
 3377                Cardinal nr,
 3378                int order)
 3379 {
 3380 #if 0
 3381     TScreen *screen = TScreenOf(term);
 3382     Drawable draw = VDrawable(screen);
 3383 
 3384     XSetClipMask(dpy, gc, None);
 3385     XDrawRectangle(screen->display, draw, gc,
 3386            x + rp->x - 1,
 3387            y + rp->y - 1,
 3388            rp->width,
 3389            rp->height);
 3390 #endif
 3391 
 3392     XSetClipRectangles(dpy, gc,
 3393                x, y, rp, (int) nr, order);
 3394     TRACE(("clipping @(%3d,%3d) (%3d,%3d)..(%3d,%3d)\n",
 3395        y, x,
 3396        rp->y, rp->x, rp->height, rp->width));
 3397 }
 3398 
 3399 #else
 3400 #define xtermSetClipRectangles(dpy, gc, x, y, rp, nr, order) \
 3401         XSetClipRectangles(dpy, gc, x, y, rp, (int) nr, order)
 3402 #endif
 3403 
 3404 #if OPT_CLIP_BOLD
 3405 /*
 3406  * This special case is a couple of percent slower, but avoids a lot of pixel
 3407  * trash in rxcurses' hanoi.cmd demo (e.g., 10x20 font).
 3408  */
 3409 #define beginClipping(screen,gc,pwidth,plength) \
 3410     if (pwidth > 2) { \
 3411         if (screen->use_clipping) { \
 3412         XRectangle clip; \
 3413         int clip_x = x; \
 3414         int clip_y = y - FontHeight(screen) + FontDescent(screen); \
 3415         clip.x = 0; \
 3416         clip.y = 0; \
 3417         clip.height = (unsigned short) FontHeight(screen); \
 3418         clip.width = (unsigned short) ((pwidth) * (plength)); \
 3419         xtermSetClipRectangles(screen->display, gc, \
 3420                        clip_x, clip_y, \
 3421                        &clip, 1, Unsorted); \
 3422         } else if (screen->use_border_clipping) { \
 3423         XRectangle clip; \
 3424         clip.x = 0; \
 3425         clip.y = 0; \
 3426         clip.height = (unsigned short) Height(screen); \
 3427         clip.width = (unsigned short) Width(screen); \
 3428         xtermSetClipRectangles(screen->display, gc, \
 3429                        0, 0, \
 3430                        &clip, 1, Unsorted); \
 3431         } \
 3432     }
 3433 #define endClipping(screen,gc) \
 3434         XSetClipMask(screen->display, gc, None)
 3435 #else
 3436 #define beginClipping(screen,gc,pwidth,plength)     /* nothing */
 3437 #define endClipping(screen,gc)  /* nothing */
 3438 #endif /* OPT_CLIP_BOLD */
 3439 
 3440 #if OPT_RENDERFONT
 3441 static int
 3442 drawClippedXftString(XTermDraw * params,
 3443              unsigned attr_flags,
 3444              XftFont *font,
 3445              XftColor *fg_color,
 3446              int x,
 3447              int y,
 3448              const IChar *text,
 3449              Cardinal len)
 3450 {
 3451     int ncells = xtermXftWidth(params, attr_flags,
 3452                    fg_color,
 3453                    font, x, y,
 3454                    text,
 3455                    len);
 3456     TScreen *screen = TScreenOf(params->xw);
 3457     int fontHigh = FontHeight(screen);
 3458     int fontWide = FontWidth(screen);
 3459 
 3460     if (fontWide > 2) {
 3461     int plength = (ncells ? ncells : 1);
 3462     Boolean halfHigh = False;
 3463 #if OPT_DEC_CHRSET
 3464     Boolean halfWide = False;
 3465 
 3466     switch (params->real_chrset) {
 3467     case CSET_SWL:
 3468         break;
 3469     case CSET_DWL:
 3470         halfWide = True;
 3471         break;
 3472     case CSET_DHL_TOP:
 3473         halfHigh = True;
 3474         halfWide = True;
 3475         break;
 3476     case CSET_DHL_BOT:
 3477         halfHigh = True;
 3478         halfWide = True;
 3479         break;
 3480     }
 3481     if (CSET_DOUBLE(params->real_chrset)) {
 3482         fontHigh = font->height;
 3483         fontWide = font->max_advance_width;
 3484         /* check if this is really a double-height font */
 3485         if (halfHigh) {
 3486         int wantHigh = (int) (FontHeight(screen) * 1.8);
 3487         halfHigh = (fontHigh >= wantHigh);
 3488         TRACE(("comparing fontHigh %d/%d vs %d:"
 3489                " double-height %s for %s\n",
 3490                fontHigh, FontHeight(screen),
 3491                wantHigh, BtoS(halfHigh),
 3492                visibleDblChrset(params->real_chrset)));
 3493         }
 3494         fontHigh = (halfHigh
 3495             ? (2 * FontHeight(screen))
 3496             : FontHeight(screen));
 3497         /* check if this is really a double-width font */
 3498         if (halfWide) {
 3499         int wantWide = (int) (FontWidth(screen) * 1.8);
 3500         halfWide = (fontWide >= wantWide);
 3501         TRACE(("comparing fontWide %d/%d vs %d:"
 3502                " double-width %s for %s\n",
 3503                fontWide, FontWidth(screen),
 3504                wantWide, BtoS(halfWide),
 3505                visibleDblChrset(params->real_chrset)));
 3506         }
 3507         fontWide = (halfWide
 3508             ? (2 * FontWidth(screen))
 3509             : FontWidth(screen));
 3510     }
 3511 #endif
 3512     if (screen->use_clipping || halfHigh) {
 3513         XRectangle clip;
 3514         double adds = ((double) screen->scale_height - 1.0f) * fontHigh;
 3515         int height = dimRound(adds + fontHigh);
 3516         int descnt = dimRound(adds / 2.0) + FontDescent(screen);
 3517         int clip_x = (x);
 3518         int clip_y = (y) - height + descnt;
 3519 
 3520         clip.x = 0;
 3521         clip.y = 0;
 3522         clip.height = (Dimension) height;
 3523         clip.width = (Dimension) (fontWide * (Dimension) (plength));
 3524 
 3525 #if OPT_DEC_CHRSET
 3526         if (halfHigh) {
 3527         int adjust;
 3528 
 3529         clip.height = (unsigned short) FontHeight(screen);
 3530         clip_y += descnt;
 3531         if (params->real_chrset == CSET_DHL_BOT) {
 3532             y -= clip.height;
 3533         }
 3534         adjust = ((clip_y - OriginY(screen)) % FontHeight(screen));
 3535         if (adjust) {
 3536             if (adjust > FontHeight(screen) / 2)
 3537             adjust -= FontHeight(screen);
 3538             clip_y -= adjust;
 3539         }
 3540         }
 3541 #endif
 3542         XftDrawSetClipRectangles(screen->renderDraw,
 3543                      clip_x, clip_y,
 3544                      &clip, 1);
 3545     } else if (screen->use_border_clipping) {
 3546         XRectangle clip;
 3547 
 3548         clip.x = (Position) OriginX(screen);
 3549         clip.y = (Position) OriginY(screen);
 3550         clip.height = (Dimension) Height(screen);
 3551         clip.width = (Dimension) Width(screen);
 3552 
 3553         XftDrawSetClipRectangles(screen->renderDraw,
 3554                      0, 0,
 3555                      &clip, 1);
 3556     }
 3557     }
 3558 
 3559     xtermXftDrawString(params, attr_flags,
 3560                fg_color,
 3561                font, x, y + ScaleShift(screen),
 3562                text,
 3563                len,
 3564                True);
 3565     XftDrawSetClip(screen->renderDraw, 0);
 3566     return ncells;
 3567 }
 3568 #endif
 3569 
 3570 #ifndef NO_ACTIVE_ICON
 3571 #define WhichVFontData(screen,name) \
 3572         (IsIcon(screen) ? getIconicFont(screen) \
 3573                 : GetNormalFont(screen, name))
 3574 #else
 3575 #define WhichVFontData(screen,name) \
 3576                 GetNormalFont(screen, name)
 3577 #endif
 3578 
 3579 static void
 3580 drawUnderline(XtermWidget xw,
 3581           GC gc,
 3582           unsigned attr_flags,
 3583           unsigned underline_len,
 3584           int font_width,
 3585           int x,
 3586           int y,
 3587           Bool did_ul)
 3588 {
 3589     TScreen *screen = TScreenOf(xw);
 3590 
 3591     if (screen->underline && !did_ul) {
 3592     int repeat = 0;
 3593     int descent = FontDescent(screen);
 3594     int length = x + (int) underline_len * font_width - 1;
 3595 
 3596 #if OPT_WIDE_ATTRS
 3597     if ((attr_flags & ATR_STRIKEOUT)) {
 3598         int where = y - ((3 * FontAscent(screen)) / 8);
 3599         XDrawLine(screen->display, VDrawable(screen), gc,
 3600               x, where,
 3601               length,
 3602               where);
 3603     }
 3604     if ((attr_flags & ATR_DBL_UNDER)) {
 3605         repeat = 2;
 3606     } else
 3607 #endif
 3608     if ((attr_flags & UNDERLINE)) {
 3609         repeat = 1;
 3610     }
 3611     while (repeat-- > 0) {
 3612         if (descent-- > 1)
 3613         y++;
 3614         XDrawLine(screen->display, VDrawable(screen), gc,
 3615               x, y,
 3616               length,
 3617               y);
 3618     }
 3619     }
 3620 }
 3621 
 3622 #if OPT_WIDE_ATTRS
 3623 /*
 3624  * As a special case, we are currently allowing italic fonts to be inexact
 3625  * matches for the normal font's size.  That introduces a problem:  either the
 3626  * ascent or descent may be shorter, leaving a gap that has to be filled in.
 3627  * Or they may be larger, requiring clipping.  Check for both cases.
 3628  */
 3629 static int
 3630 fixupItalics(XTermDraw * params,
 3631          GC gc,
 3632          XTermFonts * curFont,
 3633          int y, int x,
 3634          int font_width,
 3635          Cardinal len)
 3636 {
 3637     TScreen *screen = TScreenOf(params->xw);
 3638     VTwin *cgsWin = WhichVWin(screen);
 3639     XFontStruct *realFp = curFont->fs;
 3640     XFontStruct *thisFp = getCgsFont(params->xw, cgsWin, gc)->fs;
 3641     int need_clipping = 0;
 3642     int need_filling = 0;
 3643 
 3644     if (thisFp->ascent > realFp->ascent)
 3645     need_clipping = 1;
 3646     else if (thisFp->ascent < realFp->ascent)
 3647     need_filling = 1;
 3648 
 3649     if (thisFp->descent > realFp->descent)
 3650     need_clipping = 1;
 3651     else if (thisFp->descent < realFp->descent)
 3652     need_filling = 1;
 3653 
 3654     if (need_clipping) {
 3655     beginClipping(screen, gc, font_width, (int) len);
 3656     }
 3657     if (need_filling) {
 3658     xtermFillCells(params,
 3659                gc,
 3660                x,
 3661                y - realFp->ascent,
 3662                len);
 3663     }
 3664     return need_clipping;
 3665 }
 3666 #endif
 3667 
 3668 #if OPT_DEC_CHRSET
 3669 static int
 3670 fakeDoubleChars(XTermDraw * params,
 3671         GC gc,
 3672         int y,
 3673         int x,
 3674         const IChar *text,
 3675         Cardinal len)
 3676 {
 3677     unsigned need = 2 * len;
 3678     IChar *temp = TypeMallocN(IChar, need);
 3679 
 3680     if (temp != 0) {
 3681     unsigned n = 0;
 3682     XTermDraw recur = *params;
 3683 
 3684     recur.this_chrset = CSET_SWL;
 3685 
 3686     while (len--) {
 3687         temp[n++] = *text++;
 3688         temp[n++] = ' ';
 3689     }
 3690     x = drawXtermText(&recur,
 3691               gc,
 3692               x, y,
 3693               temp,
 3694               n);
 3695     free(temp);
 3696     }
 3697     return x;
 3698 }
 3699 #endif /* OPT_DEC_CHRSET */
 3700 
 3701 #define SetMissing(tag) \
 3702     TRACE(("%s %s: missing %d %04X\n", __FILE__, tag, missing, ch)); \
 3703     missing = 1
 3704 
 3705 #define MaxImageString 255
 3706 
 3707 /*
 3708  * Draws text with the specified combination of bold/underline.  The return
 3709  * value is the updated x position.
 3710  */
 3711 int
 3712 drawXtermText(XTermDraw * params,
 3713           GC gc,
 3714           int start_x,
 3715           int start_y,
 3716           const IChar *text,
 3717           Cardinal len)
 3718 {
 3719     XTermDraw recur = *params;
 3720     TScreen *screen = TScreenOf(recur.xw);
 3721     int x = start_x;
 3722     int y = start_y;
 3723     int y_shift = ScaleShift(screen);
 3724     Cardinal real_length = len;
 3725     Cardinal underline_len = 0;
 3726     /* Intended width of the font to draw (as opposed to the actual width of
 3727        the X font, and the width of the default font) */
 3728     int font_width = (((recur.draw_flags & DOUBLEWFONT) ? 2 : 1)
 3729               * screen->fnt_wide);
 3730     Bool did_ul = False;
 3731     XTermFonts *curFont;
 3732 #if OPT_WIDE_ATTRS
 3733     int need_clipping = 0;
 3734 #endif
 3735 
 3736 #if OPT_WIDE_CHARS
 3737     if (text == 0)
 3738     return 0;
 3739 #endif
 3740     TRACE(("DRAWTEXT%c[%4d,%4d] (%d)%3d:%s\n",
 3741        screen->cursor_state == OFF ? ' ' : '*',
 3742        y, x, recur.this_chrset, len,
 3743        visibleIChars(text, len)));
 3744 
 3745 #if OPT_DEC_CHRSET
 3746     if (CSET_DOUBLE(recur.this_chrset)) {
 3747     /* We could try drawing double-size characters in the icon, but
 3748      * given that the icon font is usually nil or nil2, there
 3749      * doesn't seem to be much point.
 3750      */
 3751     int inx = 0;
 3752     GC gc2;
 3753 
 3754 #if OPT_RENDERFONT
 3755     if (UsingRenderFont(recur.xw)) {
 3756         if (!IsIcon(screen) && screen->font_doublesize) {
 3757         TRACE(("drawing %s\n", visibleDblChrset((unsigned) recur.this_chrset)));
 3758         recur.real_chrset = recur.this_chrset;
 3759         recur.this_chrset = CSET_SWL;
 3760         x = drawXtermText(&recur,
 3761                   gc,
 3762                   x, y,
 3763                   text,
 3764                   len);
 3765         x += ((int) len) * FontWidth(screen);
 3766         } else {
 3767         x = fakeDoubleChars(&recur,
 3768                     gc, y, x,
 3769                     text, len);
 3770         }
 3771     } else
 3772 #endif
 3773         if ((!IsIcon(screen) && screen->font_doublesize)
 3774         && (gc2 = xterm_DoubleGC(&recur, gc, &inx)) != 0) {
 3775         /* draw actual double-sized characters */
 3776         XFontStruct *fs = getDoubleFont(screen, inx)->fs;
 3777         XRectangle rect, *rp = &rect;
 3778         Cardinal nr = 1;
 3779 
 3780         font_width *= 2;
 3781         recur.draw_flags |= DOUBLEWFONT;
 3782 
 3783         rect.x = 0;
 3784         rect.y = 0;
 3785         rect.width = (unsigned short) ((int) len * font_width);
 3786         rect.height = (unsigned short) (FontHeight(screen));
 3787 
 3788         TRACE(("drawing %s\n", visibleDblChrset((unsigned) recur.this_chrset)));
 3789         switch (recur.this_chrset) {
 3790         case CSET_DHL_TOP:
 3791         rect.y = (short) -(fs->ascent / 2);
 3792         y -= rect.y;
 3793         recur.draw_flags |= DOUBLEHFONT;
 3794         break;
 3795         case CSET_DHL_BOT:
 3796         rect.y = (short) (rect.height - (fs->ascent / 2));
 3797         y -= rect.y;
 3798         recur.draw_flags |= DOUBLEHFONT;
 3799         break;
 3800         case CSET_DWL:
 3801         break;
 3802         default:
 3803         nr = 0;
 3804         break;
 3805         }
 3806 
 3807         if (nr) {
 3808         xtermSetClipRectangles(screen->display, gc2,
 3809                        x, y, rp, nr, YXBanded);
 3810         xtermFillCells(&recur, gc, x, y + rect.y, len * 2);
 3811         } else {
 3812         XSetClipMask(screen->display, gc2, None);
 3813         }
 3814 
 3815         /* Call ourselves recursively with the new gc */
 3816 
 3817         /*
 3818          * If we're trying to use proportional font, or if the
 3819          * font server didn't give us what we asked for wrt
 3820          * width, position each character independently.
 3821          */
 3822         if (screen->fnt_prop
 3823         || (fs->min_bounds.width != fs->max_bounds.width)
 3824         || (fs->min_bounds.width != 2 * FontWidth(screen))) {
 3825         /* It is hard to fall-through to the main
 3826            branch: in a lot of places the check
 3827            for the cached font info is for
 3828            normal/bold fonts only. */
 3829         XTermDraw param2 = recur;
 3830         param2.this_chrset = CSET_SWL;
 3831         while (len--) {
 3832             x = drawXtermText(&param2,
 3833                       gc2,
 3834                       x, y,
 3835                       text++,
 3836                       1);
 3837             x += FontWidth(screen);
 3838         }
 3839         } else {
 3840         XTermDraw param2 = recur;
 3841         param2.this_chrset = CSET_SWL;
 3842         x = drawXtermText(&param2,
 3843                   gc2,
 3844                   x, y,
 3845                   text,
 3846                   len);
 3847         x += (int) len *FontWidth(screen);
 3848         }
 3849 
 3850     } else {        /* simulate double-sized characters */
 3851         x = fakeDoubleChars(&recur,
 3852                 gc, y, x,
 3853                 text, len);
 3854     }
 3855     TRACE(("DrewText [%4d,%4d]\n", y, x));
 3856     return x;
 3857     }
 3858 #endif
 3859 #if OPT_RENDERFONT
 3860     if (UsingRenderFont(recur.xw)) {
 3861     VTwin *currentWin = WhichVWin(screen);
 3862     Display *dpy = screen->display;
 3863     XftFont *font;
 3864     XftFont *font0;
 3865     XGCValues values;
 3866 #if OPT_RENDERWIDE
 3867     XftFont *wfont;
 3868     XftFont *wfont0;
 3869 #endif
 3870 
 3871 #if OPT_DEC_CHRSET
 3872     /*
 3873      * If this is a VT100-style double-width font, ensure that everything
 3874      * is printed using two-columns per character.
 3875      */
 3876     Boolean forceDbl = CSET_DOUBLE(recur.real_chrset);
 3877 #else
 3878     Boolean forceDbl = False;
 3879 #endif
 3880 
 3881     (void) forceDbl;
 3882     /*
 3883      * Defer creating the drawable until we need it.
 3884      */
 3885     if (!screen->renderDraw) {
 3886         int scr;
 3887         Drawable draw = VDrawable(screen);
 3888         Visual *visual;
 3889 
 3890         scr = DefaultScreen(dpy);
 3891         visual = DefaultVisual(dpy, scr);
 3892         screen->renderDraw = XftDrawCreate(dpy, draw, visual,
 3893                            DefaultColormap(dpy, scr));
 3894     }
 3895 
 3896     /*
 3897      * font0/wfont0 provide fallback to non-bolded Xft font if a glyph is
 3898      * not found in the bold version.
 3899      */
 3900 #define IS_BOLD  (recur.attr_flags & BOLDATTR(screen))
 3901 #define NOT_BOLD (recur.attr_flags & ~BOLDATTR(screen))
 3902     font = getNormXftFont(&recur, recur.attr_flags, &did_ul);
 3903     font0 = IS_BOLD ? getNormXftFont(&recur, NOT_BOLD, &did_ul) : font;
 3904     (void) font0;
 3905 #if OPT_RENDERWIDE
 3906     wfont = getWideXftFont(&recur, recur.attr_flags);
 3907     wfont0 = IS_BOLD ? getWideXftFont(&recur, NOT_BOLD) : wfont;
 3908 #endif
 3909 
 3910 #define GET_XFT_FG() getXftColor(recur.xw, values.foreground)
 3911 #define GET_XFT_BG() getXftColor(recur.xw, values.background)
 3912 
 3913     values.foreground = getCgsFore(recur.xw, currentWin, gc);
 3914     values.background = getCgsBack(recur.xw, currentWin, gc);
 3915 
 3916     if (!(recur.draw_flags & NOBACKGROUND)) {
 3917         XftColor *bg_color = GET_XFT_BG();
 3918         int ncells = xtermXftWidth(&recur, recur.attr_flags,
 3919                        bg_color,
 3920                        font, x, y,
 3921                        text,
 3922                        len);
 3923         XftDrawRect(screen->renderDraw,
 3924             bg_color,
 3925             x, y,
 3926             (unsigned) (ncells * FontWidth(screen)),
 3927             (unsigned) FontHeight(screen));
 3928     }
 3929 
 3930     y += font->ascent;
 3931 #if OPT_BOX_CHARS
 3932     {
 3933         /* adding code to substitute simulated line-drawing characters */
 3934         int last, first = 0;
 3935         int curX = x;
 3936 
 3937         for (last = 0; last < (int) len; last++) {
 3938         Boolean replace = False;
 3939         Boolean missing = False;
 3940         unsigned ch = (unsigned) text[last];
 3941         int filler = 0;
 3942 #if OPT_WIDE_CHARS
 3943         int needed = forceDbl ? 2 : CharWidth(ch);
 3944         XftFont *currFont = pickXftFont(needed, font, wfont);
 3945         XftFont *tempFont = 0;
 3946 #define CURR_TEMP (tempFont ? tempFont : currFont)
 3947 
 3948         if (xtermIsDecGraphic(ch) || ch == 0) {
 3949             /*
 3950              * Xft generally does not have the line-drawing characters
 3951              * in cells 0-31.  Assume this (we cannot inspect the
 3952              * picture easily...), and attempt to fill in from real
 3953              * line-drawing character in the font at the Unicode
 3954              * position.  Failing that, use our own box-characters.
 3955              */
 3956             if (screen->force_box_chars
 3957             || screen->broken_box_chars
 3958             || xtermXftMissing(recur.xw,
 3959                        currFont,
 3960                        dec2ucs(screen, ch))) {
 3961             SetMissing("case 1");
 3962             } else {
 3963             ch = dec2ucs(screen, ch);
 3964             replace = True;
 3965             }
 3966         } else if (ch >= 256) {
 3967             /*
 3968              * If we're reading UTF-8 from the client, we may have a
 3969              * line-drawing character.  Translate it back to our
 3970              * box-code if Xft tells us that the glyph is missing.
 3971              */
 3972             if_OPT_WIDE_CHARS(screen, {
 3973             unsigned part = ucs2dec(screen, ch);
 3974             if (xtermIsDecGraphic(part)) {
 3975                 if (screen->force_box_chars
 3976                 || screen->broken_box_chars) {
 3977                 SetMissing("case 2");
 3978                 ch = part;
 3979                 }
 3980             }
 3981             if (!missing && xtermXftMissing(recur.xw, currFont, ch)) {
 3982                 XftFont *test = findXftGlyph(recur.xw, currFont, ch);
 3983                 if (test == 0)
 3984                 test = pickXftFont(needed, font0, wfont0);
 3985                 if (!xtermXftMissing(recur.xw, test, ch)) {
 3986                 tempFont = test;
 3987                 replace = True;
 3988                 filler = 0;
 3989                 } else if ((part = AsciiEquivs(ch)) != ch) {
 3990                 filler = needed - 1;
 3991                 ch = part;
 3992                 replace = True;
 3993                 } else if (ch != HIDDEN_CHAR) {
 3994                 SetMissing("case 3");
 3995                 }
 3996             }
 3997             });
 3998         }
 3999 #else
 4000         XftFont *currFont = font;
 4001 #define CURR_TEMP (currFont)
 4002         if (xtermIsDecGraphic(ch)) {
 4003             /*
 4004              * Xft generally does not have the line-drawing characters
 4005              * in cells 1-31.  Check for this, and attempt to fill in
 4006              * from real line-drawing character in the font at the
 4007              * Unicode position.  Failing that, use our own
 4008              * box-characters.
 4009              */
 4010             if (xtermXftMissing(recur.xw, currFont, ch)) {
 4011             SetMissing("case 4");
 4012             }
 4013         }
 4014 #endif
 4015 
 4016         /*
 4017          * If we now have one of our box-codes, draw it directly.
 4018          */
 4019         if (missing || replace) {
 4020             /* line drawing character time */
 4021             if (last > first) {
 4022             int nc = drawClippedXftString(&recur,
 4023                               recur.attr_flags,
 4024                               currFont,
 4025                               GET_XFT_FG(),
 4026                               curX,
 4027                               y,
 4028                               text + first,
 4029                               (Cardinal) (last - first));
 4030             curX += nc * FontWidth(screen);
 4031             underline_len += (Cardinal) nc;
 4032             }
 4033             if (missing) {
 4034             Dimension old_wide = screen->fnt_wide;
 4035             Dimension old_high = screen->fnt_high;
 4036             screen->fnt_wide = (Dimension) FontWidth(screen);
 4037             screen->fnt_high = (Dimension) FontHeight(screen);
 4038 
 4039             xtermDrawBoxChar(&recur, ch,
 4040                      gc,
 4041                      curX,
 4042                      y - FontAscent(screen),
 4043                      1,
 4044                      True);
 4045             curX += FontWidth(screen);
 4046             underline_len += 1;
 4047             screen->fnt_wide = old_wide;
 4048             screen->fnt_high = old_high;
 4049             } else {
 4050             IChar ch2 = (IChar) ch;
 4051             int nc = drawClippedXftString(&recur,
 4052                               recur.attr_flags,
 4053                               CURR_TEMP,
 4054                               GET_XFT_FG(),
 4055                               curX,
 4056                               y,
 4057                               &ch2,
 4058                               1);
 4059             curX += nc * FontWidth(screen);
 4060             underline_len += (Cardinal) nc;
 4061             if (filler) {
 4062                 ch2 = ' ';
 4063                 nc = drawClippedXftString(&recur,
 4064                               recur.attr_flags,
 4065                               CURR_TEMP,
 4066                               GET_XFT_FG(),
 4067                               curX,
 4068                               y,
 4069                               &ch2,
 4070                               1);
 4071                 curX += nc * FontWidth(screen);
 4072                 underline_len += (Cardinal) nc;
 4073             }
 4074             }
 4075             first = last + 1;
 4076         }
 4077         }
 4078         if (last > first) {
 4079         underline_len += (Cardinal)
 4080             drawClippedXftString(&recur,
 4081                      recur.attr_flags,
 4082                      font,
 4083                      GET_XFT_FG(),
 4084                      curX,
 4085                      y,
 4086                      text + first,
 4087                      (Cardinal) (last - first));
 4088         }
 4089     }
 4090 #else
 4091     {
 4092         underline_len += (Cardinal)
 4093         drawClippedXftString(&recur,
 4094                      recur.attr_flags,
 4095                      font,
 4096                      GET_XFT_FG(),
 4097                      x,
 4098                      y,
 4099                      text,
 4100                      len);
 4101     }
 4102 #endif /* OPT_BOX_CHARS */
 4103 
 4104     drawUnderline(recur.xw,
 4105               gc,
 4106               recur.attr_flags,
 4107               underline_len,
 4108               FontWidth(screen),
 4109               x,
 4110               y + y_shift,
 4111               did_ul);
 4112 
 4113     x += (int) len *FontWidth(screen);
 4114 
 4115     return x;
 4116     }
 4117 #endif /* OPT_RENDERFONT */
 4118     curFont = ((recur.attr_flags & BOLDATTR(screen))
 4119            ? WhichVFontData(screen, fBold)
 4120            : WhichVFontData(screen, fNorm));
 4121     /*
 4122      * If we're asked to display a proportional font, do this with a fixed
 4123      * pitch.  Yes, it's ugly.  But we cannot distinguish the use of xterm
 4124      * as a dumb terminal vs its use as in fullscreen programs such as vi.
 4125      * Hint: do not try to use a proportional font in the icon.
 4126      */
 4127     if (!IsIcon(screen) && !(recur.draw_flags & CHARBYCHAR) && screen->fnt_prop) {
 4128     int adj, width;
 4129 
 4130     while (len--) {
 4131         int cells = WideCells(*text);
 4132 #if OPT_BOX_CHARS
 4133 #if OPT_WIDE_CHARS
 4134         if (*text == HIDDEN_CHAR) {
 4135         ++text;
 4136         continue;
 4137         } else
 4138 #endif
 4139         if (IsXtermMissingChar(screen, *text, curFont)) {
 4140         adj = 0;
 4141         } else
 4142 #endif
 4143         {
 4144         if_WIDE_OR_NARROW(screen, {
 4145             XChar2b temp[1];
 4146             temp[0].byte2 = LO_BYTE(*text);
 4147             temp[0].byte1 = HI_BYTE(*text);
 4148             width = XTextWidth16(curFont->fs, temp, 1);
 4149         }
 4150         , {
 4151             char temp[1];
 4152             temp[0] = (char) LO_BYTE(*text);
 4153             width = XTextWidth(curFont->fs, temp, 1);
 4154         });
 4155         adj = (FontWidth(screen) - width) / 2;
 4156         if (adj < 0)
 4157             adj = 0;
 4158         }
 4159         xtermFillCells(&recur, gc, x, y, (Cardinal) cells);
 4160         recur.draw_flags |= (NOBACKGROUND | CHARBYCHAR);
 4161         x = drawXtermText(&recur,
 4162                   gc, x + adj, y,
 4163                   text++, 1) - adj;
 4164     }
 4165 
 4166     return x;
 4167     }
 4168 #if OPT_BOX_CHARS
 4169     /*
 4170      * Draw some substitutions, if needed.  The font may not include the
 4171      * line-drawing set, or it may be incomplete (in which case we'll draw an
 4172      * empty space via xtermDrawBoxChar), or we may be told to force our
 4173      * line-drawing.
 4174      *
 4175      * The empty space is a special case which can be overridden with the
 4176      * showMissingGlyphs resource to produce an outline.  Not all fonts in
 4177      * "modern" (sic) X provide an empty space; some use a thick outline or
 4178      * something like the replacement character.  If you would rather not see
 4179      * that, you can set assumeAllChars.
 4180      */
 4181     if (!IsIcon(screen)
 4182     && !(recur.draw_flags & NOTRANSLATION)
 4183     && (!screen->fnt_boxes
 4184         || (FontIsIncomplete(curFont) && !screen->assume_all_chars)
 4185         || screen->force_box_chars)) {
 4186     /*
 4187      * Fill in missing box-characters.  Find regions without missing
 4188      * characters, and draw them calling ourselves recursively.  Draw
 4189      * missing characters via xtermDrawBoxChar().
 4190      */
 4191     int last, first = 0;
 4192     Bool drewBoxes = False;
 4193 
 4194     for (last = 0; last < (int) len; last++) {
 4195         unsigned ch = (unsigned) text[last];
 4196         Bool isMissing;
 4197         int ch_width;
 4198 #if OPT_WIDE_CHARS
 4199 
 4200         if (ch == HIDDEN_CHAR) {
 4201         if (last > first) {
 4202             XTermDraw param2 = recur;
 4203             param2.draw_flags |= NOTRANSLATION;
 4204             x = drawXtermText(&param2,
 4205                       gc,
 4206                       x, y,
 4207                       text + first,
 4208                       (unsigned) (last - first));
 4209         }
 4210         first = last + 1;
 4211         drewBoxes = True;
 4212         continue;
 4213         }
 4214         ch_width = CharWidth(ch);
 4215         isMissing =
 4216         IsXtermMissingChar(screen, ch,
 4217                    ((recur.on_wide || ch_width > 1)
 4218                     && okFont(NormalWFont(screen)))
 4219                    ? WhichVFontData(screen, fWide)
 4220                    : curFont);
 4221 #else
 4222         isMissing = IsXtermMissingChar(screen, ch, curFont);
 4223         ch_width = 1;
 4224 #endif
 4225         /*
 4226          * If the character is not missing, but we're in wide-character
 4227          * mode and the character happens to be a wide-character that
 4228          * corresponds to the line-drawing set, allow the forceBoxChars
 4229          * resource (or menu entry) to force it to display using our
 4230          * tables.
 4231          */
 4232         if_OPT_WIDE_CHARS(screen, {
 4233         if (!isMissing
 4234             && TScreenOf(recur.xw)->force_box_chars) {
 4235             if (ch > 255
 4236             && ucs2dec(screen, ch) < 32) {
 4237             ch = ucs2dec(screen, ch);
 4238             isMissing = True;
 4239             } else if (ch < 32) {
 4240             isMissing = True;
 4241             }
 4242         }
 4243         });
 4244 
 4245         if (isMissing) {
 4246         if (last > first) {
 4247             XTermDraw param2 = recur;
 4248             param2.draw_flags |= NOTRANSLATION;
 4249             x = drawXtermText(&recur,
 4250                       gc,
 4251                       x, y,
 4252                       text + first,
 4253                       (unsigned) (last - first));
 4254         }
 4255 #if OPT_WIDE_CHARS
 4256         if (ch_width <= 0 && ch < 32)
 4257             ch_width = 1;   /* special case for line-drawing */
 4258         else if (ch_width < 0)
 4259             ch_width = 1;   /* special case for combining char */
 4260         if (!ucs_workaround(&recur, ch, gc, x, y)) {
 4261             xtermDrawBoxChar(&recur, ch, gc, x, y, ch_width, False);
 4262         }
 4263 #else
 4264         xtermDrawBoxChar(&recur, ch, gc, x, y, ch_width, False);
 4265 #endif
 4266         x += (ch_width * FontWidth(screen));
 4267         first = last + 1;
 4268         drewBoxes = True;
 4269         }
 4270     }
 4271     if (last <= first) {
 4272         return x;
 4273     }
 4274     text += first;
 4275     len = (Cardinal) (last - first);
 4276     recur.draw_flags |= NOTRANSLATION;
 4277     if (drewBoxes) {
 4278         return drawXtermText(&recur,
 4279                  gc,
 4280                  x,
 4281                  y,
 4282                  text,
 4283                  len);
 4284     }
 4285     }
 4286 #endif /* OPT_BOX_CHARS */
 4287     /*
 4288      * Behave as if the font has (maybe Unicode-replacements for) drawing
 4289      * characters in the range 1-31 (either we were not asked to ignore them,
 4290      * or the caller made sure that there is none).
 4291      */
 4292 #if OPT_WIDE_ATTRS
 4293 #define AttrFlags() recur.attr_flags
 4294 #define DrawFlags() recur.draw_flags
 4295 #else
 4296 #define AttrFlags() (recur.attr_flags & DRAWX_MASK)
 4297 #define DrawFlags() (recur.draw_flags & (unsigned)~DRAWX_MASK)
 4298 #endif
 4299     TRACE(("drawtext%c[%4d,%4d] {%#x,%#x} (%d) %d:%s\n",
 4300        screen->cursor_state == OFF ? ' ' : '*',
 4301        y, x,
 4302        AttrFlags(),
 4303        DrawFlags(),
 4304        recur.this_chrset, len,
 4305        visibleIChars(text, len)));
 4306     if (screen->scale_height != 1.0f) {
 4307     xtermFillCells(&recur, gc, x, y, (Cardinal) len);
 4308     }
 4309     y += FontAscent(screen);
 4310 
 4311 #if OPT_WIDE_CHARS
 4312 
 4313     if (screen->wide_chars || screen->unicode_font) {
 4314     XChar2b *buffer;
 4315     Bool needWide = False;
 4316     int src, dst;
 4317     Bool useBoldFont;
 4318     int ascent_adjust = 0;
 4319 
 4320     BumpTypedBuffer(XChar2b, len);
 4321     buffer = BfBuf(XChar2b);
 4322 
 4323     for (src = dst = 0; src < (int) len; src++) {
 4324         IChar ch = text[src];
 4325 
 4326         if (ch == HIDDEN_CHAR)
 4327         continue;
 4328 
 4329 #if OPT_BOX_CHARS
 4330         if ((screen->fnt_boxes == 1) && (ch >= 256)) {
 4331         unsigned part = ucs2dec(screen, ch);
 4332         if (part < 32)
 4333             ch = (IChar) part;
 4334         }
 4335 #endif
 4336 
 4337         if (!needWide
 4338         && !IsIcon(screen)
 4339         && ((recur.on_wide || CharWidth(ch) > 1)
 4340             && okFont(NormalWFont(screen)))) {
 4341         needWide = True;
 4342         }
 4343 #if OPT_WIDER_ICHAR
 4344         /*
 4345          * bitmap-fonts are limited to 16-bits.
 4346          */
 4347         if (ch > NARROW_ICHAR) {
 4348         ch = 0;
 4349         }
 4350 #endif
 4351         buffer[dst].byte2 = LO_BYTE(ch);
 4352         buffer[dst].byte1 = HI_BYTE(ch);
 4353 #if OPT_MINI_LUIT
 4354 #define UCS2SBUF(value) buffer[dst].byte2 = LO_BYTE(value);\
 4355             buffer[dst].byte1 = HI_BYTE(value)
 4356 
 4357 #define Map2Sbuf(from,to) (text[src] == from) { UCS2SBUF(to); }
 4358 
 4359         if (screen->latin9_mode && !screen->utf8_mode && text[src] < 256) {
 4360 
 4361         /* see http://www.cs.tut.fi/~jkorpela/latin9.html */
 4362         /* *INDENT-OFF* */
 4363         if Map2Sbuf(0xa4, 0x20ac)
 4364         else if Map2Sbuf(0xa6, 0x0160)
 4365         else if Map2Sbuf(0xa8, 0x0161)
 4366         else if Map2Sbuf(0xb4, 0x017d)
 4367         else if Map2Sbuf(0xb8, 0x017e)
 4368         else if Map2Sbuf(0xbc, 0x0152)
 4369         else if Map2Sbuf(0xbd, 0x0153)
 4370         else if Map2Sbuf(0xbe, 0x0178)
 4371         /* *INDENT-ON* */
 4372 
 4373         }
 4374         if (screen->unicode_font
 4375         && (text[src] == ANSI_DEL ||
 4376             text[src] < ANSI_SPA)) {
 4377         unsigned ni = dec2ucs(screen,
 4378                       (unsigned) ((text[src] == ANSI_DEL)
 4379                           ? 0
 4380                           : text[src]));
 4381         UCS2SBUF(ni);
 4382         }
 4383 #endif /* OPT_MINI_LUIT */
 4384         ++dst;
 4385     }
 4386 
 4387     /*
 4388      * Check for special case where the bold font lacks glyphs found in the
 4389      * normal font, and drop down to normal fonts with overstriking to help
 4390      * show the actual characters.
 4391      */
 4392     useBoldFont = ((recur.attr_flags & BOLDATTR(screen)) != 0);
 4393     if (useBoldFont) {
 4394         XTermFonts *norm = 0;
 4395         XTermFonts *bold = 0;
 4396         Bool noBold, noNorm;
 4397 
 4398         if (needWide && okFont(BoldWFont(screen))) {
 4399         norm = WhichVFontData(screen, fWide);
 4400         bold = WhichVFontData(screen, fWBold);
 4401         } else if (okFont(BoldFont(screen))) {
 4402         norm = WhichVFontData(screen, fNorm);
 4403         bold = WhichVFontData(screen, fBold);
 4404         } else {
 4405         useBoldFont = False;
 4406         }
 4407 
 4408         if (useBoldFont && FontIsIncomplete(bold)) {
 4409         for (src = 0; src < (int) len; src++) {
 4410             IChar ch = text[src];
 4411 
 4412             if (ch == HIDDEN_CHAR)
 4413             continue;
 4414 
 4415             noBold = IsXtermMissingChar(screen, ch, bold);
 4416             if (noBold) {
 4417             noNorm = IsXtermMissingChar(screen, ch, norm);
 4418             if (!noNorm) {
 4419                 useBoldFont = False;
 4420                 break;
 4421             }
 4422             }
 4423         }
 4424         }
 4425     }
 4426 
 4427     /* FIXME This is probably wrong. But it works. */
 4428     underline_len = len;
 4429 
 4430     /* Set the drawing font */
 4431     if (!(recur.draw_flags & (DOUBLEHFONT | DOUBLEWFONT))) {
 4432         VTwin *currentWin = WhichVWin(screen);
 4433         VTFontEnum fntId;
 4434         CgsEnum cgsId;
 4435         Pixel fg = getCgsFore(recur.xw, currentWin, gc);
 4436         Pixel bg = getCgsBack(recur.xw, currentWin, gc);
 4437 
 4438         if (needWide
 4439         && useBoldFont
 4440         && okFont(BoldWFont(screen))) {
 4441         fntId = fWBold;
 4442         cgsId = gcWBold;
 4443         } else if (needWide) {
 4444         fntId = fWide;
 4445         cgsId = gcWide;
 4446         } else if (useBoldFont) {
 4447         fntId = fBold;
 4448         cgsId = gcBold;
 4449         } else {
 4450         fntId = fNorm;
 4451         cgsId = gcNorm;
 4452         }
 4453 
 4454         setCgsFore(recur.xw, currentWin, cgsId, fg);
 4455         setCgsBack(recur.xw, currentWin, cgsId, bg);
 4456         gc = getCgsGC(recur.xw, currentWin, cgsId);
 4457 
 4458 #if OPT_WIDE_ATTRS
 4459 #if OPT_DEC_CHRSET
 4460         if (!(CSET_DOUBLE(recur.this_chrset) || (recur.draw_flags & DOUBLEWFONT)))
 4461 #endif
 4462         need_clipping = fixupItalics(&recur,
 4463                          gc,
 4464                          getCgsFont(recur.xw,
 4465                             currentWin, gc),
 4466                          y, x, font_width, len);
 4467 #endif
 4468         if (fntId != fNorm) {
 4469         XFontStruct *thisFp = WhichVFont(screen, fntId);
 4470         ascent_adjust = (thisFp->ascent
 4471                  - NormalFont(screen)->ascent);
 4472         if (thisFp->max_bounds.width ==
 4473             NormalFont(screen)->max_bounds.width * 2) {
 4474             underline_len = real_length = (Cardinal) (dst * 2);
 4475         } else if (cgsId == gcWide || cgsId == gcWBold) {
 4476             underline_len = real_length = (Cardinal) (dst * 2);
 4477             xtermFillCells(&recur,
 4478                    gc,
 4479                    x,
 4480                    y - thisFp->ascent,
 4481                    real_length);
 4482         }
 4483         }
 4484     }
 4485 
 4486     if (recur.draw_flags & NOBACKGROUND) {
 4487         XDrawString16(screen->display,
 4488               VDrawable(screen), gc,
 4489               x, y + y_shift + ascent_adjust,
 4490               buffer, dst);
 4491     } else if (dst <= MaxImageString) {
 4492         XDrawImageString16(screen->display,
 4493                    VDrawable(screen), gc,
 4494                    x, y + y_shift + ascent_adjust,
 4495                    buffer, dst);
 4496     } else {
 4497         int b_pos;
 4498         int b_max = MaxImageString;
 4499         for (b_pos = 0; b_pos < dst; b_pos += b_max) {
 4500         if (b_pos + b_max > dst)
 4501             b_max = (dst - b_pos);
 4502         XDrawImageString16(screen->display,
 4503                    VDrawable(screen), gc,
 4504                    x + (b_pos * FontWidth(screen)),
 4505                    y + y_shift + ascent_adjust,
 4506                    buffer + b_pos,
 4507                    b_max);
 4508         }
 4509     }
 4510 #if OPT_WIDE_ATTRS
 4511     if (need_clipping) {
 4512         endClipping(screen, gc);
 4513     }
 4514 #endif
 4515 
 4516     if ((recur.attr_flags & BOLDATTR(screen)) && (screen->enbolden || !useBoldFont)) {
 4517         if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) {
 4518         beginClipping(screen, gc, (Cardinal) font_width, len);
 4519         }
 4520         XDrawString16(screen->display, VDrawable(screen), gc,
 4521               x + 1,
 4522               y + y_shift + ascent_adjust,
 4523               buffer, dst);
 4524         if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) {
 4525         endClipping(screen, gc);
 4526         }
 4527     }
 4528 
 4529     } else
 4530 #endif /* OPT_WIDE_CHARS */
 4531     {
 4532     int length = (int) len; /* X should have used unsigned */
 4533 #if OPT_WIDE_CHARS
 4534     char *buffer;
 4535     int dst;
 4536 
 4537     BumpTypedBuffer(char, len);
 4538     buffer = BfBuf(char);
 4539 
 4540     for (dst = 0; dst < length; ++dst)
 4541         buffer[dst] = (char) LO_BYTE(text[dst]);
 4542 #else
 4543     char *buffer = (char *) text;
 4544 #endif
 4545 
 4546 #if OPT_WIDE_ATTRS
 4547 #if OPT_DEC_CHRSET
 4548     if (!(CSET_DOUBLE(recur.this_chrset) || (recur.draw_flags & DOUBLEWFONT)))
 4549 #endif
 4550         need_clipping = fixupItalics(&recur, gc, curFont,
 4551                      y, x, font_width, len);
 4552 #endif
 4553 
 4554     if (recur.draw_flags & NOBACKGROUND) {
 4555         XDrawString(screen->display, VDrawable(screen), gc,
 4556             x, y + y_shift, buffer, length);
 4557     } else if (length <= MaxImageString) {
 4558         XDrawImageString(screen->display, VDrawable(screen), gc,
 4559                  x, y + y_shift, buffer, length);
 4560     } else {
 4561         int b_pos;
 4562         int b_max = MaxImageString;
 4563         for (b_pos = 0; b_pos < length; b_pos += b_max) {
 4564         if (b_pos + b_max > length)
 4565             b_max = (length - b_pos);
 4566         XDrawImageString(screen->display,
 4567                  VDrawable(screen), gc,
 4568                  x + (b_pos * FontWidth(screen)),
 4569                  y + y_shift,
 4570                  buffer + b_pos,
 4571                  b_max);
 4572         }
 4573     }
 4574 
 4575 #if OPT_WIDE_ATTRS
 4576     if (need_clipping) {
 4577         endClipping(screen, gc);
 4578     }
 4579 #endif
 4580     underline_len = (Cardinal) length;
 4581     if ((recur.attr_flags & BOLDATTR(screen)) && screen->enbolden) {
 4582         if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) {
 4583         beginClipping(screen, gc, font_width, length);
 4584         }
 4585         XDrawString(screen->display, VDrawable(screen), gc,
 4586             x + 1, y + y_shift, buffer, length);
 4587         if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) {
 4588         endClipping(screen, gc);
 4589         }
 4590     }
 4591     }
 4592 
 4593     drawUnderline(recur.xw,
 4594           gc,
 4595           recur.attr_flags,
 4596           underline_len,
 4597           font_width,
 4598           x,
 4599           y + y_shift,
 4600           did_ul);
 4601 
 4602     x += ((int) real_length) * FontWidth(screen);
 4603     return x;
 4604 }
 4605 
 4606 #if OPT_WIDE_CHARS
 4607 /*
 4608  * Allocate buffer - workaround for wide-character interfaces.
 4609  */
 4610 void
 4611 allocXtermChars(ScrnPtr *buffer, Cardinal length)
 4612 {
 4613     if (*buffer == 0) {
 4614     *buffer = (ScrnPtr) XtMalloc(length);
 4615     } else {
 4616     *buffer = (ScrnPtr) XtRealloc((char *) *buffer, length);
 4617     }
 4618 }
 4619 #endif
 4620 
 4621 /* set up size hints for window manager; min 1 char by 1 char */
 4622 void
 4623 xtermSizeHints(XtermWidget xw, int scrollbarWidth)
 4624 {
 4625     TScreen *screen = TScreenOf(xw);
 4626 
 4627     TRACE(("xtermSizeHints\n"));
 4628     TRACE(("   border    %d\n", xw->core.border_width));
 4629     TRACE(("   scrollbar %d\n", scrollbarWidth));
 4630 
 4631     xw->hints.base_width = 2 * screen->border + scrollbarWidth;
 4632     xw->hints.base_height = 2 * screen->border;
 4633 
 4634 #if OPT_TOOLBAR
 4635     TRACE(("   toolbar   %d\n", ToolbarHeight(xw)));
 4636 
 4637     xw->hints.base_height += ToolbarHeight(xw);
 4638     xw->hints.base_height += BorderWidth(xw) * 2;
 4639     xw->hints.base_width += BorderWidth(xw) * 2;
 4640 #endif
 4641 
 4642     if (xw->misc.resizeByPixel) {
 4643     xw->hints.width_inc = 1;
 4644     xw->hints.height_inc = 1;
 4645     } else {
 4646     xw->hints.width_inc = FontWidth(screen);
 4647     xw->hints.height_inc = FontHeight(screen);
 4648     }
 4649     xw->hints.min_width = xw->hints.base_width + xw->hints.width_inc;
 4650     xw->hints.min_height = xw->hints.base_height + xw->hints.height_inc;
 4651 
 4652     xw->hints.width = MaxCols(screen) * FontWidth(screen) + xw->hints.min_width;
 4653     xw->hints.height = MaxRows(screen) * FontHeight(screen) + xw->hints.min_height;
 4654 
 4655     xw->hints.flags |= (PSize | PBaseSize | PMinSize | PResizeInc);
 4656 
 4657     TRACE_HINTS(&(xw->hints));
 4658 }
 4659 
 4660 void
 4661 getXtermSizeHints(XtermWidget xw)
 4662 {
 4663     TScreen *screen = TScreenOf(xw);
 4664     long supp;
 4665 
 4666     if (!XGetWMNormalHints(screen->display, VShellWindow(xw),
 4667                &xw->hints, &supp))
 4668     memset(&xw->hints, 0, sizeof(xw->hints));
 4669     TRACE_HINTS(&(xw->hints));
 4670 }
 4671 
 4672 CgsEnum
 4673 whichXtermCgs(XtermWidget xw, unsigned attr_flags, Bool hilite)
 4674 {
 4675     TScreen *screen = TScreenOf(xw);
 4676     CgsEnum cgsId = gcMAX;
 4677 
 4678     if (ReverseOrHilite(screen, attr_flags, hilite)) {
 4679     if (attr_flags & BOLDATTR(screen)) {
 4680         cgsId = gcBoldReverse;
 4681     } else {
 4682         cgsId = gcNormReverse;
 4683     }
 4684     } else {
 4685     if (attr_flags & BOLDATTR(screen)) {
 4686         cgsId = gcBold;
 4687     } else {
 4688         cgsId = gcNorm;
 4689     }
 4690     }
 4691     return cgsId;
 4692 }
 4693 
 4694 /*
 4695  * Returns a GC, selected according to the font (reverse/bold/normal) that is
 4696  * required for the current position (implied).  The GC is updated with the
 4697  * current screen foreground and background colors.
 4698  */
 4699 GC
 4700 updatedXtermGC(XtermWidget xw, unsigned attr_flags, CellColor fg_bg,
 4701            Bool hilite)
 4702 {
 4703     TScreen *screen = TScreenOf(xw);
 4704     VTwin *win = WhichVWin(screen);
 4705     CgsEnum cgsId = whichXtermCgs(xw, attr_flags, hilite);
 4706     Pixel my_fg = extract_fg(xw, fg_bg, attr_flags);
 4707     Pixel my_bg = extract_bg(xw, fg_bg, attr_flags);
 4708     Pixel fg_pix = getXtermFG(xw, attr_flags, (int) my_fg);
 4709     Pixel bg_pix = getXtermBG(xw, attr_flags, (int) my_bg);
 4710     Pixel xx_pix;
 4711 #if OPT_HIGHLIGHT_COLOR
 4712     Boolean reverse2 = ((attr_flags & INVERSE) && hilite);
 4713     Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG);
 4714     Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG);
 4715     Boolean always = screen->hilite_color;
 4716     Boolean use_selbg = (Boolean) (always &&
 4717                    isNotForeground(xw, fg_pix, bg_pix, selbg_pix));
 4718     Boolean use_selfg = (Boolean) (always &&
 4719                    isNotBackground(xw, fg_pix, bg_pix, selfg_pix));
 4720 #endif
 4721 
 4722     (void) fg_bg;
 4723     (void) my_bg;
 4724     (void) my_fg;
 4725 
 4726     /*
 4727      * Discard video attributes overridden by colorXXXMode's.
 4728      */
 4729     checkVeryBoldColors(attr_flags, my_fg);
 4730 
 4731     if (ReverseOrHilite(screen, attr_flags, hilite)) {
 4732 #if OPT_HIGHLIGHT_COLOR
 4733     if (!screen->hilite_color) {
 4734         if (selbg_pix != T_COLOR(screen, TEXT_FG)
 4735         && selbg_pix != fg_pix
 4736         && selbg_pix != bg_pix
 4737         && selbg_pix != xw->dft_foreground) {
 4738         bg_pix = fg_pix;
 4739         fg_pix = selbg_pix;
 4740         }
 4741     }
 4742 #endif
 4743     EXCHANGE(fg_pix, bg_pix, xx_pix);
 4744 #if OPT_HIGHLIGHT_COLOR
 4745     if (screen->hilite_color) {
 4746         if (screen->hilite_reverse) {
 4747         if (use_selbg) {
 4748             if (use_selfg) {
 4749             bg_pix = fg_pix;
 4750             } else {
 4751             fg_pix = bg_pix;
 4752             bg_pix = selbg_pix;
 4753             }
 4754         }
 4755         if (use_selfg)
 4756             fg_pix = selfg_pix;
 4757         }
 4758     }
 4759 #endif
 4760     } else if ((attr_flags & INVERSE) && hilite) {
 4761 #if OPT_HIGHLIGHT_COLOR
 4762     if (!screen->hilite_color) {
 4763         if (selbg_pix != T_COLOR(screen, TEXT_FG)
 4764         && selbg_pix != fg_pix
 4765         && selbg_pix != bg_pix
 4766         && selbg_pix != xw->dft_foreground) {
 4767         bg_pix = fg_pix;
 4768         fg_pix = selbg_pix;
 4769         }
 4770     }
 4771 #endif
 4772     /* double-reverse... EXCHANGE(fg_pix, bg_pix, xx_pix); */
 4773 #if OPT_HIGHLIGHT_COLOR
 4774     if (screen->hilite_color) {
 4775         if (screen->hilite_reverse) {
 4776         if (use_selbg) {
 4777             if (use_selfg ^ reverse2) {
 4778             bg_pix = fg_pix;
 4779             } else {
 4780             fg_pix = bg_pix;
 4781             }
 4782             if (reverse2) {
 4783             fg_pix = selbg_pix;
 4784             } else {
 4785             bg_pix = selbg_pix;
 4786             }
 4787         }
 4788         if (use_selfg) {
 4789             if (reverse2) {
 4790             bg_pix = selfg_pix;
 4791             } else {
 4792             fg_pix = selfg_pix;
 4793             }
 4794         }
 4795         }
 4796     }
 4797 #endif
 4798     }
 4799 #if OPT_HIGHLIGHT_COLOR
 4800     if (!screen->hilite_color || !screen->hilite_reverse) {
 4801     if (hilite && !screen->hilite_reverse) {
 4802         if (use_selbg) {
 4803         if (reverse2)
 4804             fg_pix = selbg_pix;
 4805         else
 4806             bg_pix = selbg_pix;
 4807         }
 4808         if (use_selfg) {
 4809         if (reverse2)
 4810             bg_pix = selfg_pix;
 4811         else
 4812             fg_pix = selfg_pix;
 4813         }
 4814     }
 4815     }
 4816 #endif
 4817 
 4818 #if OPT_BLINK_TEXT
 4819     if ((screen->blink_state == ON) &&
 4820     (!screen->blink_as_bold) &&
 4821     (attr_flags & BLINK)) {
 4822     fg_pix = bg_pix;
 4823     }
 4824 #endif
 4825 
 4826     setCgsFore(xw, win, cgsId, fg_pix);
 4827     setCgsBack(xw, win, cgsId, bg_pix);
 4828     return getCgsGC(xw, win, cgsId);
 4829 }
 4830 
 4831 /*
 4832  * Resets the foreground/background of the GC returned by 'updatedXtermGC()'
 4833  * to the values that would be set in SGR_Foreground and SGR_Background. This
 4834  * duplicates some logic, but only modifies 1/4 as many GC's.
 4835  */
 4836 void
 4837 resetXtermGC(XtermWidget xw, unsigned attr_flags, Bool hilite)
 4838 {
 4839     TScreen *screen = TScreenOf(xw);
 4840     VTwin *win = WhichVWin(screen);
 4841     CgsEnum cgsId = whichXtermCgs(xw, attr_flags, hilite);
 4842     Pixel fg_pix = getXtermFG(xw, attr_flags, xw->cur_foreground);
 4843     Pixel bg_pix = getXtermBG(xw, attr_flags, xw->cur_background);
 4844 
 4845     checkVeryBoldColors(attr_flags, xw->cur_foreground);
 4846 
 4847     if (ReverseOrHilite(screen, attr_flags, hilite)) {
 4848     setCgsFore(xw, win, cgsId, bg_pix);
 4849     setCgsBack(xw, win, cgsId, fg_pix);
 4850     } else {
 4851     setCgsFore(xw, win, cgsId, fg_pix);
 4852     setCgsBack(xw, win, cgsId, bg_pix);
 4853     }
 4854 }
 4855 
 4856 #if OPT_ISO_COLORS
 4857 /*
 4858  * Extract the foreground-color index from a color pair.
 4859  * If we've got BOLD or UNDERLINE color-mode active, those will be used.
 4860  */
 4861 Pixel
 4862 extract_fg(XtermWidget xw, CellColor color, unsigned attr_flags)
 4863 {
 4864     unsigned fg = ExtractForeground(color);
 4865 
 4866     if (TScreenOf(xw)->colorAttrMode
 4867     || (fg == ExtractBackground(color))) {
 4868     fg = MapToColorMode(fg, TScreenOf(xw), attr_flags);
 4869     }
 4870     return fg;
 4871 }
 4872 
 4873 /*
 4874  * Extract the background-color index from a color pair.
 4875  * If we've got INVERSE color-mode active, that will be used.
 4876  */
 4877 Pixel
 4878 extract_bg(XtermWidget xw, CellColor color, unsigned attr_flags)
 4879 {
 4880     unsigned bg = ExtractBackground(color);
 4881 
 4882     if (TScreenOf(xw)->colorAttrMode
 4883     || (bg == ExtractForeground(color))) {
 4884     if (TScreenOf(xw)->colorRVMode && (attr_flags & INVERSE))
 4885         bg = COLOR_RV;
 4886     }
 4887     return bg;
 4888 }
 4889 
 4890 /*
 4891  * Combine the current foreground and background into a single 8-bit number.
 4892  * Note that we're storing the SGR foreground, since cur_foreground may be set
 4893  * to COLOR_UL, COLOR_BD or COLOR_BL, which would make the code larger than 8
 4894  * bits.
 4895  *
 4896  * This assumes that fg/bg are equal when we override with one of the special
 4897  * attribute colors.
 4898  */
 4899 CellColor
 4900 makeColorPair(XtermWidget xw)
 4901 {
 4902     CellColor result;
 4903 
 4904 #if OPT_DIRECT_COLOR
 4905     result.fg = xw->cur_foreground;
 4906     result.bg = xw->cur_background;
 4907 #else
 4908     int fg = xw->cur_foreground;
 4909     int bg = xw->cur_background;
 4910     unsigned my_bg = okIndexedColor(bg) ? (unsigned) bg : 0;
 4911     unsigned my_fg = okIndexedColor(fg) ? (unsigned) fg : my_bg;
 4912 
 4913     result = (CellColor) (my_fg | (my_bg << COLOR_BITS));
 4914 #endif
 4915 
 4916     return result;
 4917 }
 4918 
 4919 /*
 4920  * Using the "current" SGR background, clear a rectangle.
 4921  */
 4922 void
 4923 ClearCurBackground(XtermWidget xw,
 4924            int top,
 4925            int left,
 4926            unsigned height,
 4927            unsigned width,
 4928            unsigned fw)
 4929 {
 4930     TScreen *screen = TScreenOf(xw);
 4931 
 4932     TRACE(("ClearCurBackground %d,%d %dx%d with %d\n",
 4933        top, left, height, width, xw->cur_background));
 4934 
 4935     assert((int) width > 0);
 4936     assert((left + (int) width) <= screen->max_col + 1);
 4937     assert((int) height <= screen->max_row + 1);
 4938 
 4939     if (VWindow(screen)) {
 4940     set_background(xw, xw->cur_background);
 4941 
 4942     xtermClear2(xw,
 4943             CursorX2(screen, left, fw),
 4944             CursorY2(screen, top),
 4945             (width * fw),
 4946             (height * (unsigned) FontHeight(screen)));
 4947 
 4948     set_background(xw, -1);
 4949     }
 4950 }
 4951 #endif /* OPT_ISO_COLORS */
 4952 
 4953 Pixel
 4954 getXtermBackground(XtermWidget xw, unsigned attr_flags, int color)
 4955 {
 4956     Pixel result = T_COLOR(TScreenOf(xw), TEXT_BG);
 4957 
 4958 #if OPT_ISO_COLORS
 4959     if (color >= 0) {
 4960     if_OPT_DIRECT_COLOR2_else(TScreenOf(xw), (attr_flags & ATR_DIRECT_BG), {
 4961         result = (Pixel) color;
 4962     }) if ((attr_flags & BG_COLOR) && (color < MAXCOLORS)) {
 4963         result = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[color]);
 4964     }
 4965     }
 4966 #else
 4967     (void) attr_flags;
 4968     (void) color;
 4969 #endif
 4970     return result;
 4971 }
 4972 
 4973 Pixel
 4974 getXtermForeground(XtermWidget xw, unsigned attr_flags, int color)
 4975 {
 4976     Pixel result = T_COLOR(TScreenOf(xw), TEXT_FG);
 4977 
 4978 #if OPT_ISO_COLORS
 4979     if_OPT_DIRECT_COLOR2_else(TScreenOf(xw), (attr_flags & ATR_DIRECT_FG), {
 4980     result = (Pixel) color;
 4981     })
 4982     if ((attr_flags & FG_COLOR) &&
 4983         (color >= 0 && color < MAXCOLORS)) {
 4984     result = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[color]);
 4985     }
 4986 #else
 4987     (void) attr_flags;
 4988     (void) color;
 4989 #endif
 4990 
 4991 #if OPT_WIDE_ATTRS
 4992 #define DIM_IT(n) work.n = (unsigned short) ((2 * (unsigned)work.n) / 3)
 4993     if ((attr_flags & ATR_FAINT)) {
 4994     static Pixel last_in;
 4995     static Pixel last_out;
 4996     if ((result != last_in)
 4997         && ((color >= 0)
 4998         || (result != (Pixel) color))) {
 4999         XColor work;
 5000         work.pixel = result;
 5001         last_in = result;
 5002         if (XQueryColor(TScreenOf(xw)->display, xw->core.colormap, &work)) {
 5003         DIM_IT(red);
 5004         DIM_IT(green);
 5005         DIM_IT(blue);
 5006         if (allocateBestRGB(xw, &work)) {
 5007             result = work.pixel;
 5008         }
 5009         }
 5010         last_out = result;
 5011     } else {
 5012         result = last_out;
 5013     }
 5014     }
 5015 #endif
 5016     return result;
 5017 }
 5018 
 5019 /*
 5020  * Returns a single base character for the given cell.
 5021  */
 5022 unsigned
 5023 getXtermCell(TScreen *screen, int row, int col)
 5024 {
 5025     CLineData *ld = getLineData(screen, row);
 5026 
 5027     return ((ld && (col < (int) ld->lineSize))
 5028         ? ld->charData[col]
 5029         : (unsigned) ' ');
 5030 }
 5031 
 5032 /*
 5033  * Sets a single base character for the given cell.
 5034  */
 5035 void
 5036 putXtermCell(TScreen *screen, int row, int col, int ch)
 5037 {
 5038     LineData *ld = getLineData(screen, row);
 5039 
 5040     if (ld && (col < (int) ld->lineSize)) {
 5041     ld->charData[col] = (CharData) ch;
 5042     if_OPT_WIDE_CHARS(screen, {
 5043         size_t off;
 5044         for_each_combData(off, ld) {
 5045         ld->combData[off][col] = 0;
 5046         }
 5047     });
 5048     }
 5049 }
 5050 
 5051 #if OPT_WIDE_CHARS
 5052 /*
 5053  * Add a combining character for the given cell
 5054  */
 5055 void
 5056 addXtermCombining(TScreen *screen, int row, int col, unsigned ch)
 5057 {
 5058     if (ch != 0) {
 5059     LineData *ld = getLineData(screen, row);
 5060     size_t off;
 5061 
 5062     TRACE(("addXtermCombining %d,%d U+%04X (%d)\n",
 5063            row, col, ch, CharWidth(ch)));
 5064 
 5065     for_each_combData(off, ld) {
 5066         if (!ld->combData[off][col]) {
 5067         ld->combData[off][col] = (CharData) ch;
 5068         break;
 5069         }
 5070     }
 5071     }
 5072 }
 5073 
 5074 unsigned
 5075 getXtermCombining(TScreen *screen, int row, int col, int off)
 5076 {
 5077     CLineData *ld = getLineData(screen, row);
 5078     return (ld->combSize ? ld->combData[off][col] : 0U);
 5079 }
 5080 #endif
 5081 
 5082 void
 5083 update_keyboard_type(void)
 5084 {
 5085     update_delete_del();
 5086     update_tcap_fkeys();
 5087     update_old_fkeys();
 5088     update_hp_fkeys();
 5089     update_sco_fkeys();
 5090     update_sun_fkeys();
 5091     update_sun_kbd();
 5092 }
 5093 
 5094 void
 5095 set_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set)
 5096 {
 5097     xtermKeyboardType save = xw->keyboard.type;
 5098 
 5099     TRACE(("set_keyboard_type(%s, %s) currently %s\n",
 5100        visibleKeyboardType(type),
 5101        BtoS(set),
 5102        visibleKeyboardType(xw->keyboard.type)));
 5103     if (set) {
 5104     xw->keyboard.type = type;
 5105     } else {
 5106     xw->keyboard.type = keyboardIsDefault;
 5107     }
 5108 
 5109     if (save != xw->keyboard.type) {
 5110     update_keyboard_type();
 5111     }
 5112 }
 5113 
 5114 void
 5115 toggle_keyboard_type(XtermWidget xw, xtermKeyboardType type)
 5116 {
 5117     xtermKeyboardType save = xw->keyboard.type;
 5118 
 5119     TRACE(("toggle_keyboard_type(%s) currently %s\n",
 5120        visibleKeyboardType(type),
 5121        visibleKeyboardType(xw->keyboard.type)));
 5122     if (xw->keyboard.type == type) {
 5123     xw->keyboard.type = keyboardIsDefault;
 5124     } else {
 5125     xw->keyboard.type = type;
 5126     }
 5127 
 5128     if (save != xw->keyboard.type) {
 5129     update_keyboard_type();
 5130     }
 5131 }
 5132 
 5133 const char *
 5134 visibleKeyboardType(xtermKeyboardType type)
 5135 {
 5136     const char *result = "?";
 5137     switch (type) {
 5138     CASETYPE(keyboardIsLegacy); /* bogus vt220 codes for F1-F4, etc. */
 5139     CASETYPE(keyboardIsDefault);
 5140     CASETYPE(keyboardIsHP);
 5141     CASETYPE(keyboardIsSCO);
 5142     CASETYPE(keyboardIsSun);
 5143     CASETYPE(keyboardIsTermcap);
 5144     CASETYPE(keyboardIsVT220);
 5145     }
 5146     return result;
 5147 }
 5148 
 5149 static void
 5150 init_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set)
 5151 {
 5152     TRACE(("init_keyboard_type(%s, %s) currently %s\n",
 5153        visibleKeyboardType(type),
 5154        BtoS(set),
 5155        visibleKeyboardType(xw->keyboard.type)));
 5156     if (set) {
 5157     /*
 5158      * Check for conflicts, e.g., if someone asked for both Sun and HP
 5159      * function keys.
 5160      */
 5161     if (guard_keyboard_type) {
 5162         xtermWarning("Conflicting keyboard type option (%s/%s)\n",
 5163              visibleKeyboardType(xw->keyboard.type),
 5164              visibleKeyboardType(type));
 5165     }
 5166     xw->keyboard.type = type;
 5167     guard_keyboard_type = True;
 5168     update_keyboard_type();
 5169     }
 5170 }
 5171 
 5172 /*
 5173  * If the keyboardType resource is set, use that, overriding the individual
 5174  * boolean resources for different keyboard types.
 5175  */
 5176 void
 5177 decode_keyboard_type(XtermWidget xw, XTERM_RESOURCE * rp)
 5178 {
 5179 #define DATA(n, t, f) { n, t, XtOffsetOf(XTERM_RESOURCE, f) }
 5180 #define FLAG(n) *(Boolean *)(((char *)rp) + table[n].offset)
 5181     static struct {
 5182     const char *name;
 5183     xtermKeyboardType type;
 5184     unsigned offset;
 5185     } table[] = {
 5186     DATA(NAME_OLD_KT, keyboardIsLegacy, oldKeyboard),
 5187 #if OPT_HP_FUNC_KEYS
 5188         DATA(NAME_HP_KT, keyboardIsHP, hpFunctionKeys),
 5189 #endif
 5190 #if OPT_SCO_FUNC_KEYS
 5191         DATA(NAME_SCO_KT, keyboardIsSCO, scoFunctionKeys),
 5192 #endif
 5193 #if OPT_SUN_FUNC_KEYS
 5194         DATA(NAME_SUN_KT, keyboardIsSun, sunFunctionKeys),
 5195 #endif
 5196 #if OPT_SUNPC_KBD
 5197         DATA(NAME_VT220_KT, keyboardIsVT220, sunKeyboard),
 5198 #endif
 5199 #if OPT_TCAP_FKEYS
 5200         DATA(NAME_TCAP_KT, keyboardIsTermcap, termcapKeys),
 5201 #endif
 5202     };
 5203     Cardinal n;
 5204     TScreen *screen = TScreenOf(xw);
 5205 
 5206     TRACE(("decode_keyboard_type(%s)\n", rp->keyboardType));
 5207     if (!x_strcasecmp(rp->keyboardType, "unknown")) {
 5208     /*
 5209      * Let the individual resources comprise the keyboard-type.
 5210      */
 5211     for (n = 0; n < XtNumber(table); ++n)
 5212         init_keyboard_type(xw, table[n].type, FLAG(n));
 5213     } else if (!x_strcasecmp(rp->keyboardType, "default")) {
 5214     /*
 5215      * Set the keyboard-type to the Sun/PC type, allowing modified
 5216      * function keys, etc.
 5217      */
 5218     for (n = 0; n < XtNumber(table); ++n)
 5219         init_keyboard_type(xw, table[n].type, False);
 5220     } else {
 5221     Bool found = False;
 5222 
 5223     /*
 5224      * Special case: oldXtermFKeys should have been like the others.
 5225      */
 5226     if (!x_strcasecmp(rp->keyboardType, NAME_OLD_KT)) {
 5227         TRACE(("special case, setting oldXtermFKeys\n"));
 5228         screen->old_fkeys = True;
 5229         screen->old_fkeys0 = True;
 5230     }
 5231 
 5232     /*
 5233      * Choose an individual keyboard type.
 5234      */
 5235     for (n = 0; n < XtNumber(table); ++n) {
 5236         if (!x_strcasecmp(rp->keyboardType, table[n].name + 1)) {
 5237         FLAG(n) = True;
 5238         found = True;
 5239         } else {
 5240         FLAG(n) = False;
 5241         }
 5242         init_keyboard_type(xw, table[n].type, FLAG(n));
 5243     }
 5244     if (!found) {
 5245         xtermWarning("KeyboardType resource \"%s\" not found\n",
 5246              rp->keyboardType);
 5247     }
 5248     }
 5249 #undef DATA
 5250 #undef FLAG
 5251 }
 5252 
 5253 #if OPT_WIDE_CHARS
 5254 #if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
 5255 /*
 5256  * If xterm is running in a UTF-8 locale, it is still possible to encounter
 5257  * old runtime configurations which yield incomplete or inaccurate data.
 5258  */
 5259 static Bool
 5260 systemWcwidthOk(int samplesize, int samplepass)
 5261 {
 5262     wchar_t n;
 5263     int oops = 0;
 5264 
 5265     for (n = 21; n <= 25; ++n) {
 5266     wchar_t code = (wchar_t) dec2ucs(NULL, (unsigned) n);
 5267     int system_code = wcwidth(code);
 5268     int intern_code = mk_wcwidth(code);
 5269 
 5270     /*
 5271      * Solaris 10 wcwidth() returns "2" for all of the line-drawing (page
 5272      * 0x2500) and most of the geometric shapes (a few are excluded, just
 5273      * to make it more difficult to use).  Do a sanity check to avoid using
 5274      * it.
 5275      */
 5276     if ((system_code < 0 && intern_code >= 1)
 5277         || (system_code >= 0 && intern_code != system_code)) {
 5278         TRACE(("systemWcwidthOk: broken system line-drawing wcwidth\n"));
 5279         oops += (samplepass + 1);
 5280         break;
 5281     }
 5282     }
 5283 
 5284     for (n = 0; n < (wchar_t) samplesize; ++n) {
 5285     int system_code = wcwidth(n);
 5286     int intern_code = mk_wcwidth(n);
 5287 
 5288     /*
 5289      * When this check was originally implemented, there were few if any
 5290      * libraries with full Unicode coverage.  Time passes, and it is
 5291      * possible to make a full comparison of the BMP.  There are some
 5292      * differences: mk_wcwidth() marks some codes as combining and some
 5293      * as single-width, differing from GNU libc.
 5294      */
 5295     if ((system_code < 0 && intern_code >= 1)
 5296         || (system_code >= 0 && intern_code != system_code)) {
 5297         TRACE((".. width(U+%04X) = %d, expected %d\n",
 5298            (unsigned) n, system_code, intern_code));
 5299         if (++oops > samplepass)
 5300         break;
 5301     }
 5302     }
 5303     TRACE(("systemWcwidthOk: %d/%d mismatches, allowed %d\n",
 5304        oops, (int) n, samplepass));
 5305     return (oops <= samplepass);
 5306 }
 5307 #endif /* HAVE_WCWIDTH */
 5308 
 5309 void
 5310 decode_wcwidth(XtermWidget xw)
 5311 {
 5312     int mode = ((xw->misc.cjk_width ? 2 : 0)
 5313         + (xw->misc.mk_width ? 1 : 0)
 5314         + 1);
 5315 
 5316     switch (mode) {
 5317     default:
 5318 #if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
 5319     if (xtermEnvUTF8() &&
 5320         systemWcwidthOk(xw->misc.mk_samplesize, xw->misc.mk_samplepass)) {
 5321         my_wcwidth = wcwidth;
 5322         TRACE(("using system wcwidth() function\n"));
 5323         break;
 5324     }
 5325 #endif
 5326     /* FALLTHRU */
 5327     case 2:
 5328     my_wcwidth = &mk_wcwidth;
 5329     TRACE(("using MK wcwidth() function\n"));
 5330     break;
 5331     case 3:
 5332     /* FALLTHRU */
 5333     case 4:
 5334     my_wcwidth = &mk_wcwidth_cjk;
 5335     TRACE(("using MK-CJK wcwidth() function\n"));
 5336     break;
 5337     }
 5338 
 5339     for (first_widechar = 128; first_widechar < 4500; ++first_widechar) {
 5340     if (my_wcwidth((wchar_t) first_widechar) > 1) {
 5341         TRACE(("first_widechar %#x\n", first_widechar));
 5342         break;
 5343     }
 5344     }
 5345 }
 5346 #endif
 5347 
 5348 /*
 5349  * Extend a (normally) boolean resource value by checking for additional values
 5350  * which will be mapped into true/false.
 5351  */
 5352 int
 5353 extendedBoolean(const char *value, const FlagList * table, Cardinal limit)
 5354 {
 5355     int result = -1;
 5356     long check;
 5357     char *next;
 5358     Cardinal n;
 5359 
 5360     if ((x_strcasecmp(value, "true") == 0)
 5361     || (x_strcasecmp(value, "yes") == 0)
 5362     || (x_strcasecmp(value, "on") == 0)) {
 5363     result = True;
 5364     } else if ((x_strcasecmp(value, "false") == 0)
 5365            || (x_strcasecmp(value, "no") == 0)
 5366            || (x_strcasecmp(value, "off") == 0)) {
 5367     result = False;
 5368     } else if ((check = strtol(value, &next, 0)) >= 0 && FullS2L(value, next)) {
 5369     if (check >= (long) limit)  /* i.e., past False=0, True=1 */
 5370         check = True;
 5371     result = (int) check;
 5372     } else {
 5373     for (n = 0; n < limit - 2; ++n) {
 5374         if (table[n].name == NULL) {
 5375         break;
 5376         } else if (x_strcasecmp(value, table[n].name) == 0) {
 5377         result = table[n].code;
 5378         break;
 5379         }
 5380     }
 5381     }
 5382 
 5383     if (result < 0) {
 5384     xtermWarning("Unrecognized keyword: %s\n", value);
 5385     result = False;
 5386     }
 5387 
 5388     TRACE(("extendedBoolean(%s) = %d\n", value, result));
 5389     return result;
 5390 }
 5391 
 5392 /*
 5393  * Something like round() from math library, but round() is less widely-used
 5394  * than xterm.