From 6e17eb44078095360152e49c0fbfcf23492f5623 Mon Sep 17 00:00:00 2001 From: pml68 Date: Wed, 10 Jul 2024 23:36:24 +0200 Subject: feat: add dmenu qalc patch --- dmenu/config.mk | 2 +- dmenu/dmenu.1 | 3 + dmenu/dmenu.c | 164 +++++++++++++++++++----- dmenu/patches/dmenu-qalc-5.2.diff | 259 ++++++++++++++++++++++++++++++++++++++ dwm/config.def.h | 5 + dwm/config.h | 5 + 6 files changed, 405 insertions(+), 33 deletions(-) create mode 100644 dmenu/patches/dmenu-qalc-5.2.diff diff --git a/dmenu/config.mk b/dmenu/config.mk index fa2b4fc..39f8bd4 100644 --- a/dmenu/config.mk +++ b/dmenu/config.mk @@ -24,7 +24,7 @@ INCS = -I$(X11INC) -I$(FREETYPEINC) LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lXrender # flags -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) +CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS) LDFLAGS = $(LIBS) diff --git a/dmenu/dmenu.1 b/dmenu/dmenu.1 index 57ea184..2bf9c77 100644 --- a/dmenu/dmenu.1 +++ b/dmenu/dmenu.1 @@ -45,6 +45,9 @@ dmenu appears at the bottom of the screen. .B \-c dmenu appears centered on the screen. .TP +.B \-C +dmenu becomes a calculator. +.TP .B \-f dmenu grabs the keyboard before reading stdin if not reading from a tty. This is faster, but will lock up X until stdin reaches end\-of\-file. diff --git a/dmenu/dmenu.c b/dmenu/dmenu.c index 3293a88..3f462d9 100644 --- a/dmenu/dmenu.c +++ b/dmenu/dmenu.c @@ -1,11 +1,16 @@ /* See LICENSE file for copyright and license details. */ #include #include +#include +#include #include +#include #include #include #include #include +#include +#include #include #include @@ -39,6 +44,12 @@ struct item { int out; }; +static struct { + pid_t pid; + int enable, in[2], out[2]; + char buf[256]; +} qalc; + static char text[BUFSIZ] = ""; static char *embed; static int bh, mw, mh; @@ -231,7 +242,72 @@ static void grabkeyboard(void) { die("cannot grab keyboard"); } +static void init_qalc(void) { + pipe(qalc.in); + pipe2(qalc.out, O_NONBLOCK); + qalc.pid = fork(); + if (qalc.pid == -1) + die("failed to fork for qalc"); + if (qalc.pid == 0) { + dup2(qalc.in[0], STDIN_FILENO); + dup2(qalc.out[1], STDOUT_FILENO); + close(qalc.in[1]); + close(qalc.out[0]); + prctl(PR_SET_PDEATHSIG, SIGTERM); + execl("/usr/bin/qalc", "qalc", "-c0", "-t", NULL); + die("execl qalc failed"); + } else { // parent + close(qalc.in[0]); + close(qalc.out[1]); + items = malloc(sizeof(struct item) * 2); + items[0].text = malloc(LENGTH(qalc.buf)); + strcpy(items[0].text, "no result"); + items[1].out = 0; + items[1].text = NULL; + } +} + +static void recv_qalc(void) { + ssize_t r = read(qalc.out[0], qalc.buf, LENGTH(qalc.buf)); + + if (r < 0) + die("error reading qalc.out"); + + if (qalc.buf[0] == '\n') { + int i; + for (i = 3; i < LENGTH(qalc.buf) && qalc.buf[i] != '\n'; i++) + items[0].text[i - 3] = qalc.buf[i]; + items[0].text[i - 3] = 0; + if (r != LENGTH(qalc.buf)) + return; + } + + while (read(qalc.out[0], qalc.buf, LENGTH(qalc.buf)) != -1) + ; // empty the pipe + if (errno != EAGAIN && errno != EWOULDBLOCK) + die("error emptying qalc.out"); +} + +static void send_qalc(void) { + int s = strlen(text); + text[s] = '\n'; + write(qalc.in[1], text, s + 1); + text[s] = 0; +} + +static void match_qalc(void) { + matches = matchend = NULL; + appenditem(items, &matches, &matchend); + curr = sel = matches; + calcoffsets(); +} + static void match(void) { + if (qalc.enable) { + match_qalc(); + return; + } + static char **tokv = NULL; static int tokn = 0; @@ -555,6 +631,9 @@ static void keypress(XKeyEvent *ev) { break; } + if (qalc.enable) + send_qalc(); + draw: drawmenu(); } @@ -603,35 +682,50 @@ static void readstdin(void) { static void run(void) { XEvent ev; - while (!XNextEvent(dpy, &ev)) { - if (XFilterEvent(&ev, win)) - continue; - switch (ev.type) { - case DestroyNotify: - if (ev.xdestroywindow.window != win) - break; - cleanup(); - exit(1); - case Expose: - if (ev.xexpose.count == 0) - drw_map(drw, win, 0, 0, mw, mh); - break; - case FocusIn: - /* regrab focus from parent window */ - if (ev.xfocus.window != win) - grabfocus(); - break; - case KeyPress: - keypress(&ev.xkey); - break; - case SelectionNotify: - if (ev.xselection.property == utf8) - paste(); - break; - case VisibilityNotify: - if (ev.xvisibility.state != VisibilityUnobscured) - XRaiseWindow(dpy, win); - break; + fd_set rfds; + int xfd = ConnectionNumber(dpy); + + for (;;) { + FD_ZERO(&rfds); + FD_SET(xfd, &rfds); + FD_SET(qalc.out[0], &rfds); + + if (select(MAX(xfd, qalc.out[0]) + 1, &rfds, NULL, NULL, NULL) > 0) { + if (qalc.enable && FD_ISSET(qalc.out[0], &rfds)) { + recv_qalc(); + drawmenu(); + } + while (XPending(dpy) && !XNextEvent(dpy, &ev)) { + if (XFilterEvent(&ev, win)) + continue; + switch (ev.type) { + case DestroyNotify: + if (ev.xdestroywindow.window != win) + break; + cleanup(); + exit(1); + case Expose: + if (ev.xexpose.count == 0) + drw_map(drw, win, 0, 0, mw, mh); + break; + case FocusIn: + /* regrab focus from parent window */ + if (ev.xfocus.window != win) + grabfocus(); + break; + case KeyPress: + keypress(&ev.xkey); + break; + case SelectionNotify: + if (ev.xselection.property == utf8) + paste(); + break; + case VisibilityNotify: + if (ev.xvisibility.state != VisibilityUnobscured) + XRaiseWindow(dpy, win); + break; + } + } } } } @@ -682,7 +776,8 @@ static void setup(void) { i = j; } } - /* no focused window is on screen, so use pointer location instead */ + /* no focused window is on screen, so use pointer location instead + */ if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) for (i = 0; i < n; i++) @@ -755,7 +850,7 @@ static void setup(void) { } static void usage(void) { - die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + die("usage: dmenu [-bCfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" " [-nb color] [-nf color] [-sb color] [-sf color] [-w " "windowid]"); } @@ -771,6 +866,8 @@ int main(int argc, char *argv[]) { exit(0); } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ topbar = 0; + else if (!strcmp(argv[i], "-C")) /* grabs keyboard before reading stdin */ + qalc.enable = 1; else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ fast = 1; else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */ @@ -829,7 +926,10 @@ int main(int argc, char *argv[]) { die("pledge"); #endif - if (fast && !isatty(0)) { + if (qalc.enable) { + init_qalc(); + grabkeyboard(); + } else if (fast && !isatty(0)) { grabkeyboard(); readstdin(); } else { diff --git a/dmenu/patches/dmenu-qalc-5.2.diff b/dmenu/patches/dmenu-qalc-5.2.diff new file mode 100644 index 0000000..37653f8 --- /dev/null +++ b/dmenu/patches/dmenu-qalc-5.2.diff @@ -0,0 +1,259 @@ +diff -up dmenu-5.2/config.mk dmenu-qalc-5.2/config.mk +--- dmenu-5.2/config.mk 2022-10-04 13:36:58.000000000 -0400 ++++ dmenu-qalc-5.2/config.mk 2023-10-27 19:29:48.197693355 -0400 +@@ -24,7 +24,7 @@ INCS = -I$(X11INC) -I$(FREETYPEINC) + LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) + + # flags +-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) ++CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) + CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS) + LDFLAGS = $(LIBS) + +diff -up dmenu-5.2/dmenu.1 dmenu-qalc-5.2/dmenu.1 +--- dmenu-5.2/dmenu.1 2022-10-04 13:36:58.000000000 -0400 ++++ dmenu-qalc-5.2/dmenu.1 2023-10-27 19:28:48.676578875 -0400 +@@ -40,6 +40,9 @@ which lists programs in the user's $PATH + .B \-b + dmenu appears at the bottom of the screen. + .TP ++.B \-C ++dmenu becomes a calculator. ++.TP + .B \-f + dmenu grabs the keyboard before reading stdin if not reading from a tty. This + is faster, but will lock up X until stdin reaches end\-of\-file. +diff -up dmenu-5.2/dmenu.c dmenu-qalc-5.2/dmenu.c +--- dmenu-5.2/dmenu.c 2022-10-04 13:36:58.000000000 -0400 ++++ dmenu-qalc-5.2/dmenu.c 2023-10-27 20:00:21.438467597 -0400 +@@ -7,6 +7,11 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + + #include + #include +@@ -34,6 +39,12 @@ struct item { + int out; + }; + ++static struct { ++ pid_t pid; ++ int enable, in[2], out[2]; ++ char buf[256]; ++} qalc; ++ + static char text[BUFSIZ] = ""; + static char *embed; + static int bh, mw, mh; +@@ -228,8 +239,81 @@ grabkeyboard(void) + } + + static void ++init_qalc(void) ++{ ++ pipe(qalc.in); ++ pipe2(qalc.out, O_NONBLOCK); ++ qalc.pid = fork(); ++ if (qalc.pid == -1) ++ die("failed to fork for qalc"); ++ if (qalc.pid == 0) { ++ dup2(qalc.in[0], STDIN_FILENO); ++ dup2(qalc.out[1], STDOUT_FILENO); ++ close(qalc.in[1]); ++ close(qalc.out[0]); ++ prctl(PR_SET_PDEATHSIG, SIGTERM); ++ execl("/usr/bin/qalc", "qalc", "-c0", "-t", NULL); ++ die ("execl qalc failed"); ++ } else { // parent ++ close(qalc.in[0]); ++ close(qalc.out[1]); ++ items = malloc(sizeof(struct item)*2); ++ items[0].text = malloc(LENGTH(qalc.buf)); ++ strcpy(items[0].text, "no result"); ++ items[1].out = 0; ++ items[1].text = NULL; ++ } ++} ++ ++static void ++recv_qalc(void) ++{ ++ ssize_t r = read(qalc.out[0], qalc.buf, LENGTH(qalc.buf)); ++ ++ if (r < 0) ++ die("error reading qalc.out"); ++ ++ if (qalc.buf[0] == '\n') { ++ int i; ++ for (i = 3; i < LENGTH(qalc.buf) && qalc.buf[i] != '\n'; ++i) ++ items[0].text[i-3] = qalc.buf[i]; ++ items[0].text[i-3] = 0; ++ if (r != LENGTH(qalc.buf)) ++ return; ++ } ++ ++ while (read(qalc.out[0], qalc.buf, LENGTH(qalc.buf)) != -1) ++ ; // empty the pipe ++ if (errno != EAGAIN && errno != EWOULDBLOCK) ++ die("error emptying qalc.out"); ++} ++ ++static void ++send_qalc(void) ++{ ++ int s = strlen(text); ++ text[s] = '\n'; ++ write(qalc.in[1], text, s+1); ++ text[s] = 0; ++} ++ ++static void ++match_qalc(void) ++{ ++ matches = matchend = NULL; ++ appenditem(items, &matches, &matchend); ++ curr = sel = matches; ++ calcoffsets(); ++} ++ ++static void + match(void) + { ++ if (qalc.enable) { ++ match_qalc(); ++ return; ++ } ++ + static char **tokv = NULL; + static int tokn = 0; + +@@ -524,6 +608,9 @@ insert: + break; + } + ++ if (qalc.enable) ++ send_qalc(); ++ + draw: + drawmenu(); + } +@@ -573,37 +660,52 @@ run(void) + { + XEvent ev; + +- while (!XNextEvent(dpy, &ev)) { +- if (XFilterEvent(&ev, win)) +- continue; +- switch(ev.type) { +- case DestroyNotify: +- if (ev.xdestroywindow.window != win) +- break; +- cleanup(); +- exit(1); +- case Expose: +- if (ev.xexpose.count == 0) +- drw_map(drw, win, 0, 0, mw, mh); +- break; +- case FocusIn: +- /* regrab focus from parent window */ +- if (ev.xfocus.window != win) +- grabfocus(); +- break; +- case KeyPress: +- keypress(&ev.xkey); +- break; +- case SelectionNotify: +- if (ev.xselection.property == utf8) +- paste(); +- break; +- case VisibilityNotify: +- if (ev.xvisibility.state != VisibilityUnobscured) +- XRaiseWindow(dpy, win); +- break; +- } +- } ++ fd_set rfds; ++ int xfd = ConnectionNumber(dpy); ++ ++ for (;;) { ++ FD_ZERO(&rfds); ++ FD_SET(xfd, &rfds); ++ FD_SET(qalc.out[0], &rfds); ++ ++ if (select(MAX(xfd, qalc.out[0])+1, &rfds, NULL, NULL, NULL) > 0) { ++ if (qalc.enable && FD_ISSET(qalc.out[0], &rfds)) { ++ recv_qalc(); ++ drawmenu(); ++ } ++ while (XPending(dpy) && !XNextEvent(dpy, &ev)) { ++ if (XFilterEvent(&ev, win)) ++ continue; ++ switch(ev.type) { ++ case DestroyNotify: ++ if (ev.xdestroywindow.window != win) ++ break; ++ cleanup(); ++ exit(1); ++ case Expose: ++ if (ev.xexpose.count == 0) ++ drw_map(drw, win, 0, 0, mw, mh); ++ break; ++ case FocusIn: ++ /* regrab focus from parent window */ ++ if (ev.xfocus.window != win) ++ grabfocus(); ++ break; ++ case KeyPress: ++ keypress(&ev.xkey); ++ break; ++ case SelectionNotify: ++ if (ev.xselection.property == utf8) ++ paste(); ++ break; ++ case VisibilityNotify: ++ if (ev.xvisibility.state != VisibilityUnobscured) ++ XRaiseWindow(dpy, win); ++ break; ++ } ++ } ++ } ++ } + } + + static void +@@ -710,7 +812,7 @@ setup(void) + static void + usage(void) + { +- die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" ++ die("usage: dmenu [-bCfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); + } + +@@ -727,6 +829,8 @@ main(int argc, char *argv[]) + exit(0); + } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ + topbar = 0; ++ else if (!strcmp(argv[i], "-C")) /* grabs keyboard before reading stdin */ ++ qalc.enable = 1; + else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ + fast = 1; + else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ +@@ -777,7 +881,10 @@ main(int argc, char *argv[]) + die("pledge"); + #endif + +- if (fast && !isatty(0)) { ++ if (qalc.enable) { ++ init_qalc(); ++ grabkeyboard(); ++ } else if (fast && !isatty(0)) { + grabkeyboard(); + readstdin(); + } else { diff --git a/dwm/config.def.h b/dwm/config.def.h index 31a82aa..abb5b51 100644 --- a/dwm/config.def.h +++ b/dwm/config.def.h @@ -88,6 +88,10 @@ static const char *nextcmd[] = {"adb", "shell", "input", "keyevent", "87", NULL}; static const char *previouscmd[] = {"adb", "shell", "input", "keyevent", "88", NULL}; +static const char *qalccmd[] = { + "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", + col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", + col_gray4, "-C", "-l", "1", NULL}; static const Key keys[] = { /* modifier key function argument */ @@ -126,6 +130,7 @@ static const Key keys[] = { {MODKEY | ShiftMask, XK_n, spawn, {.v = nextcmd}}, {MODKEY | ShiftMask, XK_p, spawn, {.v = previouscmd}}, {MODKEY, XK_s, spawn, {.v = adbscreencmd}}, + {MODKEY, XK_c, spawn, {.v = qalccmd}}, }; /* button definitions */ diff --git a/dwm/config.h b/dwm/config.h index 31a82aa..abb5b51 100644 --- a/dwm/config.h +++ b/dwm/config.h @@ -88,6 +88,10 @@ static const char *nextcmd[] = {"adb", "shell", "input", "keyevent", "87", NULL}; static const char *previouscmd[] = {"adb", "shell", "input", "keyevent", "88", NULL}; +static const char *qalccmd[] = { + "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", + col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", + col_gray4, "-C", "-l", "1", NULL}; static const Key keys[] = { /* modifier key function argument */ @@ -126,6 +130,7 @@ static const Key keys[] = { {MODKEY | ShiftMask, XK_n, spawn, {.v = nextcmd}}, {MODKEY | ShiftMask, XK_p, spawn, {.v = previouscmd}}, {MODKEY, XK_s, spawn, {.v = adbscreencmd}}, + {MODKEY, XK_c, spawn, {.v = qalccmd}}, }; /* button definitions */ -- cgit v1.2.3