Merge remote-tracking branch 'upstream/master'

This commit is contained in:
mintycube 2024-07-22 14:23:25 +05:00
commit cde29093ca
8 changed files with 302 additions and 63 deletions

46
dmenu.c
View File

@ -178,15 +178,6 @@ static Clr *scheme[SchemeLast];
#include "config.h" #include "config.h"
#if CASEINSENSITIVE_PATCH
static char * cistrstr(const char *s, const char *sub);
static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp;
static char *(*fstrstr)(const char *, const char *) = cistrstr;
#else
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
static char *(*fstrstr)(const char *, const char *) = strstr;
#endif // CASEINSENSITIVE_PATCH
static unsigned int static unsigned int
textw_clamp(const char *str, unsigned int n) textw_clamp(const char *str, unsigned int n)
{ {
@ -216,6 +207,14 @@ static void run(void);
static void setup(void); static void setup(void);
static void usage(void); static void usage(void);
#if CASEINSENSITIVE_PATCH
static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp;
static char *(*fstrstr)(const char *, const char *) = cistrstr;
#else
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
static char *(*fstrstr)(const char *, const char *) = strstr;
#endif // CASEINSENSITIVE_PATCH
#include "patch/include.c" #include "patch/include.c"
static void static void
@ -270,6 +269,9 @@ cleanup(void)
size_t i; size_t i;
XUngrabKey(dpy, AnyKey, AnyModifier, root); XUngrabKey(dpy, AnyKey, AnyModifier, root);
#if INPUTMETHOD_PATCH
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
#endif // INPUTMETHOD_PATCH
for (i = 0; i < SchemeLast; i++) for (i = 0; i < SchemeLast; i++)
free(scheme[i]); free(scheme[i]);
for (i = 0; items && items[i].text; ++i) for (i = 0; items && items[i].text; ++i)
@ -1506,7 +1508,6 @@ run(void)
#if PRESELECT_PATCH #if PRESELECT_PATCH
int i; int i;
#endif // PRESELECT_PATCH #endif // PRESELECT_PATCH
while (!XNextEvent(dpy, &ev)) { while (!XNextEvent(dpy, &ev)) {
#if PRESELECT_PATCH #if PRESELECT_PATCH
if (preselected) { if (preselected) {
@ -1520,8 +1521,15 @@ run(void)
preselected = 0; preselected = 0;
} }
#endif // PRESELECT_PATCH #endif // PRESELECT_PATCH
#if INPUTMETHOD_PATCH
if (XFilterEvent(&ev, None))
continue;
if (composing)
continue;
#else
if (XFilterEvent(&ev, win)) if (XFilterEvent(&ev, win))
continue; continue;
#endif // INPUTMETHOD_PATCH
switch(ev.type) { switch(ev.type) {
#if MOUSE_SUPPORT_PATCH #if MOUSE_SUPPORT_PATCH
case ButtonPress: case ButtonPress:
@ -1788,13 +1796,16 @@ setup(void)
(unsigned char *) &dock, 1); (unsigned char *) &dock, 1);
#endif // WMTYPE_PATCH #endif // WMTYPE_PATCH
/* input methods */ /* input methods */
if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL)
die("XOpenIM failed: could not open input device"); die("XOpenIM failed: could not open input device");
#if INPUTMETHOD_PATCH
init_input_method(xim);
#else
xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, win, XNFocusWindow, win, NULL); XNClientWindow, win, XNFocusWindow, win, NULL);
#endif // INPUTMETHOD_PATCH
#if MANAGED_PATCH #if MANAGED_PATCH
if (managed) { if (managed) {
@ -1816,8 +1827,13 @@ setup(void)
XSelectInput(dpy, dws[i], FocusChangeMask); XSelectInput(dpy, dws[i], FocusChangeMask);
XFree(dws); XFree(dws);
} }
#if !INPUTMETHOD_PATCH
grabfocus(); grabfocus();
#endif // INPUTMETHOD_PATCH
} }
#if INPUTMETHOD_PATCH
grabfocus();
#endif // INPUTMETHOD_PATCH
drw_resize(drw, mw, mh); drw_resize(drw, mw, mh);
drawmenu(); drawmenu();
} }
@ -1933,6 +1949,10 @@ main(int argc, char *argv[])
#if XRESOURCES_PATCH #if XRESOURCES_PATCH
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
fputs("warning: no locale support\n", stderr); fputs("warning: no locale support\n", stderr);
#if INPUTMETHOD_PATCH
if (!XSetLocaleModifiers(""))
fputs("warning: could not set locale modifiers", stderr);
#endif // INPUTMETHOD_PATCH
if (!(dpy = XOpenDisplay(NULL))) if (!(dpy = XOpenDisplay(NULL)))
die("cannot open display"); die("cannot open display");
@ -2165,6 +2185,10 @@ main(int argc, char *argv[])
#else // !XRESOURCES_PATCH #else // !XRESOURCES_PATCH
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
fputs("warning: no locale support\n", stderr); fputs("warning: no locale support\n", stderr);
#if INPUTMETHOD_PATCH
if (!XSetLocaleModifiers(""))
fputs("warning: could not set locale modifiers", stderr);
#endif // INPUTMETHOD_PATCH
if (!(dpy = XOpenDisplay(NULL))) if (!(dpy = XOpenDisplay(NULL)))
die("cannot open display"); die("cannot open display");
screen = DefaultScreen(dpy); screen = DefaultScreen(dpy);

98
drw.c
View File

@ -11,63 +11,50 @@
#if !PANGO_PATCH || HIGHLIGHT_PATCH #if !PANGO_PATCH || HIGHLIGHT_PATCH
#define UTF_INVALID 0xFFFD #define UTF_INVALID 0xFFFD
#define UTF_SIZ 4
static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; static int
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; utf8decode(const char *s_in, long *u, int *err)
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
static long
utf8decodebyte(const char c, size_t *i)
{ {
for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) static const unsigned char lens[] = {
if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) /* 0XXXX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
return (unsigned char)c & ~utfmask[*i]; /* 10XXX */ 0, 0, 0, 0, 0, 0, 0, 0, /* invalid */
return 0; /* 110XX */ 2, 2, 2, 2,
} /* 1110X */ 3, 3,
/* 11110 */ 4,
/* 11111 */ 0, /* invalid */
};
static const unsigned char leading_mask[] = { 0x7F, 0x1F, 0x0F, 0x07 };
static const unsigned int overlong[] = { 0x0, 0x80, 0x0800, 0x10000 };
static size_t const unsigned char *s = (const unsigned char *)s_in;
utf8validate(long *u, size_t i) int len = lens[*s >> 3];
{
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
*u = UTF_INVALID; *u = UTF_INVALID;
for (i = 1; *u > utfmax[i]; ++i) *err = 1;
; if (len == 0)
return i;
}
static size_t
utf8decode(const char *c, long *u, size_t clen)
{
size_t i, j, len, type;
long udecoded;
*u = UTF_INVALID;
if (!clen)
return 0;
udecoded = utf8decodebyte(c[0], &len);
if (!BETWEEN(len, 1, UTF_SIZ))
return 1; return 1;
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
if (type)
return j;
}
if (j < len)
return 0;
*u = udecoded;
utf8validate(u, len);
long cp = s[0] & leading_mask[len - 1];
for (int i = 1; i < len; ++i) {
if (s[i] == '\0' || (s[i] & 0xC0) != 0x80)
return i;
cp = (cp << 6) | (s[i] & 0x3F);
}
/* out of range, surrogate, overlong encoding */
if (cp > 0x10FFFF || (cp >> 11) == 0x1B || cp < overlong[len - 1])
return len;
*err = 0;
*u = cp;
return len; return len;
} }
#if HIGHLIGHT_PATCH #if HIGHLIGHT_PATCH
size_t int
utf8len(const char *c) utf8len(const char *c)
{ {
long utf8codepoint = 0; long utf8codepoint = 0;
return utf8decode(c, &utf8codepoint, UTF_SIZ); int utf8err = 0;
return utf8decode(c, &utf8codepoint, &utf8err);
} }
#endif // HIGHLIGHT_PATCH #endif // HIGHLIGHT_PATCH
#endif // PANGO_PATCH #endif // PANGO_PATCH
@ -447,7 +434,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1; unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1;
XftDraw *d = NULL; XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont; Fnt *usedfont, *curfont, *nextfont;
int utf8strlen, utf8charlen, render = x || y || w || h; int utf8strlen, utf8charlen, utf8err, render = x || y || w || h;
long utf8codepoint = 0; long utf8codepoint = 0;
const char *utf8str; const char *utf8str;
FcCharSet *fccharset; FcCharSet *fccharset;
@ -456,7 +443,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
XftResult result; XftResult result;
int charexists = 0, overflow = 0; int charexists = 0, overflow = 0;
/* keep track of a couple codepoints for which we have no match. */ /* keep track of a couple codepoints for which we have no match. */
static unsigned int nomatches[128], ellipsis_width; static unsigned int nomatches[128], ellipsis_width, invalid_width;
static const char invalid[] = "<EFBFBD>";
const char *ellipsis = "..."; const char *ellipsis = "...";
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
@ -481,12 +469,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
usedfont = drw->fonts; usedfont = drw->fonts;
if (!ellipsis_width && render) if (!ellipsis_width && render)
ellipsis_width = drw_fontset_getwidth(drw, ellipsis); ellipsis_width = drw_fontset_getwidth(drw, ellipsis);
if (!invalid_width && render)
invalid_width = drw_fontset_getwidth(drw, invalid);
while (1) { while (1) {
ew = ellipsis_len = utf8strlen = 0; ew = ellipsis_len = utf8err = utf8strlen = 0;
utf8str = text; utf8str = text;
nextfont = NULL; nextfont = NULL;
while (*text) { while (*text) {
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); utf8charlen = utf8decode(text, &utf8codepoint, &utf8err);
for (curfont = drw->fonts; curfont; curfont = curfont->next) { for (curfont = drw->fonts; curfont; curfont = curfont->next) {
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) { if (charexists) {
@ -508,9 +498,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
else else
utf8strlen = ellipsis_len; utf8strlen = ellipsis_len;
} else if (curfont == usedfont) { } else if (curfont == usedfont) {
utf8strlen += utf8charlen;
text += utf8charlen; text += utf8charlen;
ew += tmpw; utf8strlen += utf8err ? 0 : utf8charlen;
ew += utf8err ? 0 : tmpw;
} else { } else {
nextfont = curfont; nextfont = curfont;
} }
@ -518,7 +508,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
} }
} }
if (overflow || !charexists || nextfont) if (overflow || !charexists || nextfont || utf8err)
break; break;
else else
charexists = 0; charexists = 0;
@ -533,6 +523,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
x += ew; x += ew;
w -= ew; w -= ew;
} }
if (utf8err && (!render || invalid_width < w)) {
if (render)
drw_text(drw, x, y, w, h, 0, invalid, invert);
x += invalid_width;
w -= invalid_width;
}
if (render && overflow && ellipsis_w) if (render && overflow && ellipsis_w)
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, ellipsis, invert); drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, ellipsis, invert);

2
drw.h
View File

@ -69,7 +69,7 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in
#endif // PANGO_PATCH #endif // PANGO_PATCH
#if HIGHLIGHT_PATCH #if HIGHLIGHT_PATCH
size_t utf8len(const char *c); int utf8len(const char *c);
#endif // HIGHLIGHT_PATCH #endif // HIGHLIGHT_PATCH
/* Colorscheme abstraction */ /* Colorscheme abstraction */

View File

@ -13,6 +13,9 @@
#if HIGHPRIORITY_PATCH #if HIGHPRIORITY_PATCH
#include "highpriority.c" #include "highpriority.c"
#endif #endif
#if INPUTMETHOD_PATCH
#include "inputmethod.c"
#endif
#if DYNAMIC_OPTIONS_PATCH #if DYNAMIC_OPTIONS_PATCH
#include "dynamicoptions.c" #include "dynamicoptions.c"
#endif #endif

View File

@ -4,6 +4,9 @@
#if FZFEXPECT_PATCH #if FZFEXPECT_PATCH
#include "fzfexpect.h" #include "fzfexpect.h"
#endif #endif
#if INPUTMETHOD_PATCH
#include "inputmethod.h"
#endif
#if MULTI_SELECTION_PATCH #if MULTI_SELECTION_PATCH
#include "multiselect.h" #include "multiselect.h"
#endif #endif

196
patch/inputmethod.c Normal file
View File

@ -0,0 +1,196 @@
static size_t nextrunetext(const char *text, size_t position, int inc)
{
ssize_t n;
/* return location of next utf8 rune in the given direction (+1 or -1) */
for (n = position + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
;
return n;
}
/* return bytes from beginning of text to nth utf8 rune to the right */
static size_t runebytes(const char *text, size_t n)
{
size_t ret;
ret = 0;
while (n-- > 0)
ret += nextrunetext(text + ret, 0, 1);
return ret;
}
/* return number of characters from beginning of text to nth byte to the right
*/
static size_t runechars(const char *text, size_t n)
{
size_t ret, i;
ret = i = 0;
while (i < n) {
i += nextrunetext(text + i, 0, 1);
ret++;
}
return ret;
}
/* move caret on pre-edit text */
static void preeditcaret(XIC xic, XPointer clientdata, XPointer calldata)
{
XIMPreeditCaretCallbackStruct *pcaret;
(void)xic;
pcaret = (XIMPreeditCaretCallbackStruct *)calldata;
if (!pcaret)
return;
switch (pcaret->direction) {
case XIMForwardChar:
cursor = nextrune(+1);
break;
case XIMBackwardChar:
cursor = nextrune(-1);
break;
case XIMForwardWord:
movewordedge(+1);
break;
case XIMBackwardWord:
movewordedge(-1);
break;
case XIMLineStart:
cursor = 0;
break;
case XIMLineEnd:
if (preview[cursor] != '\0')
cursor = strlen(preview);
break;
case XIMAbsolutePosition:
cursor = runebytes(text, pcaret->position);
break;
case XIMDontChange:
/* do nothing */
break;
case XIMCaretUp:
case XIMCaretDown:
case XIMNextLine:
case XIMPreviousLine:
/* not implemented */
break;
}
pcaret->position = runechars(preview, cursor);
}
/* start input method pre-editing */
static int preeditstart(XIC xic, XPointer clientdata, XPointer calldata)
{
(void)xic;
(void)calldata;
(void)clientdata;
composing = 1;
printf("PREEDIT\n");
return BUFSIZ;
}
/* end input method pre-editing */
static void preeditdone(XIC xic, XPointer clientdata, XPointer calldata)
{
(void)xic;
(void)clientdata;
(void)calldata;
printf("DONE\n");
composing = 0;
}
/* draw input method pre-edit text */
static void preeditdraw(XIC xic, XPointer clientdata, XPointer calldata)
{
XIMPreeditDrawCallbackStruct *pdraw;
size_t beg, dellen, inslen, endlen;
printf("DRAW\n");
(void)xic;
pdraw = (XIMPreeditDrawCallbackStruct *)calldata;
if (!pdraw)
return;
/* we do not support wide characters */
if (pdraw->text && pdraw->text->encoding_is_wchar == True) {
fputs("warning: wchar is not supportecd; use utf8", stderr);
return;
}
beg = runebytes(text, pdraw->chg_first);
dellen = runebytes(preview + beg, pdraw->chg_length);
inslen = pdraw->text ? runebytes(pdraw->text->string.multi_byte, pdraw->text->length) : 0;
endlen = 0;
if (beg + dellen < strlen(preview))
endlen = strlen(preview + beg + dellen);
/* we cannot change text past the end of our pre-edit string */
if (beg + dellen >= BUFSIZ || beg + inslen >= BUFSIZ)
return;
/* get space for text to be copied, and copy it */
memmove(preview + beg + inslen, preview + beg + dellen, endlen + 1);
if (pdraw->text && pdraw->text->length)
memcpy(preview + beg, pdraw->text->string.multi_byte, inslen);
(preview + beg + inslen + endlen)[0] = '\0';
/* get caret position */
cursor = runebytes(text, pdraw->caret);
}
static void init_input_method(XIM xim)
{
XVaNestedList preedit = NULL;
XICCallback start, done, draw, caret;
XIMStyle preeditstyle;
XIMStyle statusstyle;
XIMStyles *imstyles;
int i;
/* get styles supported by input method */
if (XGetIMValues(xim, XNQueryInputStyle, &imstyles, NULL) != NULL)
fputs("XGetIMValues: could not obtain input method values", stderr);
/* check whether input method support on-the-spot pre-editing */
preeditstyle = XIMPreeditNothing;
statusstyle = XIMStatusNothing;
for (i = 0; i < imstyles->count_styles; i++) {
if (imstyles->supported_styles[i] & XIMPreeditCallbacks) {
preeditstyle = XIMPreeditCallbacks;
break;
}
}
/* create callbacks for the input context */
start.client_data = NULL;
done.client_data = NULL;
draw.client_data = (XPointer)text;
caret.client_data = (XPointer)text;
start.callback = (XICProc)preeditstart;
done.callback = (XICProc)preeditdone;
draw.callback = (XICProc)preeditdraw;
caret.callback = (XICProc)preeditcaret;
/* create list of values for input context */
preedit = XVaCreateNestedList(0, XNPreeditStartCallback, &start, XNPreeditDoneCallback,
&done, XNPreeditDrawCallback, &draw, XNPreeditCaretCallback,
&caret, NULL);
if (preedit == NULL)
fputs("XVaCreateNestedList: could not create nested list", stderr);
xic = XCreateIC(xim, XNInputStyle, preeditstyle | statusstyle, XNPreeditAttributes, preedit,
XNClientWindow, win, XNFocusWindow, win, NULL);
XFree(preedit);
long eventmask;
/* get events the input method is interested in */
if (XGetICValues(xic, XNFilterEvents, &eventmask, NULL))
fputs("XGetICValues: could not obtain input context values", stderr);
XSelectInput(dpy, win,
ExposureMask | KeyPressMask | VisibilityChangeMask | ButtonPressMask |
PointerMotionMask | eventmask);
}

11
patch/inputmethod.h Normal file
View File

@ -0,0 +1,11 @@
static int composing;
static char preview[512] = "";
static size_t nextrunetext(const char *text, size_t position, int inc);
static size_t runebytes(const char *text, size_t n);
static size_t runechars(const char *text, size_t n);
static void preeditcaret(XIC xic, XPointer clientdata, XPointer calldata);
static int preeditstart(XIC xic, XPointer clientdata, XPointer calldata);
static void preeditdone(XIC xic, XPointer clientdata, XPointer calldata);
static void preeditdraw(XIC xic, XPointer clientdata, XPointer calldata);
static void init_input_method(XIM xim);

View File

@ -108,6 +108,12 @@
*/ */
#define INITIALTEXT_PATCH 0 #define INITIALTEXT_PATCH 0
/* Adds support for input methods (fctix, ibus, etc.) allowing the user to change the
* keyboard layout while dmenu is open.
* https://github.com/bakkeby/dmenu-flexipatch/pull/22
*/
#define INPUTMETHOD_PATCH 0
/* This patch adds a flag which will cause dmenu to select an item immediately if there /* This patch adds a flag which will cause dmenu to select an item immediately if there
* is only one matching option left. * is only one matching option left.
* https://tools.suckless.org/dmenu/patches/instant/ * https://tools.suckless.org/dmenu/patches/instant/