dmenu-qalc-5.3.diff (6137B)
1 From 1e5ee55ff70ca7abcc8c223ae34ff5b94e0a647d Mon Sep 17 00:00:00 2001 2 From: Justinas Grigas <dev@jstnas.com> 3 Date: Sat, 15 Jun 2024 21:13:12 +0100 4 Subject: [PATCH] qalc: calculator mode 5 6 Updates over previous patch: 7 - add flag to manpage synopsis. 8 - uses poll instead of select (prevents hang when qalc is not installed). 9 - follow suckless style. 10 - qalc function names start with qalc. 11 --- 12 dmenu.1 | 5 +- 13 dmenu.c | 160 +++++++++++++++++++++++++++++++++++++++++++++----------- 14 2 files changed, 133 insertions(+), 32 deletions(-) 15 16 diff --git a/dmenu.1 b/dmenu.1 17 index 323f93c..ee5ca31 100644 18 --- a/dmenu.1 19 +++ b/dmenu.1 20 @@ -3,7 +3,7 @@ 21 dmenu \- dynamic menu 22 .SH SYNOPSIS 23 .B dmenu 24 -.RB [ \-bfiv ] 25 +.RB [ \-bCfiv ] 26 .RB [ \-l 27 .IR lines ] 28 .RB [ \-m 29 @@ -40,6 +40,9 @@ which lists programs in the user's $PATH and runs the result in their $SHELL. 30 .B \-b 31 dmenu appears at the bottom of the screen. 32 .TP 33 +.B \-C 34 +dmenu becomes a calculator. 35 +.TP 36 .B \-f 37 dmenu grabs the keyboard before reading stdin if not reading from a tty. This 38 is faster, but will lock up X until stdin reaches end\-of\-file. 39 diff --git a/dmenu.c b/dmenu.c 40 index 40f93e0..67b7f02 100644 41 --- a/dmenu.c 42 +++ b/dmenu.c 43 @@ -7,6 +7,11 @@ 44 #include <strings.h> 45 #include <time.h> 46 #include <unistd.h> 47 +#include <errno.h> 48 +#include <fcntl.h> 49 +#include <poll.h> 50 +#include <signal.h> 51 +#include <sys/prctl.h> 52 53 #include <X11/Xlib.h> 54 #include <X11/Xatom.h> 55 @@ -33,6 +38,12 @@ struct item { 56 int out; 57 }; 58 59 +static struct { 60 + pid_t pid; 61 + int enable, in[2], out[2]; 62 + char buf[256]; 63 +} qalc; 64 + 65 static char text[BUFSIZ] = ""; 66 static char *embed; 67 static int bh, mw, mh; 68 @@ -226,9 +237,78 @@ grabkeyboard(void) 69 die("cannot grab keyboard"); 70 } 71 72 +static void 73 +qalc_init(void) 74 +{ 75 + pipe(qalc.in); 76 + pipe2(qalc.out, O_NONBLOCK); 77 + qalc.pid = fork(); 78 + if (qalc.pid == -1) 79 + die("failed to fork for qalc"); 80 + if (qalc.pid == 0) { 81 + dup2(qalc.in[0], STDIN_FILENO); 82 + dup2(qalc.out[1], STDOUT_FILENO); 83 + close(qalc.in[1]); 84 + close(qalc.out[0]); 85 + prctl(PR_SET_PDEATHSIG, SIGTERM); 86 + execl("/usr/bin/qalc", "qalc", "-c0", "-t", NULL); 87 + die("execl qalc failed"); 88 + } else { /* parent */ 89 + close(qalc.in[0]); 90 + close(qalc.out[1]); 91 + items = malloc(sizeof(struct item) * 2); 92 + items[0].text = malloc(LENGTH(qalc.buf)); 93 + strcpy(items[0].text, "no result"); 94 + items[1].out = 0; 95 + items[1].text = NULL; 96 + } 97 +} 98 + 99 +static void 100 +qalc_recv(void) 101 +{ 102 + ssize_t r = read(qalc.out[0], qalc.buf, LENGTH(qalc.buf)); 103 + if (r < 0) 104 + die("error reading qalc.out"); 105 + if (qalc.buf[0] == '\n') { 106 + int i; 107 + for (i = 3; i < LENGTH(qalc.buf) && qalc.buf[i] != '\n'; ++i) 108 + items[0].text[i - 3] = qalc.buf[i]; 109 + items[0].text[i - 3] = 0; 110 + if (r != LENGTH(qalc.buf)) 111 + return; 112 + } 113 + while (read(qalc.out[0], qalc.buf, LENGTH(qalc.buf)) != -1) 114 + ; /* empty the pipe */ 115 + if (errno != EAGAIN && errno != EWOULDBLOCK) 116 + die("error emptying qalc.out"); 117 +} 118 + 119 +static void 120 +qalc_send(void) 121 +{ 122 + int s = strlen(text); 123 + text[s] = '\n'; 124 + write(qalc.in[1], text, s + 1); 125 + text[s] = 0; 126 +} 127 + 128 +static void 129 +qalc_match(void) 130 +{ 131 + matches = matchend = NULL; 132 + appenditem(items, &matches, &matchend); 133 + curr = sel = matches; 134 + calcoffsets(); 135 +} 136 + 137 static void 138 match(void) 139 { 140 + if (qalc.enable) { 141 + qalc_match(); 142 + return; 143 + } 144 static char **tokv = NULL; 145 static int tokn = 0; 146 147 @@ -523,6 +603,9 @@ insert: 148 break; 149 } 150 151 + if (qalc.enable) 152 + qalc_send(); 153 + 154 draw: 155 drawmenu(); 156 } 157 @@ -576,36 +659,46 @@ static void 158 run(void) 159 { 160 XEvent ev; 161 - 162 - while (!XNextEvent(dpy, &ev)) { 163 - if (XFilterEvent(&ev, win)) 164 - continue; 165 - switch(ev.type) { 166 - case DestroyNotify: 167 - if (ev.xdestroywindow.window != win) 168 + int xfd = ConnectionNumber(dpy); 169 + struct pollfd fds[] = { 170 + {xfd, POLLIN, 0}, 171 + {qalc.out[0], POLLIN, 0}, 172 + }; 173 + while (poll(fds, 2, -1) > 0) { 174 + if (qalc.enable && fds[1].revents & POLLIN) { 175 + qalc_recv(); 176 + drawmenu(); 177 + } 178 + while (XPending(dpy) && !XNextEvent(dpy, &ev)) { 179 + if (XFilterEvent(&ev, win)) 180 + continue; 181 + switch (ev.type) { 182 + case DestroyNotify: 183 + if (ev.xdestroywindow.window != win) 184 + break; 185 + cleanup(); 186 + exit(1); 187 + case Expose: 188 + if (ev.xexpose.count == 0) 189 + drw_map(drw, win, 0, 0, mw, mh); 190 break; 191 - cleanup(); 192 - exit(1); 193 - case Expose: 194 - if (ev.xexpose.count == 0) 195 - drw_map(drw, win, 0, 0, mw, mh); 196 - break; 197 - case FocusIn: 198 - /* regrab focus from parent window */ 199 - if (ev.xfocus.window != win) 200 - grabfocus(); 201 - break; 202 - case KeyPress: 203 - keypress(&ev.xkey); 204 - break; 205 - case SelectionNotify: 206 - if (ev.xselection.property == utf8) 207 - paste(); 208 - break; 209 - case VisibilityNotify: 210 - if (ev.xvisibility.state != VisibilityUnobscured) 211 - XRaiseWindow(dpy, win); 212 - break; 213 + case FocusIn: 214 + /* regrab focus from parent window */ 215 + if (ev.xfocus.window != win) 216 + grabfocus(); 217 + break; 218 + case KeyPress: 219 + keypress(&ev.xkey); 220 + break; 221 + case SelectionNotify: 222 + if (ev.xselection.property == utf8) 223 + paste(); 224 + break; 225 + case VisibilityNotify: 226 + if (ev.xvisibility.state != VisibilityUnobscured) 227 + XRaiseWindow(dpy, win); 228 + break; 229 + } 230 } 231 } 232 } 233 @@ -715,7 +808,7 @@ setup(void) 234 static void 235 usage(void) 236 { 237 - die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" 238 + die("usage: dmenu [-bCfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" 239 " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); 240 } 241 242 @@ -732,6 +825,8 @@ main(int argc, char *argv[]) 243 exit(0); 244 } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ 245 topbar = 0; 246 + else if (!strcmp(argv[i], "-C")) /* enable calculator */ 247 + qalc.enable = 1; 248 else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ 249 fast = 1; 250 else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ 251 @@ -782,7 +877,10 @@ main(int argc, char *argv[]) 252 die("pledge"); 253 #endif 254 255 - if (fast && !isatty(0)) { 256 + if (qalc.enable) { 257 + qalc_init(); 258 + grabkeyboard(); 259 + } else if (fast && !isatty(0)) { 260 grabkeyboard(); 261 readstdin(); 262 } else { 263 -- 264 2.45.2 265