diff --git a/FAQ b/FAQ index 0f9609d..969b195 100644 --- a/FAQ +++ b/FAQ @@ -29,8 +29,8 @@ you can manually run `tic -sx st.info`. ## I would like to have utmp and/or scroll functionality by default -You can add the absolute patch of both programs in your config.h -file. You only have to modify the value of utmp and scroll variables. +You can add the absolute path of both programs in your config.h file. You only +have to modify the value of utmp and scroll variables. ## Why doesn't the Del key work in some programs? diff --git a/LICENSE b/LICENSE index d80eb47..3cbf420 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT/X Consortium License -© 2014-2020 Hiltjo Posthuma +© 2014-2022 Hiltjo Posthuma © 2018 Devin J. Pohly © 2014-2017 Quentin Rameau © 2009-2012 Aurélien APTEL diff --git a/config.def.h b/config.def.h index 7ba1b79..1f2fe9d 100644 --- a/config.def.h +++ b/config.def.h @@ -171,8 +171,8 @@ static const char *colorname[] = { /* more colors can be added after 255 to use with DefaultXX */ "#cccccc", "#555555", - "black", - "gray90", + "gray90", /* default foreground colour */ + "black", /* default background colour */ }; @@ -180,9 +180,9 @@ static const char *colorname[] = { * Default colors (colorname index) * foreground, background, cursor, reverse cursor */ -unsigned int defaultfg = 259; -unsigned int defaultbg = 258; -static unsigned int defaultcs = 256; +unsigned int defaultfg = 258; +unsigned int defaultbg = 259; +unsigned int defaultcs = 256; static unsigned int defaultrcs = 257; /* diff --git a/config.mk b/config.mk index aaa54ff..0114bad 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # st version -VERSION = 0.8.4 +VERSION = 0.8.5 # Customize below to fit your system diff --git a/st.c b/st.c index 73adad4..5e311dc 100644 --- a/st.c +++ b/st.c @@ -196,18 +196,18 @@ static void tputc(Rune); static void treset(void); static void tscrollup(int, int, int); static void tscrolldown(int, int, int); -static void tsetattr(int *, int); -static void tsetchar(Rune, Glyph *, int, int); +static void tsetattr(const int *, int); +static void tsetchar(Rune, const Glyph *, int, int); static void tsetdirt(int, int); static void tsetscroll(int, int); static void tswapscreen(void); -static void tsetmode(int, int, int *, int); +static void tsetmode(int, int, const int *, int); static int twrite(const char *, int, int); static void tfulldirt(void); static void tcontrolcode(uchar ); static void tdectest(char ); static void tdefutf8(char); -static int32_t tdefcolor(int *, int *, int); +static int32_t tdefcolor(const int *, int *, int); static void tdeftran(char); static void tstrsequence(uchar); @@ -236,10 +236,10 @@ static int iofd = 1; static int cmdfd; static pid_t pid; -static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; -static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; -static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; -static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; +static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; ssize_t xwrite(int fd, const char *s, size_t len) @@ -279,12 +279,14 @@ xrealloc(void *p, size_t len) } char * -xstrdup(char *s) +xstrdup(const char *s) { - if ((s = strdup(s)) == NULL) + char *p; + + if ((p = strdup(s)) == NULL) die("strdup: %s\n", strerror(errno)); - return s; + return p; } size_t @@ -528,7 +530,7 @@ selsnap(int *x, int *y, int direction) { int newx, newy, xt, yt; int delim, prevdelim; - Glyph *gp, *prevgp; + const Glyph *gp, *prevgp; switch (sel.snap) { case SNAP_WORD: @@ -601,7 +603,7 @@ getsel(void) { char *str, *ptr; int y, bufsize, lastx, linelen; - Glyph *gp, *last; + const Glyph *gp, *last; if (sel.ob.x == -1) return NULL; @@ -768,7 +770,7 @@ stty(char **args) } int -ttynew(char *line, char *cmd, char *out, char **args) +ttynew(const char *line, char *cmd, const char *out, char **args) { int m, s; @@ -801,14 +803,15 @@ ttynew(char *line, char *cmd, char *out, char **args) break; case 0: close(iofd); + close(m); setsid(); /* create a new process group */ dup2(s, 0); dup2(s, 1); dup2(s, 2); if (ioctl(s, TIOCSCTTY, NULL) < 0) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); - close(s); - close(m); + if (s > 2) + close(s); #ifdef __OpenBSD__ if (pledge("stdio getpw proc exec", NULL) == -1) die("pledge\n"); @@ -1285,9 +1288,9 @@ tmoveto(int x, int y) } void -tsetchar(Rune u, Glyph *attr, int x, int y) +tsetchar(Rune u, const Glyph *attr, int x, int y) { - static char *vt100_0[62] = { /* 0x41 - 0x7e */ + static const char *vt100_0[62] = { /* 0x41 - 0x7e */ "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ @@ -1402,7 +1405,7 @@ tdeleteline(int n) } int32_t -tdefcolor(int *attr, int *npar, int l) +tdefcolor(const int *attr, int *npar, int l) { int32_t idx = -1; uint r, g, b; @@ -1452,7 +1455,7 @@ tdefcolor(int *attr, int *npar, int l) } void -tsetattr(int *attr, int l) +tsetattr(const int *attr, int l) { int i; int32_t idx; @@ -1593,9 +1596,9 @@ tsetscroll(int t, int b) } void -tsetmode(int priv, int set, int *args, int narg) +tsetmode(int priv, int set, const int *args, int narg) { - int alt, *lim; + int alt; const int *lim; for (lim = args + narg; args < lim; ++args) { if (priv) { @@ -1964,6 +1967,42 @@ csireset(void) memset(&csiescseq, 0, sizeof(csiescseq)); } +void +osc4_color_response(int num) +{ + int n; + char buf[32]; + unsigned char r, g, b; + + if (xgetcolor(num, &r, &g, &b)) { + fprintf(stderr, "erresc: failed to fetch osc4 color %d\n", num); + return; + } + + n = snprintf(buf, sizeof buf, "\033]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", + num, r, r, g, g, b, b); + + ttywrite(buf, n, 1); +} + +void +osc_color_response(int index, int num) +{ + int n; + char buf[32]; + unsigned char r, g, b; + + if (xgetcolor(index, &r, &g, &b)) { + fprintf(stderr, "erresc: failed to fetch osc color %d\n", index); + return; + } + + n = snprintf(buf, sizeof buf, "\033]%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", + num, r, r, g, g, b, b); + + ttywrite(buf, n, 1); +} + void strhandle(void) { @@ -2002,14 +2041,56 @@ strhandle(void) } } return; + case 10: + if (narg < 2) + break; + + p = strescseq.args[1]; + + if (!strcmp(p, "?")) + osc_color_response(defaultfg, 10); + else if (xsetcolorname(defaultfg, p)) + fprintf(stderr, "erresc: invalid foreground color: %s\n", p); + else + tfulldirt(); + return; + case 11: + if (narg < 2) + break; + + p = strescseq.args[1]; + + if (!strcmp(p, "?")) + osc_color_response(defaultbg, 11); + else if (xsetcolorname(defaultbg, p)) + fprintf(stderr, "erresc: invalid background color: %s\n", p); + else + tfulldirt(); + return; + case 12: + if (narg < 2) + break; + + p = strescseq.args[1]; + + if (!strcmp(p, "?")) + osc_color_response(defaultcs, 12); + else if (xsetcolorname(defaultcs, p)) + fprintf(stderr, "erresc: invalid cursor color: %s\n", p); + else + tfulldirt(); + return; case 4: /* color set */ if (narg < 3) break; p = strescseq.args[2]; /* FALLTHROUGH */ - case 104: /* color reset, here p = NULL */ + case 104: /* color reset */ j = (narg > 1) ? atoi(strescseq.args[1]) : -1; - if (xsetcolorname(j, p)) { + + if (p && !strcmp(p, "?")) + osc4_color_response(j); + else if (xsetcolorname(j, p)) { if (par == 104 && narg <= 1) return; /* color reset without parameter */ fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", @@ -2019,7 +2100,7 @@ strhandle(void) * TODO if defaultbg color is changed, borders * are dirty */ - redraw(); + tfulldirt(); } return; } @@ -2198,7 +2279,7 @@ void tdumpline(int n) { char buf[UTF_SIZ]; - Glyph *bp, *end; + const Glyph *bp, *end; bp = &term.line[n][0]; end = &bp[MIN(tlinelen(n), term.col) - 1]; @@ -2604,6 +2685,10 @@ tputc(Rune u) if (width == 2) { gp->mode |= ATTR_WIDE; if (term.c.x+1 < term.col) { + if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) { + gp[2].u = ' '; + gp[2].mode &= ~ATTR_WDUMMY; + } gp[1].u = '\0'; gp[1].mode = ATTR_WDUMMY; } diff --git a/st.h b/st.h index 7f175ee..8849800 100644 --- a/st.h +++ b/st.h @@ -99,7 +99,7 @@ void tnew(int, int); void tresize(int, int); void tsetdirtattr(int); void ttyhangup(void); -int ttynew(char *, char *, char *, char **); +int ttynew(const char *, char *, const char *, char **); size_t ttyread(void); void ttyresize(int, int); void ttywrite(const char *, size_t, int); @@ -117,7 +117,9 @@ size_t utf8encode(Rune, char *); void *xmalloc(size_t); void *xrealloc(void *, size_t); -char *xstrdup(char *); +char *xstrdup(const char *); + +int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b); int isboxdraw(Rune); ushort boxdrawindex(const Glyph *); @@ -146,3 +148,4 @@ extern int disablebold; extern int disableitalic; extern int disableroman; extern unsigned int max_bold_weight_infelicity; +extern unsigned int defaultcs; diff --git a/x.c b/x.c index 830cada..91c3f10 100644 --- a/x.c +++ b/x.c @@ -58,7 +58,7 @@ enum undercurl_slope_type { /* X modifiers */ #define XK_ANY_MOD UINT_MAX #define XK_NO_MOD 0 -#define XK_SWITCH_MOD (1<<13) +#define XK_SWITCH_MOD (1<<13|1<<14) /* function definitions used in config.h */ static void clipcopy(const Arg *); @@ -171,7 +171,7 @@ static void xresize(int, int); static void xhints(void); static int xloadcolor(int, const char *, Color *); static int xloadfont(Font *, FcPattern *); -static void xloadfonts(char *, double); +static void xloadfonts(const char *, double); static int xloadsparefont(FcPattern *, int); static void xloadsparefonts(void); static void xunloadfont(Font *); @@ -272,7 +272,7 @@ static char *opt_line = NULL; static char *opt_name = NULL; static char *opt_title = NULL; -static int oldbutton = 3; /* button event on startup: 3 = release */ +static uint buttons; /* bit field of pressed buttons */ char* getusedfont() @@ -393,59 +393,68 @@ mousesel(XEvent *e, int done) void mousereport(XEvent *e) { - int len, x = evcol(e), y = evrow(e), - button = e->xbutton.button, state = e->xbutton.state; + int len, btn, code; + int x = evcol(e), y = evrow(e); + int state = e->xbutton.state; char buf[40]; static int ox, oy; - /* from urxvt */ - if (e->xbutton.type == MotionNotify) { + if (e->type == MotionNotify) { if (x == ox && y == oy) return; if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) return; - /* MOUSE_MOTION: no reporting if no button is pressed */ - if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) + /* MODE_MOUSEMOTION: no reporting if no button is pressed */ + if (IS_SET(MODE_MOUSEMOTION) && buttons == 0) return; - - button = oldbutton + 32; - ox = x; - oy = y; + /* Set btn to lowest-numbered pressed button, or 12 if no + * buttons are pressed. */ + for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++) + ; + code = 32; } else { - if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { - button = 3; - } else { - button -= Button1; - if (button >= 3) - button += 64 - 3; - } - if (e->xbutton.type == ButtonPress) { - oldbutton = button; - ox = x; - oy = y; - } else if (e->xbutton.type == ButtonRelease) { - oldbutton = 3; + btn = e->xbutton.button; + /* Only buttons 1 through 11 can be encoded */ + if (btn < 1 || btn > 11) + return; + if (e->type == ButtonRelease) { /* MODE_MOUSEX10: no button release reporting */ if (IS_SET(MODE_MOUSEX10)) return; - if (button == 64 || button == 65) + /* Don't send release events for the scroll wheel */ + if (btn == 4 || btn == 5) return; } + code = 0; } + ox = x; + oy = y; + + /* Encode btn into code. If no button is pressed for a motion event in + * MODE_MOUSEMANY, then encode it as a release. */ + if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12) + code += 3; + else if (btn >= 8) + code += 128 + btn - 8; + else if (btn >= 4) + code += 64 + btn - 4; + else + code += btn - 1; + if (!IS_SET(MODE_MOUSEX10)) { - button += ((state & ShiftMask ) ? 4 : 0) - + ((state & Mod4Mask ) ? 8 : 0) - + ((state & ControlMask) ? 16 : 0); + code += ((state & ShiftMask ) ? 4 : 0) + + ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */ + + ((state & ControlMask) ? 16 : 0); } if (IS_SET(MODE_MOUSESGR)) { len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", - button, x+1, y+1, - e->xbutton.type == ButtonRelease ? 'm' : 'M'); + code, x+1, y+1, + e->type == ButtonRelease ? 'm' : 'M'); } else if (x < 223 && y < 223) { len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", - 32+button, 32+x+1, 32+y+1); + 32+code, 32+x+1, 32+y+1); } else { return; } @@ -489,9 +498,13 @@ mouseaction(XEvent *e, uint release) void bpress(XEvent *e) { + int btn = e->xbutton.button; struct timespec now; int snap; + if (1 <= btn && btn <= 11) + buttons |= 1 << (btn-1); + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { mousereport(e); return; @@ -500,7 +513,7 @@ bpress(XEvent *e) if (mouseaction(e, 0)) return; - if (e->xbutton.button == Button1) { + if (btn == Button1) { /* * If the user clicks below predefined timeouts specific * snapping behaviour is exposed. @@ -715,6 +728,11 @@ xsetsel(char *str) void brelease(XEvent *e) { + int btn = e->xbutton.button; + + if (1 <= btn && btn <= 11) + buttons &= ~(1 << (btn-1)); + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { mousereport(e); return; @@ -722,7 +740,7 @@ brelease(XEvent *e) if (mouseaction(e, 1)) return; - if (e->xbutton.button == Button1) + if (btn == Button1) mousesel(e, 1); } @@ -856,6 +874,19 @@ xloadcols(void) loaded = 1; } +int +xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b) +{ + if (!BETWEEN(x, 0, dc.collen)) + return 1; + + *r = dc.col[x].color.red >> 8; + *g = dc.col[x].color.green >> 8; + *b = dc.col[x].color.blue >> 8; + + return 0; +} + int xsetcolorname(int x, const char *name) { @@ -1012,7 +1043,7 @@ xloadfont(Font *f, FcPattern *pattern) } void -xloadfonts(char *fontstr, double fontsize) +xloadfonts(const char *fontstr, double fontsize) { FcPattern *pattern; double fontval; @@ -1020,7 +1051,7 @@ xloadfonts(char *fontstr, double fontsize) if (fontstr[0] == '-') pattern = XftXlfdParse(fontstr, False, False); else - pattern = FcNameParse((FcChar8 *)fontstr); + pattern = FcNameParse((const FcChar8 *)fontstr); if (!pattern) die("can't open font %s\n", fontstr); @@ -2068,7 +2099,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i if (base.mode & ATTR_UNDERLINE) { // Underline if (base.ustyle != 3) { - XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent + 1, width, 1); + XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent * chscale + 1, width, 1); // Undercurl } else if (base.ustyle == 3) { const int widthThreshold = undercurl_thickness_threshold; // +1 width every widthThreshold px of font @@ -2101,8 +2132,8 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i /* Render strikethrough. */ if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent / 3, - width, 1); + XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent * chscale / 3, + width, 1); } /* Reset clip to none. */ @@ -2229,8 +2260,9 @@ xseticontitle(char *p) XTextProperty prop; DEFAULT(p, opt_title); - Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, - &prop); + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop) != Success) + return; XSetWMIconName(xw.dpy, xw.win, &prop); XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname); XFree(prop.value); @@ -2242,8 +2274,9 @@ xsettitle(char *p) XTextProperty prop; DEFAULT(p, opt_title); - Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, - &prop); + if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop) != Success) + return; XSetWMName(xw.dpy, xw.win, &prop); XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); XFree(prop.value);