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;