Merge remote-tracking branch 'upstream/master'

This commit is contained in:
EEva (JPotier) 2020-03-03 21:46:21 +02:00
commit aab5b71e1d
6 changed files with 194 additions and 124 deletions

48
FAQ
View file

@ -1,6 +1,6 @@
## Why does st not handle utmp entries? ## Why does st not handle utmp entries?
Use the excellent tool of [utmp](http://git.suckless.org/utmp/) for this task. Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task.
## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever! ## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever!
@ -15,13 +15,6 @@ you can manually run `tic -sx st.info`.
* Some programs dont complain about the lacking st description and default to * Some programs dont complain about the lacking st description and default to
another terminal. In that case see the question about terminfo. another terminal. In that case see the question about terminfo.
## I get some weird glitches/visual bug on _random program_!
Try launching it with a different TERM: $ TERM=xterm myapp. toe(1) will give
you a list of available terminals, but youll most likely switch between xterm,
st or st-256color. The default value for TERM can be changed in config.h
(TNAME).
## How do I scroll back up? ## How do I scroll back up?
Using a terminal multiplexer. Using a terminal multiplexer.
@ -104,7 +97,7 @@ St is emulating the Linux way of handling backspace being delete and delete bein
backspace. backspace.
This is an issue that was discussed in suckless mailing list This is an issue that was discussed in suckless mailing list
<http://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy <https://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy
terminal users wants its backspace to be how he feels it: terminal users wants its backspace to be how he feels it:
Well, I am going to comment why I want to change the behaviour Well, I am going to comment why I want to change the behaviour
@ -163,5 +156,40 @@ terminal users wants its backspace to be how he feels it:
Apply [1]. Apply [1].
[1] http://st.suckless.org/patches/delkey [1] https://st.suckless.org/patches/delkey
## Why do images not work in st (in programs such as w3m)?
This is a terrible hack that overdraws an image on top of the terminal emulator
window. It also relies on a very specific way the terminal draws it's contents.
A more proper (but limited way) would be using sixels. Which st doesn't
support.
## BadLength X error in Xft when trying to render emoji
Xft makes st crash when rendering color emojis with the following error:
"X Error of failed request: BadLength (poly request too large or internal Xlib length error)"
Major opcode of failed request: 139 (RENDER)
Minor opcode of failed request: 20 (RenderAddGlyphs)
Serial number of failed request: 1595
Current serial number in output stream: 1818"
This is a known bug in Xft (not st) which happens on some platforms and
combination of particular fonts and fontconfig settings.
See also:
https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6
https://bugs.freedesktop.org/show_bug.cgi?id=107534
https://bugzilla.redhat.com/show_bug.cgi?id=1498269
The solution is to remove color emoji fonts or disable this in the fontconfig
XML configuration. As an ugly workaround (which may work only on newer
fontconfig versions (FC_COLOR)), the following code can be used to mask color
fonts:
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
Please don't bother reporting this bug to st, but notify the upstream Xft
developers about fixing this bug.

View file

@ -30,9 +30,9 @@ static float chscale = 1.0;
/* /*
* word delimiter string * word delimiter string
* *
* More advanced example: " `'\"()[]{}" * More advanced example: L" `'\"()[]{}"
*/ */
char *worddelimiters = " `'\"()[]{}"; wchar_t *worddelimiters = L" ";
/* selection timeouts (in milliseconds) */ /* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300; static unsigned int doubleclicktimeout = 300;
@ -163,14 +163,22 @@ static unsigned int mousebg = 0;
*/ */
static unsigned int defaultattr = 11; static unsigned int defaultattr = 11;
/*
* Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forcemousemod = ShiftMask;
/* /*
* Internal mouse shortcuts. * Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection. * Beware that overloading Button1 will disable the selection.
*/ */
static MouseShortcut mshortcuts[] = { static MouseShortcut mshortcuts[] = {
/* button mask string */ /* mask button function argument release */
{ Button4, XK_ANY_MOD, "\031" }, { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ Button5, XK_ANY_MOD, "\005" }, { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
}; };
/* Internal keyboard shortcuts. */ /* Internal keyboard shortcuts. */
@ -209,10 +217,6 @@ static Shortcut shortcuts[] = {
* * 0: no value * * 0: no value
* * > 0: cursor application mode enabled * * > 0: cursor application mode enabled
* * < 0: cursor application mode disabled * * < 0: cursor application mode disabled
* crlf value
* * 0: no value
* * > 0: crlf mode is enabled
* * < 0: crlf mode is disabled
* *
* Be careful with the order of the definitions because st searches in * Be careful with the order of the definitions because st searches in
* this table sequentially, so any XK_ANY_MOD must be in the last * this table sequentially, so any XK_ANY_MOD must be in the last
@ -231,13 +235,6 @@ static KeySym mappedkeys[] = { -1 };
*/ */
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
/*
* Override mouse-select while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forceselmod = ShiftMask;
/* /*
* This is the huge key array which defines all compatibility to the Linux * This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely. * world. Please decide about changes wisely.

62
st.c
View file

@ -41,7 +41,7 @@
#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL) #define ISDELIM(u) (u && wcschr(worddelimiters, u))
enum term_mode { enum term_mode {
MODE_WRAP = 1 << 0, MODE_WRAP = 1 << 0,
@ -135,7 +135,7 @@ typedef struct {
/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */ /* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
typedef struct { typedef struct {
char buf[ESC_BUF_SIZ]; /* raw string */ char buf[ESC_BUF_SIZ]; /* raw string */
int len; /* raw string length */ size_t len; /* raw string length */
char priv; char priv;
int arg[ESC_ARG_SIZ]; int arg[ESC_ARG_SIZ];
int narg; /* nb of args */ int narg; /* nb of args */
@ -146,8 +146,9 @@ typedef struct {
/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */ /* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
typedef struct { typedef struct {
char type; /* ESC type ... */ char type; /* ESC type ... */
char buf[STR_BUF_SIZ]; /* raw string */ char *buf; /* allocated raw string */
int len; /* raw string length */ size_t siz; /* allocation size */
size_t len; /* raw string length */
char *args[STR_ARG_SIZ]; char *args[STR_ARG_SIZ];
int narg; /* nb of args */ int narg; /* nb of args */
} STREscape; } STREscape;
@ -210,7 +211,6 @@ static void selsnap(int *, int *, int);
static size_t utf8decode(const char *, Rune *, size_t); static size_t utf8decode(const char *, Rune *, size_t);
static Rune utf8decodebyte(char, size_t *); static Rune utf8decodebyte(char, size_t *);
static char utf8encodebyte(Rune, size_t); static char utf8encodebyte(Rune, size_t);
static char *utf8strchr(char *, Rune);
static size_t utf8validate(Rune *, size_t); static size_t utf8validate(Rune *, size_t);
static char *base64dec(const char *); static char *base64dec(const char *);
@ -337,23 +337,6 @@ utf8encodebyte(Rune u, size_t i)
return utfbyte[i] | (u & ~utfmask[i]); return utfbyte[i] | (u & ~utfmask[i]);
} }
char *
utf8strchr(char *s, Rune u)
{
Rune r;
size_t i, j, len;
len = strlen(s);
for (i = 0, j = 0; i < len; i += j) {
if (!(j = utf8decode(&s[i], &r, len - i)))
break;
if (r == u)
return &(s[i]);
}
return NULL;
}
size_t size_t
utf8validate(Rune *u, size_t i) utf8validate(Rune *u, size_t i)
{ {
@ -384,7 +367,7 @@ char
base64dec_getc(const char **src) base64dec_getc(const char **src)
{ {
while (**src && !isprint(**src)) (*src)++; while (**src && !isprint(**src)) (*src)++;
return *((*src)++); return **src ? *((*src)++) : '='; /* emulate padding if string ends */
} }
char * char *
@ -402,6 +385,10 @@ base64dec(const char *src)
int c = base64_digits[(unsigned char) base64dec_getc(&src)]; int c = base64_digits[(unsigned char) base64dec_getc(&src)];
int d = base64_digits[(unsigned char) base64dec_getc(&src)]; int d = base64_digits[(unsigned char) base64dec_getc(&src)];
/* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */
if (a == -1 || b == -1)
break;
*dst++ = (a << 2) | ((b & 0x30) >> 4); *dst++ = (a << 2) | ((b & 0x30) >> 4);
if (c == -1) if (c == -1)
break; break;
@ -476,7 +463,7 @@ selextend(int col, int row, int type, int done)
selnormalize(); selnormalize();
sel.type = type; sel.type = type;
if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type) if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY)
tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
sel.mode = done ? SEL_IDLE : SEL_READY; sel.mode = done ? SEL_IDLE : SEL_READY;
@ -1575,6 +1562,7 @@ tsetmode(int priv, int set, int *args, int narg)
case 1015: /* urxvt mangled mouse mode; incompatible case 1015: /* urxvt mangled mouse mode; incompatible
and can be mistaken for other control and can be mistaken for other control
codes. */ codes. */
break;
default: default:
fprintf(stderr, fprintf(stderr,
"erresc: unknown private set/reset mode %d\n", "erresc: unknown private set/reset mode %d\n",
@ -1816,7 +1804,7 @@ csihandle(void)
void void
csidump(void) csidump(void)
{ {
int i; size_t i;
uint c; uint c;
fprintf(stderr, "ESC["); fprintf(stderr, "ESC[");
@ -1846,7 +1834,7 @@ csireset(void)
void void
strhandle(void) strhandle(void)
{ {
char *p = NULL; char *p = NULL, *dec;
int j, narg, par; int j, narg, par;
term.esc &= ~(ESC_STR_END|ESC_STR); term.esc &= ~(ESC_STR_END|ESC_STR);
@ -1864,8 +1852,6 @@ strhandle(void)
return; return;
case 52: case 52:
if (narg > 2) { if (narg > 2) {
char *dec;
dec = base64dec(strescseq.args[2]); dec = base64dec(strescseq.args[2]);
if (dec) { if (dec) {
xsetsel(dec); xsetsel(dec);
@ -1883,7 +1869,10 @@ strhandle(void)
case 104: /* color reset, here p = NULL */ case 104: /* color reset, here p = NULL */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1; j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
if (xsetcolorname(j, p)) { if (xsetcolorname(j, p)) {
fprintf(stderr, "erresc: invalid color %s\n", p); if (par == 104 && narg <= 1)
return; /* color reset without parameter */
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
j, p ? p : "(null)");
} else { } else {
/* /*
* TODO if defaultbg color is changed, borders * TODO if defaultbg color is changed, borders
@ -1933,7 +1922,7 @@ strparse(void)
void void
strdump(void) strdump(void)
{ {
int i; size_t i;
uint c; uint c;
fprintf(stderr, "ESC%c", strescseq.type); fprintf(stderr, "ESC%c", strescseq.type);
@ -1960,7 +1949,10 @@ strdump(void)
void void
strreset(void) strreset(void)
{ {
memset(&strescseq, 0, sizeof(strescseq)); strescseq = (STREscape){
.buf = xrealloc(strescseq.buf, STR_BUF_SIZ),
.siz = STR_BUF_SIZ,
};
} }
void void
@ -2335,7 +2327,6 @@ tputc(Rune u)
goto check_control_code; goto check_control_code;
} }
if (IS_SET(MODE_SIXEL)) { if (IS_SET(MODE_SIXEL)) {
/* TODO: implement sixel mode */ /* TODO: implement sixel mode */
return; return;
@ -2343,7 +2334,7 @@ tputc(Rune u)
if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q') if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
term.mode |= MODE_SIXEL; term.mode |= MODE_SIXEL;
if (strescseq.len+len >= sizeof(strescseq.buf)-1) { if (strescseq.len+len >= strescseq.siz) {
/* /*
* Here is a bug in terminals. If the user never sends * Here is a bug in terminals. If the user never sends
* some code to stop the str or esc command, then st * some code to stop the str or esc command, then st
@ -2357,7 +2348,10 @@ tputc(Rune u)
* term.esc = 0; * term.esc = 0;
* strhandle(); * strhandle();
*/ */
return; if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2)
return;
strescseq.siz *= 2;
strescseq.buf = xrealloc(strescseq.buf, strescseq.siz);
} }
memmove(&strescseq.buf[strescseq.len], c, len); memmove(&strescseq.buf[strescseq.len], c, len);

3
st.h
View file

@ -74,6 +74,7 @@ typedef union {
uint ui; uint ui;
float f; float f;
const void *v; const void *v;
const char *s;
} Arg; } Arg;
void die(const char *, ...); void die(const char *, ...);
@ -114,7 +115,7 @@ char *xstrdup(char *);
extern char *utmp; extern char *utmp;
extern char *stty_args; extern char *stty_args;
extern char *vtiden; extern char *vtiden;
extern char *worddelimiters; extern wchar_t *worddelimiters;
extern int allowaltscreen; extern int allowaltscreen;
extern char *termname; extern char *termname;
extern int usealtcolors; extern int usealtcolors;

View file

@ -189,10 +189,10 @@ st| simpleterm,
rmxx=\E[29m, rmxx=\E[29m,
smxx=\E[9m, smxx=\E[9m,
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1) # tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
Se,
Ss,
Tc, Tc,
Ms=\E]52;%p1%s;%p2%s\007, Ms=\E]52;%p1%s;%p2%s\007,
Se=\E[2 q,
Ss=\E[%p1%d q,
st-256color| simpleterm with 256 colors, st-256color| simpleterm with 256 colors,
use=st, use=st,

172
x.c
View file

@ -29,9 +29,11 @@ typedef struct {
} Shortcut; } Shortcut;
typedef struct { typedef struct {
uint b; uint mod;
uint mask; uint button;
char *s; void (*func)(const Arg *);
const Arg arg;
uint release;
} MouseShortcut; } MouseShortcut;
typedef struct { typedef struct {
@ -57,6 +59,7 @@ static void swapcolors(const Arg *);
static void zoom(const Arg *); static void zoom(const Arg *);
static void zoomabs(const Arg *); static void zoomabs(const Arg *);
static void zoomreset(const Arg *); static void zoomreset(const Arg *);
static void ttysend(const Arg *);
/* config.h for applying patches and the configuration. */ /* config.h for applying patches and the configuration. */
#include "config.h" #include "config.h"
@ -93,8 +96,12 @@ typedef struct {
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, netwmpid;
XIM xim; struct {
XIC xic; XIM xim;
XIC xic;
XPoint spot;
XVaNestedList spotlist;
} ime;
Draw draw; Draw draw;
Visual *vis; Visual *vis;
XSetWindowAttributes attrs; XSetWindowAttributes attrs;
@ -141,9 +148,10 @@ static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
static void xdrawglyph(Glyph, int, int); static void xdrawglyph(Glyph, int, int);
static void xclear(int, int, int, int); static void xclear(int, int, int, int);
static int xgeommasktogravity(int); static int xgeommasktogravity(int);
static void ximopen(Display *); static int ximopen(Display *);
static void ximinstantiate(Display *, XPointer, XPointer); static void ximinstantiate(Display *, XPointer, XPointer);
static void ximdestroy(XIM, XPointer, XPointer); static void ximdestroy(XIM, XPointer, XPointer);
static int xicdestroy(XIC, XPointer, XPointer);
static void xinit(int, int); static void xinit(int, int);
static void cresize(int, int); static void cresize(int, int);
static void xresize(int, int); static void xresize(int, int);
@ -165,6 +173,7 @@ static void kpress(XEvent *);
static void cmessage(XEvent *); static void cmessage(XEvent *);
static void resize(XEvent *); static void resize(XEvent *);
static void focus(XEvent *); static void focus(XEvent *);
static int mouseaction(XEvent *, uint);
static void brelease(XEvent *); static void brelease(XEvent *);
static void bpress(XEvent *); static void bpress(XEvent *);
static void bmotion(XEvent *); static void bmotion(XEvent *);
@ -228,8 +237,9 @@ typedef struct {
} Fontcache; } Fontcache;
/* Fontcache is an array now. A new font will be appended to the array. */ /* Fontcache is an array now. A new font will be appended to the array. */
static Fontcache frc[16]; static Fontcache *frc = NULL;
static int frclen = 0; static int frclen = 0;
static int frccap = 0;
static char *usedfont = NULL; static char *usedfont = NULL;
static double usedfontsize = 0; static double usedfontsize = 0;
static double defaultfontsize = 0; static double defaultfontsize = 0;
@ -323,6 +333,12 @@ zoomreset(const Arg *arg)
} }
} }
void
ttysend(const Arg *arg)
{
ttywrite(arg->s, strlen(arg->s), 1);
}
int int
evcol(XEvent *e) evcol(XEvent *e)
{ {
@ -343,7 +359,7 @@ void
mousesel(XEvent *e, int done) mousesel(XEvent *e, int done)
{ {
int type, seltype = SEL_REGULAR; int type, seltype = SEL_REGULAR;
uint state = e->xbutton.state & ~(Button1Mask | forceselmod); uint state = e->xbutton.state & ~(Button1Mask | forcemousemod);
for (type = 1; type < LEN(selmasks); ++type) { for (type = 1; type < LEN(selmasks); ++type) {
if (match(selmasks[type], state)) { if (match(selmasks[type], state)) {
@ -419,25 +435,37 @@ mousereport(XEvent *e)
ttywrite(buf, len, 0); ttywrite(buf, len, 0);
} }
int
mouseaction(XEvent *e, uint release)
{
MouseShortcut *ms;
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
if (ms->release == release &&
ms->button == e->xbutton.button &&
(match(ms->mod, e->xbutton.state) || /* exact or forced */
match(ms->mod, e->xbutton.state & ~forcemousemod))) {
ms->func(&(ms->arg));
return 1;
}
}
return 0;
}
void void
bpress(XEvent *e) bpress(XEvent *e)
{ {
struct timespec now; struct timespec now;
MouseShortcut *ms;
int snap; int snap;
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
return; return;
} }
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { if (mouseaction(e, 0))
if (e->xbutton.button == ms->b return;
&& match(ms->mask, e->xbutton.state)) {
ttywrite(ms->s, strlen(ms->s), 1);
return;
}
}
if (e->xbutton.button == Button1) { if (e->xbutton.button == Button1) {
/* /*
@ -653,21 +681,21 @@ xsetsel(char *str)
void void
brelease(XEvent *e) brelease(XEvent *e)
{ {
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
return; return;
} }
if (e->xbutton.button == Button2) if (mouseaction(e, 1))
selpaste(NULL); return;
else if (e->xbutton.button == Button1) if (e->xbutton.button == Button1)
mousesel(e, 1); mousesel(e, 1);
} }
void void
bmotion(XEvent *e) bmotion(XEvent *e)
{ {
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
return; return;
} }
@ -785,7 +813,6 @@ xsetcolorname(int x, const char *name)
if (!BETWEEN(x, 0, dc.collen)) if (!BETWEEN(x, 0, dc.collen))
return 1; return 1;
if (!xloadcolor(x, name, &ncolor)) if (!xloadcolor(x, name, &ncolor))
return 1; return 1;
@ -1022,41 +1049,58 @@ xunloadfonts(void)
xunloadfont(&dc.ibfont); xunloadfont(&dc.ibfont);
} }
void int
ximopen(Display *dpy) ximopen(Display *dpy)
{ {
XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy }; XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy };
XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy };
if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
XSetLocaleModifiers("@im=local"); if (xw.ime.xim == NULL)
if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { return 0;
XSetLocaleModifiers("@im=");
if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL))
die("XOpenIM failed. Could not open input device.\n"); fprintf(stderr, "XSetIMValues: "
} "Could not set XNDestroyCallback.\n");
xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot,
NULL);
if (xw.ime.xic == NULL) {
xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle,
XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, xw.win,
XNDestroyCallback, &icdestroy,
NULL);
} }
if (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL) if (xw.ime.xic == NULL)
die("XSetIMValues failed. Could not set input method value.\n"); fprintf(stderr, "XCreateIC: Could not create input context.\n");
xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL); return 1;
if (xw.xic == NULL)
die("XCreateIC failed. Could not obtain input method.\n");
} }
void void
ximinstantiate(Display *dpy, XPointer client, XPointer call) ximinstantiate(Display *dpy, XPointer client, XPointer call)
{ {
ximopen(dpy); if (ximopen(dpy))
XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
ximinstantiate, NULL); ximinstantiate, NULL);
} }
void void
ximdestroy(XIM xim, XPointer client, XPointer call) ximdestroy(XIM xim, XPointer client, XPointer call)
{ {
xw.xim = NULL; xw.ime.xim = NULL;
XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
ximinstantiate, NULL); ximinstantiate, NULL);
XFree(xw.ime.spotlist);
}
int
xicdestroy(XIC xim, XPointer client, XPointer call)
{
xw.ime.xic = NULL;
return 1;
} }
void void
@ -1124,7 +1168,10 @@ xinit(int cols, int rows)
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
/* input methods */ /* input methods */
ximopen(xw.dpy); if (!ximopen(xw.dpy)) {
XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
ximinstantiate, NULL);
}
/* white cursor, black outline */ /* white cursor, black outline */
cursor = XCreateFontCursor(xw.dpy, mouseshape); cursor = XCreateFontCursor(xw.dpy, mouseshape);
@ -1155,8 +1202,8 @@ xinit(int cols, int rows)
win.mode = MODE_NUMLOCK; win.mode = MODE_NUMLOCK;
resettitle(); resettitle();
XMapWindow(xw.dpy, xw.win);
xhints(); xhints();
XMapWindow(xw.dpy, xw.win);
XSync(xw.dpy, False); XSync(xw.dpy, False);
clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1);
@ -1266,13 +1313,10 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
fontpattern = FcFontSetMatch(0, fcsets, 1, fontpattern = FcFontSetMatch(0, fcsets, 1,
fcpattern, &fcres); fcpattern, &fcres);
/* /* Allocate memory for the new cache entry. */
* Overwrite or create the new cache entry. if (frclen >= frccap) {
*/ frccap += 16;
if (frclen >= LEN(frc)) { frc = xrealloc(frc, frccap * sizeof(Fontcache));
frclen = LEN(frc) - 1;
XftFontClose(xw.dpy, frc[frclen].font);
frc[frclen].unicodep = 0;
} }
frc[frclen].font = XftFontOpenPattern(xw.dpy, frc[frclen].font = XftFontOpenPattern(xw.dpy,
@ -1601,11 +1645,13 @@ xfinishdraw(void)
void void
xximspot(int x, int y) xximspot(int x, int y)
{ {
XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch }; if (xw.ime.xic == NULL)
XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); return;
XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL); xw.ime.spot.x = borderpx + x * win.cw;
XFree(attr); xw.ime.spot.y = borderpx + (y + 1) * win.ch;
XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL);
} }
void void
@ -1682,13 +1728,15 @@ focus(XEvent *ev)
return; return;
if (ev->type == FocusIn) { if (ev->type == FocusIn) {
XSetICFocus(xw.xic); if (xw.ime.xic)
XSetICFocus(xw.ime.xic);
win.mode |= MODE_FOCUSED; win.mode |= MODE_FOCUSED;
xseturgency(0); xseturgency(0);
if (IS_SET(MODE_FOCUS)) if (IS_SET(MODE_FOCUS))
ttywrite("\033[I", 3, 0); ttywrite("\033[I", 3, 0);
} else { } else {
XUnsetICFocus(xw.xic); if (xw.ime.xic)
XUnsetICFocus(xw.ime.xic);
win.mode &= ~MODE_FOCUSED; win.mode &= ~MODE_FOCUSED;
if (IS_SET(MODE_FOCUS)) if (IS_SET(MODE_FOCUS))
ttywrite("\033[O", 3, 0); ttywrite("\033[O", 3, 0);
@ -1743,7 +1791,7 @@ kpress(XEvent *ev)
{ {
XKeyEvent *e = &ev->xkey; XKeyEvent *e = &ev->xkey;
KeySym ksym; KeySym ksym;
char buf[32], *customkey; char buf[64], *customkey;
int len; int len;
Rune c; Rune c;
Status status; Status status;
@ -1752,7 +1800,10 @@ kpress(XEvent *ev)
if (IS_SET(MODE_KBDLOCK)) if (IS_SET(MODE_KBDLOCK))
return; return;
len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status); if (xw.ime.xic)
len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
else
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)) {
@ -1785,7 +1836,6 @@ kpress(XEvent *ev)
ttywrite(buf, len, 1); ttywrite(buf, len, 1);
} }
void void
cmessage(XEvent *e) cmessage(XEvent *e)
{ {