feat: upgrade st to v0.9.2

This commit is contained in:
Dan Anglin 2024-05-28 21:58:55 +01:00
parent 6adfb45f71
commit 43efc0814d
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
12 changed files with 155 additions and 146 deletions

3
FAQ
View file

@ -248,3 +248,6 @@ fonts:
Please don't bother reporting this bug to st, but notify the upstream Xft Please don't bother reporting this bug to st, but notify the upstream Xft
developers about fixing this bug. developers about fixing this bug.
As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5:
https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS

View file

@ -1,6 +1,6 @@
MIT/X Consortium License MIT/X Consortium License
© 2014-2020 Hiltjo Posthuma <hiltjo at codemadness dot org> © 2014-2022 Hiltjo Posthuma <hiltjo at codemadness dot org>
© 2018 Devin J. Pohly <djpohly at gmail dot com> © 2018 Devin J. Pohly <djpohly at gmail dot com>
© 2014-2017 Quentin Rameau <quinq at fifth dot space> © 2014-2017 Quentin Rameau <quinq at fifth dot space>
© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com> © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>

View file

@ -7,13 +7,7 @@ include config.mk
SRC = st.c x.c SRC = st.c x.c
OBJ = $(SRC:.c=.o) OBJ = $(SRC:.c=.o)
all: options st all: st
options:
@echo st build options:
@echo "CFLAGS = $(STCFLAGS)"
@echo "LDFLAGS = $(STLDFLAGS)"
@echo "CC = $(CC)"
config.h: config.h:
cp config.def.h config.h cp config.def.h config.h
@ -54,4 +48,4 @@ uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/st rm -f $(DESTDIR)$(PREFIX)/bin/st
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
.PHONY: all options clean dist install uninstall .PHONY: all clean dist install uninstall

View file

@ -15,15 +15,15 @@ This can be edited to match your own local setup.
Enter the following command to build and install st (if necessary as root): Enter the following command to build and install st (if necessary as root):
```bash ```bash
$ make clean install make clean install
``` ```
# Running st # Running st
If you did not install st with make clean install, you must compile If you did not install st with make clean install, you must compile
the st terminfo entry with the following command: the st terminfo entry with the following command:
``` ```bash
$ tic -sx st.info tic -sx st.info
``` ```
See the man page for additional details. See the man page for additional details.

View file

@ -53,7 +53,7 @@ int allowwindowops = 0;
* near minlatency, but it waits longer for slow updates to avoid partial draw. * near minlatency, but it waits longer for slow updates to avoid partial draw.
* low minlatency will tear/flicker more, as it can "detect" idle too early. * low minlatency will tear/flicker more, as it can "detect" idle too early.
*/ */
static double minlatency = 8; static double minlatency = 2;
static double maxlatency = 33; static double maxlatency = 33;
/* /*

View file

@ -5,7 +5,6 @@
* *
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/ */
static char *font = "SauceCodePro Nerd Font Mono:pixelsize=14:antialias=true:autohint=true"; static char *font = "SauceCodePro Nerd Font Mono:pixelsize=14:antialias=true:autohint=true";
static int borderpx = 2; static int borderpx = 2;
@ -17,7 +16,6 @@ static int borderpx = 2;
* 4: value of shell in /etc/passwd * 4: value of shell in /etc/passwd
* 5: value of shell in config.h * 5: value of shell in config.h
*/ */
static char *shell = "/bin/bash"; static char *shell = "/bin/bash";
char *utmp = NULL; char *utmp = NULL;
/* scroll program: to enable use a string like "scroll" */ /* scroll program: to enable use a string like "scroll" */
@ -55,7 +53,7 @@ int allowwindowops = 0;
* near minlatency, but it waits longer for slow updates to avoid partial draw. * near minlatency, but it waits longer for slow updates to avoid partial draw.
* low minlatency will tear/flicker more, as it can "detect" idle too early. * low minlatency will tear/flicker more, as it can "detect" idle too early.
*/ */
static double minlatency = 8; static double minlatency = 2;
static double maxlatency = 33; static double maxlatency = 33;
/* /*
@ -73,7 +71,7 @@ static unsigned int cursorthickness = 2;
* bell volume. It must be a value between -100 and 100. Use 0 for disabling * bell volume. It must be a value between -100 and 100. Use 0 for disabling
* it * it
*/ */
static int bellvolume = 30; static int bellvolume = 0;
/* default TERM value */ /* default TERM value */
char *termname = "st-256color"; char *termname = "st-256color";

View file

@ -1,5 +1,5 @@
# st version # st version
VERSION = 0.8.5 VERSION = 0.9.2
# Customize below to fit your system # Customize below to fit your system
@ -30,6 +30,7 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
# `$(PKG_CONFIG) --libs fontconfig` \ # `$(PKG_CONFIG) --libs fontconfig` \
# `$(PKG_CONFIG) --libs freetype2` # `$(PKG_CONFIG) --libs freetype2`
#MANPREFIX = ${PREFIX}/man
# compiler and linker # compiler and linker
# CC = c99 # CC = c99

153
st.c
View file

@ -161,6 +161,7 @@ static void csidump(void);
static void csihandle(void); static void csihandle(void);
static void csiparse(void); static void csiparse(void);
static void csireset(void); static void csireset(void);
static void osc_color_response(int, int, int);
static int eschandle(uchar); static int eschandle(uchar);
static void strdump(void); static void strdump(void);
static void strhandle(void); static void strhandle(void);
@ -349,25 +350,10 @@ utf8validate(Rune *u, size_t i)
return i; return i;
} }
static const char base64_digits[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
char char
base64dec_getc(const char **src) base64dec_getc(const char **src)
{ {
while (**src && !isprint(**src)) while (**src && !isprint((unsigned char)**src))
(*src)++; (*src)++;
return **src ? *((*src)++) : '='; /* emulate padding if string ends */ return **src ? *((*src)++) : '='; /* emulate padding if string ends */
} }
@ -377,6 +363,13 @@ base64dec(const char *src)
{ {
size_t in_len = strlen(src); size_t in_len = strlen(src);
char *result, *dst; char *result, *dst;
static const char base64_digits[256] = {
[43] = 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0,
0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
};
if (in_len % 4) if (in_len % 4)
in_len += 4 - (in_len % 4); in_len += 4 - (in_len % 4);
@ -946,7 +939,7 @@ ttyresize(int tw, int th)
} }
void void
ttyhangup() ttyhangup(void)
{ {
/* Send SIGHUP to shell */ /* Send SIGHUP to shell */
kill(pid, SIGHUP); kill(pid, SIGHUP);
@ -1104,7 +1097,7 @@ tscrollup(int orig, int n)
void void
selscroll(int orig, int n) selscroll(int orig, int n)
{ {
if (sel.ob.x == -1) if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
return; return;
if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
@ -1650,7 +1643,7 @@ csihandle(void)
ttywrite(vtiden, strlen(vtiden), 0); ttywrite(vtiden, strlen(vtiden), 0);
break; break;
case 'b': /* REP -- if last char is printable print it <n> more times */ case 'b': /* REP -- if last char is printable print it <n> more times */
DEFAULT(csiescseq.arg[0], 1); LIMIT(csiescseq.arg[0], 1, 65535);
if (term.lastc) if (term.lastc)
while (csiescseq.arg[0]-- > 0) while (csiescseq.arg[0]-- > 0)
tputc(term.lastc); tputc(term.lastc);
@ -1735,6 +1728,7 @@ csihandle(void)
} }
break; break;
case 'S': /* SU -- Scroll <n> line up */ case 'S': /* SU -- Scroll <n> line up */
if (csiescseq.priv) break;
DEFAULT(csiescseq.arg[0], 1); DEFAULT(csiescseq.arg[0], 1);
tscrollup(term.top, csiescseq.arg[0]); tscrollup(term.top, csiescseq.arg[0]);
break; break;
@ -1776,11 +1770,18 @@ csihandle(void)
case 'm': /* SGR -- Terminal attribute (color) */ case 'm': /* SGR -- Terminal attribute (color) */
tsetattr(csiescseq.arg, csiescseq.narg); tsetattr(csiescseq.arg, csiescseq.narg);
break; break;
case 'n': /* DSR Device Status Report (cursor position) */ case 'n': /* DSR -- Device Status Report */
if (csiescseq.arg[0] == 6) { switch (csiescseq.arg[0]) {
case 5: /* Status Report "OK" `0n` */
ttywrite("\033[0n", sizeof("\033[0n") - 1, 0);
break;
case 6: /* Report Cursor Position (CPR) "<row>;<column>R" */
len = snprintf(buf, sizeof(buf), "\033[%i;%iR", len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
term.c.y+1, term.c.x+1); term.c.y+1, term.c.x+1);
ttywrite(buf, len, 0); ttywrite(buf, len, 0);
break;
default:
goto unknown;
} }
break; break;
case 'r': /* DECSTBM -- Set Scrolling Region */ case 'r': /* DECSTBM -- Set Scrolling Region */
@ -1843,39 +1844,28 @@ csireset(void)
} }
void void
osc4_color_response(int num) osc_color_response(int num, int index, int is_osc4)
{ {
int n; int n;
char buf[32]; char buf[32];
unsigned char r, g, b; unsigned char r, g, b;
if (xgetcolor(num, &r, &g, &b)) { if (xgetcolor(is_osc4 ? num : index, &r, &g, &b)) {
fprintf(stderr, "erresc: failed to fetch osc4 color %d\n", num); fprintf(stderr, "erresc: failed to fetch %s color %d\n",
is_osc4 ? "osc4" : "osc",
is_osc4 ? num : index);
return; return;
} }
n = snprintf(buf, sizeof buf, "\033]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", n = snprintf(buf, sizeof buf, "\033]%s%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
num, r, r, g, g, b, b); is_osc4 ? "4;" : "", num, r, r, g, g, b, b);
if (n < 0 || n >= sizeof(buf)) {
ttywrite(buf, n, 1); fprintf(stderr, "error: %s while printing %s response\n",
} n < 0 ? "snprintf failed" : "truncation occurred",
is_osc4 ? "osc4" : "osc");
void } else {
osc_color_response(int index, int num) ttywrite(buf, n, 1);
{
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
@ -1883,6 +1873,11 @@ strhandle(void)
{ {
char *p = NULL, *dec; char *p = NULL, *dec;
int j, narg, par; int j, narg, par;
const struct { int idx; char *str; } osc_table[] = {
{ defaultfg, "foreground" },
{ defaultbg, "background" },
{ defaultcs, "cursor" }
};
term.esc &= ~(ESC_STR_END|ESC_STR); term.esc &= ~(ESC_STR_END|ESC_STR);
strparse(); strparse();
@ -1917,43 +1912,22 @@ strhandle(void)
} }
return; return;
case 10: 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: 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: case 12:
if (narg < 2) if (narg < 2)
break; break;
p = strescseq.args[1]; p = strescseq.args[1];
if ((j = par - 10) < 0 || j >= LEN(osc_table))
break; /* shouldn't be possible */
if (!strcmp(p, "?")) if (!strcmp(p, "?")) {
osc_color_response(defaultcs, 12); osc_color_response(par, osc_table[j].idx, 0);
else if (xsetcolorname(defaultcs, p)) } else if (xsetcolorname(osc_table[j].idx, p)) {
fprintf(stderr, "erresc: invalid cursor color: %s\n", p); fprintf(stderr, "erresc: invalid %s color: %s\n",
else osc_table[j].str, p);
redraw(); } else {
tfulldirt();
}
return; return;
case 4: /* color set */ case 4: /* color set */
if (narg < 3) if (narg < 3)
@ -1963,11 +1937,13 @@ strhandle(void)
case 104: /* color reset */ case 104: /* color reset */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1; j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
if (p && !strcmp(p, "?")) if (p && !strcmp(p, "?")) {
osc4_color_response(j); osc_color_response(j, 0, 1);
else if (xsetcolorname(j, p)) { } else if (xsetcolorname(j, p)) {
if (par == 104 && narg <= 1) if (par == 104 && narg <= 1) {
xloadcols();
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",
j, p ? p : "(null)"); j, p ? p : "(null)");
} else { } else {
@ -1975,7 +1951,7 @@ strhandle(void)
* TODO if defaultbg color is changed, borders * TODO if defaultbg color is changed, borders
* are dirty * are dirty
*/ */
redraw(); tfulldirt();
} }
return; return;
} }
@ -2355,6 +2331,7 @@ eschandle(uchar ascii)
treset(); treset();
resettitle(); resettitle();
xloadcols(); xloadcols();
xsetmode(0, MODE_HIDE);
break; break;
case '=': /* DECPAM -- Application keypad */ case '=': /* DECPAM -- Application keypad */
xsetmode(1, MODE_APPKEYPAD); xsetmode(1, MODE_APPKEYPAD);
@ -2447,6 +2424,9 @@ check_control_code:
* they must not cause conflicts with sequences. * they must not cause conflicts with sequences.
*/ */
if (control) { if (control) {
/* in UTF-8 mode ignore handling C1 control characters */
if (IS_SET(MODE_UTF8) && ISCONTROLC1(u))
return;
tcontrolcode(u); tcontrolcode(u);
/* /*
* control codes are not shown ever * control codes are not shown ever
@ -2493,11 +2473,16 @@ check_control_code:
gp = &term.line[term.c.y][term.c.x]; gp = &term.line[term.c.y][term.c.x];
} }
if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) {
memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph));
gp->mode &= ~ATTR_WIDE;
}
if (term.c.x+width > term.col) { if (term.c.x+width > term.col) {
tnewline(1); if (IS_SET(MODE_WRAP))
tnewline(1);
else
tmoveto(term.col - width, term.c.y);
gp = &term.line[term.c.y][term.c.x]; gp = &term.line[term.c.y][term.c.x];
} }

2
st.h
View file

@ -111,8 +111,6 @@ void *xmalloc(size_t);
void *xrealloc(void *, size_t); void *xrealloc(void *, size_t);
char *xstrdup(const 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;
extern char *scroll; extern char *scroll;

View file

@ -184,6 +184,10 @@ st-mono| simpleterm monocolor,
# XTerm extensions # XTerm extensions
rmxx=\E[29m, rmxx=\E[29m,
smxx=\E[9m, smxx=\E[9m,
BE=\E[?2004h,
BD=\E[?2004l,
PS=\E[200~,
PE=\E[201~,
# disabled rep for now: causes some issues with older ncurses versions. # disabled rep for now: causes some issues with older ncurses versions.
# rep=%p1%c\E[%p2%{1}%-%db, # rep=%p1%c\E[%p2%{1}%-%db,
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1) # tmux extensions, see TERMINFO EXTENSIONS in tmux(1)

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 *);
int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *);
void xseticontitle(char *); void xseticontitle(char *);
void xsettitle(char *); void xsettitle(char *);
int xsetcursor(int); int xsetcursor(int);

109
x.c
View file

@ -252,7 +252,7 @@ static char *opt_line = NULL;
static char *opt_name = NULL; static char *opt_name = NULL;
static char *opt_title = NULL; static char *opt_title = NULL;
static int oldbutton = 3; /* button event on startup: 3 = release */ static uint buttons; /* bit field of pressed buttons */
void void
clipcopy(const Arg *dummy) clipcopy(const Arg *dummy)
@ -364,61 +364,68 @@ mousesel(XEvent *e, int done)
void void
mousereport(XEvent *e) mousereport(XEvent *e)
{ {
int len, x = evcol(e), y = evrow(e), int len, btn, code;
button = e->xbutton.button, state = e->xbutton.state; int x = evcol(e), y = evrow(e);
int state = e->xbutton.state;
char buf[40]; char buf[40];
static int ox, oy; static int ox, oy;
/* from urxvt */ if (e->type == MotionNotify) {
if (e->xbutton.type == MotionNotify) {
if (x == ox && y == oy) if (x == ox && y == oy)
return; return;
if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
return; return;
/* MOUSE_MOTION: no reporting if no button is pressed */ /* MODE_MOUSEMOTION: no reporting if no button is pressed */
if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
return; return;
/* Set btn to lowest-numbered pressed button, or 12 if no
button = oldbutton + 32; * buttons are pressed. */
ox = x; for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
oy = y; ;
code = 32;
} else { } else {
if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { btn = e->xbutton.button;
button = 3; /* Only buttons 1 through 11 can be encoded */
} else { if (btn < 1 || btn > 11)
button -= Button1; return;
if (button >= 7) if (e->type == ButtonRelease) {
button += 128 - 7;
else 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;
/* MODE_MOUSEX10: no button release reporting */ /* MODE_MOUSEX10: no button release reporting */
if (IS_SET(MODE_MOUSEX10)) if (IS_SET(MODE_MOUSEX10))
return; return;
if (button == 64 || button == 65) /* Don't send release events for the scroll wheel */
if (btn == 4 || btn == 5)
return; 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)) { if (!IS_SET(MODE_MOUSEX10)) {
button += ((state & ShiftMask ) ? 4 : 0) code += ((state & ShiftMask ) ? 4 : 0)
+ ((state & Mod4Mask ) ? 8 : 0) + ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */
+ ((state & ControlMask) ? 16 : 0); + ((state & ControlMask) ? 16 : 0);
} }
if (IS_SET(MODE_MOUSESGR)) { if (IS_SET(MODE_MOUSESGR)) {
len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
button, x+1, y+1, code, x+1, y+1,
e->xbutton.type == ButtonRelease ? 'm' : 'M'); e->type == ButtonRelease ? 'm' : 'M');
} else if (x < 223 && y < 223) { } else if (x < 223 && y < 223) {
len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", 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 { } else {
return; return;
} }
@ -461,9 +468,13 @@ mouseaction(XEvent *e, uint release)
void void
bpress(XEvent *e) bpress(XEvent *e)
{ {
int btn = e->xbutton.button;
struct timespec now; struct timespec now;
int snap; int snap;
if (1 <= btn && btn <= 11)
buttons |= 1 << (btn-1);
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
return; return;
@ -472,7 +483,7 @@ bpress(XEvent *e)
if (mouseaction(e, 0)) if (mouseaction(e, 0))
return; return;
if (e->xbutton.button == Button1) { if (btn == Button1) {
/* /*
* If the user clicks below predefined timeouts specific * If the user clicks below predefined timeouts specific
* snapping behaviour is exposed. * snapping behaviour is exposed.
@ -686,6 +697,11 @@ xsetsel(char *str)
void void
brelease(XEvent *e) 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)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
return; return;
@ -693,7 +709,7 @@ brelease(XEvent *e)
if (mouseaction(e, 1)) if (mouseaction(e, 1))
return; return;
if (e->xbutton.button == Button1) if (btn == Button1)
mousesel(e, 1); mousesel(e, 1);
} }
@ -802,7 +818,7 @@ xloadcols(void)
int int
xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b) xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
{ {
if (!BETWEEN(x, 0, dc.collen)) if (!BETWEEN(x, 0, dc.collen - 1))
return 1; return 1;
*r = dc.col[x].color.red >> 8; *r = dc.col[x].color.red >> 8;
@ -817,7 +833,7 @@ xsetcolorname(int x, const char *name)
{ {
Color ncolor; Color ncolor;
if (!BETWEEN(x, 0, dc.collen)) if (!BETWEEN(x, 0, dc.collen - 1))
return 1; return 1;
if (!xloadcolor(x, name, &ncolor)) if (!xloadcolor(x, name, &ncolor))
@ -1477,12 +1493,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
/* Render underline and strikethrough. */ /* Render underline and strikethrough. */
if (base.mode & ATTR_UNDERLINE) { if (base.mode & ATTR_UNDERLINE) {
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
width, 1); width, 1);
} }
if (base.mode & ATTR_STRUCK) { if (base.mode & ATTR_STRUCK) {
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
width, 1); width, 1);
} }
@ -1601,6 +1617,9 @@ xseticontitle(char *p)
XTextProperty prop; XTextProperty prop;
DEFAULT(p, opt_title); DEFAULT(p, opt_title);
if (p[0] == '\0')
p = opt_title;
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop) != Success) &prop) != Success)
return; return;
@ -1615,6 +1634,9 @@ xsettitle(char *p)
XTextProperty prop; XTextProperty prop;
DEFAULT(p, opt_title); DEFAULT(p, opt_title);
if (p[0] == '\0')
p = opt_title;
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop) != Success) &prop) != Success)
return; return;
@ -1817,7 +1839,7 @@ void
kpress(XEvent *ev) kpress(XEvent *ev)
{ {
XKeyEvent *e = &ev->xkey; XKeyEvent *e = &ev->xkey;
KeySym ksym; KeySym ksym = NoSymbol;
char buf[64], *customkey; char buf[64], *customkey;
int len; int len;
Rune c; Rune c;
@ -1827,10 +1849,13 @@ kpress(XEvent *ev)
if (IS_SET(MODE_KBDLOCK)) if (IS_SET(MODE_KBDLOCK))
return; return;
if (xw.ime.xic) if (xw.ime.xic) {
len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
else if (status == XBufferOverflow)
return;
} else {
len = XLookupString(e, buf, sizeof buf, &ksym, NULL); len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
}
/* 1. shortcuts */ /* 1. shortcuts */
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
if (ksym == bp->keysym && match(bp->mod, e->state)) { if (ksym == bp->keysym && match(bp->mod, e->state)) {