#define IS_SET(flag) ((term.mode & (flag)) != 0)
#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
+#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
+#define IS_TRUECOL(x) (1 << 24 & (x))
+#define TRUERED(x) (((x) & 0xff0000) >> 8)
+#define TRUEGREEN(x) (((x) & 0xff00))
+#define TRUEBLUE(x) (((x) & 0xff) << 8)
+
+
#define VT102ID "\033[?6c"
enum glyph_attribute {
enum cursor_state {
CURSOR_DEFAULT = 0,
CURSOR_WRAPNEXT = 1,
- CURSOR_ORIGIN = 2
+ CURSOR_ORIGIN = 2
};
enum term_mode {
- MODE_WRAP = 1,
+ MODE_WRAP = 1,
MODE_INSERT = 2,
MODE_APPKEYPAD = 4,
MODE_ALTSCREEN = 8,
- MODE_CRLF = 16,
+ MODE_CRLF = 16,
MODE_MOUSEBTN = 32,
MODE_MOUSEMOTION = 64,
MODE_REVERSE = 128,
MODE_KBDLOCK = 256,
- MODE_HIDE = 512,
- MODE_ECHO = 1024,
- MODE_APPCURSOR = 2048,
+ MODE_HIDE = 512,
+ MODE_ECHO = 1024,
+ MODE_APPCURSOR = 2048,
MODE_MOUSESGR = 4096,
- MODE_8BIT = 8192,
- MODE_BLINK = 16384,
- MODE_FBLINK = 32768,
- MODE_FOCUS = 65536,
- MODE_MOUSEX10 = 131072,
+ MODE_8BIT = 8192,
+ MODE_BLINK = 16384,
+ MODE_FBLINK = 32768,
+ MODE_FOCUS = 65536,
+ MODE_MOUSEX10 = 131072,
MODE_MOUSEMANY = 262144,
MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
- |MODE_MOUSEMANY,
+ |MODE_MOUSEMANY,
};
enum escape_state {
ESC_START = 1,
- ESC_CSI = 2,
- ESC_STR = 4, /* DSC, OSC, PM, APC */
+ ESC_CSI = 2,
+ ESC_STR = 4, /* DSC, OSC, PM, APC */
ESC_ALTCHARSET = 8,
ESC_STR_END = 16, /* a final string was encountered */
ESC_TEST = 32, /* Enter in test mode */
typedef unsigned short ushort;
typedef struct {
- char c[UTF_SIZ]; /* character code */
- uchar mode; /* attribute flags */
- ushort fg; /* foreground */
- ushort bg; /* background */
+ char c[UTF_SIZ]; /* character code */
+ uchar mode; /* attribute flags */
+ ulong fg; /* foreground */
+ ulong bg; /* background */
} Glyph;
typedef Glyph *Line;
typedef struct {
- Glyph attr; /* current char attributes */
+ Glyph attr; /* current char attributes */
int x;
int y;
char state;
/* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
typedef struct {
char buf[ESC_BUF_SIZ]; /* raw string */
- int len; /* raw string length */
+ int len; /* raw string length */
char priv;
int arg[ESC_ARG_SIZ];
- int narg; /* nb of args */
+ int narg; /* nb of args */
char mode;
} CSIEscape;
/* STR Escape sequence structs */
/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
typedef struct {
- char type; /* ESC type ... */
+ char type; /* ESC type ... */
char buf[STR_BUF_SIZ]; /* raw string */
- int len; /* raw string length */
+ int len; /* raw string length */
char *args[STR_ARG_SIZ];
- int narg; /* nb of args */
+ int narg; /* nb of args */
} STREscape;
/* Internal representation of the screen */
typedef struct {
- int row; /* nb row */
- int col; /* nb col */
- Line *line; /* screen */
- Line *alt; /* alternate screen */
- bool *dirty; /* dirtyness of lines */
- TCursor c; /* cursor */
- int top; /* top scroll limit */
- int bot; /* bottom scroll limit */
- int mode; /* terminal mode flags */
- int esc; /* escape state flags */
- bool numlock; /* lock numbers in keyboard */
+ int row; /* nb row */
+ int col; /* nb col */
+ Line *line; /* screen */
+ Line *alt; /* alternate screen */
+ bool *dirty; /* dirtyness of lines */
+ TCursor c; /* cursor */
+ int top; /* top scroll limit */
+ int bot; /* bottom scroll limit */
+ int mode; /* terminal mode flags */
+ int esc; /* escape state flags */
+ bool numlock; /* lock numbers in keyboard */
bool *tabs;
} Term;
uint mask;
char s[ESC_BUF_SIZ];
/* three valued logic variables: 0 indifferent, 1 on, -1 off */
- signed char appkey; /* application keypad */
- signed char appcursor; /* application cursor */
- signed char crlf; /* crlf mode */
+ signed char appkey; /* application keypad */
+ signed char appcursor; /* application cursor */
+ signed char crlf; /* crlf mode */
} Key;
typedef struct {
static void tsetmode(bool, bool, int *, int);
static void tfulldirt(void);
static void techo(char *, int);
-
+static ulong tdefcolor(int *, int *, int);
static inline bool match(uint, uint);
static void ttynew(void);
static void ttyread(void);
typedef struct {
XftFont *font;
- long c;
int flags;
} Fontcache;
-/*
- * Fontcache is a ring buffer, with frccur as current position and frclen as
- * the current length of used elements.
- */
-
-static Fontcache frc[1024];
-static int frccur = -1, frclen = 0;
+/* Fontcache is an array now. A new font will be appended to the array. */
+static Fontcache frc[16];
+static int frclen = 0;
ssize_t
xwrite(int fd, char *s, size_t len) {
int stat = 0;
if(waitpid(pid, &stat, 0) < 0)
- die("Waiting for pid %hd failed: %s\n", pid, SERRNO);
+ die("Waiting for pid %hd failed: %s\n", pid, SERRNO);
if(WIFEXITED(stat)) {
exit(WEXITSTATUS(stat));
tscrollup(term.c.y, n);
}
+ulong
+tdefcolor(int *attr, int *npar, int l) {
+ long idx = -1;
+ uint r, g, b;
+
+ switch (attr[*npar + 1]) {
+ case 2: /* direct colour in RGB space */
+ if (*npar + 4 >= l) {
+ fprintf(stderr,
+ "erresc(38): Incorrect number of parameters (%d)\n",
+ *npar);
+ break;
+ }
+ r = attr[*npar + 2];
+ g = attr[*npar + 3];
+ b = attr[*npar + 4];
+ *npar += 4;
+ if(!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255))
+ fprintf(stderr, "erresc: bad rgb color (%d,%d,%d)\n",
+ r, g, b);
+ else
+ idx = TRUECOLOR(r, g, b);
+ break;
+ case 5: /* indexed colour */
+ if (*npar + 2 >= l) {
+ fprintf(stderr,
+ "erresc(38): Incorrect number of parameters (%d)\n",
+ *npar);
+ break;
+ }
+ *npar += 2;
+ if(!BETWEEN(attr[*npar], 0, 255))
+ fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]);
+ else
+ idx = attr[*npar];
+ break;
+ case 0: /* implemented defined (only foreground) */
+ case 1: /* transparent */
+ case 3: /* direct colour in CMY space */
+ case 4: /* direct colour in CMYK space */
+ default:
+ fprintf(stderr,
+ "erresc(38): gfx attr %d unknown\n", attr[*npar]);
+ }
+
+ return idx;
+}
+
void
tsetattr(int *attr, int l) {
int i;
+ ulong idx;
for(i = 0; i < l; i++) {
switch(attr[i]) {
term.c.attr.mode &= ~ATTR_REVERSE;
break;
case 38:
- if(i + 2 < l && attr[i + 1] == 5) {
- i += 2;
- if(BETWEEN(attr[i], 0, 255)) {
- term.c.attr.fg = attr[i];
- } else {
- fprintf(stderr,
- "erresc: bad fgcolor %d\n",
- attr[i]);
- }
- } else {
- fprintf(stderr,
- "erresc(38): gfx attr %d unknown\n",
- attr[i]);
- }
+ if ((idx = tdefcolor(attr, &i, l)) >= 0)
+ term.c.attr.fg = idx;
break;
case 39:
term.c.attr.fg = defaultfg;
break;
case 48:
- if(i + 2 < l && attr[i + 1] == 5) {
- i += 2;
- if(BETWEEN(attr[i], 0, 255)) {
- term.c.attr.bg = attr[i];
- } else {
- fprintf(stderr,
- "erresc: bad bgcolor %d\n",
- attr[i]);
- }
- } else {
- fprintf(stderr,
- "erresc(48): gfx attr %d unknown\n",
- attr[i]);
- }
+ if ((idx = tdefcolor(attr, &i, l)) >= 0)
+ term.c.attr.bg = idx;
break;
case 49:
term.c.attr.bg = defaultbg;
tclearregion(0, 0, term.col-1,
term.row-1);
}
- if(set ^ alt) /* set is always 1 or 0 */
+ if(set ^ alt) /* set is always 1 or 0 */
tswapscreen();
if(*args != 1049)
break;
for(; len > 0; buf++, len--) {
char c = *buf;
- if(c == '\033') { /* escape */
+ if(c == '\033') { /* escape */
tputc("^", 1);
tputc("[", 1);
- } else if(c < '\x20') { /* control code */
+ } else if(c < '\x20') { /* control code */
if(c != '\n' && c != '\r' && c != '\t') {
c |= '\x40';
tputc("^", 1);
*/
if(control) {
switch(ascii) {
- case '\t': /* HT */
+ case '\t': /* HT */
tputtab(1);
return;
- case '\b': /* BS */
+ case '\b': /* BS */
tmoveto(term.c.x-1, term.c.y);
return;
- case '\r': /* CR */
+ case '\r': /* CR */
tmoveto(0, term.c.y);
return;
- case '\f': /* LF */
- case '\v': /* VT */
- case '\n': /* LF */
+ 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 */
+ case '\a': /* BEL */
if(!(xw.state & WIN_FOCUSED))
xseturgency(1);
return;
- case '\033': /* ESC */
+ case '\033': /* ESC */
csireset();
term.esc = ESC_START;
return;
- case '\016': /* SO */
- case '\017': /* SI */
+ case '\016': /* SO */
+ case '\017': /* SI */
/*
* Different charsets are hard to handle. Applications
* should use the right alt charset escapes for the
* rest is incompatible history st should not support.
*/
return;
- case '\032': /* SUB */
- case '\030': /* CAN */
+ 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) */
+ case '\005': /* ENQ (IGNORED) */
+ case '\000': /* NUL (IGNORED) */
+ case '\021': /* XON (IGNORED) */
+ case '\023': /* XOFF (IGNORED) */
+ case 0177: /* DEL (IGNORED) */
return;
}
} else if(term.esc & ESC_START) {
treset();
term.esc = 0;
xresettitle();
+ xloadcols();
break;
case '=': /* DECPAM -- Application keypad */
term.mode |= MODE_APPKEYPAD;
xloadcols(void) {
int i, r, g, b;
XRenderColor color = { .alpha = 0xffff };
+ static bool loaded;
+ Colour *cp;
+
+ if(loaded) {
+ for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp)
+ XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+ }
/* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
for(i = 0; i < LEN(colorname); i++) {
die("Could not allocate color %d\n", i);
}
}
+ loaded = true;
}
int
void
xunloadfonts(void) {
- int i, ip;
+ int i;
- /*
- * Free the loaded fonts in the font cache. This is done backwards
- * from the frccur.
- */
- for(i = 0, ip = frccur; i < frclen; i++, ip--) {
- if(ip < 0)
- ip = LEN(frc) - 1;
- XftFontClose(xw.dpy, frc[ip].font);
+ /* Free the loaded fonts in the font cache. */
+ for(i = 0; i < frclen; i++) {
+ XftFontClose(xw.dpy, frc[i].font);
}
- frccur = -1;
frclen = 0;
xunloadfont(&dc.font);
xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
width = charlen * xw.cw, xp, i;
- int frp, frcflags;
+ int frcflags;
int u8fl, u8fblen, u8cblen, doesexist;
char *u8c, *u8fs;
long u8char;
FcPattern *fcpattern, *fontpattern;
FcFontSet *fcsets[] = { NULL };
FcCharSet *fccharset;
- Colour *fg, *bg, *temp, revfg, revbg;
+ Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg;
XRenderColor colfg, colbg;
Rectangle r;
if(base.fg == defaultfg)
base.fg = defaultunderline;
}
- fg = &dc.col[base.fg];
- bg = &dc.col[base.bg];
+ if(IS_TRUECOL(base.fg)) {
+ colfg.red = TRUERED(base.fg);
+ colfg.green = TRUEGREEN(base.fg);
+ colfg.blue = TRUEBLUE(base.fg);
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg);
+ fg = &truefg;
+ } else {
+ fg = &dc.col[base.fg];
+ }
+
+ if(IS_TRUECOL(base.bg)) {
+ colbg.green = TRUEGREEN(base.bg);
+ colbg.red = TRUERED(base.bg);
+ colbg.blue = TRUEBLUE(base.bg);
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg);
+ bg = &truebg;
+ } else {
+ bg = &dc.col[base.bg];
+ }
+
+
if(base.mode & ATTR_BOLD) {
if(BETWEEN(base.fg, 0, 7)) {
}
/*
* Those ranges will not be brightened:
- * 8 - 15 – bright system colors
- * 196 - 231 – highest 256 color cube
- * 252 - 255 – brightest colors in greyscale
+ * 8 - 15 – bright system colors
+ * 196 - 231 – highest 256 color cube
+ * 252 - 255 – brightest colors in greyscale
*/
font = &dc.bfont;
frcflags = FRC_BOLD;
s += u8cblen;
bytelen -= u8cblen;
- doesexist = XftCharIndex(xw.dpy, font->match, u8char);
+ doesexist = XftCharExists(xw.dpy, font->match, u8char);
if(!doesexist || bytelen <= 0) {
if(bytelen <= 0) {
if(doesexist) {
if(doesexist)
break;
- frp = frccur;
/* Search the font cache. */
- for(i = 0; i < frclen; i++, frp--) {
- if(frp <= 0)
- frp = LEN(frc) - 1;
-
- if(frc[frp].c == u8char
- && frc[frp].flags == frcflags) {
+ for(i = 0; i < frclen; i++) {
+ if(XftCharExists(xw.dpy, frc[i].font, u8char)
+ && frc[i].flags == frcflags) {
break;
}
}
/*
* Overwrite or create the new cache entry.
*/
- frccur++;
- frclen++;
- if(frccur >= LEN(frc))
- frccur = 0;
- if(frclen > LEN(frc)) {
- frclen = LEN(frc);
- XftFontClose(xw.dpy, frc[frccur].font);
+ if(frclen >= LEN(frc)) {
+ frclen = LEN(frc) - 1;
+ XftFontClose(xw.dpy, frc[frclen].font);
}
- frc[frccur].font = XftFontOpenPattern(xw.dpy,
+ frc[frclen].font = XftFontOpenPattern(xw.dpy,
fontpattern);
- frc[frccur].c = u8char;
- frc[frccur].flags = frcflags;
+ frc[frclen].flags = frcflags;
+
+ i = frclen;
+ frclen++;
FcPatternDestroy(fcpattern);
FcCharSetDestroy(fccharset);
-
- frp = frccur;
}
- XftDrawStringUtf8(xw.draw, fg, frc[frp].font,
- xp, winy + frc[frp].font->ascent,
+ XftDrawStringUtf8(xw.draw, fg, frc[i].font,
+ xp, winy + frc[i].font->ascent,
(FcChar8 *)u8c, u8cblen);
xp += font->width;
void
run(void) {
XEvent ev;
+ int w = xw.w, h = xw.h;
fd_set rfd;
int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
struct timeval drawtimeout, *tv = NULL, now, last, lastblink;
+ /* Waiting for window mapping */
+ while(1) {
+ XNextEvent(xw.dpy, &ev);
+ if(ev.type == ConfigureNotify) {
+ w = ev.xconfigure.width;
+ h = ev.xconfigure.height;
+ } else if(ev.type == MapNotify) {
+ break;
+ }
+ }
+
+ if(!xw.isfixed)
+ cresize(w, h);
+ else
+ cresize(xw.fw, xw.fh);
+ ttynew();
+
gettimeofday(&lastblink, NULL);
gettimeofday(&last, NULL);
XSetLocaleModifiers("");
tnew(80, 24);
xinit();
- ttynew();
selinit();
- if(xw.isfixed)
- cresize(xw.h, xw.w);
run();
return 0;