#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+#define ISDELIM(u) (BETWEEN(u, 0, 127) && strchr(worddelimiters, u) != NULL)
#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)
enum window_state {
WIN_VISIBLE = 1,
- WIN_REDRAW = 2,
- WIN_FOCUSED = 4
+ WIN_FOCUSED = 2
};
enum selection_type {
typedef XftColor Color;
typedef struct {
- char c[UTF_SIZ]; /* character code */
+ long u; /* character code */
ushort mode; /* attribute flags */
- uint32_t fg; /* foreground */
- uint32_t bg; /* background */
+ ushort fg; /* foreground */
+ ushort bg; /* background */
} Glyph;
typedef Glyph *Line;
static void redraw(void);
static void drawregion(int, int, int, int);
static void execsh(void);
+static void stty(void);
static void sigchld(int);
static void run(void);
static void tnew(int, int);
static void tnewline(int);
static void tputtab(int);
-static void tputc(char *, int);
+static void tputc(long);
static void treset(void);
static void tresize(int, int);
static void tscrollup(int, int);
static void tscrolldown(int, int);
static void tsetattr(int *, int);
-static void tsetchar(char *, Glyph *, int, int);
+static void tsetchar(long, Glyph *, int, int);
static void tsetscroll(int, int);
static void tswapscreen(void);
static void tsetdirt(int, int);
static void tsetdirtattr(int);
static void tsetmode(bool, bool, int *, int);
static void tfulldirt(void);
-static void techo(char *, int);
+static void techo(long);
static void tcontrolcode(uchar );
static void tdectest(char );
static int32_t tdefcolor(int *, int *, int);
static inline ushort sixd_to_16bit(int);
static void xdraws(char *, Glyph, int, int, int, int);
+static void xdrawglyph(Glyph, int, int);
static void xhints(void);
static void xclear(int, int, int, int);
static void xdrawcursor(void);
static void xresettitle(void);
static void xsetpointermotion(int);
static void xseturgency(int);
-static void xsetsel(char *);
+static void xsetsel(char *, Time);
static void xtermclear(int, int, int, int);
static void xunloadfont(Font *);
static void xunloadfonts(void);
static void selnormalize(void);
static inline bool selected(int, int);
static char *getsel(void);
-static void selcopy(void);
+static void selcopy(Time);
static void selscroll(int, int);
static void selsnap(int, int *, int *, int);
static int x2col(int);
static size_t utf8decode(char *, long *, size_t);
static long utf8decodebyte(char, size_t *);
-static size_t utf8encode(long, char *, size_t);
+static size_t utf8encode(long, char *);
static char utf8encodebyte(long, size_t);
-static size_t utf8len(char *);
static size_t utf8validate(long *, size_t);
static ssize_t xwrite(int, const char *, size_t);
static char *opt_embed = NULL;
static char *opt_class = NULL;
static char *opt_font = NULL;
+static char *opt_line = NULL;
static int oldbutton = 3; /* button event on startup: 3 = release */
static char *usedfont = NULL;
}
size_t
-utf8encode(long u, char *c, size_t clen) {
+utf8encode(long u, char *c) {
size_t len, i;
len = utf8validate(&u, 0);
- if(clen < len)
+ if(len > UTF_SIZ)
return 0;
for(i = len - 1; i != 0; --i) {
c[i] = utf8encodebyte(u, 0);
return utfbyte[i] | (u & ~utfmask[i]);
}
-size_t
-utf8len(char *c) {
- return utf8decode(c, &(long){0}, UTF_SIZ);
-}
-
size_t
utf8validate(long *u, size_t i) {
if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
return LIMIT(y, 0, term.row-1);
}
-int tlinelen(int y) {
+int
+tlinelen(int y) {
int i = term.col;
if(term.line[y][i - 1].mode & ATTR_WRAP)
return i;
- while(i > 0 && term.line[y][i - 1].c[0] == ' ')
+ while(i > 0 && term.line[y][i - 1].u == ' ')
--i;
return i;
* beginning of a line.
*/
prevgp = &term.line[*y][*x];
- prevdelim = strchr(worddelimiters, prevgp->c[0]) != NULL;
+ prevdelim = ISDELIM(prevgp->u);
for(;;) {
newx = *x + direction;
newy = *y;
break;
gp = &term.line[newy][newx];
- delim = strchr(worddelimiters, gp->c[0]) != NULL;
+ delim = ISDELIM(gp->u);
if(!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
- || (delim && gp->c[0] != prevgp->c[0])))
+ || (delim && gp->u != prevgp->u)))
break;
*x = newx;
}
if(!IS_SET(MODE_MOUSEX10)) {
- button += (state & ShiftMask ? 4 : 0)
- + (state & Mod4Mask ? 8 : 0)
- + (state & ControlMask ? 16 : 0);
+ button += ((state & ShiftMask ) ? 4 : 0)
+ + ((state & Mod4Mask ) ? 8 : 0)
+ + ((state & ControlMask) ? 16 : 0);
}
len = 0;
char *
getsel(void) {
char *str, *ptr;
- int y, bufsize, size, lastx, linelen;
+ int y, bufsize, lastx, linelen;
Glyph *gp, *last;
if(sel.ob.x == -1)
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
}
last = &term.line[y][MIN(lastx, linelen-1)];
- while(last >= gp && last->c[0] == ' ')
+ while(last >= gp && last->u == ' ')
--last;
for( ; gp <= last; ++gp) {
if(gp->mode & ATTR_WDUMMY)
continue;
- size = utf8len(gp->c);
- memcpy(ptr, gp->c, size);
- ptr += size;
+ ptr += utf8encode(gp->u, ptr);
}
/*
}
void
-selcopy(void) {
- xsetsel(getsel());
+selcopy(Time t) {
+ xsetsel(getsel(), t);
}
void
XSelectionEvent *xsev;
ofs = 0;
- xsev = (XSelectionEvent *)e;
+ xsev = &e->xselection;
if (xsev->property == None)
return;
do {
xev.selection = xsre->selection;
xev.target = xsre->target;
xev.time = xsre->time;
+ if (xsre->property == None)
+ xsre->property = xsre->target;
+
/* reject */
xev.property = None;
}
void
-xsetsel(char *str) {
+xsetsel(char *str, Time t) {
free(sel.primary);
sel.primary = str;
- XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, CurrentTime);
+ XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
+ if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
+ selclear(0);
}
void
selclear(NULL);
} else {
getbuttoninfo(e);
- selcopy();
+ selcopy(e->xbutton.time);
}
sel.mode = 0;
tsetdirt(sel.nb.y, sel.ne.y);
exit(EXIT_SUCCESS);
}
+
+void
+stty(void)
+{
+ char cmd[_POSIX_ARG_MAX], **p, *q, *s;
+ size_t n, siz;
+
+ if((n = strlen(stty_args)) > sizeof(cmd)-1)
+ die("incorrect stty parameters\n");
+ memcpy(cmd, stty_args, n);
+ q = cmd + n;
+ siz = sizeof(cmd) - n;
+ for(p = opt_cmd; p && (s = *p); ++p) {
+ if((n = strlen(s)) > siz-1)
+ die("stty parameter length too long\n");
+ *q++ = ' ';
+ q = memcpy(q, s, n);
+ q += n;
+ siz-= n + 1;
+ }
+ *q = '\0';
+ if (system(cmd) != 0)
+ perror("Couldn't call stty");
+}
+
void
ttynew(void) {
int m, s;
struct winsize w = {term.row, term.col, 0, 0};
+ if(opt_io) {
+ term.mode |= MODE_PRINT;
+ iofd = (!strcmp(opt_io, "-")) ?
+ STDOUT_FILENO :
+ open(opt_io, O_WRONLY | O_CREAT, 0666);
+ if(iofd < 0) {
+ fprintf(stderr, "Error opening %s:%s\n",
+ opt_io, strerror(errno));
+ }
+ }
+
+ if (opt_line) {
+ if((cmdfd = open(opt_line, O_RDWR)) < 0)
+ die("open line failed: %s\n", strerror(errno));
+ close(STDIN_FILENO);
+ dup(cmdfd);
+ stty();
+ return;
+ }
+
/* seems to work fine on linux, openbsd and freebsd */
if(openpty(&m, &s, NULL, NULL, &w) < 0)
die("openpty failed: %s\n", strerror(errno));
die("fork failed\n");
break;
case 0:
+ close(iofd);
setsid(); /* create a new process group */
dup2(s, STDIN_FILENO);
dup2(s, STDOUT_FILENO);
close(s);
cmdfd = m;
signal(SIGCHLD, sigchld);
- if(opt_io) {
- term.mode |= MODE_PRINT;
- iofd = (!strcmp(opt_io, "-")) ?
- STDOUT_FILENO :
- open(opt_io, O_WRONLY | O_CREAT, 0666);
- if(iofd < 0) {
- fprintf(stderr, "Error opening %s:%s\n",
- opt_io, strerror(errno));
- }
- }
break;
}
}
static char buf[BUFSIZ];
static int buflen = 0;
char *ptr;
- char s[UTF_SIZ];
int charsize; /* size of utf8 char in bytes */
long unicodep;
int ret;
buflen += ret;
ptr = buf;
while((charsize = utf8decode(ptr, &unicodep, buflen))) {
- utf8encode(unicodep, s, UTF_SIZ);
- tputc(s, charsize);
+ tputc(unicodep);
ptr += charsize;
buflen -= charsize;
}
void
ttysend(char *s, size_t n) {
+ int len;
+ long u;
+
ttywrite(s, n);
if(IS_SET(MODE_ECHO))
- techo(s, n);
+ while((len = utf8decode(s, &u, n)) > 0) {
+ techo(u);
+ n -= len;
+ s += len;
+ }
}
void
term.top = 0;
term.bot = term.row - 1;
term.mode = MODE_WRAP;
- memset(term.trantbl, sizeof(term.trantbl), CS_USA);
+ memset(term.trantbl, CS_USA, sizeof(term.trantbl));
term.charset = 0;
for(i = 0; i < 2; i++) {
}
void
-tsetchar(char *c, Glyph *attr, int x, int y) {
+tsetchar(long u, Glyph *attr, int x, int y) {
static char *vt100_0[62] = { /* 0x41 - 0x7e */
"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
/*
* The table is proudly stolen from rxvt.
*/
- if(term.trantbl[term.charset] == CS_GRAPHIC0) {
- if(BETWEEN(c[0], 0x41, 0x7e) && vt100_0[c[0] - 0x41]) {
- c = vt100_0[c[0] - 0x41];
- }
- }
+ if(term.trantbl[term.charset] == CS_GRAPHIC0 &&
+ BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
+ utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ);
if(term.line[y][x].mode & ATTR_WIDE) {
if(x+1 < term.col) {
- term.line[y][x+1].c[0] = ' ';
+ term.line[y][x+1].u = ' ';
term.line[y][x+1].mode &= ~ATTR_WDUMMY;
}
} else if(term.line[y][x].mode & ATTR_WDUMMY) {
- term.line[y][x-1].c[0] = ' ';
+ term.line[y][x-1].u = ' ';
term.line[y][x-1].mode &= ~ATTR_WIDE;
}
term.dirty[y] = 1;
term.line[y][x] = *attr;
- memcpy(term.line[y][x].c, c, UTF_SIZ);
+ term.line[y][x].u = u;
}
void
gp->fg = term.c.attr.fg;
gp->bg = term.c.attr.bg;
gp->mode = 0;
- memcpy(gp->c, " ", 2);
+ gp->u = ' ';
}
}
}
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",
+ fprintf(stderr, "erresc: bad rgb color (%u,%u,%u)\n",
r, g, b);
else
idx = TRUECOLOR(r, g, b);
term.esc &= ~(ESC_STR_END|ESC_STR);
strparse();
- narg = strescseq.narg;
- par = atoi(strescseq.args[0]);
+ par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0;
switch(strescseq.type) {
case ']': /* OSC -- Operating System Command */
void
tdumpline(int n) {
+ char buf[UTF_SIZ];
Glyph *bp, *end;
bp = &term.line[n][0];
end = &bp[MIN(tlinelen(n), term.col) - 1];
- if(bp != end || bp->c[0] != ' ') {
+ if(bp != end || bp->u != ' ') {
for( ;bp <= end; ++bp)
- tprinter(bp->c, utf8len(bp->c));
+ tprinter(buf, utf8encode(bp->u, buf));
}
tprinter("\n", 1);
}
for(--x; x > 0 && !term.tabs[x]; --x)
/* nothing */ ;
}
- tmoveto(x, term.c.y);
+ term.c.x = LIMIT(x, 0, term.col-1);
}
void
-techo(char *buf, int len) {
- for(; len > 0; buf++, len--) {
- char c = *buf;
-
- if(ISCONTROL((uchar) c)) { /* control code */
- if(c & 0x80) {
- c &= 0x7f;
- tputc("^", 1);
- tputc("[", 1);
- } else if(c != '\n' && c != '\r' && c != '\t') {
- c ^= 0x40;
- tputc("^", 1);
- }
- tputc(&c, 1);
- } else {
- break;
+techo(long u) {
+ if(ISCONTROL(u)) { /* control code */
+ if(u & 0x80) {
+ u &= 0x7f;
+ tputc('^');
+ tputc('[');
+ } else if(u != '\n' && u != '\r' && u != '\t') {
+ u ^= 0x40;
+ tputc('^');
}
}
- if(len)
- tputc(buf, len);
+ tputc(u);
}
void
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);
+ tsetchar('E', &term.c.attr, x, y);
}
}
}
strreset();
strescseq.type = c;
term.esc |= ESC_STR;
- return;
}
void
tcontrolcode(uchar ascii) {
- static char question[UTF_SIZ] = "?";
-
switch(ascii) {
case '\t': /* HT */
tputtab(1);
term.charset = 1 - (ascii - '\016');
return;
case '\032': /* SUB */
- tsetchar(question, &term.c.attr, term.c.x, term.c.y);
+ tsetchar('?', &term.c.attr, term.c.x, term.c.y);
case '\030': /* CAN */
csireset();
break;
}
/* only CAN, SUB, \a and C1 chars interrupt a sequence */
term.esc &= ~(ESC_STR_END|ESC_STR);
- return;
}
/*
}
void
-tputc(char *c, int len) {
- uchar ascii;
+tputc(long u) {
+ char c[UTF_SIZ];
bool control;
- long unicodep;
- int width;
+ int width, len;
Glyph *gp;
- if(len == 1) {
+ len = utf8encode(u, c);
+ if((width = wcwidth(u)) == -1) {
+ memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
width = 1;
- unicodep = ascii = *c;
- } else {
- utf8decode(c, &unicodep, UTF_SIZ);
- if ((width = wcwidth(unicodep)) == -1) {
- c = "\357\277\275"; /* UTF_INVALID */
- width = 1;
- }
- ascii = unicodep;
}
if(IS_SET(MODE_PRINT))
tprinter(c, len);
- control = ISCONTROL(unicodep);
+ control = ISCONTROL(u);
/*
* STR sequence must be checked before anything else
* character.
*/
if(term.esc & ESC_STR) {
- if(len == 1 &&
- (ascii == '\a' || ascii == 030 ||
- ascii == 032 || ascii == 033 ||
- ISCONTROLC1(unicodep))) {
+ if(u == '\a' || u == 030 || u == 032 || u == 033 ||
+ ISCONTROLC1(u)) {
term.esc &= ~(ESC_START|ESC_STR);
term.esc |= ESC_STR_END;
} else if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
* they must not cause conflicts with sequences.
*/
if(control) {
- tcontrolcode(ascii);
+ tcontrolcode(u);
/*
* control codes are not shown ever
*/
return;
} else if(term.esc & ESC_START) {
if(term.esc & ESC_CSI) {
- csiescseq.buf[csiescseq.len++] = ascii;
- if(BETWEEN(ascii, 0x40, 0x7E)
+ csiescseq.buf[csiescseq.len++] = u;
+ if(BETWEEN(u, 0x40, 0x7E)
|| csiescseq.len >= \
sizeof(csiescseq.buf)-1) {
term.esc = 0;
}
return;
} else if(term.esc & ESC_ALTCHARSET) {
- tdeftran(ascii);
+ tdeftran(u);
} else if(term.esc & ESC_TEST) {
- tdectest(ascii);
+ tdectest(u);
} else {
- if (!eschandle(ascii))
+ if (!eschandle(u))
return;
/* sequence already finished */
}
gp = &term.line[term.c.y][term.c.x];
}
- tsetchar(c, &term.c.attr, term.c.x, term.c.y);
+ tsetchar(u, &term.c.attr, term.c.x, term.c.y);
if(width == 2) {
gp->mode |= ATTR_WIDE;
if(term.c.x+1 < term.col) {
- gp[1].c[0] = '\0';
+ gp[1].u = '\0';
gp[1].mode = ATTR_WDUMMY;
}
}
free(term.line[i]);
free(term.alt[i]);
}
- memmove(term.line, term.line + i, row * sizeof(Line));
- memmove(term.alt, term.alt + i, row * sizeof(Line));
+ /* ensure that both src and dst are not NULL */
+ if (i > 0) {
+ memmove(term.line, term.line + i, row * sizeof(Line));
+ memmove(term.alt, term.alt + i, row * sizeof(Line));
+ }
for(i += row; i < term.row; i++) {
free(term.line[i]);
free(term.alt[i]);
return x == 0 ? 0 : 0x3737 + 0x2828 * x;
}
+bool
+xloadcolor(int i, const char *name, Color *ncolor) {
+ XRenderColor color = { .alpha = 0xffff };
+
+ if(!name) {
+ if(BETWEEN(i, 16, 255)) { /* 256 color */
+ if(i < 6*6*6+16) { /* same colors as xterm */
+ 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 );
+ } else { /* greyscale */
+ color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16));
+ color.green = color.blue = color.red;
+ }
+ return XftColorAllocValue(xw.dpy, xw.vis,
+ xw.cmap, &color, ncolor);
+ } else
+ name = colorname[i];
+ }
+ return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
+}
+
void
xloadcols(void) {
int i;
- XRenderColor color = { .alpha = 0xffff };
static bool loaded;
Color *cp;
if(loaded) {
- for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp)
+ for (cp = dc.col; cp < &dc.col[LEN(dc.col)]; ++cp)
XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
}
- /* load colors [0-15] and [256-LEN(colorname)] (config.h) */
- for(i = 0; i < LEN(colorname); i++) {
- if(!colorname[i])
- continue;
- if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.col[i])) {
- die("Could not allocate color '%s'\n", colorname[i]);
+ for(i = 0; i < LEN(dc.col); i++)
+ if(!xloadcolor(i, NULL, &dc.col[i])) {
+ if(colorname[i])
+ die("Could not allocate color '%s'\n", colorname[i]);
+ else
+ die("Could not allocate color %d\n", i);
}
- }
-
- /* load colors [16-231] ; same colors 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);
- }
-
- /* load colors [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 };
Color ncolor;
- if(!BETWEEN(x, 0, LEN(colorname)))
+ if(!BETWEEN(x, 0, LEN(dc.col)))
return 1;
- if(!name) {
- if(BETWEEN(x, 16, 16 + 215)) { /* 256 color */
- 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, &ncolor)) {
- return 1;
- }
- XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
- dc.col[x] = ncolor;
- return 0;
- } else if(BETWEEN(x, 16 + 216, 255)) { /* greyscale */
- color.red = color.green = color.blue = \
- 0x0808 + 0x0a0a * (x - (16 + 216));
- if(!XftColorAllocValue(xw.dpy, xw.vis,
- xw.cmap, &color, &ncolor)) {
- return 1;
- }
-
- XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
- dc.col[x] = ncolor;
- return 0;
- } else { /* system colors */
- name = colorname[x];
- }
- }
- if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &ncolor))
+ if(!xloadcolor(x, name, &ncolor))
return 1;
XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
XftDrawSetClip(xw.draw, 0);
}
+void
+xdrawglyph(Glyph g, int x, int y) {
+ static char buf[UTF_SIZ];
+ size_t len = utf8encode(g.u, buf);
+ int width = g.mode & ATTR_WIDE ? 2 : 1;
+
+ xdraws(buf, g, x, y, width, len);
+}
+
void
xdrawcursor(void) {
static int oldx = 0, oldy = 0;
- int sl, width, curx;
- Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs};
+ int curx;
+ Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs};
LIMIT(oldx, 0, term.col-1);
LIMIT(oldy, 0, term.row-1);
if(term.line[term.c.y][curx].mode & ATTR_WDUMMY)
curx--;
- memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ);
+ g.u = term.line[term.c.y][term.c.x].u;
/* remove the old cursor */
- sl = utf8len(term.line[oldy][oldx].c);
- width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1;
- xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx,
- oldy, width, sl);
+ xdrawglyph(term.line[oldy][oldx], oldx, oldy);
if(IS_SET(MODE_HIDE))
return;
g.bg = defaultfg;
}
- sl = utf8len(g.c);
- width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\
- ? 2 : 1;
- xdraws(g.c, g, term.c.x, term.c.y, width, sl);
+ g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
+ xdrawglyph(g, term.c.x, term.c.y);
break;
case 3: /* Blinking Underline */
case 4: /* Steady Underline */
void
drawregion(int x1, int y1, int x2, int y2) {
- int ic, ib, x, y, ox, sl;
+ int ic, ib, x, y, ox;
Glyph base, new;
char buf[DRAW_BUF_SIZ];
bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
- long unicodep;
if(!(xw.state & WIN_VISIBLE))
return;
base = new;
}
- sl = utf8decode(new.c, &unicodep, UTF_SIZ);
- memcpy(buf+ib, new.c, sl);
- ib += sl;
+ ib += utf8encode(new.u, buf+ib);
ic += (new.mode & ATTR_WIDE)? 2 : 1;
}
if(ib > 0)
void
expose(XEvent *ev) {
- XExposeEvent *e = &ev->xexpose;
-
- if(xw.state & WIN_REDRAW) {
- if(!e->count)
- xw.state &= ~WIN_REDRAW;
- }
redraw();
}
visibility(XEvent *ev) {
XVisibilityEvent *e = &ev->xvisibility;
- if(e->state == VisibilityFullyObscured) {
- xw.state &= ~WIN_VISIBLE;
- } else if(!(xw.state & WIN_VISIBLE)) {
- /* need a full redraw for next Expose, not just a buf copy */
- xw.state |= WIN_VISIBLE | WIN_REDRAW;
- }
+ MODBIT(xw.state, e->state != VisibilityFullyObscured, WIN_VISIBLE);
}
void
if(IS_SET(MODE_8BIT)) {
if(*buf < 0177) {
c = *buf | 0x80;
- len = utf8encode(c, buf, UTF_SIZ);
+ len = utf8encode(c, buf);
}
} else {
buf[1] = buf[0];
clock_gettime(CLOCK_MONOTONIC, &now);
drawtimeout.tv_sec = 0;
- drawtimeout.tv_nsec = (1000/xfps) * 1E6;
+ drawtimeout.tv_nsec = (1000 * 1E6)/ xfps;
tv = &drawtimeout;
dodraw = 0;
dodraw = 1;
}
deltatime = TIMEDIFF(now, last);
- if(deltatime > (xev? (1000/xfps) : (1000/actionfps))
- || deltatime < 0) {
+ if(deltatime > 1000 / (xev ? xfps : actionfps)) {
dodraw = 1;
last = now;
}
void
usage(void) {
- die("%s " VERSION " (c) 2010-2015 st engineers\n" \
+ die("%s " VERSION " (c) 2010-2015 st engineers\n"
"usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
- " [-i] [-t title] [-w windowid] [-e command ...]\n", argv0);
+ " [-i] [-t title] [-w windowid] [-e command ...] [command ...]\n"
+ " st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
+ " [-i] [-t title] [-w windowid] [-l line] [stty_args ...]\n",
+ argv0);
}
int
opt_class = EARGF(usage());
break;
case 'e':
- /* eat all remaining arguments */
- if(argc > 1) {
- opt_cmd = &argv[1];
- if(argv[1] != NULL && opt_title == NULL)
- opt_title = basename(xstrdup(argv[1]));
- }
+ if(argc > 1)
+ --argc, ++argv;
goto run;
case 'f':
opt_font = EARGF(usage());
case 'o':
opt_io = EARGF(usage());
break;
+ case 'l':
+ opt_line = EARGF(usage());
+ break;
case 't':
opt_title = EARGF(usage());
break;
} ARGEND;
run:
+ if(argc > 0) {
+ /* eat all remaining arguments */
+ opt_cmd = argv;
+ if(!opt_title && !opt_line)
+ opt_title = basename(xstrdup(argv[0]));
+ }
setlocale(LC_CTYPE, "");
XSetLocaleModifiers("");
tnew(MAX(cols, 1), MAX(rows, 1));