13 Commits
0.8.4 ... 0.8.5

Author SHA1 Message Date
7fb0c0cc68 bump version to 0.8.5 2022-01-07 12:39:57 +01:00
7e1c68f25d FAQ: fix a typo, patch -> path 2022-01-02 12:16:57 +01:00
65f1dc4283 Fix overtyping wide characters.
Overtyping the first half of a wide character with the
second half of a wide character results in display garbage.
This is because the trailing dummy is not cleaned up.

i.e.  ATTR_WIDE, ATTR_WDUMMY, ATTR_WDUMMY

Here is a short script for demonstrating the behavior:

	#!/bin/sh
	alias printf=/usr/bin/printf
	printf こんにちは!; sleep 2
	printf '\x1b[5D'; sleep 2
	printf へ; sleep 2
	printf ' '; sleep 2
	echo
2021-12-30 18:37:17 +01:00
a0467c802d Fix null pointer access in strhandle
According to the spec the argument is optional for 104, so p can be
NULL as can be tested with printf '\x1b]104\x07'. This is a regression
of 8e31030.
2021-12-27 13:07:11 +01:00
273db5ceaf follow-up fix for OSC color sequences, return
Otherwise the message "erresc: unknown str" is printed.
2021-12-26 19:00:41 +01:00
8e31030390 Add support for OSC color sequences 2021-12-26 18:57:44 +01:00
2f6e597ed8 fix possible rare crash when Xutf8TextPropertyToTextList fails
from the XmbTextListToTextProperty(3) man page:

"If insufficient memory is available for the new value string, the functions
return XNoMemory.  If the current locale is not supported, the functions return
XLocaleNotSupported.  In both of these error cases, the functions do not set
text_prop_return."

Reported by Steffen Nurpmeso <steffen@sdaoden.eu>, thanks!
2021-08-24 13:44:35 +02:00
1d3142da96 fix a problem that the standard streams are unexpectedly closed
In the current implementation, the slave PTY (assigned to the variable
`s') is always closed after duplicating it to file descriptors of
standard streams (0, 1, and 2).  However, when the allocated slave PTY
`s' is already one of 0, 1, or 2, this causes unexpected closing of a
standard stream.  The same problem occurs when the file descriptor of
the master PTY (the variable `m') is one of 0, 1, or 2.

In this patch, the original master PTY (m) is closed before it would
be overwritten by duplicated slave PTYs.  The original slave PTY (s)
is closed only when it is not one of the stanrad streams.
2021-08-24 13:30:11 +02:00
2ec571a30c Add 14th bit to XK_SWITCH_MOD bitmask
The bits of uint signal in an XKeyEvent which concern the key group (keyboard
layout) are bits 13 and 14, as documented here:
https://www.x.org/releases/X11R7.7/doc/libX11/XKB/xkblib.html#Groups_and_Shift_Levels
In the older version, only bit 13 was marked as part of XK_SWITCH_MOD, this
causes issues for users who have more than two keymaps. the 14th bit is not
in ignoremod, key sequences are not caught by match(), if they switch to a third
or fourth keyboard.
2021-07-18 11:44:56 +02:00
4536f46cff Mild const-correctness improvements.
Only touch a few things, the main focus is to
improve code readability.
2021-05-06 18:21:10 +02:00
9e68fdbcdb fix: correctly encode mouse buttons >= 8 in X10 and SGR mode
These are typically mapped in X11 to the side-buttons (backward/forwards) on
the mouse. A comparison of the button numbers in SGR mode (first field):

st old:
0 1 2 64 65 66 67 68 69 70

st new (it is the same as xterm now):
0 1 2 64 65 66 67 128 129 130

A script to test and reproduce it, first argument is "h" (on) or "l" (off):

	#!/bin/sh
	printf '\x1b[?1000%s\x1b[?1006%s' "$1" "$1"

	for n in 1 2 3 4 5 6 7 8 9 10; do
		printf 'button %d\n' "$n"
		xdotool click "$n"
		printf '\n\n'
	done
2021-03-19 11:58:59 +01:00
4ef0cbd8b9 remove unused variable from previous patch 2020-10-18 11:18:03 +02:00
28b4c822c5 ST: Add WM_ICON_NAME property support
Also added _NET_WM_ICON_NAME.
2020-10-18 11:17:11 +02:00
7 changed files with 171 additions and 41 deletions

4
FAQ
View File

@ -29,8 +29,8 @@ you can manually run `tic -sx st.info`.
## I would like to have utmp and/or scroll functionality by default ## 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 You can add the absolute path of both programs in your config.h file. You only
file. You only have to modify the value of utmp and scroll variables. have to modify the value of utmp and scroll variables.
## Why doesn't the Del key work in some programs? ## Why doesn't the Del key work in some programs?

View File

@ -120,6 +120,8 @@ static const char *colorname[] = {
/* more colors can be added after 255 to use with DefaultXX */ /* more colors can be added after 255 to use with DefaultXX */
"#cccccc", "#cccccc",
"#555555", "#555555",
"gray90", /* default foreground colour */
"black", /* default background colour */
}; };
@ -127,9 +129,9 @@ static const char *colorname[] = {
* Default colors (colorname index) * Default colors (colorname index)
* foreground, background, cursor, reverse cursor * foreground, background, cursor, reverse cursor
*/ */
unsigned int defaultfg = 7; unsigned int defaultfg = 258;
unsigned int defaultbg = 0; unsigned int defaultbg = 259;
static unsigned int defaultcs = 256; unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257; static unsigned int defaultrcs = 257;
/* /*

View File

@ -1,5 +1,5 @@
# st version # st version
VERSION = 0.8.4 VERSION = 0.8.5
# Customize below to fit your system # Customize below to fit your system

143
st.c
View File

@ -186,18 +186,18 @@ static void tputc(Rune);
static void treset(void); static void treset(void);
static void tscrollup(int, int); static void tscrollup(int, int);
static void tscrolldown(int, int); static void tscrolldown(int, int);
static void tsetattr(int *, int); static void tsetattr(const int *, int);
static void tsetchar(Rune, Glyph *, int, int); static void tsetchar(Rune, const Glyph *, int, int);
static void tsetdirt(int, int); static void tsetdirt(int, int);
static void tsetscroll(int, int); static void tsetscroll(int, int);
static void tswapscreen(void); 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 int twrite(const char *, int, int);
static void tfulldirt(void); static void tfulldirt(void);
static void tcontrolcode(uchar ); static void tcontrolcode(uchar );
static void tdectest(char ); static void tdectest(char );
static void tdefutf8(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 tdeftran(char);
static void tstrsequence(uchar); static void tstrsequence(uchar);
@ -226,10 +226,10 @@ static int iofd = 1;
static int cmdfd; static int cmdfd;
static pid_t pid; static pid_t pid;
static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
ssize_t ssize_t
xwrite(int fd, const char *s, size_t len) xwrite(int fd, const char *s, size_t len)
@ -269,12 +269,14 @@ xrealloc(void *p, size_t len)
} }
char * 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)); die("strdup: %s\n", strerror(errno));
return s; return p;
} }
size_t size_t
@ -518,7 +520,7 @@ selsnap(int *x, int *y, int direction)
{ {
int newx, newy, xt, yt; int newx, newy, xt, yt;
int delim, prevdelim; int delim, prevdelim;
Glyph *gp, *prevgp; const Glyph *gp, *prevgp;
switch (sel.snap) { switch (sel.snap) {
case SNAP_WORD: case SNAP_WORD:
@ -591,7 +593,7 @@ getsel(void)
{ {
char *str, *ptr; char *str, *ptr;
int y, bufsize, lastx, linelen; int y, bufsize, lastx, linelen;
Glyph *gp, *last; const Glyph *gp, *last;
if (sel.ob.x == -1) if (sel.ob.x == -1)
return NULL; return NULL;
@ -758,7 +760,7 @@ stty(char **args)
} }
int int
ttynew(char *line, char *cmd, char *out, char **args) ttynew(const char *line, char *cmd, const char *out, char **args)
{ {
int m, s; int m, s;
@ -791,14 +793,15 @@ ttynew(char *line, char *cmd, char *out, char **args)
break; break;
case 0: case 0:
close(iofd); close(iofd);
close(m);
setsid(); /* create a new process group */ setsid(); /* create a new process group */
dup2(s, 0); dup2(s, 0);
dup2(s, 1); dup2(s, 1);
dup2(s, 2); dup2(s, 2);
if (ioctl(s, TIOCSCTTY, NULL) < 0) if (ioctl(s, TIOCSCTTY, NULL) < 0)
die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
close(s); if (s > 2)
close(m); close(s);
#ifdef __OpenBSD__ #ifdef __OpenBSD__
if (pledge("stdio getpw proc exec", NULL) == -1) if (pledge("stdio getpw proc exec", NULL) == -1)
die("pledge\n"); die("pledge\n");
@ -1186,9 +1189,9 @@ tmoveto(int x, int y)
} }
void 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 */ "", "", "", "", "", "", "", /* A - G */
0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */
@ -1300,7 +1303,7 @@ tdeleteline(int n)
} }
int32_t int32_t
tdefcolor(int *attr, int *npar, int l) tdefcolor(const int *attr, int *npar, int l)
{ {
int32_t idx = -1; int32_t idx = -1;
uint r, g, b; uint r, g, b;
@ -1350,7 +1353,7 @@ tdefcolor(int *attr, int *npar, int l)
} }
void void
tsetattr(int *attr, int l) tsetattr(const int *attr, int l)
{ {
int i; int i;
int32_t idx; int32_t idx;
@ -1468,9 +1471,9 @@ tsetscroll(int t, int b)
} }
void 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) { for (lim = args + narg; args < lim; ++args) {
if (priv) { if (priv) {
@ -1839,6 +1842,42 @@ csireset(void)
memset(&csiescseq, 0, sizeof(csiescseq)); 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 void
strhandle(void) strhandle(void)
{ {
@ -1853,7 +1892,15 @@ strhandle(void)
case ']': /* OSC -- Operating System Command */ case ']': /* OSC -- Operating System Command */
switch (par) { switch (par) {
case 0: case 0:
if (narg > 1) {
xsettitle(strescseq.args[1]);
xseticontitle(strescseq.args[1]);
}
return;
case 1: case 1:
if (narg > 1)
xseticontitle(strescseq.args[1]);
return;
case 2: case 2:
if (narg > 1) if (narg > 1)
xsettitle(strescseq.args[1]); xsettitle(strescseq.args[1]);
@ -1869,14 +1916,56 @@ strhandle(void)
} }
} }
return; 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
redraw();
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
redraw();
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
redraw();
return;
case 4: /* color set */ case 4: /* color set */
if (narg < 3) if (narg < 3)
break; break;
p = strescseq.args[2]; p = strescseq.args[2];
/* FALLTHROUGH */ /* FALLTHROUGH */
case 104: /* color reset, here p = NULL */ case 104: /* color reset */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1; 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) if (par == 104 && narg <= 1)
return; /* color reset without parameter */ return; /* color reset without parameter */
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
@ -2012,7 +2101,7 @@ void
tdumpline(int n) tdumpline(int n)
{ {
char buf[UTF_SIZ]; char buf[UTF_SIZ];
Glyph *bp, *end; const Glyph *bp, *end;
bp = &term.line[n][0]; bp = &term.line[n][0];
end = &bp[MIN(tlinelen(n), term.col) - 1]; end = &bp[MIN(tlinelen(n), term.col) - 1];
@ -2418,6 +2507,10 @@ check_control_code:
if (width == 2) { if (width == 2) {
gp->mode |= ATTR_WIDE; gp->mode |= ATTR_WIDE;
if (term.c.x+1 < term.col) { 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].u = '\0';
gp[1].mode = ATTR_WDUMMY; gp[1].mode = ATTR_WDUMMY;
} }

7
st.h
View File

@ -91,7 +91,7 @@ void tnew(int, int);
void tresize(int, int); void tresize(int, int);
void tsetdirtattr(int); void tsetdirtattr(int);
void ttyhangup(void); void ttyhangup(void);
int ttynew(char *, char *, char *, char **); int ttynew(const char *, char *, const char *, char **);
size_t ttyread(void); size_t ttyread(void);
void ttyresize(int, int); void ttyresize(int, int);
void ttywrite(const char *, size_t, int); void ttywrite(const char *, size_t, int);
@ -109,7 +109,9 @@ size_t utf8encode(Rune, char *);
void *xmalloc(size_t); void *xmalloc(size_t);
void *xrealloc(void *, 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);
/* config.h globals */ /* config.h globals */
extern char *utmp; extern char *utmp;
@ -123,3 +125,4 @@ extern char *termname;
extern unsigned int tabspaces; extern unsigned int tabspaces;
extern unsigned int defaultfg; extern unsigned int defaultfg;
extern unsigned int defaultbg; extern unsigned int defaultbg;
extern unsigned int defaultcs;

1
win.h
View File

@ -30,6 +30,7 @@ void xdrawline(Line, int, int, int);
void xfinishdraw(void); void xfinishdraw(void);
void xloadcols(void); void xloadcols(void);
int xsetcolorname(int, const char *); int xsetcolorname(int, const char *);
void xseticontitle(char *);
void xsettitle(char *); void xsettitle(char *);
int xsetcursor(int); int xsetcursor(int);
void xsetmode(int, unsigned int); void xsetmode(int, unsigned int);

47
x.c
View File

@ -48,7 +48,7 @@ typedef struct {
/* X modifiers */ /* X modifiers */
#define XK_ANY_MOD UINT_MAX #define XK_ANY_MOD UINT_MAX
#define XK_NO_MOD 0 #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 */ /* function definitions used in config.h */
static void clipcopy(const Arg *); static void clipcopy(const Arg *);
@ -93,7 +93,7 @@ typedef struct {
Window win; Window win;
Drawable buf; Drawable buf;
GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
Atom xembed, wmdeletewin, netwmname, netwmpid; Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
struct { struct {
XIM xim; XIM xim;
XIC xic; XIC xic;
@ -156,7 +156,7 @@ static void xresize(int, int);
static void xhints(void); static void xhints(void);
static int xloadcolor(int, const char *, Color *); static int xloadcolor(int, const char *, Color *);
static int xloadfont(Font *, FcPattern *); static int xloadfont(Font *, FcPattern *);
static void xloadfonts(char *, double); static void xloadfonts(const char *, double);
static void xunloadfont(Font *); static void xunloadfont(Font *);
static void xunloadfonts(void); static void xunloadfonts(void);
static void xsetenv(void); static void xsetenv(void);
@ -387,7 +387,9 @@ mousereport(XEvent *e)
button = 3; button = 3;
} else { } else {
button -= Button1; button -= Button1;
if (button >= 3) if (button >= 7)
button += 128 - 7;
else if (button >= 3)
button += 64 - 3; button += 64 - 3;
} }
if (e->xbutton.type == ButtonPress) { if (e->xbutton.type == ButtonPress) {
@ -797,6 +799,19 @@ xloadcols(void)
loaded = 1; 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 int
xsetcolorname(int x, const char *name) xsetcolorname(int x, const char *name)
{ {
@ -950,7 +965,7 @@ xloadfont(Font *f, FcPattern *pattern)
} }
void void
xloadfonts(char *fontstr, double fontsize) xloadfonts(const char *fontstr, double fontsize)
{ {
FcPattern *pattern; FcPattern *pattern;
double fontval; double fontval;
@ -958,7 +973,7 @@ xloadfonts(char *fontstr, double fontsize)
if (fontstr[0] == '-') if (fontstr[0] == '-')
pattern = XftXlfdParse(fontstr, False, False); pattern = XftXlfdParse(fontstr, False, False);
else else
pattern = FcNameParse((FcChar8 *)fontstr); pattern = FcNameParse((const FcChar8 *)fontstr);
if (!pattern) if (!pattern)
die("can't open font %s\n", fontstr); die("can't open font %s\n", fontstr);
@ -1186,6 +1201,7 @@ xinit(int cols, int rows)
xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False);
XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
@ -1579,14 +1595,29 @@ xsetenv(void)
setenv("WINDOWID", buf, 1); setenv("WINDOWID", buf, 1);
} }
void
xseticontitle(char *p)
{
XTextProperty prop;
DEFAULT(p, opt_title);
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);
}
void void
xsettitle(char *p) xsettitle(char *p)
{ {
XTextProperty prop; XTextProperty prop;
DEFAULT(p, opt_title); DEFAULT(p, opt_title);
Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop); &prop) != Success)
return;
XSetWMName(xw.dpy, xw.win, &prop); XSetWMName(xw.dpy, xw.win, &prop);
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
XFree(prop.value); XFree(prop.value);