#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)
-#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
-#define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
+#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6)
#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
#define VT102ID "\033[?6c"
enum glyph_attribute {
- ATTR_NULL = 0,
- ATTR_REVERSE = 1,
- ATTR_UNDERLINE = 2,
- ATTR_BOLD = 4,
- ATTR_ITALIC = 8,
+ ATTR_NULL = 0,
+ ATTR_BOLD = 1,
+ ATTR_FAINT = 2,
+ ATTR_ITALIC = 4,
+ ATTR_UNDERLINE = 8,
ATTR_BLINK = 16,
- ATTR_WRAP = 32,
- ATTR_WIDE = 64,
- ATTR_WDUMMY = 128,
+ ATTR_FASTBLINK = 32,
+ ATTR_REVERSE = 64,
+ ATTR_INVISIBLE = 128,
+ ATTR_STRUCK = 256,
+ ATTR_WRAP = 512,
+ ATTR_WIDE = 1024,
+ ATTR_WDUMMY = 2048,
};
enum cursor_movement {
typedef unsigned short ushort;
typedef XftDraw *Draw;
-typedef XftColor Colour;
-typedef Colormap Colourmap;
+typedef XftColor Color;
typedef struct {
char c[UTF_SIZ]; /* character code */
/* Purely graphic info */
typedef struct {
Display *dpy;
- Colourmap cmap;
+ Colormap cmap;
Window win;
Drawable buf;
Atom xembed, wmdeletewin, netwmname, netwmpid;
char *clip;
Atom xtarget;
bool alt;
- struct timeval tclick1;
- struct timeval tclick2;
+ struct timespec tclick1;
+ struct timespec tclick2;
} Selection;
typedef union {
/* Drawing Context */
typedef struct {
- Colour col[MAX(LEN(colorname), 256)];
+ Color col[MAX(LEN(colorname), 256)];
Font font, bfont, ifont, ibfont;
GC gc;
} DC;
static void selrequest(XEvent *);
static void selinit(void);
-static void selsort(void);
+static void selnormalize(void);
static inline bool selected(int, int);
static char *getsel(void);
static void selcopy(void);
return LIMIT(y, 0, term.row-1);
}
+static int tlinelen(int y) {
+ int i = term.col;
+
+ while (i > 0 && term.line[y][i - 1].c[0] == ' ')
+ --i;
+
+ return i;
+}
+
static void
-selsort(void) {
- if(sel.ob.y == sel.oe.y) {
+selnormalize(void) {
+ int i;
+
+ if(sel.ob.y == sel.oe.y || sel.type == SEL_RECTANGULAR) {
sel.nb.x = MIN(sel.ob.x, sel.oe.x);
sel.ne.x = MAX(sel.ob.x, sel.oe.x);
} else {
}
sel.nb.y = MIN(sel.ob.y, sel.oe.y);
sel.ne.y = MAX(sel.ob.y, sel.oe.y);
+
+ /* expand selection over line breaks */
+ if (sel.type == SEL_RECTANGULAR)
+ return;
+ i = tlinelen(sel.nb.y);
+ if (i < sel.nb.x)
+ sel.nb.x = i;
+ if (tlinelen(sel.ne.y) <= sel.ne.x)
+ sel.ne.x = term.col - 1;
}
static inline bool
void
selsnap(int mode, int *x, int *y, int direction) {
- int i;
+ int newx, newy, xt, yt;
+ Glyph *gp;
switch(mode) {
case SNAP_WORD:
* beginning of a line.
*/
for(;;) {
- if(direction < 0 && *x <= 0) {
- if(*y > 0 && term.line[*y - 1][term.col-1].mode
- & ATTR_WRAP) {
- *y -= 1;
- *x = term.col-1;
- } else {
+ newx = *x + direction;
+ newy = *y;
+ if(!BETWEEN(newx, 0, term.col - 1)) {
+ newy += direction;
+ newx = (newx + term.col) % term.col;
+ if (!BETWEEN(newy, 0, term.row - 1))
break;
- }
- }
- if(direction > 0 && *x >= term.col-1) {
- if(*y < term.row-1 && term.line[*y][*x].mode
- & ATTR_WRAP) {
- *y += 1;
- *x = 0;
- } else {
+
+ if(direction > 0)
+ yt = *y, xt = *x;
+ else
+ yt = newy, xt = newx;
+ if(!(term.line[yt][xt].mode & ATTR_WRAP))
break;
- }
}
- if(term.line[*y][*x+direction].mode & ATTR_WDUMMY) {
- *x += direction;
- continue;
- }
+ if (newx >= tlinelen(newy))
+ break;
- if(strchr(worddelimiters,
- term.line[*y][*x+direction].c[0])) {
+ gp = &term.line[newy][newx];
+ if (!(gp->mode & ATTR_WDUMMY) && strchr(worddelimiters, gp->c[0]))
break;
- }
- *x += direction;
+ *x = newx;
+ *y = newy;
}
break;
case SNAP_LINE:
}
}
break;
- default:
- /*
- * Select the whole line when the end of line is reached.
- */
- if(direction > 0) {
- i = term.col;
- while(--i > 0 && term.line[*y][i].c[0] == ' ')
- /* nothing */;
- if(i > 0 && i < *x)
- *x = term.col - 1;
- }
- break;
}
}
selsnap(sel.snap, &sel.oe.x, &sel.oe.y, -1);
selsnap(sel.snap, &sel.ob.x, &sel.ob.y, +1);
}
- selsort();
+ selnormalize();
sel.type = SEL_REGULAR;
for(type = 1; type < LEN(selmasks); ++type) {
/* MODE_MOUSEX10: no button release reporting */
if(IS_SET(MODE_MOUSEX10))
return;
+ if (button == 64 || button == 65)
+ return;
}
}
void
bpress(XEvent *e) {
- struct timeval now;
+ struct timespec now;
Mousekey *mk;
if(IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
}
if(e->xbutton.button == Button1) {
- gettimeofday(&now, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &now);
/* Clear previous selection, logically and visually. */
selclear(NULL);
}
selsnap(sel.snap, &sel.ob.x, &sel.ob.y, -1);
selsnap(sel.snap, &sel.oe.x, &sel.oe.y, +1);
- selsort();
+ selnormalize();
/*
* Draw selection, unless it's regular and we don't want to
char *
getsel(void) {
char *str, *ptr;
- int x, y, bufsize, size, i, ex;
+ int x, y, bufsize, size, ex;
Glyph *gp, *last;
if(sel.ob.x == -1)
* st.
* FIXME: Fix the computer world.
*/
- if(y < sel.ne.y && x > 0 && !((gp-1)->mode & ATTR_WRAP))
+ if(y < sel.ne.y && !(x > 0 && (gp-1)->mode & ATTR_WRAP))
*ptr++ = '\n';
/*
* 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)
+ if(tlinelen(y) < ex)
*ptr++ = '\n';
}
}
sel.oe.x = term.col;
}
}
- selsort();
+ selnormalize();
}
}
uint r, g, b;
switch (attr[*npar + 1]) {
- case 2: /* direct colour in RGB space */
+ case 2: /* direct color in RGB space */
if (*npar + 4 >= l) {
fprintf(stderr,
"erresc(38): Incorrect number of parameters (%d)\n",
else
idx = TRUECOLOR(r, g, b);
break;
- case 5: /* indexed colour */
+ case 5: /* indexed color */
if (*npar + 2 >= l) {
fprintf(stderr,
"erresc(38): Incorrect number of parameters (%d)\n",
break;
case 0: /* implemented defined (only foreground) */
case 1: /* transparent */
- case 3: /* direct colour in CMY space */
- case 4: /* direct colour in CMYK space */
+ case 3: /* direct color in CMY space */
+ case 4: /* direct color in CMYK space */
default:
fprintf(stderr,
"erresc(38): gfx attr %d unknown\n", attr[*npar]);
for(i = 0; i < l; i++) {
switch(attr[i]) {
case 0:
- term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE \
- | ATTR_BOLD | ATTR_ITALIC \
- | ATTR_BLINK);
+ term.c.attr.mode &= ~(
+ ATTR_BOLD |
+ ATTR_FAINT |
+ ATTR_ITALIC |
+ ATTR_UNDERLINE |
+ ATTR_BLINK |
+ ATTR_FASTBLINK |
+ ATTR_REVERSE |
+ ATTR_INVISIBLE |
+ ATTR_STRUCK );
term.c.attr.fg = defaultfg;
term.c.attr.bg = defaultbg;
break;
case 1:
term.c.attr.mode |= ATTR_BOLD;
break;
+ case 2:
+ term.c.attr.mode |= ATTR_FAINT;
+ break;
case 3:
term.c.attr.mode |= ATTR_ITALIC;
break;
term.c.attr.mode |= ATTR_UNDERLINE;
break;
case 5: /* slow blink */
- case 6: /* rapid blink */
term.c.attr.mode |= ATTR_BLINK;
break;
+ case 6: /* rapid blink */
+ term.c.attr.mode |= ATTR_FASTBLINK;
+ break;
case 7:
term.c.attr.mode |= ATTR_REVERSE;
break;
+ case 8:
+ term.c.attr.mode |= ATTR_INVISIBLE;
+ break;
+ case 9:
+ term.c.attr.mode |= ATTR_STRUCK;
+ break;
case 21:
- case 22:
term.c.attr.mode &= ~ATTR_BOLD;
break;
+ case 22:
+ term.c.attr.mode &= ~ATTR_FAINT;
+ break;
case 23:
term.c.attr.mode &= ~ATTR_ITALIC;
break;
term.c.attr.mode &= ~ATTR_UNDERLINE;
break;
case 25:
- case 26:
term.c.attr.mode &= ~ATTR_BLINK;
break;
+ case 26:
+ term.c.attr.mode &= ~ATTR_FASTBLINK;
+ break;
case 27:
term.c.attr.mode &= ~ATTR_REVERSE;
break;
+ case 28:
+ term.c.attr.mode &= ~ATTR_INVISIBLE;
+ break;
+ case 29:
+ term.c.attr.mode &= ~ATTR_STRUCK;
+ break;
case 38:
if ((idx = tdefcolor(attr, &i, l)) >= 0)
term.c.attr.fg = idx;
/* FALLTHROUGH */
case 104: /* color reset, here p = NULL */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
- if (!xsetcolorname(j, p)) {
+ if(xsetcolorname(j, p)) {
fprintf(stderr, "erresc: invalid color %s\n", p);
} else {
/*
void
tdeftran(char ascii) {
- char c, (*bp)[2];
- static char tbl[][2] = {
- {'0', CS_GRAPHIC0}, {'B', CS_USA},
- {0, 0}
- };
+ static char cs[] = "0B";
+ static int vcs[] = {CS_GRAPHIC0, CS_USA};
+ char *p;
- for (bp = &tbl[0]; (c = (*bp)[0]) && c != ascii; ++bp)
- /* nothing */;
-
- if (c == 0)
+ if((p = strchr(cs, ascii)) == NULL) {
fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
- else
- term.trantbl[term.icharset] = (*bp)[1];
+ } else {
+ term.trantbl[term.icharset] = vcs[p - cs];
+ }
}
void
int i;
XRenderColor color = { .alpha = 0xffff };
static bool loaded;
- Colour *cp;
+ Color *cp;
if(loaded) {
for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp)
XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
}
- /* load colours [0-15] and [256-LEN(colorname)] (config.h) */
+ /* load colors [0-15] and [256-LEN(colorname)] (config.h) */
for(i = 0; i < LEN(colorname); i++) {
if(!colorname[i])
continue;
}
}
- /* load colours [16-231] ; same colours as xterm */
+ /* 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 );
if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i]))
die("Could not allocate color %d\n", i);
}
-
- /* load colours [232-255] ; grayscale */
+
+ /* 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]))
int
xsetcolorname(int x, const char *name) {
XRenderColor color = { .alpha = 0xffff };
- Colour colour;
+ Color ncolor;
+
if(!BETWEEN(x, 0, LEN(colorname)))
- return -1;
+ 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;
- 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;
- return 1;
- } else {
+ 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, &colour))
- return 0;
- dc.col[x] = colour;
- return 1;
+ if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &ncolor))
+ return 1;
+
+ XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
+ dc.col[x] = ncolor;
+ return 0;
}
void
FcPattern *pattern;
FcResult r_sz, r_psz;
double fontval;
+ float ceilf(float);
if(fontstr[0] == '-') {
pattern = XftXlfdParse(fontstr, False, False);
}
/* Setting character width and height. */
- xw.cw = CEIL(dc.font.width * cwscale);
- xw.ch = CEIL(dc.font.height * chscale);
+ xw.cw = ceilf(dc.font.width * cwscale);
+ xw.ch = ceilf(dc.font.height * chscale);
FcPatternDel(pattern, FC_SLANT);
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
xloadfonts(usedfont, usedfontsize + arg->i);
cresize(0, 0);
redraw(0);
+ xhints();
}
void
FcPattern *fcpattern, *fontpattern;
FcFontSet *fcsets[] = { NULL };
FcCharSet *fccharset;
- Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg;
+ Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
XRenderColor colfg, colbg;
XRectangle r;
int oneatatime;
if(base.mode & ATTR_BOLD) {
/*
- * change basic system colours [0-7]
- * to bright system colours [8-15]
+ * change basic system colors [0-7]
+ * to bright system colors [8-15]
*/
if(BETWEEN(base.fg, 0, 7))
fg = &dc.col[base.fg + 8];
-
- font = &dc.bfont;
- frcflags = FRC_BOLD;
+
+ if(base.mode & ATTR_ITALIC) {
+ font = &dc.ibfont;
+ frcflags = FRC_ITALICBOLD;
+ } else {
+ font = &dc.bfont;
+ frcflags = FRC_BOLD;
+ }
}
if(IS_SET(MODE_REVERSE)) {
if(base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
fg = bg;
+ if(base.mode & ATTR_INVISIBLE)
+ fg = bg;
+
/* Intelligent cleaning up of the borders. */
if(x == 0) {
xclear(0, (y == 0)? 0 : winy, borderpx,
bytelen -= u8cblen;
doesexist = XftCharExists(xw.dpy, font->match, unicodep);
- if(oneatatime || !doesexist || bytelen <= 0) {
- if(oneatatime || bytelen <= 0) {
- if(doesexist) {
- u8fl++;
- u8fblen += u8cblen;
- }
- }
-
- if(u8fl > 0) {
- XftDrawStringUtf8(xw.draw, fg,
- font->match, xp,
- winy + font->ascent,
- (FcChar8 *)u8fs,
- u8fblen);
- xp += xw.cw * u8fl;
-
- }
- break;
+ if(doesexist) {
+ u8fl++;
+ u8fblen += u8cblen;
+ if(!oneatatime && bytelen > 0)
+ continue;
}
- u8fl++;
- u8fblen += u8cblen;
+ if(u8fl > 0) {
+ XftDrawStringUtf8(xw.draw, fg,
+ font->match, xp,
+ winy + font->ascent,
+ (FcChar8 *)u8fs,
+ u8fblen);
+ xp += xw.cw * u8fl;
+ }
+ break;
}
if(doesexist) {
if(oneatatime)
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;
+ struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
+ long deltatime;
/* Waiting for window mapping */
while(1) {
ttynew();
cresize(w, h);
- gettimeofday(&last, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &last);
lastblink = last;
for(xev = actionfps;;) {
- long deltatime;
-
FD_ZERO(&rfd);
FD_SET(cmdfd, &rfd);
FD_SET(xfd, &rfd);
- if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) {
+ if(pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
if(errno == EINTR)
continue;
die("select failed: %s\n", strerror(errno));
if(FD_ISSET(xfd, &rfd))
xev = actionfps;
- gettimeofday(&now, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &now);
drawtimeout.tv_sec = 0;
- drawtimeout.tv_usec = (1000/xfps) * 1000;
+ drawtimeout.tv_nsec = (1000/xfps) * 1E6;
tv = &drawtimeout;
dodraw = 0;
if(blinkset) {
if(TIMEDIFF(now, lastblink) \
> blinktimeout) {
- drawtimeout.tv_usec = 1;
+ drawtimeout.tv_nsec = 1000;
} else {
- drawtimeout.tv_usec = (1000 * \
+ drawtimeout.tv_nsec = (1E6 * \
(blinktimeout - \
TIMEDIFF(now,
lastblink)));