commit ac24492
wf
·
2026-06-05 18:56:09 +0000 UTC
parent 19fcff6
Broken modules impl
1 files changed,
+309,
-45
+309,
-45
1@@ -2,7 +2,7 @@
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5-#include <stdint.h>
6+#include <inttypes.h>
7 #include <stdbool.h>
8 #include <getopt.h>
9 #include <signal.h>
10@@ -21,7 +21,7 @@
11 #include "xdg-shell-protocol.h"
12 #include "wlr-layer-shell-unstable-v1.h"
13
14-#define MAXMOD 3
15+#define MAXMOD 4
16
17 #define LOG(...) fprintf(stderr, "panko: " __VA_ARGS__)
18 #define ERRNUM(elem) \
19@@ -41,6 +41,12 @@ struct module {
20 int border_width;
21 uint32_t border_color;
22 } style;
23+
24+ pid_t pid;
25+ int fd;
26+ char *buf;
27+ size_t buflen;
28+ uint64_t next;
29 };
30
31 struct config {
32@@ -55,8 +61,8 @@ struct config {
33 };
34
35 struct panel {
36- struct module *parsed, modules[3][MAXMOD];
37- size_t plen, mlen;
38+ struct module **parsed, *modules[3][MAXMOD];
39+ size_t plen;
40 };
41
42 struct app {
43@@ -77,6 +83,7 @@ struct app {
44 struct wld_surface *wld_surface;
45
46 struct config config;
47+ struct panel panel;
48 };
49
50 static volatile sig_atomic_t running = 1;
51@@ -129,8 +136,105 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
52 .closed = handle_panel_close
53 };
54
55+static uint64_t
56+now_ms(void) {
57+ struct timespec ts;
58+ clock_gettime(CLOCK_MONOTONIC, &ts);
59+ return (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
60+}
61+
62 static void
63-module_add(struct module *m, int side) {
64+module_add(struct app *app, struct module *m, int side) {
65+ for (size_t i = 0; i < MAXMOD; i++) {
66+ if (app->panel.modules[side][i] == NULL) {
67+ app->panel.modules[side][i] = m;
68+ return;
69+ }
70+ }
71+ LOG("too many modules on the %s side\n",
72+ (side == SIDE_LEFT) ? "left" : (side == SIDE_MIDDLE) ? "middle" : "right");
73+}
74+
75+static bool
76+module_run(struct module *m) {
77+ if (!m->command)
78+ return false;
79+
80+ int fds[2];
81+ if (pipe(fds) < 0)
82+ return false;
83+
84+ pid_t pid = fork();
85+ if (pid < 0) {
86+ close(fds[0]);
87+ close(fds[1]);
88+ return false;
89+ }
90+
91+ if (pid == 0) {
92+ dup2(fds[1], STDOUT_FILENO);
93+ dup2(fds[1], STDERR_FILENO);
94+ close(fds[0]);
95+ close(fds[1]);
96+ execl("/bin/sh", "sh", "-c", m->command, NULL);
97+ _exit(127);
98+ }
99+
100+ close(fds[1]);
101+ m->pid = pid;
102+ m->fd = fds[0];
103+
104+ int f = fcntl(m->fd, F_GETFL, 0);
105+ if (f < 0 || fcntl(m->fd, F_SETFL, f | O_NONBLOCK) < 0) {
106+ close(m->fd);
107+ m->fd = -1;
108+ kill(m->pid, SIGTERM);
109+ m->pid = 0;
110+ return false;
111+ }
112+
113+ m->next = m->interval ? now_ms() + m->interval * 1000 : UINT64_MAX;
114+ return true;
115+}
116+
117+static void
118+module_out(struct module *m) {
119+ if (m->fd < 0)
120+ return;
121+ char buf[1024];
122+ size_t total = 0;
123+ ssize_t r = 0;
124+ char *out = NULL;
125+
126+ while ((r = read(m->fd, buf, sizeof(buf))) > 0) {
127+ char *n = realloc(out, total + r + 1);
128+ if (!n) {
129+ free(out);
130+ out = NULL;
131+ break;
132+ }
133+ out = n;
134+ memcpy(out + total, buf, r);
135+ total += r;
136+ out[total] = '\0';
137+ }
138+
139+ if (m->fd >= 0) {
140+ close(m->fd);
141+ m->fd = -1;
142+ }
143+
144+ if (out) {
145+ while (total > 0 && (out[total-1] == '\n' || out[total-1] == '\r'))
146+ out[--total] = '\0';
147+ free(m->buf);
148+ m->buf = out;
149+ m->buflen = total;
150+ } else {
151+ free(m->buf);
152+ m->buf = strdup("");
153+ m->buflen = 0;
154+ }
155 }
156
157 static bool
158@@ -230,6 +334,7 @@ parse_config(const char *path, struct app *app) {
159 struct module m = {0};
160 memset(&m, 0, sizeof(m));
161 m.name = strdup(d.params[0]);
162+ m.style.font = strdup(app->config.style.font);
163
164 struct scfg_block sub = d.children;
165 for (size_t j = 0; j < sub.directives_len; j++) {
166@@ -308,28 +413,52 @@ parse_config(const char *path, struct app *app) {
167 }
168 }
169 }
170- LOG("parsed module `%s` with command `%s`\n", m.name, m.command);
171- free(m.name);
172- free(m.command);
173- free(m.style.font);
174+
175+ struct module *new = calloc(1, sizeof(*new));
176+ if (!new) {
177+ LOG("couldn't allocate\n");
178+ if (m.name) free(m.name);
179+ if (m.command) free(m.command);
180+ if (m.style.font) free(m.style.font);
181+ scfg_block_finish(&block);
182+ return false;
183+ }
184+ *new = m;
185+
186+ app->panel.parsed = realloc(app->panel.parsed, (app->panel.plen + 1) * sizeof(*app->panel.parsed));
187+ if (!app->panel.parsed) {
188+ LOG("couldn't allocate\n");
189+ free(new);
190+ if (m.name) free(m.name);
191+ if (m.command) free(m.command);
192+ if (m.style.font) free(m.style.font);
193+ scfg_block_finish(&block);
194+ return false;
195+ }
196+ app->panel.parsed[app->panel.plen++] = new;
197 }
198
199 else if (strcmp(d.name, "modules-left") == 0 || strcmp(d.name, "modules-middle") == 0 || strcmp(d.name, "modules-right") == 0) {
200 if (d.params_len < 0) {
201 ERRNUM(d);
202 }
203- if (d.params[0][0] == '\0')
204- continue;
205-
206-#if 0
207- TODO TODO TODO TODO TODO TODO
208- for (size_t i = 0; i < app->panel.plen; i++)
209- for (size_t j = 0; j < d.params_len; j++)
210- if (strcmp(d.params[j], app->panel.parsed[i]) == 0) {
211- int side = d.params[0][8] == 'l' ? SIDE_LEFT : d.params[0][8] == 'm' ? SIDE_MIDDLE : SIDE_RIGHT;
212- module_add(&m, side);
213+ int side = (d.name[8] == 'l') ? SIDE_LEFT : (d.name[8] == 'm') ? SIDE_MIDDLE : SIDE_RIGHT;
214+ for (size_t p = 0; p < d.params_len; p++) {
215+ const char *name = d.params[p];
216+ if (name[0] == '\0')
217+ continue;
218+
219+ struct module *m = NULL;
220+ for (size_t i = 0; i < app->panel.plen; i++)
221+ if (strcmp(app->panel.parsed[i]->name, name) == 0) {
222+ m = app->panel.parsed[i];
223+ break;
224 }
225-#endif
226+
227+ if (m) module_add(app, m, side);
228+ else
229+ LOG("module `%s` referenced but not defined\n", name);
230+ }
231 }
232 }
233
234@@ -346,9 +475,17 @@ static bool
235 setup(struct app *app) {
236 memset(app, 0, sizeof(*app));
237
238- signal(SIGINT, sig_handler);
239- signal(SIGTERM, sig_handler);
240- signal(SIGQUIT, sig_handler);
241+ struct sigaction sa = {0};
242+ sa.sa_handler = sig_handler;
243+ sigemptyset(&sa.sa_mask);
244+ sa.sa_flags = 0;
245+ sigaction(SIGINT, &sa, NULL);
246+ sigaction(SIGTERM, &sa, NULL);
247+
248+ struct sigaction sa_chld = {0};
249+ sa_chld.sa_handler = SIG_IGN;
250+ sa_chld.sa_flags = SA_NOCLDWAIT;
251+ sigaction(SIGCHLD, &sa_chld, NULL);
252
253 app->dpy = wl_display_connect(NULL);
254 if (!app->dpy) {
255@@ -391,7 +528,7 @@ setup(struct app *app) {
256 zwlr_layer_surface_v1_add_listener(
257 app->layer_surface,
258 &layer_surface_listener,
259- &app
260+ NULL
261 );
262
263 if (config_path[0] == '\0') {
264@@ -454,7 +591,7 @@ setup(struct app *app) {
265
266 app->wld_font = wld_font_open_name(app->wld_fctx, app->config.style.font);
267 if (!app->wld_font) {
268- LOG("couldn't open font: %s\n", app->config.style.font);
269+ LOG("couldn't open font `%s`\n", app->config.style.font);
270 return false;
271 }
272
273@@ -466,29 +603,168 @@ setup(struct app *app) {
274 return false;
275 }
276
277+ for (size_t i = 0; i < app->panel.plen; i++) {
278+ struct module *m = app->panel.parsed[i];
279+ m->fd = -1;
280+ m->pid = 0;
281+ m->buf = NULL;
282+ m->buflen = 0;
283+ m->next = 0;
284+
285+ if (!module_run(m))
286+ LOG("failed to start module `%s`\n", m->name);
287+ }
288+
289+ return true;
290+}
291+
292+static void
293+draw(struct app *app) {
294+ uint32_t start_x[3] = {0, app->config.width / 2, app->config.width};
295+
296 wld_set_target_surface(app->wld_ren, app->wld_surface);
297 wld_fill_rectangle(app->wld_ren, app->config.style.background, 0, 0,
298 app->config.width, app->config.height);
299
300- struct wld_extents ext;
301- wld_font_text_extents(app->wld_font, "wowie zowie", &ext);
302- int y = app->config.height / 2 + app->wld_font->height / 2 - app->wld_font->descent
303- + app->config.padding[0] - app->config.padding[2];
304+ for (int s = 0; s < 3; s++) {
305+ for (size_t i = 0; i < MAXMOD; i++) {
306+ if (app->panel.modules[s][i] != NULL) {
307+ struct module *m = app->panel.modules[s][i];
308+
309+ struct wld_extents ext;
310+ wld_font_text_extents(app->wld_font, m->buf, &ext);
311+ int y = app->config.height / 2 + app->wld_font->height / 2 - app->wld_font->descent
312+ + app->config.padding[0] - app->config.padding[2];
313
314- wld_draw_text(app->wld_ren, app->wld_font, app->config.style.foreground,
315- app->config.padding[3], y, "wowie zowie", strlen("wowie zowie"), NULL);
316+ wld_draw_text(app->wld_ren, app->wld_font, app->config.style.foreground,
317+ app->config.padding[3], y, m->buf, m->buflen, NULL);
318+ }
319+ }
320+ }
321
322 wl_surface_damage(app->surface, 0, 0, app->config.width, app->config.height);
323 wld_flush(app->wld_ren);
324 wld_swap(app->wld_surface);
325+}
326
327- return true;
328+static void
329+run(struct app *app) {
330+ while (running) {
331+ uint64_t now = now_ms();
332+ int timeout = -1, count = 0;
333+
334+ for (size_t i = 0; i < app->panel.plen; i++) {
335+ struct module *m = app->panel.parsed[i];
336+ if (m->next != UINT64_MAX) {
337+ if ((int64_t)(m->next - now) <= 0)
338+ timeout = 100;
339+ else {
340+ int64_t t = (int64_t)(m->next - now);
341+ if (timeout < 0 || t < timeout)
342+ timeout = (int)t;
343+ }
344+ }
345+ if (m->fd >= 0)
346+ count++;
347+ }
348+
349+ int fds = 1 + count;
350+ struct pollfd *pfds = calloc(fds, sizeof(*pfds));
351+ if (!pfds)
352+ return;
353+
354+ int n = 0;
355+ pfds[n].fd = wl_display_get_fd(app->dpy);
356+ pfds[n].events = POLLIN;
357+ n++;
358+
359+ for (size_t i = 0; i < app->panel.plen; i++) {
360+ struct module *m = app->panel.parsed[i];
361+ if (m->fd >= 0) {
362+ pfds[n].fd = m->fd;
363+ pfds[n].events = POLLIN;
364+ n++;
365+ }
366+ }
367+
368+ wl_display_dispatch_pending(app->dpy);
369+ if (wl_display_flush(app->dpy) < 0 && errno != EAGAIN) {
370+ free(pfds);
371+ break;
372+ }
373+
374+ // int ret = poll(pfds, fds, timeout);
375+ int ret = poll(pfds, n, timeout);
376+ now = now_ms();
377+
378+ if (ret < 0) {
379+ if (errno == EINTR) {
380+ free(pfds);
381+ continue;
382+ }
383+ free(pfds);
384+ break;
385+ }
386+
387+ if (ret == 0) {
388+ for (size_t i = 0; i < app->panel.plen; i++) {
389+ struct module *m = app->panel.parsed[i];
390+ if (m->fd < 0 && m->pid == 0 && m->interval && now_ms() >= m->next)
391+ module_run(m);
392+ }
393+ free(pfds);
394+ continue;
395+ }
396+
397+ if (pfds[0].revents & POLLIN)
398+ wl_display_dispatch(app->dpy);
399+
400+ n = 1;
401+ for (size_t i = 0; i < app->panel.plen; i++) {
402+ struct module *m = app->panel.parsed[i];
403+ if (m->fd >= 0) {
404+ if (pfds[n].revents & (POLLIN | POLLHUP | POLLRDHUP)) {
405+ module_out(m);
406+ draw(app);
407+ }
408+ n++;
409+ }
410+
411+ if (m->fd < 0 && m->pid == 0 && m->interval && now >= m->next)
412+ module_run(m);
413+ }
414+
415+ free(pfds);
416+ }
417 }
418
419 static void
420 cleanup(struct app *app) {
421 if (app->config.style.font)
422 free(app->config.style.font);
423+ if (app->panel.parsed) {
424+ for (size_t i = 0; i < app->panel.plen; i++) {
425+ struct module *m = app->panel.parsed[i];
426+ if (!m) continue;
427+ if (m->pid > 0)
428+ kill(m->pid, SIGTERM);
429+ if (m->fd >= 0)
430+ close(m->fd);
431+ if (m->buf)
432+ free(m->buf);
433+ if (m->name)
434+ free(m->name);
435+ if (m->command)
436+ free(m->command);
437+ if (m->style.font)
438+ free(m->style.font);
439+ free(m);
440+ }
441+ free(app->panel.parsed);
442+ app->panel.parsed = NULL;
443+ }
444+ memset(app->panel.modules, 0, sizeof(app->panel.modules));
445+
446 if (app->wld_surface)
447 wld_destroy_surface(app->wld_surface);
448 if (app->wld_font)
449@@ -518,7 +794,6 @@ cleanup(struct app *app) {
450 int
451 main(int argc, char **argv) {
452 struct app app = {0};
453- struct pollfd pfd;
454 config_path[0] = '\0';
455
456 int opt;
457@@ -548,18 +823,7 @@ main(int argc, char **argv) {
458 if (!setup(&app))
459 goto error;
460
461- pfd.fd = wl_display_get_fd(app.dpy);
462- pfd.events = POLLIN;
463-
464- while (running) {
465- wl_display_dispatch_pending(app.dpy);
466- if (wl_display_flush(app.dpy) < 0 && errno != EAGAIN)
467- break;
468-
469- poll(&pfd, 1, -1);
470- if (pfd.revents & POLLIN)
471- wl_display_dispatch(app.dpy);
472- }
473+ run(&app);
474
475 cleanup(&app);
476 return 0;