#include <stdio.h>
#include <xterm.h>
#include <error.h>
#include <data.h>
#include <xcharmouse.h>
#include <xterm_io.h>
#if OPT_WIDE_CHARS
#include <fontutils.h>
#include <menu.h>
#endif
#include <assert.h>
#include <signal.h>
#define inSaveBuf(screen, buf, inx) \
((buf) == (screen)->saveBuf_index && \
((inx) < (screen)->savelines || (screen)->savelines == 0))
#define getMinRow(screen) ((xw->flags & ORIGIN) ? (screen)->top_marg : 0)
#define getMaxRow(screen) ((xw->flags & ORIGIN) ? (screen)->bot_marg : (screen)->max_row)
#define getMinCol(screen) 0
#define getMaxCol(screen) ((screen)->max_col)
#define MoveLineData(base, dst, src, len) \
memmove(scrnHeadAddr(screen, base, dst), \
scrnHeadAddr(screen, base, src), \
scrnHeadSize(screen, len))
#define SaveLineData(base, src, len) \
(void) ScrnPointers(screen, len); \
memcpy (screen->save_ptr, \
scrnHeadAddr(screen, base, src), \
scrnHeadSize(screen, len))
#define RestoreLineData(base, dst, len) \
memcpy (scrnHeadAddr(screen, base, dst), \
screen->save_ptr, \
scrnHeadSize(screen, len))
#if OPT_SAVE_LINES
#define VisBuf(screen) screen->editBuf_index[screen->whichBuf]
#else
#define VisBuf(screen) scrnHeadAddr(screen, screen->saveBuf_index, (unsigned) savelines)
#endif
#define SizeofScrnPtr(name) \
sizeof(*((LineData *)0)->name)
#define AlignMask() (sizeof(int) - 1)
#define IsAligned(value) (((unsigned long) (value) & AlignMask()) == 0)
#define AlignValue(value) \
if (!IsAligned(value)) \
value = (value | AlignMask()) + 1
#define SetupScrnPtr(dst,src,type) \
dst = (type *) src; \
assert(IsAligned(dst)); \
src += skipNcol##type
#define ScrnBufAddr(ptrs, offset) (ScrnBuf) ((char *) (ptrs) + (offset))
#define LineDataAddr(ptrs, offset) (LineData *) ((char *) (ptrs) + (offset))
#if OPT_TRACE > 1
static void
traceScrnBuf(const char *tag, TScreen * screen, ScrnBuf sb, unsigned len)
{
unsigned j;
TRACE(("traceScrnBuf %s\n", tag));
for (j = 0; j < len; ++j) {
LineData *src = (LineData *) scrnHeadAddr(screen, sb, j);
TRACE(("%p %s%3d:%s\n",
src, ((int) j >= screen->savelines) ? "*" : " ",
j, visibleIChars(src->charData, src->lineSize)));
}
TRACE(("...traceScrnBuf %s\n", tag));
}
#define TRACE_SCRNBUF(tag, screen, sb, len) traceScrnBuf(tag, screen, sb, len)
#else
#define TRACE_SCRNBUF(tag, screen, sb, len)
#endif
static unsigned
scrnHeadSize(TScreen * screen, unsigned count)
{
unsigned result = SizeOfLineData;
(void) screen;
#if OPT_WIDE_CHARS
if (screen->wide_chars) {
result += screen->lineExtra;
}
#endif
result *= count;
return result;
}
ScrnBuf
scrnHeadAddr(TScreen * screen, ScrnBuf base, unsigned offset)
{
unsigned size = scrnHeadSize(screen, offset);
ScrnBuf result = ScrnBufAddr(base, size);
assert((int) offset >= 0);
return result;
}
void
setupLineData(TScreen * screen, ScrnBuf base, Char * data, unsigned nrow, unsigned ncol)
{
unsigned i;
unsigned offset = 0;
unsigned jump = scrnHeadSize(screen, 1);
LineData *ptr;
#if OPT_WIDE_CHARS
unsigned j;
#endif
unsigned skipNcolChar = (ncol * SizeofScrnPtr(attribs));
unsigned skipNcolCharData = (ncol * SizeofScrnPtr(charData));
#if OPT_ISO_COLORS
unsigned skipNcolCellColor = (ncol * SizeofScrnPtr(color));
#endif
AlignValue(skipNcolChar);
#if OPT_ISO_COLORS
AlignValue(skipNcolCellColor);
#endif
AlignValue(skipNcolCharData);
for (i = 0; i < nrow; i++, offset += jump) {
ptr = LineDataAddr(base, offset);
ptr->lineSize = (Dimension) ncol;
ptr->bufHead = 0;
#if OPT_DEC_CHRSET
SetLineDblCS(ptr, 0);
#endif
SetupScrnPtr(ptr->attribs, data, Char);
#if OPT_ISO_COLORS
SetupScrnPtr(ptr->color, data, CellColor);
#endif
SetupScrnPtr(ptr->charData, data, CharData);
#if OPT_WIDE_CHARS
if (screen->wide_chars) {
unsigned extra = (unsigned) screen->max_combining;
ptr->combSize = (Char) extra;
for (j = 0; j < extra; ++j) {
SetupScrnPtr(ptr->combData[j], data, CharData);
}
}
#endif
}
}
#define ExtractScrnData(name) \
memcpy(dstPtrs->name, \
((LineData *) srcPtrs)->name,\
dstCols * sizeof(dstPtrs->name[0])); \
nextPtr += (srcCols * sizeof(dstPtrs->name[0]))
static void
extractScrnData(TScreen * screen,
ScrnBuf dstPtrs,
ScrnBuf srcPtrs,
unsigned nrows,
unsigned move_down)
{
unsigned j;
TRACE(("extractScrnData(nrows %d)\n", nrows));
TRACE_SCRNBUF("extract from", screen, srcPtrs, nrows);
for (j = 0; j < nrows; j++) {
LineData *dst = (LineData *) scrnHeadAddr(screen,
dstPtrs, j + move_down);
LineData *src = (LineData *) scrnHeadAddr(screen,
srcPtrs, j);
copyLineData(dst, src);
}
}
static ScrnPtr *
allocScrnHead(TScreen * screen, unsigned nrow)
{
ScrnPtr *result;
unsigned size = scrnHeadSize(screen, 1);
result = (ScrnPtr *) calloc(nrow, size);
if (result == 0)
SysError(ERROR_SCALLOC);
TRACE(("allocScrnHead %d -> %d -> %p..%p\n", nrow, nrow * size,
(void *) result,
(char *) result + (nrow * size) - 1));
return result;
}
static unsigned
sizeofScrnRow(TScreen * screen, unsigned ncol)
{
unsigned result;
unsigned sizeAttribs;
#if OPT_ISO_COLORS
unsigned sizeColors;
#endif
(void) screen;
result = (ncol * sizeof(CharData));
AlignValue(result);
#if OPT_WIDE_CHARS
if (screen->wide_chars) {
result *= (unsigned) (1 + screen->max_combining);
}
#endif
sizeAttribs = (ncol * SizeofScrnPtr(attribs));
AlignValue(sizeAttribs);
result += sizeAttribs;
#if OPT_ISO_COLORS
sizeColors = (ncol * SizeofScrnPtr(color));
AlignValue(sizeColors);
result += sizeColors;
#endif
return result;
}
Char *
allocScrnData(TScreen * screen, unsigned nrow, unsigned ncol)
{
Char *result;
size_t length = (nrow * sizeofScrnRow(screen, ncol));
if ((result = (Char *) calloc(length, sizeof(Char))) == 0)
SysError(ERROR_SCALLOC2);
TRACE(("allocScrnData %dx%d -> %d -> %p..%p\n",
nrow, ncol, length, result, result + length - 1));
return result;
}
ScrnBuf
allocScrnBuf(XtermWidget xw, unsigned nrow, unsigned ncol, Char ** addr)
{
TScreen *screen = TScreenOf(xw);
ScrnBuf base = 0;
if (nrow != 0) {
base = allocScrnHead(screen, nrow);
*addr = allocScrnData(screen, nrow, ncol);
setupLineData(screen, base, *addr, nrow, ncol);
}
TRACE(("allocScrnBuf %dx%d ->%p\n", nrow, ncol, (void *) base));
return (base);
}
#if OPT_SAVE_LINES
static void
saveEditBufLines(TScreen * screen, ScrnBuf sb, unsigned n)
{
unsigned j;
TRACE(("...copying %d lines from editBuf to saveBuf\n", n));
#if OPT_FIFO_LINES
(void) sb;
#endif
for (j = 0; j < n; ++j) {
#if OPT_FIFO_LINES
LineData *dst = addScrollback(screen);
#else
unsigned k = (screen->savelines + j - n);
LineData *dst = (LineData *) scrnHeadAddr(screen, sb, k);
#endif
LineData *src = getLineData(screen, (int) j);
copyLineData(dst, src);
}
}
static void
unsaveEditBufLines(TScreen * screen, ScrnBuf sb, unsigned n)
{
unsigned j;
TRACE(("...copying %d lines from saveBuf to editBuf\n", n));
for (j = 0; j < n; ++j) {
int extra = (int) (n - j);
LineData *dst = (LineData *) scrnHeadAddr(screen, sb, j);
#if OPT_FIFO_LINES
LineData *src;
if ((screen->saved_fifo - extra) <= 0) {
TRACE(("...FIXME: must clear text!\n"));
continue;
}
src = getScrollback(screen, -extra);
#else
unsigned k = (screen->savelines - extra);
LineData *src = (LineData *) scrnHeadAddr(screen,
screen->saveBuf_index, k);
#endif
copyLineData(dst, src);
}
}
#endif
static int
Reallocate(XtermWidget xw,
ScrnBuf * sbuf,
Char ** sbufaddr,
unsigned nrow,
unsigned ncol,
unsigned oldrow,
unsigned oldcol)
{
TScreen *screen = TScreenOf(xw);
ScrnBuf oldBufHead;
ScrnBuf newBufHead;
Char *newBufData;
unsigned minrows;
unsigned mincols;
Char *oldBufData;
int move_down = 0, move_up = 0;
if (sbuf == NULL || *sbuf == NULL) {
return 0;
}
oldBufData = *sbufaddr;
TRACE(("Reallocate %dx%d -> %dx%d\n", oldrow, oldcol, nrow, ncol));
TRACE(("Check move_up, nrow %d vs oldrow %d (resizeGravity %s)\n",
nrow, oldrow,
BtoS(GravityIsSouthWest(xw))));
if (GravityIsSouthWest(xw)) {
if (nrow < oldrow) {
move_up = (int) (oldrow - nrow)
- (xw->screen.max_row - xw->screen.cur_row);
if (move_up < 0)
move_up = 0;
TRACE(("move_up %d\n", move_up));
if (move_up) {
ScrnBuf dst = *sbuf;
unsigned len = (unsigned) ((int) oldrow - move_up);
TRACE_SCRNBUF("before move_up", screen, dst, oldrow);
SaveLineData(dst, 0, (size_t) move_up);
MoveLineData(dst, 0, (size_t) move_up, len);
RestoreLineData(dst, len, (size_t) move_up);
TRACE_SCRNBUF("after move_up", screen, dst, oldrow);
}
}
}
oldBufHead = *sbuf;
*sbuf = allocScrnHead(screen, (unsigned) nrow);
newBufHead = *sbuf;
newBufData = allocScrnData(screen, nrow, ncol);
*sbufaddr = newBufData;
minrows = (oldrow < nrow) ? oldrow : nrow;
mincols = (oldcol < ncol) ? oldcol : ncol;
if (GravityIsSouthWest(xw)) {
if (nrow > oldrow) {
move_down = Min((int) (nrow - oldrow), xw->screen.savedlines);
}
}
setupLineData(screen, newBufHead, *sbufaddr, nrow, ncol);
extractScrnData(screen, newBufHead, oldBufHead, minrows,
#if OPT_SAVE_LINES
0
#else
(unsigned) move_down
#endif
);
free(oldBufHead);
free(oldBufData);
TRACE(("...Reallocate %dx%d ->%p\n", nrow, ncol, (void *) newBufHead));
return move_down ? move_down : -move_up;
}
#if OPT_WIDE_CHARS
static void
ReallocateBufOffsets(XtermWidget xw,
ScrnBuf * sbuf,
Char ** sbufaddr,
unsigned nrow,
unsigned ncol)
{
TScreen *screen = TScreenOf(xw);
unsigned i;
ScrnBuf newBufHead;
Char *oldBufData;
ScrnBuf oldBufHead;
unsigned old_jump = scrnHeadSize(screen, 1);
unsigned new_jump;
unsigned new_ptrs = 1 + (unsigned) (screen->max_combining);
unsigned dstCols = ncol;
unsigned srcCols = ncol;
LineData *dstPtrs;
LineData *srcPtrs;
Char *nextPtr;
assert(nrow != 0);
assert(ncol != 0);
oldBufData = *sbufaddr;
oldBufHead = *sbuf;
screen->wide_chars = True;
new_jump = scrnHeadSize(screen, 1);
newBufHead = allocScrnHead(screen, nrow);
*sbufaddr = allocScrnData(screen, nrow, ncol);
setupLineData(screen, newBufHead, *sbufaddr, nrow, ncol);
screen->wide_chars = False;
nextPtr = *sbufaddr;
srcPtrs = (LineData *) oldBufHead;
dstPtrs = (LineData *) newBufHead;
for (i = 0; i < nrow; i++) {
dstPtrs->bufHead = srcPtrs->bufHead;
ExtractScrnData(attribs);
#if OPT_ISO_COLORS
ExtractScrnData(color);
#endif
ExtractScrnData(charData);
nextPtr += ncol * new_ptrs;
srcPtrs = LineDataAddr(srcPtrs, old_jump);
dstPtrs = LineDataAddr(dstPtrs, new_jump);
}
free(oldBufData);
free(oldBufHead);
*sbuf = newBufHead;
TRACE(("ReallocateBufOffsets %dx%d ->%p\n", nrow, ncol, *sbufaddr));
}
void
ChangeToWide(XtermWidget xw)
{
TScreen *screen = &(xw->screen);
int savelines = screen->scrollWidget ? screen->savelines : 0;
if (screen->wide_chars)
return;
TRACE(("ChangeToWide\n"));
if (xtermLoadWideFonts(xw, True)) {
if (savelines < 0)
savelines = 0;
if (screen->whichBuf)
SwitchBufPtrs(screen);
#if OPT_SAVE_LINES
#if !OPT_FIFO_LINES
ReallocateBufOffsets(xw,
&screen->saveBuf_index,
&screen->saveBuf_data,
(unsigned) savelines,
(unsigned) MaxCols(screen));
#endif
if (screen->editBuf_index[0]) {
ReallocateBufOffsets(xw,
&screen->editBuf_index[0],
&screen->editBuf_data[0],
(unsigned) MaxRows(screen),
(unsigned) MaxCols(screen));
}
#else
ReallocateBufOffsets(xw,
&screen->saveBuf_index,
&screen->saveBuf_data,
(unsigned) (MaxRows(screen) + savelines),
(unsigned) MaxCols(screen));
#endif
if (screen->editBuf_index[1]) {
ReallocateBufOffsets(xw,
&screen->editBuf_index[1],
&screen->editBuf_data[1],
(unsigned) MaxRows(screen),
(unsigned) MaxCols(screen));
}
screen->wide_chars = True;
screen->visbuf = VisBuf(screen);
if (screen->whichBuf)
SwitchBufPtrs(screen);
update_font_utf8_mode();
SetVTFont(xw, screen->menu_font_number, True, NULL);
}
TRACE(("...ChangeToWide\n"));
}
#endif
void
ClearCells(XtermWidget xw, int flags, unsigned len, int row, int col)
{
if (len != 0) {
TScreen *screen = &(xw->screen);
LineData *ld;
unsigned n;
ld = getLineData(screen, row);
flags |= TERM_COLOR_FLAGS(xw);
for (n = 0; n < len; ++n)
ld->charData[(unsigned) col + n] = (CharData) ' ';
memset(ld->attribs + col, flags, len);
if_OPT_ISO_COLORS(screen, {
CellColor p = xtermColorPair(xw);
for (n = 0; n < len; ++n) {
ld->color[(unsigned) col + n] = p;
}
});
if_OPT_WIDE_CHARS(screen, {
size_t off;
for_each_combData(off, ld) {
memset(ld->combData[off] + col, 0, len * sizeof(IChar));
}
});
}
}
void
ScrnClearCells(XtermWidget xw, int row, int col, unsigned len)
{
#if OPT_WIDE_CHARS
TScreen *screen = &(xw->screen);
#endif
int flags = 0;
if_OPT_WIDE_CHARS(screen, {
int kl;
int kr;
if (DamagedCells(screen, len, &kl, &kr, row, col)
&& kr >= kl) {
ClearCells(xw, flags, (unsigned) (kr - kl + 1), row, kl);
}
});
ClearCells(xw, flags, len, row, col);
}
void
ScrnDisownSelection(XtermWidget xw)
{
if (ScrnHaveSelection(&(xw->screen))) {
if (xw->screen.keepSelection) {
UnhiliteSelection(xw);
} else {
DisownSelection(xw);
}
}
}
void
ScrnWriteText(XtermWidget xw,
IChar * str,
unsigned flags,
CellColor cur_fg_bg,
unsigned length)
{
TScreen *screen = &(xw->screen);
LineData *ld;
#if OPT_ISO_COLORS
CellColor *fb = 0;
#endif
Char *attrs;
int avail = MaxCols(screen) - screen->cur_col;
IChar *chars;
#if OPT_WIDE_CHARS
IChar starcol1;
#endif
unsigned n;
unsigned real_width = visual_width(str, length);
(void) cur_fg_bg;
if (real_width + (unsigned) screen->cur_col > (unsigned) MaxCols(screen)) {
real_width = (unsigned) (MaxCols(screen) - screen->cur_col);
}
if (avail <= 0)
return;
if (length > (unsigned) avail)
length = (unsigned) avail;
if (length == 0 || real_width == 0)
return;
ld = getLineData(screen, screen->cur_row);
chars = ld->charData + screen->cur_col;
attrs = ld->attribs + screen->cur_col;
if_OPT_ISO_COLORS(screen, {
fb = ld->color + screen->cur_col;
});
#if OPT_WIDE_CHARS
starcol1 = *chars;
#endif
for (n = 0; n < length; ++n) {
if ((flags & INVISIBLE))
chars[n] = ' ';
else
chars[n] = str[n];
}
#if OPT_BLINK_TEXT
if ((flags & BLINK) && !(screen->blink_as_bold)) {
LineSetBlinked(ld);
}
#endif
if_OPT_WIDE_CHARS(screen, {
if (real_width != length) {
IChar *char1 = chars;
if (screen->cur_col
&& starcol1 == HIDDEN_CHAR
&& isWide((int) char1[-1])) {
char1[-1] = (CharData) ' ';
}
while (length) {
int ch = (int) str[0];
*char1++ = *str++;
length--;
if (isWide(ch)) {
*char1++ = (CharData) HIDDEN_CHAR;
}
}
if (*char1 == HIDDEN_CHAR
&& char1[-1] == HIDDEN_CHAR) {
*char1 = (CharData) ' ';
}
} else {
if (screen->cur_col
&& starcol1 == HIDDEN_CHAR
&& isWide((int) chars[-1])) {
chars[-1] = (CharData) ' ';
}
if (chars[length] == HIDDEN_CHAR
&& isWide((int) chars[length - 1])) {
chars[length] = (CharData) ' ';
}
}
});
flags &= ATTRIBUTES;
flags |= CHARDRAWN;
memset(attrs, (Char) flags, real_width);
if_OPT_WIDE_CHARS(screen, {
size_t off;
for_each_combData(off, ld) {
memset(ld->combData[off] + screen->cur_col,
0,
real_width * sizeof(IChar));
}
});
if_OPT_ISO_COLORS(screen, {
unsigned j;
for (j = 0; j < real_width; ++j)
fb[j] = cur_fg_bg;
});
if_OPT_WIDE_CHARS(screen, {
screen->last_written_col = screen->cur_col + (int) real_width - 1;
screen->last_written_row = screen->cur_row;
});
if_OPT_XMC_GLITCH(screen, {
Resolve_XMC(xw);
});
return;
}
static void
ScrnClearLines(XtermWidget xw, ScrnBuf sb, int where, unsigned n, unsigned size)
{
TScreen *screen = &(xw->screen);
ScrnPtr *base;
unsigned jump = scrnHeadSize(screen, 1);
unsigned i;
LineData *work;
unsigned flags = TERM_COLOR_FLAGS(xw);
#if OPT_ISO_COLORS
unsigned j;
#endif
TRACE(("ScrnClearLines(%s:where %d, n %d, size %d)\n",
(sb == screen->saveBuf_index) ? "save" : "edit",
where, n, size));
assert(n != 0);
assert(size != 0);
SaveLineData(sb, (unsigned) where, (size_t) n);
base = screen->save_ptr;
for (i = 0; i < n; ++i) {
work = (LineData *) base;
work->bufHead = 0;
#if OPT_DEC_CHRSET
SetLineDblCS(work, 0);
#endif
memset(work->charData, 0, size * sizeof(IChar));
if (TERM_COLOR_FLAGS(xw)) {
memset(work->attribs, (int) flags, size);
#if OPT_ISO_COLORS
{
CellColor p = xtermColorPair(xw);
for (j = 0; j < size; ++j) {
work->color[j] = p;
}
}
#endif
} else {
memset(work->attribs, 0, size);
#if OPT_ISO_COLORS
memset(work->color, 0, size * sizeof(work->color[0]));
#endif
}
#if OPT_WIDE_CHARS
if (screen->wide_chars) {
size_t off;
for (off = 0; off < work->combSize; ++off) {
memset(work->combData[off], 0, size * sizeof(IChar));
}
}
#endif
base = ScrnBufAddr(base, jump);
}
}
#if OPT_SAVE_LINES
#define OkAllocBuf(screen) (screen->editBuf_index[0] != 0)
#else
#define OkAllocBuf(screen) (screen->saveBuf_index != 0)
#endif
void
ScrnAllocBuf(XtermWidget xw)
{
TScreen *screen = TScreenOf(xw);
if (!OkAllocBuf(screen)) {
int nrows = MaxRows(screen);
#if !OPT_SAVE_LINES
int savelines = screen->scrollWidget ? screen->savelines : 0;
#endif
TRACE(("ScrnAllocBuf %dx%d (%d)\n",
nrows, MaxCols(screen), screen->savelines));
#if OPT_SAVE_LINES
if (screen->savelines != 0) {
#if OPT_FIFO_LINES
screen->saveBuf_index = allocScrnHead(screen,
(unsigned) (screen->savelines));
#else
screen->saveBuf_index = allocScrnBuf(xw,
(unsigned) screen->savelines,
(unsigned) MaxCols(screen),
&screen->saveBuf_data);
#endif
} else {
screen->saveBuf_index = 0;
}
screen->editBuf_index[0] = allocScrnBuf(xw,
(unsigned) nrows,
(unsigned) MaxCols(screen),
&screen->editBuf_data[0]);
#else
screen->saveBuf_index = allocScrnBuf(xw,
(unsigned) (nrows + screen->savelines),
(unsigned) (MaxCols(screen)),
&screen->saveBuf_data);
#endif
screen->visbuf = VisBuf(screen);
}
return;
}
size_t
ScrnPointers(TScreen * screen, size_t len)
{
size_t result = scrnHeadSize(screen, len);
if (result > screen->save_len) {
if (screen->save_len)
screen->save_ptr = (ScrnPtr *) realloc(screen->save_ptr, result);
else
screen->save_ptr = (ScrnPtr *) malloc(result);
screen->save_len = len;
if (screen->save_ptr == 0)
SysError(ERROR_SAVE_PTR);
}
TRACE2(("ScrnPointers %ld ->%p\n", (long) len, screen->save_ptr));
return result;
}
void
ScrnInsertLine(XtermWidget xw, ScrnBuf sb, int last, int where, unsigned n)
{
TScreen *screen = &(xw->screen);
unsigned size = (unsigned) MaxCols(screen);
TRACE(("ScrnInsertLine(last %d, where %d, n %d, size %d)\n",
last, where, n, size));
assert(where >= 0);
assert(last >= (int) n);
assert(last >= where);
assert(n != 0);
assert(size != 0);
ScrnClearLines(xw, sb, (last -= (int) n - 1), n, size);
assert(last >= where);
MoveLineData(sb,
(unsigned) (where + (int) n),
(unsigned) where,
(unsigned) (last - where));
RestoreLineData(sb, (unsigned) where, n);
}
void
ScrnDeleteLine(XtermWidget xw, ScrnBuf sb, int last, int where, unsigned n)
{
TScreen *screen = &(xw->screen);
unsigned size = (unsigned) MaxCols(screen);
TRACE(("ScrnDeleteLine(%s:last %d, where %d, n %d, size %d)\n",
(sb == screen->saveBuf_index) ? "save" : "edit",
last, where, n, size));
assert(where >= 0);
assert(last >= where + (int) n - 1);
assert(n != 0);
assert(size != 0);
last -= ((int) n - 1);
#if OPT_SAVE_LINES
if (inSaveBuf(screen, sb, where)) {
#if !OPT_FIFO_LINES
int from = where + n;
#endif
assert(last >= screen->savelines);
if (sb != 0) {
#if OPT_FIFO_LINES
saveEditBufLines(screen, sb, n);
#else
ScrnClearLines(xw, sb, where, n, size);
TRACE(("...%smoving pointers in saveBuf (compare %d %d)\n",
((screen->savelines > from)
? ""
: "SKIP "),
screen->savelines,
from));
if (screen->savelines > from) {
MoveLineData(sb,
(unsigned) where,
(unsigned) from,
(unsigned) (screen->savelines - from));
}
TRACE(("...reuse %d lines storage in saveBuf\n", n));
RestoreLineData(sb, (unsigned) screen->savelines - n, n);
saveEditBufLines(screen, sb, n);
#endif
}
TRACE(("...adjusting variables, to work on editBuf alone\n"));
last -= screen->savelines;
where = 0;
sb = screen->visbuf;
}
#endif
ScrnClearLines(xw, sb, where, n, size);
MoveLineData(sb,
(unsigned) where,
(unsigned) (where + (int) n),
(size_t) (last - where));
RestoreLineData(sb, (unsigned) last, n);
}
void
ScrnInsertChar(XtermWidget xw, unsigned n)
{
#define MemMove(data) \
for (j = last - 1; j >= (col + (int) n); --j) \
data[j] = data[j - (int) n]
TScreen *screen = &(xw->screen);
int last = MaxCols(screen);
int row = screen->cur_row;
int col = screen->cur_col;
int j, nbytes;
LineData *ld;
if (last <= (col + (int) n)) {
if (last <= col)
return;
n = (unsigned) (last - col);
}
nbytes = (last - (col + (int) n));
assert(screen->cur_col >= 0);
assert(screen->cur_row >= 0);
assert(n > 0);
assert(last > (int) n);
if_OPT_WIDE_CHARS(screen, {
int xx = screen->cur_row;
int kl;
int kr = screen->cur_col;
if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) {
ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl);
}
kr = screen->max_col - (int) n + 1;
if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) {
ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl);
}
});
if ((ld = getLineData(screen, row)) != 0) {
MemMove(ld->charData);
MemMove(ld->attribs);
if_OPT_ISO_COLORS(screen, {
MemMove(ld->color);
});
if_OPT_WIDE_CHARS(screen, {
size_t off;
for_each_combData(off, ld) {
MemMove(ld->combData[off]);
}
});
}
ClearCells(xw, CHARDRAWN, n, row, col);
#undef MemMove
}
void
ScrnDeleteChar(XtermWidget xw, unsigned n)
{
#define MemMove(data) \
for (j = col; j < last - (int) n; ++j) \
data[j] = data[j + (int) n]
TScreen *screen = &(xw->screen);
int last = MaxCols(screen);
int row = screen->cur_row;
int col = screen->cur_col;
int j, nbytes;
LineData *ld;
if (last <= (col + (int) n)) {
if (last <= col)
return;
n = (unsigned) (last - col);
}
nbytes = (last - (col + (int) n));
assert(screen->cur_col >= 0);
assert(screen->cur_row >= 0);
assert(n > 0);
assert(last > (int) n);
if_OPT_WIDE_CHARS(screen, {
int kl;
int kr;
if (DamagedCells(screen, n, &kl, &kr,
screen->cur_row,
screen->cur_col))
ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl);
});
if ((ld = getLineData(screen, row)) != 0) {
MemMove(ld->charData);
MemMove(ld->attribs);
if_OPT_ISO_COLORS(screen, {
MemMove(ld->color);
});
if_OPT_WIDE_CHARS(screen, {
size_t off;
for_each_combData(off, ld) {
MemMove(ld->combData[off]);
}
});
LineClrWrapped(ld);
}
ClearCells(xw, 0, n, row, (last - (int) n));
#undef MemMove
}
void
ScrnRefresh(XtermWidget xw,
int toprow,
int leftcol,
int nrows,
int ncols,
Bool force)
{
TScreen *screen = &(xw->screen);
LineData *ld;
int y = toprow * FontHeight(screen) + screen->border;
int row;
int maxrow = toprow + nrows - 1;
int scrollamt = screen->scroll_amt;
int max = screen->max_row;
unsigned gc_changes = 0;
#ifdef __CYGWIN__
static char first_time = 1;
#endif
static int recurse = 0;
TRACE(("ScrnRefresh (%d,%d) - (%d,%d)%s {{\n",
toprow, leftcol,
nrows, ncols,
force ? " force" : ""));
if (screen->cursorp.col >= leftcol
&& screen->cursorp.col <= (leftcol + ncols - 1)
&& screen->cursorp.row >= ROW2INX(screen, toprow)
&& screen->cursorp.row <= ROW2INX(screen, maxrow))
screen->cursor_state = OFF;
for (row = toprow; row <= maxrow; y += FontHeight(screen), row++) {
#if OPT_ISO_COLORS
CellColor *fb = 0;
#define ColorOf(col) fb[col]
#endif
#if OPT_WIDE_CHARS
int wideness = 0;
#endif
#define BLANK_CEL(cell) (chars[cell] == ' ')
IChar *chars;
Char *attrs;
int col = leftcol;
int maxcol = leftcol + ncols - 1;
int hi_col = maxcol;
int lastind;
unsigned flags;
unsigned test;
CellColor fg_bg = 0;
unsigned fg = 0, bg = 0;
int x;
GC gc;
Bool hilite;
(void) fg;
(void) bg;
#if !OPT_ISO_COLORS
fg_bg = 0;
#endif
if (row < screen->top_marg || row > screen->bot_marg)
lastind = row;
else
lastind = row - scrollamt;
TRACE2(("ScrnRefresh row=%d lastind=%d/%d\n", row, lastind, max));
if (lastind < 0 || lastind > max)
continue;
if ((ld = getLineData(screen, ROW2INX(screen, lastind))) == 0)
break;
if (maxcol >= (int) ld->lineSize) {
maxcol = ld->lineSize - 1;
hi_col = maxcol;
}
chars = ld->charData;
attrs = ld->attribs;
if_OPT_WIDE_CHARS(screen, {
if (recurse < 3) {
if (leftcol > 0 &&
chars[leftcol] == HIDDEN_CHAR &&
isWide((int) chars[leftcol - 1])) {
leftcol--;
ncols++;
col = leftcol;
}
} else {
fprintf(stderr, "This should not happen. Why is it so?\n");
}
});
if (row < screen->startH.row || row > screen->endH.row ||
(row == screen->startH.row && maxcol < screen->startH.col) ||
(row == screen->endH.row && col >= screen->endH.col)) {
#if OPT_DEC_CHRSET
if (CSET_DOUBLE(GetLineDblCS(ld))) {
col /= 2;
maxcol /= 2;
}
#endif
if (!force) {
while (col <= maxcol && (attrs[col] & ~BOLD) == 0 &&
BLANK_CEL(col))
col++;
while (col <= maxcol && (attrs[maxcol] & ~BOLD) == 0 &&
BLANK_CEL(maxcol))
maxcol--;
}
#if OPT_DEC_CHRSET
if (CSET_DOUBLE(GetLineDblCS(ld))) {
col *= 2;
maxcol *= 2;
}
#endif
hilite = False;
} else {
if (row == screen->startH.row && col < screen->startH.col) {
recurse++;
ScrnRefresh(xw, row, col, 1, screen->startH.col - col,
force);
col = screen->startH.col;
}
if (row == screen->endH.row && maxcol >= screen->endH.col) {
recurse++;
ScrnRefresh(xw, row, screen->endH.col, 1,
maxcol - screen->endH.col + 1, force);
maxcol = screen->endH.col - 1;
}
if (screen->highlight_selection
&& screen->send_mouse_pos != VT200_HIGHLIGHT_MOUSE) {
hi_col = screen->max_col;
while (hi_col > 0 && !(attrs[hi_col] & CHARDRAWN))
hi_col--;
}
hilite = True;
}
if (col > maxcol)
continue;
if_OPT_DEC_CHRSET({
if (CSET_DOUBLE(GetLineDblCS(ld))) {
col /= 2;
maxcol /= 2;
}
});
flags = attrs[col];
if_OPT_WIDE_CHARS(screen, {
wideness = isWide((int) chars[col]);
});
if_OPT_ISO_COLORS(screen, {
fb = ld->color;
fg_bg = ColorOf(col);
fg = extract_fg(xw, fg_bg, flags);
bg = extract_bg(xw, fg_bg, flags);
});
gc = updatedXtermGC(xw, flags, fg_bg, hilite);
gc_changes |= (flags & (FG_COLOR | BG_COLOR));
x = LineCursorX(screen, ld, col);
lastind = col;
for (; col <= maxcol; col++) {
if ((attrs[col] != flags)
|| (hilite && (col > hi_col))
#if OPT_ISO_COLORS
|| ((flags & FG_COLOR)
&& (extract_fg(xw, ColorOf(col), attrs[col]) != fg))
|| ((flags & BG_COLOR)
&& (extract_bg(xw, ColorOf(col), attrs[col]) != bg))
#endif
#if OPT_WIDE_CHARS
|| (isWide((int) chars[col]) != wideness
&& chars[col] != HIDDEN_CHAR)
#endif
) {
assert(col >= lastind);
TRACE(("ScrnRefresh looping drawXtermText %d..%d:%s\n",
lastind, col,
visibleIChars((&chars[lastind]),
(unsigned) (col - lastind))));
test = flags;
checkVeryBoldColors(test, fg);
x = drawXtermText(xw, test & DRAWX_MASK, gc, x, y,
GetLineDblCS(ld),
&chars[lastind],
(unsigned) (col - lastind), 0);
if_OPT_WIDE_CHARS(screen, {
int i;
size_t off;
for_each_combData(off, ld) {
IChar *com_off = ld->combData[off];
for (i = lastind; i < col; i++) {
int my_x = LineCursorX(screen, ld, i);
IChar base = chars[i];
if (isWide((int) base))
my_x = LineCursorX(screen, ld, i - 1);
if (com_off[i] != 0)
drawXtermText(xw,
(test & DRAWX_MASK)
| NOBACKGROUND,
gc, my_x, y,
GetLineDblCS(ld),
com_off + i,
1, isWide((int) base));
}
}
});
resetXtermGC(xw, flags, hilite);
lastind = col;
if (hilite && (col > hi_col))
hilite = False;
flags = attrs[col];
if_OPT_ISO_COLORS(screen, {
fg_bg = ColorOf(col);
fg = extract_fg(xw, fg_bg, flags);
bg = extract_bg(xw, fg_bg, flags);
});
if_OPT_WIDE_CHARS(screen, {
wideness = isWide((int) chars[col]);
});
gc = updatedXtermGC(xw, flags, fg_bg, hilite);
gc_changes |= (flags & (FG_COLOR | BG_COLOR));
}
if (chars[col] == 0) {
chars[col] = ' ';
}
}
assert(col >= lastind);
TRACE(("ScrnRefresh calling drawXtermText %d..%d:%s\n",
lastind, col,
visibleIChars(&chars[lastind], (unsigned) (col - lastind))));
test = flags;
checkVeryBoldColors(test, fg);
drawXtermText(xw, test & DRAWX_MASK, gc, x, y,
GetLineDblCS(ld),
&chars[lastind],
(unsigned) (col - lastind), 0);
if_OPT_WIDE_CHARS(screen, {
int i;
size_t off;
for_each_combData(off, ld) {
IChar *com_off = ld->combData[off];
for (i = lastind; i < col; i++) {
int my_x = LineCursorX(screen, ld, i);
int base = (int) chars[i];
if (isWide(base))
my_x = LineCursorX(screen, ld, i - 1);
if (com_off[i] != 0)
drawXtermText(xw,
(test & DRAWX_MASK)
| NOBACKGROUND,
gc, my_x, y,
GetLineDblCS(ld),
com_off + i,
1, isWide(base));
}
}
});
resetXtermGC(xw, flags, hilite);
}
if_OPT_ISO_COLORS(screen, {
if (gc_changes & FG_COLOR)
SGR_Foreground(xw, xw->cur_foreground);
if (gc_changes & BG_COLOR)
SGR_Background(xw, xw->cur_background);
});
#if defined(__CYGWIN__) && defined(TIOCSWINSZ)
if (first_time == 1) {
TTYSIZE_STRUCT ts;
first_time = 0;
TTYSIZE_ROWS(ts) = nrows;
TTYSIZE_COLS(ts) = ncols;
ts.ws_xpixel = xw->core.width;
ts.ws_ypixel = xw->core.height;
SET_TTYSIZE(screen->respond, ts);
}
#endif
recurse--;
TRACE(("...}} ScrnRefresh\n"));
return;
}
void
ScrnUpdate(XtermWidget xw,
int toprow,
int leftcol,
int nrows,
int ncols,
Bool force)
{
TScreen *screen = &(xw->screen);
if (ScrnHaveSelection(screen)
&& (toprow <= screen->endH.row)
&& (toprow + nrows - 1 >= screen->startH.row)) {
ScrnDisownSelection(xw);
}
ScrnRefresh(xw, toprow, leftcol, nrows, ncols, force);
}
void
ClearBufRows(XtermWidget xw,
int first,
int last)
{
TScreen *screen = &(xw->screen);
unsigned len = (unsigned) MaxCols(screen);
int row;
TRACE(("ClearBufRows %d..%d\n", first, last));
for (row = first; row <= last; row++) {
LineData *ld = getLineData(screen, row);
if (ld != 0) {
if_OPT_DEC_CHRSET({
SetLineDblCS(ld, CSET_SWL);
});
LineClrWrapped(ld);
ClearCells(xw, 0, len, row, 0);
}
}
}
int
ScreenResize(XtermWidget xw,
int width,
int height,
unsigned *flags)
{
TScreen *screen = &(xw->screen);
int code, rows, cols;
int border = 2 * screen->border;
int move_down_by = 0;
#ifdef TTYSIZE_STRUCT
TTYSIZE_STRUCT ts;
#endif
Window tw = VWindow(screen);
TRACE(("ScreenResize %dx%d border %d font %dx%d\n",
height, width, border,
FontHeight(screen), FontWidth(screen)));
assert(width > 0);
assert(height > 0);
if (screen->is_running) {
if (width >= (int) FullWidth(screen)) {
XClearArea(screen->display, tw,
FullWidth(screen), 0,
0, (unsigned) height,
False);
}
if (height >= (int) FullHeight(screen)) {
XClearArea(screen->display, tw,
0, FullHeight(screen),
(unsigned) width, 0,
False);
}
}
TRACE(("...computing rows/cols: %.2f %.2f\n",
(double) (height - border) / FontHeight(screen),
(double) (width - border - ScrollbarWidth(screen)) / FontWidth(screen)));
rows = (height - border) / FontHeight(screen);
cols = (width - border - ScrollbarWidth(screen)) / FontWidth(screen);
if (rows < 1)
rows = 1;
if (cols < 1)
cols = 1;
if (MaxRows(screen) != rows || MaxCols(screen) != cols) {
int delta_rows = rows - MaxRows(screen);
#if OPT_TRACE
int delta_cols = cols - MaxCols(screen);
#endif
TRACE(("...ScreenResize chars %dx%d delta %dx%d\n",
rows, cols, delta_rows, delta_cols));
if (screen->is_running) {
#if !OPT_FIFO_LINES
int savelines = (screen->scrollWidget
? screen->savelines
: 0);
#endif
if (screen->cursor_state)
HideCursor();
#if OPT_SAVE_LINES
if (screen->editBuf_index[!screen->whichBuf]) {
(void) Reallocate(xw,
&screen->editBuf_index[!screen->whichBuf],
&screen->editBuf_data[!screen->whichBuf],
(unsigned) rows,
(unsigned) cols,
(unsigned) MaxRows(screen),
(unsigned) MaxCols(screen));
}
if (GravityIsSouthWest(xw)
&& delta_rows
&& screen->saveBuf_index != 0) {
move_down_by = delta_rows;
if (delta_rows < 0) {
unsigned move_up = (unsigned) (-delta_rows);
ScrnBuf dst = screen->saveBuf_index;
#if OPT_FIFO_LINES
int amount = ((MaxRows(screen) - (int) move_up - 1)
- screen->cur_row);
if (amount < 0) {
saveEditBufLines(screen, dst, (unsigned) -amount);
move_up = (unsigned) -amount;
move_down_by = amount;
} else {
move_down_by = 0;
}
#else
int amount = screen->savelines - (int) move_up;
TRACE_SCRNBUF("before save", screen, dst, screen->savelines);
TRACE(("...%smoving pointers in saveBuf (compare %d %d)\n",
(amount > 0
? ""
: "SKIP "),
screen->savelines,
move_up));
if (amount > 0) {
SaveLineData(dst, 0, move_up);
MoveLineData(dst,
0,
move_up,
(unsigned) amount);
TRACE(("...reuse %d lines storage in saveBuf\n", move_up));
RestoreLineData(dst,
(unsigned) amount,
move_up);
TRACE_SCRNBUF("restoresave", screen, dst, screen->savelines);
}
saveEditBufLines(screen, dst, move_up);
(void) Reallocate(xw,
&screen->saveBuf_index,
&screen->saveBuf_data,
(unsigned) savelines,
(unsigned) cols,
(unsigned) savelines,
(unsigned) MaxCols(screen));
TRACE_SCRNBUF("reallocSAVE",
screen,
screen->saveBuf_index,
savelines);
#endif
(void) Reallocate(xw,
&screen->editBuf_index[screen->whichBuf],
&screen->editBuf_data[screen->whichBuf],
(unsigned) rows,
(unsigned) cols,
(unsigned) MaxRows(screen),
(unsigned) MaxCols(screen));
TRACE_SCRNBUF("reallocEDIT",
screen,
screen->editBuf_index[screen->whichBuf],
rows);
} else {
unsigned move_down = (unsigned) delta_rows;
#if OPT_FIFO_LINES
long unsave_fifo;
#else
ScrnBuf src = screen->saveBuf_index;
#endif
ScrnBuf dst;
int amount;
if ((int) move_down > screen->savedlines) {
move_down = (unsigned) screen->savedlines;
}
move_down_by = (int) move_down;
amount = rows - (int) move_down;
(void) Reallocate(xw,
&screen->editBuf_index[screen->whichBuf],
&screen->editBuf_data[screen->whichBuf],
(unsigned) rows,
(unsigned) cols,
(unsigned) MaxRows(screen),
(unsigned) MaxCols(screen));
dst = screen->editBuf_index[screen->whichBuf];
TRACE_SCRNBUF("reallocEDIT", screen, dst, rows);
TRACE(("...%smoving pointers in editBuf (compare %d %d)\n",
(amount > 0
? ""
: "SKIP "),
rows,
move_down));
if (amount > 0) {
SaveLineData(dst, (unsigned) amount, (size_t) move_down);
MoveLineData(dst,
move_down,
0,
(unsigned) amount);
TRACE(("...reuse %d lines storage in editBuf\n", move_down));
RestoreLineData(dst,
0,
move_down);
TRACE_SCRNBUF("shifted", screen, dst, rows);
}
unsaveEditBufLines(screen, dst, move_down);
TRACE_SCRNBUF("copied", screen, dst, rows);
#if OPT_FIFO_LINES
unsave_fifo = (long) move_down;
if (screen->saved_fifo < (int) unsave_fifo)
unsave_fifo = screen->saved_fifo;
while (unsave_fifo-- > 0) {
deleteScrollback(screen, -1);
screen->saved_fifo--;
}
#else
amount = (screen->savelines - (int) move_down);
TRACE(("...%smoving pointers in saveBuf (compare %d %d)\n",
(amount > 0
? ""
: "SKIP "),
rows,
move_down));
if (amount > 0) {
src = screen->saveBuf_index;
SaveLineData(src, amount, move_down);
MoveLineData(src,
move_down,
0,
(unsigned) amount);
TRACE(("...reuse %d lines storage in saveBuf\n", move_down));
RestoreLineData(src,
0,
move_down);
}
#endif
}
} else {
#if !OPT_FIFO_LINES
(void) Reallocate(xw,
&screen->saveBuf_index,
&screen->saveBuf_data,
(unsigned) savelines,
(unsigned) cols,
(unsigned) savelines,
(unsigned) MaxCols(screen));
#endif
(void) Reallocate(xw,
&screen->editBuf_index[screen->whichBuf],
&screen->editBuf_data[screen->whichBuf],
(unsigned) rows,
(unsigned) cols,
(unsigned) MaxRows(screen),
(unsigned) MaxCols(screen));
}
#else
if (screen->whichBuf
&& GravityIsSouthWest(xw))
SwitchBufPtrs(screen);
if (screen->editBuf_index[1])
(void) Reallocate(xw,
&screen->editBuf_index[1],
&screen->editBuf_data[1],
(unsigned) rows,
(unsigned) cols,
(unsigned) MaxRows(screen),
(unsigned) MaxCols(screen));
move_down_by = Reallocate(xw,
&screen->saveBuf_index,
&screen->saveBuf_data,
(unsigned) (rows + savelines),
(unsigned) cols,
(unsigned) (MaxRows(screen) + savelines),
(unsigned) MaxCols(screen));
#endif
screen->visbuf = VisBuf(screen);
}
AdjustSavedCursor(xw, move_down_by);
set_max_row(screen, screen->max_row + delta_rows);
set_max_col(screen, cols - 1);
if (screen->is_running) {
if (GravityIsSouthWest(xw)) {
screen->savedlines -= move_down_by;
if (screen->savedlines < 0)
screen->savedlines = 0;
if (screen->savedlines > screen->savelines)
screen->savedlines = screen->savelines;
if (screen->topline < -screen->savedlines)
screen->topline = -screen->savedlines;
set_cur_row(screen, screen->cur_row + move_down_by);
screen->cursorp.row += move_down_by;
ScrollSelection(screen, move_down_by, True);
if (screen->whichBuf)
SwitchBufPtrs(screen);
}
}
set_tb_margins(screen, 0, screen->max_row);
*flags &= ~ORIGIN;
if (screen->cur_row > screen->max_row)
set_cur_row(screen, screen->max_row);
if (screen->cur_col > screen->max_col)
set_cur_col(screen, screen->max_col);
screen->fullVwin.height = height - border;
screen->fullVwin.width = width - border - screen->fullVwin.sb_info.width;
} else if (FullHeight(screen) == height && FullWidth(screen) == width)
return (0);
screen->fullVwin.fullheight = (Dimension) height;
screen->fullVwin.fullwidth = (Dimension) width;
ResizeScrollBar(xw);
ResizeSelection(screen, rows, cols);
#ifndef NO_ACTIVE_ICON
if (screen->iconVwin.window) {
XWindowChanges changes;
screen->iconVwin.width =
MaxCols(screen) * screen->iconVwin.f_width;
screen->iconVwin.height =
MaxRows(screen) * screen->iconVwin.f_height;
changes.width = screen->iconVwin.fullwidth =
(Dimension) (screen->iconVwin.width + 2 * xw->misc.icon_border_width);
changes.height = screen->iconVwin.fullheight =
(Dimension) (screen->iconVwin.height + 2 * xw->misc.icon_border_width);
changes.border_width = (int) xw->misc.icon_border_width;
TRACE(("resizing icon window %dx%d\n", changes.height, changes.width));
XConfigureWindow(XtDisplay(xw), screen->iconVwin.window,
CWWidth | CWHeight | CWBorderWidth, &changes);
}
#endif
#ifdef TTYSIZE_STRUCT
TTYSIZE_ROWS(ts) = rows;
TTYSIZE_COLS(ts) = cols;
#ifdef USE_STRUCT_WINSIZE
ts.ws_xpixel = width;
ts.ws_ypixel = height;
#endif
code = SET_TTYSIZE(screen->respond, ts);
TRACE(("return %d from SET_TTYSIZE %dx%d\n", code, rows, cols));
(void) code;
#if defined(SIGWINCH) && defined(USE_STRUCT_TTYSIZE)
if (screen->pid > 1) {
int pgrp;
TRACE(("getting process-group\n"));
if (ioctl(screen->respond, TIOCGPGRP, &pgrp) != -1) {
TRACE(("sending SIGWINCH to process group %d\n", pgrp));
kill_process_group(pgrp, SIGWINCH);
}
}
#endif
#else
TRACE(("ScreenResize cannot do anything to pty\n"));
#endif
return (0);
}
Bool
non_blank_line(TScreen * screen,
int row,
int col,
int len)
{
int i;
Bool found = False;
LineData *ld = getLineData(screen, row);
if (ld != 0) {
for (i = col; i < len; i++) {
if (ld->charData[i]) {
found = True;
break;
}
}
}
return found;
}
#define minRectRow(screen) (getMinRow(screen) + 1)
#define minRectCol(screen) (getMinCol(screen) + 1)
#define maxRectRow(screen) (getMaxRow(screen) + 1)
#define maxRectCol(screen) (getMaxCol(screen) + 1)
static int
limitedParseRow(XtermWidget xw, TScreen * screen, int row)
{
int min_row = minRectRow(screen);
int max_row = maxRectRow(screen);
if (row < min_row)
row = min_row;
else if (row > max_row)
row = max_row;
return row;
}
static int
limitedParseCol(XtermWidget xw, TScreen * screen, int col)
{
int min_col = minRectCol(screen);
int max_col = maxRectCol(screen);
(void) xw;
if (col < min_col)
col = min_col;
else if (col > max_col)
col = max_col;
return col;
}
#define LimitedParse(num, func, dft) \
func(xw, screen, (nparams > num) ? params[num] : dft)
void
xtermParseRect(XtermWidget xw, int nparams, int *params, XTermRect * target)
{
TScreen *screen = &(xw->screen);
memset(target, 0, sizeof(*target));
target->top = LimitedParse(0, limitedParseRow, minRectRow(screen));
target->left = LimitedParse(1, limitedParseCol, minRectCol(screen));
target->bottom = LimitedParse(2, limitedParseRow, maxRectRow(screen));
target->right = LimitedParse(3, limitedParseCol, maxRectCol(screen));
TRACE(("parsed rectangle %d,%d %d,%d\n",
target->top,
target->left,
target->bottom,
target->right));
}
static Bool
validRect(XtermWidget xw, XTermRect * target)
{
TScreen *screen = &(xw->screen);
TRACE(("comparing against screensize %dx%d\n",
maxRectRow(screen),
maxRectCol(screen)));
return (target != 0
&& target->top >= minRectRow(screen)
&& target->left >= minRectCol(screen)
&& target->top <= target->bottom
&& target->left <= target->right
&& target->top <= maxRectRow(screen)
&& target->right <= maxRectCol(screen));
}
void
ScrnFillRectangle(XtermWidget xw,
XTermRect * target,
int value,
unsigned flags,
Bool keepColors)
{
TScreen *screen = &(xw->screen);
TRACE(("filling rectangle with '%c' flags %#x\n", value, flags));
if (validRect(xw, target)) {
LineData *ld;
unsigned left = (unsigned) (target->left - 1);
unsigned size = (unsigned) (target->right - (int) left);
unsigned attrs = flags;
int row, col;
(void) size;
attrs &= ATTRIBUTES;
attrs |= CHARDRAWN;
for (row = target->bottom - 1; row >= (target->top - 1); row--) {
ld = getLineData(screen, row);
TRACE(("filling %d [%d..%d]\n", row, left, left + size));
for (col = (int) left; col < target->right; ++col) {
unsigned temp = ld->attribs[col];
if (!keepColors) {
temp &= ~(FG_COLOR | BG_COLOR);
}
temp = attrs | (temp & (FG_COLOR | BG_COLOR | PROTECTED));
temp |= CHARDRAWN;
ld->attribs[col] = (Char) temp;
#if OPT_ISO_COLORS
if (attrs & (FG_COLOR | BG_COLOR)) {
if_OPT_ISO_COLORS(screen, {
ld->color[col] = xtermColorPair(xw);
});
}
#endif
}
for (col = (int) left; col < target->right; ++col)
ld->charData[col] = (CharData) value;
if_OPT_WIDE_CHARS(screen, {
size_t off;
for_each_combData(off, ld) {
memset(ld->combData[off] + left, 0, size * sizeof(IChar));
}
})
}
ScrnUpdate(xw,
target->top - 1,
target->left - 1,
(target->bottom - target->top) + 1,
(target->right - target->left) + 1,
False);
}
}
#if OPT_DEC_RECTOPS
void
ScrnCopyRectangle(XtermWidget xw, XTermRect * source, int nparam, int *params)
{
TScreen *screen = &(xw->screen);
TRACE(("copying rectangle\n"));
if (validRect(xw, source)) {
XTermRect target;
xtermParseRect(xw,
((nparam > 3) ? 2 : (nparam - 1)),
params,
&target);
if (validRect(xw, &target)) {
Cardinal high = (Cardinal) (source->bottom - source->top) + 1;
Cardinal wide = (Cardinal) (source->right - source->left) + 1;
Cardinal size = (high * wide);
int row, col;
Cardinal j, k;
LineData *ld;
CellData *cells = newCellData(xw, size);
if (cells != 0) {
TRACE(("OK - make copy %dx%d\n", high, wide));
target.bottom = target.top + (int) (high - 1);
target.right = target.left + (int) (wide - 1);
for (row = source->top - 1; row < source->bottom; ++row) {
ld = getLineData(screen, row);
j = (Cardinal) (row - (source->top - 1));
for (col = source->left - 1; col < source->right; ++col) {
k = (Cardinal) (col - (source->left - 1));
saveCellData(screen, cells,
(j * wide) + k,
ld, col);
}
}
for (row = target.top - 1; row < target.bottom; ++row) {
ld = getLineData(screen, row);
j = (Cardinal) (row - (target.top - 1));
for (col = target.left - 1; col < target.right; ++col) {
k = (Cardinal) (col - (target.left - 1));
if (row >= getMinRow(screen)
&& row <= getMaxRow(screen)
&& col >= getMinCol(screen)
&& col <= getMaxCol(screen)) {
if (j < high && k < wide) {
restoreCellData(screen, cells,
(j * wide) + k,
ld, col);
} else {
}
ld->attribs[col] |= CHARDRAWN;
}
}
}
free(cells);
ScrnUpdate(xw,
(target.top - 1),
(target.left - 1),
(target.bottom - target.top) + 1,
((target.right - target.left) + 1),
False);
}
}
}
}
void
ScrnMarkRectangle(XtermWidget xw,
XTermRect * target,
Bool reverse,
int nparam,
int *params)
{
TScreen *screen = &(xw->screen);
Bool exact = (screen->cur_decsace == 2);
TRACE(("%s %s\n",
reverse ? "reversing" : "marking",
(exact
? "rectangle"
: "region")));
if (validRect(xw, target)) {
LineData *ld;
int top = target->top - 1;
int bottom = target->bottom - 1;
int row, col;
int n;
for (row = top; row <= bottom; ++row) {
int left = ((exact || (row == top))
? (target->left - 1)
: getMinCol(screen));
int right = ((exact || (row == bottom))
? (target->right - 1)
: getMaxCol(screen));
ld = getLineData(screen, row);
TRACE(("marking %d [%d..%d]\n", row, left, right));
for (col = left; col <= right; ++col) {
unsigned flags = ld->attribs[col];
for (n = 0; n < nparam; ++n) {
#if OPT_TRACE
if (row == top && col == left)
TRACE(("attr param[%d] %d\n", n + 1, params[n]));
#endif
if (reverse) {
switch (params[n]) {
case 1:
flags ^= BOLD;
break;
case 4:
flags ^= UNDERLINE;
break;
case 5:
flags ^= BLINK;
break;
case 7:
flags ^= INVERSE;
break;
case 8:
flags ^= INVISIBLE;
break;
}
} else {
switch (params[n]) {
case 0:
flags &= ~SGR_MASK;
break;
case 1:
flags |= BOLD;
break;
case 4:
flags |= UNDERLINE;
break;
case 5:
flags |= BLINK;
break;
case 7:
flags |= INVERSE;
break;
case 8:
flags |= INVISIBLE;
break;
case 22:
flags &= ~BOLD;
break;
case 24:
flags &= ~UNDERLINE;
break;
case 25:
flags &= ~BLINK;
break;
case 27:
flags &= ~INVERSE;
break;
case 28:
flags &= ~INVISIBLE;
break;
}
}
}
#if OPT_TRACE
if (row == top && col == left)
TRACE(("first mask-change is %#x\n",
ld->attribs[col] ^ flags));
#endif
ld->attribs[col] = (Char) flags;
}
}
ScrnRefresh(xw,
(target->top - 1),
(exact ? (target->left - 1) : getMinCol(screen)),
(target->bottom - target->top) + 1,
(exact
? ((target->right - target->left) + 1)
: (getMaxCol(screen) - getMinCol(screen) + 1)),
False);
}
}
void
ScrnWipeRectangle(XtermWidget xw,
XTermRect * target)
{
TScreen *screen = &(xw->screen);
TRACE(("wiping rectangle\n"));
if (validRect(xw, target)) {
LineData *ld;
int top = target->top - 1;
int bottom = target->bottom - 1;
int row, col;
for (row = top; row <= bottom; ++row) {
int left = (target->left - 1);
int right = (target->right - 1);
TRACE(("wiping %d [%d..%d]\n", row, left, right));
ld = getLineData(screen, row);
for (col = left; col <= right; ++col) {
if (!((screen->protected_mode == DEC_PROTECT)
&& (ld->attribs[col] & PROTECTED))) {
ld->attribs[col] |= CHARDRAWN;
ld->charData[col] = ' ';
if_OPT_WIDE_CHARS(screen, {
size_t off;
for_each_combData(off, ld) {
ld->combData[off][col] = '\0';
}
})
}
}
}
ScrnUpdate(xw,
(target->top - 1),
(target->left - 1),
(target->bottom - target->top) + 1,
((target->right - target->left) + 1),
False);
}
}
#endif