commit 41a6f1fc48b828be0f509752a49dcdc5b17e90f7
Author: Justinas Grigas <[email protected]>
Date:   Mon Jun 17 01:43:03 2024 +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.

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
new file mode 100644
index 00000000..94a34179
--- /dev/null
+++ 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 <[email protected]>
+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] == '
') {
++              int i;
++              for (i = 3; i < LENGTH(qalc.buf) && qalc.buf[i] != '
'; ++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] = '
';
++      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]
"
++      die("usage: dmenu [-bCfiv] [-l lines] [-p prompt] [-fn font] [-m 
monitor]
"
+           "             [-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
index e224a292..3048553b 100644
--- 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 <[email protected]>
+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 <[email protected]>
+- Justinas Grigas <[email protected]> (5.3)


Reply via email to