コード例 #1
0
ファイル: screen.c プロジェクト: ThomasDickey/old-xterm
/*
 * This function dynamically adds support for wide-characters.
 */
void
ChangeToWide(TScreen * screen)
{
    unsigned new_bufoffset = (OFF_COM2H + 1);
    int savelines = screen->scrollWidget ? screen->savelines : 0;

    if (screen->wide_chars)
	return;

    TRACE(("ChangeToWide\n"));
    if (xtermLoadWideFonts(term, True)) {
	if (savelines < 0)
	    savelines = 0;
	ReallocateBufOffsets(&screen->allbuf, &screen->sbuf_address,
			     (unsigned) (MaxRows(screen) + savelines),
			     (unsigned) MaxCols(screen),
			     new_bufoffset);
	if (screen->altbuf)
	    ReallocateBufOffsets(&screen->altbuf, &screen->abuf_address,
				 (unsigned) MaxRows(screen),
				 (unsigned) MaxCols(screen),
				 new_bufoffset);
	screen->wide_chars = True;
	term->num_ptrs = new_bufoffset;
	screen->visbuf = &screen->allbuf[MAX_PTRS * savelines];
	update_font_utf8_mode();
	SetVTFont(term, screen->menu_font_number, TRUE, NULL);
    }
    TRACE(("...ChangeToWide\n"));
}
コード例 #2
0
void
WindowScroll(XtermWidget xw, int top, Bool always GCC_UNUSED)
{
    TScreen *screen = TScreenOf(xw);

#if OPT_SCROLL_LOCK
    if (screen->allowScrollLock && (screen->scroll_lock && !always)) {
	if (screen->scroll_dirty) {
	    screen->scroll_dirty = False;
	    ScrnRefresh(xw, 0, 0, MaxRows(screen), MaxCols(screen), False);
	}
    } else
#endif
    {
	int i;

	if (top < -screen->savedlines) {
	    top = -screen->savedlines;
	} else if (top > 0) {
	    top = 0;
	}

	if ((i = screen->topline - top) != 0) {
	    int lines;
	    int scrolltop, scrollheight, refreshtop;

	    if (screen->cursor_state)
		HideCursor();
	    lines = i > 0 ? i : -i;
	    if (lines > MaxRows(screen))
		lines = MaxRows(screen);
	    scrollheight = screen->max_row - lines + 1;
	    if (i > 0)
		refreshtop = scrolltop = 0;
	    else {
		scrolltop = lines;
		refreshtop = scrollheight;
	    }
	    scrolling_copy_area(xw, scrolltop, scrollheight, -i);
	    screen->topline = top;

	    ScrollSelection(screen, i, True);

	    xtermClear2(xw,
			OriginX(screen),
			OriginY(screen) + refreshtop * FontHeight(screen),
			(unsigned) Width(screen),
			(unsigned) (lines * FontHeight(screen)));
	    ScrnRefresh(xw, refreshtop, 0, lines, MaxCols(screen), False);

#if OPT_BLINK_CURS || OPT_BLINK_TEXT
	    RestartBlinking(screen);
#endif
	}
    }
    ScrollBarDrawThumb(screen->scrollWidget);
}
コード例 #3
0
ファイル: testxmc.c プロジェクト: aosm/X11apps
/*
 * After writing text to the screen, resolve mismatch between the current
 * location and any attributes that would have been set by preceding locations.
 */
void
Resolve_XMC(XtermWidget xw)
{
    TScreen *screen = TScreenOf(xw);
    LineData *ld;
    Bool changed = False;
    Char start;
    Char my_attrs = CharOf(screen->xmc_attributes & XMC_FLAGS);
    int row = screen->cur_row;
    int col = screen->cur_col;

    /* Find the preceding cell.
     */
    ld = getLineData(screen, row);
    if (ld->charData[col] != XMC_GLITCH) {
	if (col != 0) {
	    col--;
	} else if (!screen->xmc_inline && row != 0) {
	    ld = getLineData(screen, --row);
	    col = LineMaxCol(screen, ld);
	}
    }
    start = (ld->attribs[col] & my_attrs);

    /* Now propagate the starting state until we reach a cell which holds
     * a glitch.
     */
    for (;;) {
	if (col < LineMaxCol(screen, ld)) {
	    col++;
	} else if (!screen->xmc_inline && row < screen->max_row) {
	    col = 0;
	    ld = getLineData(screen, ++row);
	} else
	    break;
	if (ld->charData[col] == XMC_GLITCH)
	    break;
	if ((ld->attribs[col] & my_attrs) != start) {
	    ld->attribs[col] =
		CharOf(start | (ld->attribs[col] & ~my_attrs));
	    changed = True;
	}
    }

    TRACE(("XMC %s (%s:%d/%d) from %d,%d to %d,%d\n",
	   changed ? "Ripple" : "Nochange",
	   BtoS(xw->flags & my_attrs),
	   my_attrs, start,
	   screen->cur_row, screen->cur_col,
	   row, col));

    if (changed) {
	ScrnUpdate(xw, screen->cur_row, 0, row + 1 - screen->cur_row,
		   MaxCols(screen), True);
    }
}
コード例 #4
0
static void
repaint_line(XtermWidget xw, unsigned newChrSet)
{
    TScreen *screen = TScreenOf(xw);
    LineData *ld;
    int curcol = screen->cur_col;
    int currow = screen->cur_row;
    int width = MaxCols(screen);
    unsigned len = (unsigned) width;

    assert(width > 0);

    /*
     * Ignore repetition.
     */
    if (!IsLeftRightMode(xw)
	&& (ld = getLineData(screen, currow)) != 0) {
	unsigned oldChrSet = GetLineDblCS(ld);

	if (oldChrSet != newChrSet) {
	    TRACE(("repaint_line(%2d,%2d) (%s -> %s)\n", currow, screen->cur_col,
		   visibleDblChrset(oldChrSet),
		   visibleDblChrset(newChrSet)));
	    HideCursor();

	    /* If switching from single-width, keep the cursor in the visible part
	     * of the line.
	     */
	    if (CSET_DOUBLE(newChrSet)) {
		width /= 2;
		if (curcol > width)
		    curcol = width;
	    }

	    /*
	     * ScrnRefresh won't paint blanks for us if we're switching between a
	     * single-size and double-size font.  So we paint our own.
	     */
	    ClearCurBackground(xw,
			       currow,
			       0,
			       1,
			       len,
			       (unsigned) LineFontWidth(screen, ld));

	    SetLineDblCS(ld, newChrSet);

	    set_cur_col(screen, 0);
	    ScrnUpdate(xw, currow, 0, 1, (int) len, True);
	    set_cur_col(screen, curcol);
	}
    }
}
コード例 #5
0
ファイル: screen.c プロジェクト: ThomasDickey/old-xterm
/*
 * Writes str into buf at screen's current row and column.  Characters are set
 * to match flags.
 */
void
ScreenWrite(TScreen * screen,
	    PAIRED_CHARS(Char * str, Char * str2),
	    unsigned flags,
	    unsigned cur_fg_bg,
	    unsigned length)
{
#if OPT_ISO_COLORS
#if OPT_EXT_COLORS
    Char *fbf = 0;
    Char *fbb = 0;
#else
    Char *fb = 0;
#endif
#endif
#if OPT_DEC_CHRSET
    Char *cb = 0;
#endif
    Char *attrs;
    int avail = MaxCols(screen) - screen->cur_col;
    Char *chars;
    int wrappedbit;
#if OPT_WIDE_CHARS
    Char starcol1, starcol2;
    Char *comb1l = 0, *comb1h = 0, *comb2l = 0, *comb2h = 0;
#endif
    unsigned real_width = visual_width(PAIRED_CHARS(str, str2), length);

    if (avail <= 0)
	return;
    if (length > (unsigned) avail)
	length = avail;
    if (length == 0 || real_width == 0)
	return;

    chars = SCRN_BUF_CHARS(screen, screen->cur_row) + screen->cur_col;
    attrs = SCRN_BUF_ATTRS(screen, screen->cur_row) + screen->cur_col;

    if_OPT_WIDE_CHARS(screen, {
	comb1l = SCRN_BUF_COM1L(screen, screen->cur_row) + screen->cur_col;
	comb1h = SCRN_BUF_COM1H(screen, screen->cur_row) + screen->cur_col;
	comb2l = SCRN_BUF_COM2L(screen, screen->cur_row) + screen->cur_col;
	comb2h = SCRN_BUF_COM2H(screen, screen->cur_row) + screen->cur_col;
    });
コード例 #6
0
/*
 * Allocate a new row in the scrollback FIFO, returning a pointer to it.
 */
LineData *
addScrollback(TScreen * screen)
{
    ScrnBuf where = 0;
    unsigned which;
    unsigned ncols = (unsigned) MaxCols(screen);
    Char *block;

    if (screen->saveBuf_index != 0) {
	screen->saved_fifo++;
	TRACE(("addScrollback %lu\n", screen->saved_fifo));

	/* first, see which index we'll use */
	which = (unsigned) (screen->saved_fifo % screen->savelines);
	where = scrnHeadAddr(screen, screen->saveBuf_index, which);

	/* discard any obsolete index data */
	if (screen->saved_fifo > screen->savelines) {
	    LineData *prior = (LineData *) where;
	    /*
	     * setupLineData uses the attribs as the first address used from the
	     * data block.
	     */
	    if (prior->attribs != 0) {
		TRACE(("...freeing prior FIFO data in slot %d: %p->%p\n",
		       which, (void *) prior, prior->attribs));
		free(prior->attribs);
		prior->attribs = 0;
	    }
	}

	/* allocate the new data */
	block = allocScrnData(screen, 1, ncols);

	/* record the new data in the index */
	setupLineData(screen, where, (Char *) block, 1, ncols);

	TRACE(("...storing new FIFO data in slot %d: %p->%p\n",
	       which, (void *) where, block));

    }
    return (LineData *) where;
}
コード例 #7
0
static void
dumpSvgScreen(XtermWidget xw, FILE *fp)
{
    TScreen *s = TScreenOf(xw);
    int row;

    fprintf(fp, "  <rect x='0' y='0' width='%u' height='%u' fill='%s'/>\n",
	    cols * CELLW + 2 * (bw + ib), rows * CELLH + 2 * (bw + ib),
	    PixelToCSSColor(xw, xw->core.border_pixel));
    fprintf(fp, "  <rect x='%u' y='%u' width='%u' height='%u' fill='%s'/>\n",
	    bw, bw,
	    MaxCols(s) * CELLW + 2 * ib,
	    (unsigned) (rows * CELLH + 2 * ib),
	    PixelToCSSColor(xw, xw->old_background));

    for (row = s->top_marg; row <= s->bot_marg; ++row) {
	fprintf(fp, "  <!-- Row %d -->\n", row);
	dumpSvgLine(xw, row, fp);
    }
}
コード例 #8
0
static void
dumpSvgHeader(XtermWidget xw, FILE *fp)
{
    TScreen *s = TScreenOf(xw);

    rows = s->bot_marg - s->top_marg + 1;
    cols = MaxCols(s);
    bw = BorderWidth(xw);
    ib = s->border;

    fputs("<?xml version='1.0' encoding='UTF-8'?>\n", fp);
    fputs("<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN'\n", fp);
    fputs("  'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>\n", fp);
    fputs("<svg xmlns='http://www.w3.org/2000/svg'\n", fp);
    fputs(" version='1.1' baseProfile='full'\n", fp);
    fprintf(fp, " viewBox='0 0 %d %d'>\n", 2 * (bw + ib) + cols * CELLW, 2 *
	    (bw + ib) +
	    rows * CELLH);
    fprintf(fp, " <desc>%s Screen Dump</desc>\n", xtermVersion());
    fprintf(fp,
	    " <g font-size='%.2f' font-family='monospace, monospace'>\n",
	    0.80 * CELLH);
}
コード例 #9
0
ファイル: linedata.c プロジェクト: Bluerise/bitrig-xenocara
void
saveCellData(TScreen * screen,
	     CellData * data,
	     Cardinal cell,
	     LineData * ld,
	     int column)
{
    CellData *item = CellDataAddr(screen, data, cell);

    if (column < MaxCols(screen)) {
	item->attribs = ld->attribs[column];
#if OPT_ISO_COLORS
	item->color = ld->color[column];
#endif
	item->charData = ld->charData[column];
	if_OPT_WIDE_CHARS(screen, {
	    size_t off;
	    item->combSize = ld->combSize;
	    for_each_combData(off, ld) {
		item->combData[off] = ld->combData[off][column];
	    }
	})
    }
コード例 #10
0
ファイル: cursor.c プロジェクト: ThomasDickey/old-xterm
/*
 * moves the cursor left n, no wrap around
 */
void
CursorBack(TScreen * screen, int n)
{
    int i, j, k, rev;

    if ((rev = (term->flags & (REVERSEWRAP | WRAPAROUND)) ==
	 (REVERSEWRAP | WRAPAROUND)) != 0
	&& screen->do_wrap)
	n--;
    if ((screen->cur_col -= n) < 0) {
	if (rev) {
	    if ((i = ((j = MaxCols(screen))
		      * screen->cur_row) + screen->cur_col) < 0) {
		k = j * MaxRows(screen);
		i += ((-i) / k + 1) * k;
	    }
	    set_cur_row(screen, i / j);
	    set_cur_col(screen, i % j);
	} else
	    set_cur_col(screen, 0);
    }
    screen->do_wrap = 0;
}
コード例 #11
0
ファイル: linedata.c プロジェクト: Bluerise/bitrig-xenocara
/*
 * Given a row-number, find the corresponding data for the line in the VT100
 * widget.  Row numbers can be positive or negative.
 *
 * If the data comes from the scrollback, defer that to getScrollback().
 */
LineData *
getLineData(TScreen * screen, int row)
{
    LineData *result = 0;
    ScrnBuf buffer;
    int max_row = screen->max_row;

    if (row >= 0) {
	buffer = screen->visbuf;
    } else {
#if OPT_FIFO_LINES
	buffer = 0;
	result = getScrollback(screen, row);
#else
	buffer = screen->saveBuf_index;
	row += screen->savelines;
	max_row += screen->savelines;
#endif
    }
    if (row >= 0 && row <= max_row) {
	result = (LineData *) scrnHeadAddr(screen, buffer, (unsigned) row);
	if (result != 0) {
#if 1				/* FIXME - these should be done in setupLineData, etc. */
	    result->lineSize = (Dimension) MaxCols(screen);
#if OPT_WIDE_CHARS
	    if (screen->wide_chars) {
		result->combSize = (Char) screen->max_combining;
	    } else {
		result->combSize = 0;
	    }
#endif
#endif /* FIXME */
	}
    }

    return result;
}
コード例 #12
0
/* Resize the text window for a terminal screen, modifying the
 * appropriate WM_SIZE_HINTS and taking advantage of bit gravity.
 */
void
DoResizeScreen(XtermWidget xw)
{
    TScreen *screen = TScreenOf(xw);

    int border = 2 * screen->border;
    int min_wide = border + screen->fullVwin.sb_info.width;
    int min_high = border;
    XtGeometryResult geomreqresult;
    Dimension reqWidth, reqHeight, repWidth, repHeight;
#ifndef NO_ACTIVE_ICON
    VTwin *saveWin = WhichVWin(screen);

    /* all units here want to be in the normal font units */
    WhichVWin(screen) = &screen->fullVwin;
#endif /* NO_ACTIVE_ICON */

    /*
     * I'm going to try to explain, as I understand it, why we
     * have to do XGetWMNormalHints and XSetWMNormalHints here,
     * although I can't guarantee that I've got it right.
     *
     * In a correctly written toolkit program, the Shell widget
     * parses the user supplied geometry argument.  However,
     * because of the way xterm does things, the VT100 widget does
     * the parsing of the geometry option, not the Shell widget.
     * The result of this is that the Shell widget doesn't set the
     * correct window manager hints, and doesn't know that the
     * user has specified a geometry.
     *
     * The XtVaSetValues call below tells the Shell widget to
     * change its hints.  However, since it's confused about the
     * hints to begin with, it doesn't get them all right when it
     * does the SetValues -- it undoes some of what the VT100
     * widget did when it originally set the hints.
     *
     * To fix this, we do the following:
     *
     * 1. Get the sizehints directly from the window, going around
     *    the (confused) shell widget.
     * 2. Call XtVaSetValues to let the shell widget know which
     *    hints have changed.  Note that this may not even be
     *    necessary, since we're going to right ahead after that
     *    and set the hints ourselves, but it's good to put it
     *    here anyway, so that when we finally do fix the code so
     *    that the Shell does the right thing with hints, we
     *    already have the XtVaSetValues in place.
     * 3. We set the sizehints directly, this fixing up whatever
     *    damage was done by the Shell widget during the
     *    XtVaSetValues.
     *
     * Gross, huh?
     *
     * The correct fix is to redo VTRealize, VTInitialize and
     * VTSetValues so that font processing happens early enough to
     * give back responsibility for the size hints to the Shell.
     *
     * Someday, we hope to have time to do this.  Someday, we hope
     * to have time to completely rewrite xterm.
     */

    TRACE(("DoResizeScreen\n"));

#if 1				/* ndef nothack */
    /*
     * NOTE: the hints and the XtVaSetValues() must match.
     */
    TRACE(("%s@%d -- ", __FILE__, __LINE__));
    TRACE_WM_HINTS(xw);
    getXtermSizeHints(xw);

    xtermSizeHints(xw, ScrollbarWidth(screen));

    /* These are obsolete, but old clients may use them */
    xw->hints.width = MaxCols(screen) * FontWidth(screen) + xw->hints.min_width;
    xw->hints.height = MaxRows(screen) * FontHeight(screen) + xw->hints.min_height;
#if OPT_MAXIMIZE
    /* assure single-increment resize for fullscreen */
    if (xw->work.ewmh[0].mode) {
	xw->hints.width_inc = 1;
	xw->hints.height_inc = 1;
    }
#endif /* OPT_MAXIMIZE */
#endif

    XSetWMNormalHints(screen->display, VShellWindow(xw), &xw->hints);

    reqWidth = (Dimension) (MaxCols(screen) * FontWidth(screen) + min_wide);
    reqHeight = (Dimension) (MaxRows(screen) * FontHeight(screen) + min_high);

#if OPT_MAXIMIZE
    /* compensate for fullscreen mode */
    if (xw->work.ewmh[0].mode) {
	Screen *xscreen = DefaultScreenOfDisplay(xw->screen.display);
	reqWidth = (Dimension) WidthOfScreen(xscreen);
	reqHeight = (Dimension) HeightOfScreen(xscreen);
	ScreenResize(xw, reqWidth, reqHeight, &xw->flags);
    }
#endif /* OPT_MAXIMIZE */

    TRACE(("...requesting screensize chars %dx%d, pixels %dx%d\n",
	   MaxRows(screen),
	   MaxCols(screen),
	   reqHeight, reqWidth));

    geomreqresult = REQ_RESIZE((Widget) xw, reqWidth, reqHeight,
			       &repWidth, &repHeight);

    if (geomreqresult == XtGeometryAlmost) {
	TRACE(("...almost, retry screensize %dx%d\n", repHeight, repWidth));
	geomreqresult = REQ_RESIZE((Widget) xw, repWidth,
				   repHeight, NULL, NULL);
    }

    if (geomreqresult != XtGeometryYes) {
	/* The resize wasn't successful, so we might need to adjust
	   our idea of how large the screen is. */
	TRACE(("...still no (%d) - resize the core-class\n", geomreqresult));
	xw->core.widget_class->core_class.resize((Widget) xw);
    }
#if 1				/* ndef nothack */
    /*
     * XtMakeResizeRequest() has the undesirable side-effect of clearing
     * the window manager's hints, even on a failed request.  This would
     * presumably be fixed if the shell did its own work.
     */
    if (xw->hints.flags
	&& repHeight
	&& repWidth) {
	xw->hints.height = repHeight;
	xw->hints.width = repWidth;
	TRACE_HINTS(&xw->hints);
	XSetWMNormalHints(screen->display, VShellWindow(xw), &xw->hints);
    }
#endif
    XSync(screen->display, False);	/* synchronize */
    if (xtermAppPending())
	xevents();

#ifndef NO_ACTIVE_ICON
    WhichVWin(screen) = saveWin;
#endif /* NO_ACTIVE_ICON */
}
コード例 #13
0
static void
dumpSvgLine(XtermWidget xw, int row, FILE *fp)
{
    TScreen *s = TScreenOf(xw);
    int inx = ROW2INX(s, row);
    LineData *ld = getLineData(s, inx);
    int col, sal, i;		/* sal: same attribute length */

    if (ld == 0)
	return;

    for (col = 0; col < MaxCols(s); col += sal) {
	XColor fgcolor, bgcolor;

	/* Count how many consecutive cells have the same color & attributes. */
	for (sal = 1; col + sal < MaxCols(s); ++sal) {
#if OPT_ISO_COLORS
	    if (ld->color[col] != ld->color[col + sal])
		break;
#endif
	    if (ld->attribs[col] != ld->attribs[col + sal])
		break;
	}

	fgcolor.pixel = xw->old_foreground;
	bgcolor.pixel = xw->old_background;
#if OPT_ISO_COLORS
	if (ld->attribs[col] & FG_COLOR) {
	    unsigned fg = extract_fg(xw, ld->color[col], ld->attribs[col]);
	    fgcolor.pixel = s->Acolors[fg].value;
	}
	if (ld->attribs[col] & BG_COLOR) {
	    unsigned bg = extract_bg(xw, ld->color[col], ld->attribs[col]);
	    bgcolor.pixel = s->Acolors[bg].value;
	}
#endif

	XQueryColor(xw->screen.display, xw->core.colormap, &fgcolor);
	XQueryColor(xw->screen.display, xw->core.colormap, &bgcolor);
	if (ld->attribs[col] & BLINK) {
	    /* White on red. */
	    fgcolor.red = fgcolor.green = fgcolor.blue = 65535u;
	    bgcolor.red = 65535u;
	    bgcolor.green = bgcolor.blue = 0u;
	}
#if OPT_WIDE_ATTRS
	if (ld->attribs[col] & ATR_FAINT) {
	    fgcolor.red = (unsigned short) ((2 * fgcolor.red) / 3);
	    fgcolor.green = (unsigned short) ((2 * fgcolor.green) / 3);
	    fgcolor.blue = (unsigned short) ((2 * fgcolor.blue) / 3);
	}
#endif
	if (ld->attribs[col] & INVERSE) {
	    XColor tmp = fgcolor;
	    fgcolor = bgcolor;
	    bgcolor = tmp;
	}

	/* Draw the background rectangle. */
	fprintf(fp, "  <rect x='%d' y='%d' ", bw + ib + col * CELLW, bw + ib
		+ row * CELLH);
	fprintf(fp, "height='%d' width='%d' ", CELLH, sal * CELLW);
	fprintf(fp, "fill='rgb(%.2f%%, %.2f%%, %.2f%%)'/>\n", RGBPCT(bgcolor));

	/* Now the <text>. */
	/*
	 * SVG: Rendering text strings into a given rectangle is a challenge.
	 * Some renderers accept and do the right thing with the 'textLength'
	 * attribute, while others ignore it. The only predictable way to place
	 * (even monospaced) text properly is to do it character by character.
	 */

	fprintf(fp, "  <g");
	if (ld->attribs[col] & BOLD)
	    fprintf(fp, " font-weight='bold'");
#if OPT_WIDE_ATTRS
	if (ld->attribs[col] & ATR_ITALIC)
	    fprintf(fp, " font-style='italic'");
#endif
	fprintf(fp, " fill='rgb(%.2f%%, %.2f%%, %.2f%%)'>\n", RGBPCT(fgcolor));

	for (i = 0; i < sal; ++i) {
	    IChar chr = ld->charData[col + i];

	    if (chr == ' ')
		continue;
	    fprintf(fp, "   <text x='%d' y='%d'>", bw + ib + (col + i) *
		    CELLW, bw + ib + row * CELLH + (CELLH * 3) / 4);
#if OPT_WIDE_CHARS
	    if (chr > 127) {
		/* Ignore hidden characters. */
		if (chr != HIDDEN_CHAR) {
		    Char temp[10];
		    *convertToUTF8(temp, chr) = 0;
		    fputs((char *) temp, fp);
		}
	    } else
#endif
		switch (chr) {
		case 0:
		    /* This sometimes happens when resizing... ignore. */
		    break;
		case '&':
		    fputs("&amp;", fp);
		    break;
		case '<':
		    fputs("&lt;", fp);
		    break;
		case '>':
		    fputs("&gt;", fp);
		    break;
		default:
		    fputc((int) chr, fp);
		}
	    fprintf(fp, "</text>\n");
	}
	fprintf(fp, "  </g>\n");

#define HLINE(x) \
  fprintf(fp, "  <line x1='%d' y1='%d' " \
                      "x2='%d' y2='%d' " \
                  "stroke='rgb(%.2f%%, %.2f%%, %.2f%%)'/>\n", \
    bw + ib + col * CELLW,         bw + ib + row * CELLH + CELLH - (x), \
    bw + ib + (col + sal) * CELLW, bw + ib + row * CELLH + CELLH - (x), \
    RGBPCT(fgcolor))

	/* Now the line attributes. */
	if (ld->attribs[col] & UNDERLINE) {
	    HLINE(4);
	}
#if OPT_WIDE_ATTRS
	if (ld->attribs[col] & ATR_STRIKEOUT) {
	    HLINE(9);
	}
	if (ld->attribs[col] & ATR_DBL_UNDER) {
	    HLINE(3);
	    HLINE(1);
	}
#endif
    }
}