sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit 41a6f1fc48b828be0f509752a49dcdc5b17e90f7
parent 5c92f82b2cfa18c2c4d2495c21e58e11784070d6
Author: Justinas Grigas <dev@jstnas.com>
Date:   Mon, 17 Jun 2024 01:43:03 +0100

dmenu(qalc): update to 5.3

the main motivation behind the new patch is to prevent dmenu hanging
when qalc is not installed. This is done by using poll instead of
select.

Diffstat:
Atools.suckless.org/dmenu/patches/qalc/dmenu-qalc-5.3.diff | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools.suckless.org/dmenu/patches/qalc/index.md | 30+++++++++++++++++++++---------
2 files changed, 286 insertions(+), 9 deletions(-)

diff --git a/tools.suckless.org/dmenu/patches/qalc/dmenu-qalc-5.3.diff b/tools.suckless.org/dmenu/patches/qalc/dmenu-qalc-5.3.diff @@ -0,0 +1,265 @@ +From 1e5ee55ff70ca7abcc8c223ae34ff5b94e0a647d Mon Sep 17 00:00:00 2001 +From: Justinas Grigas <dev@jstnas.com> +Date: Sat, 15 Jun 2024 21:13:12 +0100 +Subject: [PATCH] qalc: calculator mode + +Updates over previous patch: +- add flag to manpage synopsis. +- uses poll instead of select (prevents hang when qalc is not installed). +- follow suckless style. +- qalc function names start with qalc. +--- + dmenu.1 | 5 +- + dmenu.c | 160 +++++++++++++++++++++++++++++++++++++++++++++----------- + 2 files changed, 133 insertions(+), 32 deletions(-) + +diff --git a/dmenu.1 b/dmenu.1 +index 323f93c..ee5ca31 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -3,7 +3,7 @@ + dmenu \- dynamic menu + .SH SYNOPSIS + .B dmenu +-.RB [ \-bfiv ] ++.RB [ \-bCfiv ] + .RB [ \-l + .IR lines ] + .RB [ \-m +@@ -40,6 +40,9 @@ which lists programs in the user's $PATH and runs the result in their $SHELL. + .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 --git a/dmenu.c b/dmenu.c +index 40f93e0..67b7f02 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -7,6 +7,11 @@ + #include <strings.h> + #include <time.h> + #include <unistd.h> ++#include <errno.h> ++#include <fcntl.h> ++#include <poll.h> ++#include <signal.h> ++#include <sys/prctl.h> + + #include <X11/Xlib.h> + #include <X11/Xatom.h> +@@ -33,6 +38,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; +@@ -226,9 +237,78 @@ grabkeyboard(void) + die("cannot grab keyboard"); + } + ++static void ++qalc_init(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 ++qalc_recv(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 ++qalc_send(void) ++{ ++ int s = strlen(text); ++ text[s] = '\n'; ++ write(qalc.in[1], text, s + 1); ++ text[s] = 0; ++} ++ ++static void ++qalc_match(void) ++{ ++ matches = matchend = NULL; ++ appenditem(items, &matches, &matchend); ++ curr = sel = matches; ++ calcoffsets(); ++} ++ + static void + match(void) + { ++ if (qalc.enable) { ++ qalc_match(); ++ return; ++ } + static char **tokv = NULL; + static int tokn = 0; + +@@ -523,6 +603,9 @@ insert: + break; + } + ++ if (qalc.enable) ++ qalc_send(); ++ + draw: + drawmenu(); + } +@@ -576,36 +659,46 @@ 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) ++ int xfd = ConnectionNumber(dpy); ++ struct pollfd fds[] = { ++ {xfd, POLLIN, 0}, ++ {qalc.out[0], POLLIN, 0}, ++ }; ++ while (poll(fds, 2, -1) > 0) { ++ if (qalc.enable && fds[1].revents & POLLIN) { ++ qalc_recv(); ++ 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; +- 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; ++ 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; ++ } + } + } + } +@@ -715,7 +808,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]"); + } + +@@ -732,6 +825,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")) /* enable calculator */ ++ 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 */ +@@ -782,7 +877,10 @@ main(int argc, char *argv[]) + die("pledge"); + #endif + +- if (fast && !isatty(0)) { ++ if (qalc.enable) { ++ qalc_init(); ++ grabkeyboard(); ++ } else if (fast && !isatty(0)) { + grabkeyboard(); + readstdin(); + } else { +-- +2.45.2 + diff --git a/tools.suckless.org/dmenu/patches/qalc/index.md b/tools.suckless.org/dmenu/patches/qalc/index.md @@ -1,11 +1,23 @@ -qalc -================== -This patch adds an additional flag to dmenu, -C, which turns the app into a calculator, à la rofi-calc. The feedback is very smooth and the result of the equation is updated every time a key is pressed. This patch requires the *qalculate* CLI tool to be installed in /usr/bin/. For more info on its capabilities and syntax, visit <https://qalculate.github.io/>. +# qalc -Download --------- -* [dmenu-qalc-5.2.diff](dmenu-qalc-5.2.diff) +## Description -Author ------- -* woland <w3323421@gmail.com> +Add a calculator mode to dmenu using `qalc`. +Uses `poll` to update result on key press for smooth feedback. + +## Notes + +- Enable calculator mode using `-C` flag. +- Make sure to install qalculate CLI tool `qalc`. +- For more info on `qalc` capabilities and syntax, visit + <https://qalculate.github.io/>. + +## Download + +- [dmenu-qalc-5.2.diff](./dmenu-qalc-5.2.diff) +- [dmenu-qalc-5.3.diff](./dmenu-qalc-5.2.diff) + +## Authors + +- woland <w3323421@gmail.com> +- Justinas Grigas <dev@jstnas.com> (5.3)