mirror of
https://github.com/mintycube/dmenu.git
synced 2024-10-22 14:05:48 +02:00
parent
1c584542f4
commit
34b991503c
@ -28,6 +28,8 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/YjT2DD6j
|
|||||||
|
|
||||||
### Changelog:
|
### Changelog:
|
||||||
|
|
||||||
|
2024-07-17 - Added the input method patch
|
||||||
|
|
||||||
2024-07-16 - Added the mouse motion support patch
|
2024-07-16 - Added the mouse motion support patch
|
||||||
|
|
||||||
2023-06-15 - Added the caret width patch
|
2023-06-15 - Added the caret width patch
|
||||||
@ -138,6 +140,9 @@ Browsing patches? There is a [map of patches](https://coggle.it/diagram/YjT2DD6j
|
|||||||
- [initialtext](https://tools.suckless.org/dmenu/patches/initialtext/)
|
- [initialtext](https://tools.suckless.org/dmenu/patches/initialtext/)
|
||||||
- adds an option to provide preselected text
|
- adds an option to provide preselected text
|
||||||
|
|
||||||
|
- input-method
|
||||||
|
- adds support for input methods (fctix, ibus, etc.)
|
||||||
|
|
||||||
- [instant](https://tools.suckless.org/dmenu/patches/instant/)
|
- [instant](https://tools.suckless.org/dmenu/patches/instant/)
|
||||||
- adds a flag that will cause dmenu to select an item immediately if there is only one
|
- adds a flag that will cause dmenu to select an item immediately if there is only one
|
||||||
matching option left
|
matching option left
|
||||||
|
29
dmenu.c
29
dmenu.c
@ -269,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)
|
||||||
@ -1505,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) {
|
||||||
@ -1519,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:
|
||||||
@ -1787,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) {
|
||||||
@ -1815,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();
|
||||||
}
|
}
|
||||||
@ -1932,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");
|
||||||
|
|
||||||
@ -2164,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);
|
||||||
|
@ -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
|
||||||
|
@ -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
196
patch/inputmethod.c
Normal 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
11
patch/inputmethod.h
Normal 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);
|
@ -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/
|
||||||
|
Loading…
Reference in New Issue
Block a user