#define LEN(a) (sizeof(a) / sizeof(a)[0])
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
+#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f))
+#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
#define IS_SET(flag) ((term.mode & (flag)) != 0)
ATTR_REVERSE = 1,
ATTR_UNDERLINE = 2,
ATTR_BOLD = 4,
- ATTR_GFX = 8,
- ATTR_ITALIC = 16,
- ATTR_BLINK = 32,
- ATTR_WRAP = 64,
- ATTR_WIDE = 128,
- ATTR_WDUMMY = 256,
+ ATTR_ITALIC = 8,
+ ATTR_BLINK = 16,
+ ATTR_WRAP = 32,
+ ATTR_WIDE = 64,
+ ATTR_WDUMMY = 128,
};
enum cursor_movement {
enum escape_state {
ESC_START = 1,
ESC_CSI = 2,
- ESC_STR = 4, /* DSC, OSC, PM, APC */
+ ESC_STR = 4, /* DCS, OSC, PM, APC */
ESC_ALTCHARSET = 8,
ESC_STR_END = 16, /* a final string was encountered */
ESC_TEST = 32, /* Enter in test mode */
/* Drawing Context */
typedef struct {
- Colour col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
+ Colour col[MAX(LEN(colorname), 256)];
Font font, bfont, ifont, ibfont;
GC gc;
} DC;
static void tsetmode(bool, bool, int *, int);
static void tfulldirt(void);
static void techo(char *, int);
+static void tcontrolcode(uchar );
+static void tdectest(char );
static int32_t tdefcolor(int *, int *, int);
-static void tselcs(void);
static void tdeftran(char);
static inline bool match(uint, uint);
static void ttynew(void);
static void selcopy(void);
static void selscroll(int, int);
static void selsnap(int, int *, int *, int);
+static void getbuttoninfo(XEvent *);
+static void mousereport(XEvent *);
static size_t utf8decode(char *, long *, size_t);
static long utf8decodebyte(char, size_t *);
static size_t utf8len(char *);
static size_t utf8validate(long *, size_t);
-static ssize_t xwrite(int, char *, size_t);
+static ssize_t xwrite(int, const char *, size_t);
static void *xmalloc(size_t);
static void *xrealloc(void *, size_t);
static char *xstrdup(char *);
+static void usage(void);
+
static void (*handler[LASTEvent])(XEvent *) = {
[KeyPress] = kpress,
[ClientMessage] = cmessage,
static int frclen = 0;
ssize_t
-xwrite(int fd, char *s, size_t len) {
+xwrite(int fd, const char *s, size_t len) {
size_t aux = len;
while(len > 0) {
static inline bool
selected(int x, int y) {
- if(sel.ne.y == y && sel.nb.y == y)
- return BETWEEN(x, sel.nb.x, sel.ne.x);
-
- if(sel.type == SEL_RECTANGULAR) {
- return ((sel.nb.y <= y && y <= sel.ne.y)
- && (sel.nb.x <= x && x <= sel.ne.x));
- }
+ if(sel.type == SEL_RECTANGULAR)
+ return BETWEEN(y, sel.nb.y, sel.ne.y)
+ && BETWEEN(x, sel.nb.x, sel.ne.x);
- return ((sel.nb.y < y && y < sel.ne.y)
- || (y == sel.ne.y && x <= sel.ne.x))
- || (y == sel.nb.y && x >= sel.nb.x
- && (x <= sel.ne.x || sel.nb.y != sel.ne.y));
+ return BETWEEN(y, sel.nb.y, sel.ne.y)
+ && (y != sel.nb.y || x >= sel.nb.x)
+ && (y != sel.ne.y || x <= sel.ne.x);
}
void
void
getbuttoninfo(XEvent *e) {
int type;
- uint state = e->xbutton.state &~Button1Mask;
+ uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
sel.alt = IS_SET(MODE_ALTSCREEN);
/* MODE_MOUSEX10: no button release reporting */
if(IS_SET(MODE_MOUSEX10))
return;
+ if (button == 64 || button == 65)
+ return;
}
}
struct timeval now;
Mousekey *mk;
- if(IS_SET(MODE_MOUSE)) {
+ if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
mousereport(e);
return;
}
int x, y, bufsize, size, i, ex;
Glyph *gp, *last;
- if(sel.ob.x == -1) {
- str = NULL;
- } else {
- bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
- ptr = str = xmalloc(bufsize);
+ if(sel.ob.x == -1)
+ return NULL;
- /* append every set & selected glyph to the selection */
- for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
- gp = &term.line[y][0];
- last = &gp[term.col-1];
+ bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
+ ptr = str = xmalloc(bufsize);
- while(last >= gp && !(selected(last - gp, y) &&
- strcmp(last->c, " ") != 0)) {
- --last;
- }
+ /* append every set & selected glyph to the selection */
+ for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
+ gp = &term.line[y][0];
+ last = &gp[term.col-1];
- for(x = 0; gp <= last; x++, ++gp) {
- if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
- continue;
+ while(last >= gp && !(selected(last - gp, y) &&
+ strcmp(last->c, " ") != 0)) {
+ --last;
+ }
- size = utf8len(gp->c);
- memcpy(ptr, gp->c, size);
- ptr += size;
- }
+ for(x = 0; gp <= last; x++, ++gp) {
+ if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
+ continue;
- /*
- * Copy and pasting of line endings is inconsistent
- * in the inconsistent terminal and GUI world.
- * The best solution seems like to produce '\n' when
- * something is copied from st and convert '\n' to
- * '\r', when something to be pasted is received by
- * st.
- * FIXME: Fix the computer world.
- */
- if(y < sel.ne.y && x > 0 && !((gp-1)->mode & ATTR_WRAP))
- *ptr++ = '\n';
+ size = utf8len(gp->c);
+ memcpy(ptr, gp->c, size);
+ ptr += size;
+ }
- /*
- * If the last selected line expands in the selection
- * after the visible text '\n' is appended.
- */
- if(y == sel.ne.y) {
- i = term.col;
- while(--i > 0 && term.line[y][i].c[0] == ' ')
- /* nothing */;
- ex = sel.ne.x;
- if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
- ex = sel.nb.x;
- if(i < ex)
- *ptr++ = '\n';
- }
+ /*
+ * Copy and pasting of line endings is inconsistent
+ * in the inconsistent terminal and GUI world.
+ * The best solution seems like to produce '\n' when
+ * something is copied from st and convert '\n' to
+ * '\r', when something to be pasted is received by
+ * st.
+ * FIXME: Fix the computer world.
+ */
+ if(y < sel.ne.y && !(x > 0 && (gp-1)->mode & ATTR_WRAP))
+ *ptr++ = '\n';
+
+ /*
+ * If the last selected line expands in the selection
+ * after the visible text '\n' is appended.
+ */
+ if(y == sel.ne.y) {
+ i = term.col;
+ while(--i > 0 && term.line[y][i].c[0] == ' ')
+ /* nothing */;
+ ex = sel.ne.x;
+ if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
+ ex = sel.nb.x;
+ if(i < ex)
+ *ptr++ = '\n';
}
- *ptr = 0;
}
+ *ptr = 0;
return str;
}
void
brelease(XEvent *e) {
- if(IS_SET(MODE_MOUSE)) {
+ if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
mousereport(e);
return;
}
bmotion(XEvent *e) {
int oldey, oldex, oldsby, oldsey;
- if(IS_SET(MODE_MOUSE)) {
+ if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
mousereport(e);
return;
}
opt_io, strerror(errno));
}
}
+ break;
}
}
-void
-dump(char c) {
- static int col;
-
- fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
- if(++col % 10 == 0)
- fprintf(stderr, "\n");
-}
-
void
ttyread(void) {
static char buf[BUFSIZ];
void
ttywrite(const char *s, size_t n) {
- if(write(cmdfd, s, n) == -1)
+ if(xwrite(cmdfd, s, n) == -1)
die("write error on tty: %s\n", strerror(errno));
}
/*
* The table is proudly stolen from rxvt.
*/
- if(attr->mode & ATTR_GFX) {
+ if(term.trantbl[term.charset] == CS_GRAPHIC0) {
if(BETWEEN(c[0], 0x41, 0x7e) && vt100_0[c[0] - 0x41]) {
c = vt100_0[c[0] - 0x41];
}
default:
fprintf(stderr,
"erresc(38): gfx attr %d unknown\n", attr[*npar]);
+ break;
}
return idx;
for(lim = args + narg; args < lim; ++args) {
if(priv) {
switch(*args) {
- break;
case 1: /* DECCKM -- Cursor key */
MODBIT(term.mode, set, MODE_APPCURSOR);
break;
if (!allowaltscreen)
break;
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
- /* FALLTHRU */
+ /* FALLTHROUGH */
case 47: /* swap screen */
case 1047:
if (!allowaltscreen)
tswapscreen();
if(*args != 1049)
break;
- /* FALLTRU */
+ /* FALLTHROUGH */
case 1048:
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
break;
len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
term.c.y+1, term.c.x+1);
ttywrite(buf, len);
- break;
}
+ break;
case 'r': /* DECSTBM -- Set Scrolling Region */
if(csiescseq.priv) {
goto unknown;
char *p = NULL;
int j, narg, par;
+ term.esc &= ~(ESC_STR_END|ESC_STR);
strparse();
narg = strescseq.narg;
par = atoi(strescseq.args[0]);
if(narg < 3)
break;
p = strescseq.args[2];
- /* fall through */
+ /* FALLTHROUGH */
case 104: /* color reset, here p = NULL */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
if (!xsetcolorname(j, p)) {
case 'k': /* old title set compatibility */
xsettitle(strescseq.args[0]);
return;
- case 'P': /* DSC -- Device Control String */
+ case 'P': /* DCS -- Device Control String */
case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */
return;
for(; len > 0; buf++, len--) {
char c = *buf;
- if(c < 0x20 || c == 0177) { /* control code */
- if(c != '\n' && c != '\r' && c != '\t') {
+ if(ISCONTROL(c)) { /* control code */
+ if(c & 0x80) {
+ c &= 0x7f;
+ tputc("^", 1);
+ tputc("[", 1);
+ } else if(c != '\n' && c != '\r' && c != '\t') {
c ^= '\x40';
tputc("^", 1);
}
tdeftran(char ascii) {
char c, (*bp)[2];
static char tbl[][2] = {
- {'0', CS_GRAPHIC0}, {'1', CS_GRAPHIC1}, {'A', CS_UK},
- {'B', CS_USA}, {'<', CS_MULTI}, {'K', CS_GER},
- {'5', CS_FIN}, {'C', CS_FIN},
+ {'0', CS_GRAPHIC0}, {'B', CS_USA},
{0, 0}
};
}
void
-tselcs(void) {
- MODBIT(term.c.attr.mode,
- term.trantbl[term.charset] == CS_GRAPHIC0,
- ATTR_GFX);
+tcontrolcode(uchar ascii) {
+ static char question[UTF_SIZ] = "?";
+
+ switch(ascii) {
+ case '\t': /* HT */
+ tputtab(1);
+ return;
+ case '\b': /* BS */
+ tmoveto(term.c.x-1, term.c.y);
+ return;
+ case '\r': /* CR */
+ tmoveto(0, term.c.y);
+ return;
+ case '\f': /* LF */
+ case '\v': /* VT */
+ case '\n': /* LF */
+ /* go to first col if the mode is set */
+ tnewline(IS_SET(MODE_CRLF));
+ return;
+ case '\a': /* BEL */
+ if(term.esc & ESC_STR_END) {
+ /* backwards compatibility to xterm */
+ strhandle();
+ } else {
+ if(!(xw.state & WIN_FOCUSED))
+ xseturgency(1);
+ if (bellvolume)
+ XBell(xw.dpy, bellvolume);
+ }
+ break;
+ case '\033': /* ESC */
+ csireset();
+ term.esc &= ~(ESC_CSI|ESC_ALTCHARSET|ESC_TEST);
+ term.esc |= ESC_START;
+ return;
+ case '\016': /* SO */
+ term.charset = 0;
+ return;
+ case '\017': /* SI */
+ term.charset = 1;
+ return;
+ case '\032': /* SUB */
+ tsetchar(question, &term.c.attr, term.c.x, term.c.y);
+ case '\030': /* CAN */
+ csireset();
+ break;
+ case '\005': /* ENQ (IGNORED) */
+ case '\000': /* NUL (IGNORED) */
+ case '\021': /* XON (IGNORED) */
+ case '\023': /* XOFF (IGNORED) */
+ case 0177: /* DEL (IGNORED) */
+ return;
+ case 0x84: /* TODO: IND */
+ case 0x85: /* TODO: NEL */
+ case 0x88: /* TODO: HTS */
+ case 0x8d: /* TODO: RI */
+ case 0x8e: /* TODO: SS2 */
+ case 0x8f: /* TODO: SS3 */
+ case 0x90: /* TODO: DCS */
+ case 0x98: /* TODO: SOS */
+ case 0x9a: /* TODO: DECID */
+ case 0x9b: /* TODO: CSI */
+ case 0x9c: /* TODO: ST */
+ case 0x9d: /* TODO: OSC */
+ case 0x9e: /* TODO: PM */
+ case 0x9f: /* TODO: APC */
+ break;
+ }
+ /* only CAN, SUB, \a and C1 chars interrupt a sequence */
+ term.esc &= ~(ESC_STR_END|ESC_STR);
+ return;
+}
+
+void
+tdectest(char c) {
+ static char E[UTF_SIZ] = "E";
+ int x, y;
+
+ if(c == '8') { /* DEC screen alignment test. */
+ for(x = 0; x < term.col; ++x) {
+ for(y = 0; y < term.row; ++y)
+ tsetchar(E, &term.c.attr, x, y);
+ }
+ }
}
void
tputc(char *c, int len) {
- uchar ascii = *c;
- bool control = ascii < '\x20' || ascii == 0177;
+ uchar ascii;
+ bool control;
long unicodep;
int width;
+ Glyph *gp;
if(len == 1) {
width = 1;
+ unicodep = ascii = *c;
} else {
utf8decode(c, &unicodep, UTF_SIZ);
width = wcwidth(unicodep);
+ control = ISCONTROLC1(unicodep);
+ ascii = unicodep;
}
if(IS_SET(MODE_PRINT))
tprinter(c, len);
+ control = ISCONTROL(unicodep);
/*
- * STR sequences must be checked before anything else
- * because it can use some control codes as part of the sequence.
+ * STR sequence must be checked before anything else
+ * because it uses all following characters until it
+ * receives a ESC, a SUB, a ST or any other C1 control
+ * character.
*/
if(term.esc & ESC_STR) {
- switch(ascii) {
- case '\033':
- term.esc = ESC_START | ESC_STR_END;
- break;
- case '\a': /* backwards compatibility to xterm */
- term.esc = 0;
- strhandle();
- break;
- default:
- if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
- memmove(&strescseq.buf[strescseq.len], c, len);
- strescseq.len += len;
- } else {
- /*
- * Here is a bug in terminals. If the user never sends
- * some code to stop the str or esc command, then st
- * will stop responding. But this is better than
- * silently failing with unknown characters. At least
- * then users will report back.
- *
- * In the case users ever get fixed, here is the code:
- */
- /*
- * term.esc = 0;
- * strhandle();
- */
- }
+ if(width == 1 &&
+ (ascii == '\a' || ascii == 030 ||
+ ascii == 032 || ascii == 033 ||
+ ISCONTROLC1(unicodep))) {
+ term.esc &= ~(ESC_START|ESC_STR);
+ term.esc |= ESC_STR_END;
+ } else if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
+ memmove(&strescseq.buf[strescseq.len], c, len);
+ strescseq.len += len;
+ return;
+ } else {
+ /*
+ * Here is a bug in terminals. If the user never sends
+ * some code to stop the str or esc command, then st
+ * will stop responding. But this is better than
+ * silently failing with unknown characters. At least
+ * then users will report back.
+ *
+ * In the case users ever get fixed, here is the code:
+ */
+ /*
+ * term.esc = 0;
+ * strhandle();
+ */
+ return;
}
- return;
}
/*
* they must not cause conflicts with sequences.
*/
if(control) {
- switch(ascii) {
- case '\t': /* HT */
- tputtab(1);
- return;
- case '\b': /* BS */
- tmoveto(term.c.x-1, term.c.y);
- return;
- case '\r': /* CR */
- tmoveto(0, term.c.y);
- return;
- case '\f': /* LF */
- case '\v': /* VT */
- case '\n': /* LF */
- /* go to first col if the mode is set */
- tnewline(IS_SET(MODE_CRLF));
- return;
- case '\a': /* BEL */
- if(!(xw.state & WIN_FOCUSED))
- xseturgency(1);
- if (bellvolume)
- XBell(xw.dpy, bellvolume);
- return;
- case '\033': /* ESC */
- csireset();
- term.esc = ESC_START;
- return;
- case '\016': /* SO */
- term.charset = 0;
- tselcs();
- return;
- case '\017': /* SI */
- term.charset = 1;
- tselcs();
- return;
- case '\032': /* SUB */
- case '\030': /* CAN */
- csireset();
- return;
- case '\005': /* ENQ (IGNORED) */
- case '\000': /* NUL (IGNORED) */
- case '\021': /* XON (IGNORED) */
- case '\023': /* XOFF (IGNORED) */
- case 0177: /* DEL (IGNORED) */
- return;
- }
+ tcontrolcode(ascii);
+ /*
+ * control codes are not shown ever
+ */
+ return;
} else if(term.esc & ESC_START) {
if(term.esc & ESC_CSI) {
csiescseq.buf[csiescseq.len++] = ascii;
csiparse();
csihandle();
}
- } else if(term.esc & ESC_STR_END) {
- term.esc = 0;
- if(ascii == '\\')
- strhandle();
+ return;
} else if(term.esc & ESC_ALTCHARSET) {
tdeftran(ascii);
- tselcs();
- term.esc = 0;
} else if(term.esc & ESC_TEST) {
- if(ascii == '8') { /* DEC screen alignment test. */
- char E[UTF_SIZ] = "E";
- int x, y;
-
- for(x = 0; x < term.col; ++x) {
- for(y = 0; y < term.row; ++y)
- tsetchar(E, &term.c.attr, x, y);
- }
- }
- term.esc = 0;
+ tdectest(ascii);
} else {
switch(ascii) {
case '[':
term.esc |= ESC_CSI;
- break;
+ return;
case '#':
term.esc |= ESC_TEST;
- break;
+ return;
case 'P': /* DCS -- Device Control String */
case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */
strreset();
strescseq.type = ascii;
term.esc |= ESC_STR;
- break;
+ return;
case '(': /* set primary charset G0 */
case ')': /* set secondary charset G1 */
case '*': /* set tertiary charset G2 */
case '+': /* set quaternary charset G3 */
term.icharset = ascii - '(';
term.esc |= ESC_ALTCHARSET;
- break;
+ return;
case 'D': /* IND -- Linefeed */
if(term.c.y == term.bot) {
tscrollup(term.top, 1);
} else {
tmoveto(term.c.x, term.c.y+1);
}
- term.esc = 0;
break;
case 'E': /* NEL -- Next line */
tnewline(1); /* always go to first col */
- term.esc = 0;
break;
case 'H': /* HTS -- Horizontal tab stop */
term.tabs[term.c.x] = 1;
- term.esc = 0;
break;
case 'M': /* RI -- Reverse index */
if(term.c.y == term.top) {
} else {
tmoveto(term.c.x, term.c.y-1);
}
- term.esc = 0;
break;
case 'Z': /* DECID -- Identify Terminal */
ttywrite(VT102ID, sizeof(VT102ID) - 1);
- term.esc = 0;
break;
case 'c': /* RIS -- Reset to inital state */
treset();
- term.esc = 0;
xresettitle();
xloadcols();
break;
case '=': /* DECPAM -- Application keypad */
term.mode |= MODE_APPKEYPAD;
- term.esc = 0;
break;
case '>': /* DECPNM -- Normal keypad */
term.mode &= ~MODE_APPKEYPAD;
- term.esc = 0;
break;
case '7': /* DECSC -- Save Cursor */
tcursor(CURSOR_SAVE);
- term.esc = 0;
break;
case '8': /* DECRC -- Restore Cursor */
tcursor(CURSOR_LOAD);
- term.esc = 0;
break;
- case '\\': /* ST -- Stop */
- term.esc = 0;
+ case '\\': /* ST -- String Terminator */
+ if(term.esc & ESC_STR_END)
+ strhandle();
break;
default:
fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
(uchar) ascii, isprint(ascii)? ascii:'.');
- term.esc = 0;
+ break;
}
}
+ term.esc = 0;
/*
* All characters which form part of a sequence are not
* printed
*/
return;
}
- /*
- * Display control codes only if we are in graphic mode
- */
- if(control && !(term.c.attr.mode & ATTR_GFX))
- return;
if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
selclear(NULL);
+
+ gp = &term.line[term.c.y][term.c.x];
if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
- term.line[term.c.y][term.c.x].mode |= ATTR_WRAP;
+ gp->mode |= ATTR_WRAP;
tnewline(1);
}
- if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col) {
- memmove(&term.line[term.c.y][term.c.x+1],
- &term.line[term.c.y][term.c.x],
- (term.col - term.c.x - 1) * sizeof(Glyph));
- }
+ if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col)
+ memmove(gp+1, gp, (term.col - term.c.x - 1) * sizeof(Glyph));
if(term.c.x+width > term.col)
tnewline(1);
tsetchar(c, &term.c.attr, term.c.x, term.c.y);
if(width == 2) {
- term.line[term.c.y][term.c.x].mode |= ATTR_WIDE;
+ gp->mode |= ATTR_WIDE;
if(term.c.x+1 < term.col) {
- term.line[term.c.y][term.c.x+1].c[0] = '\0';
- term.line[term.c.y][term.c.x+1].mode = ATTR_WDUMMY;
+ gp[1].c[0] = '\0';
+ gp[1].mode = ATTR_WDUMMY;
}
}
if(term.c.x+width < term.col) {
int slide = term.c.y - row + 1;
bool *bp;
Line *orig;
+ TCursor c;
if(col < 1 || row < 1)
return 0;
tmoveto(term.c.x, term.c.y);
/* Clearing both screens */
orig = term.line;
+ c = term.c;
do {
if(mincol < col && 0 < minrow) {
tclearregion(mincol, 0, col - 1, minrow - 1);
if(0 < col && minrow < row) {
tclearregion(0, minrow, col - 1, row - 1);
}
- tcursor(CURSOR_SAVE);
tswapscreen();
tcursor(CURSOR_LOAD);
} while(orig != term.line);
+ term.c = c;
return (slide > 0);
}
void
xloadcols(void) {
- int i, r, g, b;
+ int i;
XRenderColor color = { .alpha = 0xffff };
static bool loaded;
Colour *cp;
XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
}
- /* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
+ /* load colours [0-15] and [256-LEN(colorname)] (config.h) */
for(i = 0; i < LEN(colorname); i++) {
if(!colorname[i])
continue;
}
}
- /* load colors [16-255] ; same colors as xterm */
- for(i = 16, r = 0; r < 6; r++) {
- for(g = 0; g < 6; g++) {
- for(b = 0; b < 6; b++) {
- color.red = sixd_to_16bit(r);
- color.green = sixd_to_16bit(g);
- color.blue = sixd_to_16bit(b);
- if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) {
- die("Could not allocate color %d\n", i);
- }
- i++;
- }
- }
+ /* load colours [16-231] ; same colours as xterm */
+ for(i = 16; i < 6*6*6+16; i++) {
+ color.red = sixd_to_16bit( ((i-16)/36)%6 );
+ color.green = sixd_to_16bit( ((i-16)/6) %6 );
+ color.blue = sixd_to_16bit( ((i-16)/1) %6 );
+ if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i]))
+ die("Could not allocate color %d\n", i);
}
- for(r = 0; r < 24; r++, i++) {
- color.red = color.green = color.blue = 0x0808 + 0x0a0a * r;
- if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color,
- &dc.col[i])) {
+ /* load colours [232-255] ; grayscale */
+ for(; i < 256; i++) {
+ color.red = color.green = color.blue = 0x0808 + 0x0a0a * (i-(6*6*6+16));
+ if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i]))
die("Could not allocate color %d\n", i);
- }
}
loaded = true;
}
int
xsetcolorname(int x, const char *name) {
XRenderColor color = { .alpha = 0xffff };
- Colour colour;
+
if(!BETWEEN(x, 0, LEN(colorname)))
return -1;
if(!name) {
- if(BETWEEN(x, 16, 16 + 215)) {
- int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b = (x - 16) % 6;
- color.red = sixd_to_16bit(r);
- color.green = sixd_to_16bit(g);
- color.blue = sixd_to_16bit(b);
- if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
- return 0; /* something went wrong */
- dc.col[x] = colour;
+ if(BETWEEN(x, 16, 6*6*6+16)) { /* 256 colour */
+ color.red = sixd_to_16bit( ((x-16)/36)%6 );
+ color.green = sixd_to_16bit( ((x-16)/6) %6 );
+ color.blue = sixd_to_16bit( ((x-16)/1) %6 );
+ if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[x]))
+ die("Could not allocate color %d\n", x);
return 1;
- } else if(BETWEEN(x, 16 + 216, 255)) {
- color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x - (16 + 216));
- if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour))
- return 0; /* something went wrong */
- dc.col[x] = colour;
+ } else if(BETWEEN(x, 6*6*6+16, 255)) { /* grayscale */
+ color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x-(6*6*6+16));
+ if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[x]))
+ die("Could not allocate color %d\n", x);
return 1;
- } else {
+ } else { /* system colours */
name = colorname[x];
}
}
- if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &colour))
- return 0;
- dc.col[x] = colour;
+ if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &dc.col[x]))
+ return 0; /* invalid name */
return 1;
}
void
xunloadfonts(void) {
- int i;
-
/* Free the loaded fonts in the font cache. */
- for(i = 0; i < frclen; i++) {
- XftFontClose(xw.dpy, frc[i].font);
- }
- frclen = 0;
+ while(frclen > 0)
+ XftFontClose(xw.dpy, frc[--frclen].font);
xunloadfont(&dc.font);
xunloadfont(&dc.bfont);
}
if(base.mode & ATTR_BOLD) {
- if(BETWEEN(base.fg, 0, 7)) {
- /* basic system colors */
- fg = &dc.col[base.fg + 8];
- } else if(BETWEEN(base.fg, 16, 195)) {
- /* 256 colors */
- fg = &dc.col[base.fg + 36];
- } else if(BETWEEN(base.fg, 232, 251)) {
- /* greyscale */
- fg = &dc.col[base.fg + 4];
- }
/*
- * Those ranges will not be brightened:
- * 8 - 15 – bright system colors
- * 196 - 231 – highest 256 color cube
- * 252 - 255 – brightest colors in greyscale
+ * change basic system colours [0-7]
+ * to bright system colours [8-15]
*/
- font = &dc.bfont;
- frcflags = FRC_BOLD;
+ if(BETWEEN(base.fg, 0, 7))
+ fg = &dc.col[base.fg + 8];
+
+ if(base.mode & ATTR_ITALIC) {
+ font = &dc.ibfont;
+ frcflags = FRC_ITALICBOLD;
+ } else {
+ font = &dc.bfont;
+ frcflags = FRC_BOLD;
+ }
}
if(IS_SET(MODE_REVERSE)) {
redraw(int timeout) {
struct timespec tv = {0, timeout * 1000};
+ tfulldirt();
draw();
if(timeout > 0) {
int ic, ib, x, y, ox, sl;
Glyph base, new;
char buf[DRAW_BUF_SIZ];
- bool ena_sel = sel.ob.x != -1;
+ bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
long unicodep;
- if(sel.alt != IS_SET(MODE_ALTSCREEN))
- ena_sel = 0;
-
if(!(xw.state & WIN_VISIBLE))
return;
xseturgency(int add) {
XWMHints *h = XGetWMHints(xw.dpy, xw.win);
- h->flags = add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
+ MODBIT(h->flags, add, XUrgencyHint);
XSetWMHints(xw.dpy, xw.win, h);
XFree(h);
}