commit dd0bc95

wf  ·  2026-04-01 00:07:34 +0000 UTC
parent 9191525
Finally fix IPC
9 files changed,  +198, -174
M README
M howl.c
M ipc.c
D util.c
+3, -3
 1@@ -1,14 +1,14 @@
 2 CC        ?= cc
 3-CFLAGS    := -std=c99 -Wall -Wimplicit-function-declaration -O3 -pedantic
 4+CFLAGS    := -std=c99 -Wall -Wimplicit-function-declaration -O0 -g -pedantic
 5 LDFLAGS   := `pkg-config --cflags --libs swc` -Iinclude
 6 LDLIBS    := `pkg-config --libs swc`
 7 PREFIX    ?= /usr/local
 8 
 9 howl      := howl
10-howl_src  := ipc.c log.c util.c howl.c
11+howl_src  := ipc.c log.c howl.c
12 
13 howlc     := howlc
14-howlc_src := ipc.c util.c client.c
15+howlc_src := ipc.c client.c
16 
17 .PHONY: all install uninstall clean
18 
M README
+0, -1
1@@ -13,7 +13,6 @@ dependencies
2 todo
3 ----
4 
5- - make sense of IPC
6  - titlebars(?), keybindings
7  - allow for more scriptability, assign pseudorandom IDs to windows etc.
8  - document IPC interface
+51, -7
 1@@ -1,4 +1,5 @@
 2 #include <stdio.h>
 3+#include <stdlib.h>
 4 #include <string.h>
 5 #include <unistd.h>
 6 #include <sys/socket.h>
 7@@ -8,16 +9,49 @@
 8 #include "types.h"
 9 #include "ipc.h"
10 
11+struct command {
12+	const char *name;
13+	enum cmd id;
14+	int argc;
15+	bool config;
16+};
17+
18+static const struct command commands[] = {
19+	{ "move",     cmd_move,     2, false },
20+	{ "resize",   cmd_resize,   2, false },
21+	{ "teleport", cmd_teleport, 4, false },
22+	{ "center",   cmd_center,   0, false },
23+	{ "hide",     cmd_hide,     0, false },
24+	{ "show",     cmd_show,     0, false },
25+	{ "close",    cmd_close,    0, false },
26+	{ "geometry", cmd_geometry, 0, false },
27+	{ "pid",      cmd_pid,      0, false },
28+	{ "title",    cmd_title,    0, false },
29+	{ "appid",    cmd_app_id,   0, false },
30+
31+	{ "focus_color",   cmd_focus_color,   1, true },
32+	{ "unfocus_color", cmd_unfocus_color, 1, true },
33+	{ "border_width",  cmd_border_width,  1, true },
34+};
35+
36+static char *
37+int_str(int i) {
38+	const size_t len = 4 * sizeof(int);
39+	char t[len];
40+	snprintf(t, len, "%d", i);
41+	return t;
42+}
43+
44 static void
45-ipc_msg(char **cmd) {
46+ipc_msg(const struct command *cmd, int argc, char **argv) {
47 	struct sockaddr_un addr;
48-	char msg[256];
49+	char msg[256] = "", *data[8];
50 
51 	memset(&addr, 0, sizeof(struct sockaddr_un));
52 	addr.sun_family = AF_UNIX;
53 	strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path) - 1);
54 
55-	cfd = socket(AF_UNIX, SOCK_STREAM, 0);
56+	cfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
57 	if (cfd == -1) {
58 		perror("couldn't open IPC socket");
59 		return;
60@@ -29,10 +63,20 @@ ipc_msg(char **cmd) {
61 		return;
62 	}
63 
64-	snprintf(msg, sizeof(msg), "%s", cmd[0]);
65-	for (int i = 1; cmd[i] != NULL; i++) {
66+	if (cmd->config) {
67+		data[0] = int_str(cmd_config);
68+		data[1] = int_str(cmd->id);
69+	} else {
70+		data[0] = int_str(cmd->id);
71+	}
72+
73+	for (int i = 0; i < argc - 2; i++)
74+		data[i + (cmd->config ? 2 : 1)] = argv[i + 2];
75+
76+	msg[0] = '\0';
77+	for (int i = 0; data[i] != NULL; i++) {
78 		strcat(msg, " ");
79-		strcat(msg, cmd[i]);
80+		strcat(msg, data[i]);
81 	}
82 
83 	if (send(cfd, msg, strlen(msg), 0) == -1) {
84@@ -55,7 +99,7 @@ main(int argc, char **argv) {
85 				fprintf(stderr, "wrong number of arguments for %s (need %d)\n", commands[i].name, commands[i].argc);
86 				return 1;
87 			}
88-			ipc_msg(argv + 1);
89+			ipc_msg(&commands[i], argc, argv + 1);
90 			return 0;
91 		}
92 	}
M howl.c
+36, -30
  1@@ -13,6 +13,7 @@
  2 #include <swc.h>
  3 
  4 #include "howl.h"
  5+#include "types.h"
  6 #include "ipc.h"
  7 
  8 static void new_screen(struct swc_screen *);
  9@@ -21,7 +22,19 @@ static void on_win_destroy(void *);
 10 static void on_win_entered(void *);
 11 static void on_scr_destroy(void *);
 12 static bool is_ws_client(const struct client *, const struct screen *);
 13-static void reload_config(void);
 14+
 15+extern void ipc_move(char **);
 16+extern void ipc_resize(char **);
 17+extern void ipc_teleport(char **);
 18+extern void ipc_center(char **);
 19+extern void ipc_hide(char **);
 20+extern void ipc_show(char **);
 21+extern void ipc_close(char **);
 22+extern void ipc_get_geometry(char **);
 23+extern void ipc_get_pid(char **);
 24+extern void ipc_get_title(char **);
 25+extern void ipc_get_app_id(char **);
 26+extern void ipc_config(char **);
 27 
 28 bool have_config = true;
 29 struct wm wm;
 30@@ -41,6 +54,22 @@ static struct swc_screen_handler scr_handler = {
 31 	.destroy = on_scr_destroy
 32 };
 33 
 34+typedef void (*cmd_handler_t)(char **);
 35+static const cmd_handler_t cmd_handler [cmd_last] = {
 36+	[cmd_move]     = ipc_move,
 37+	[cmd_resize]   = ipc_resize,
 38+	[cmd_teleport] = ipc_teleport,
 39+	[cmd_center]   = ipc_center,
 40+	[cmd_hide]     = ipc_hide,
 41+	[cmd_show]     = ipc_show,
 42+	[cmd_close]    = ipc_close,
 43+	[cmd_geometry] = ipc_get_geometry,
 44+	[cmd_pid]      = ipc_get_pid,
 45+	[cmd_title]    = ipc_get_title,
 46+	[cmd_app_id]   = ipc_get_app_id,
 47+	[cmd_config]   = ipc_config
 48+};
 49+
 50 static int
 51 handler(int fd, uint32_t mask, void *data) {
 52 	UNUSED(data);
 53@@ -97,14 +126,11 @@ handler(int fd, uint32_t mask, void *data) {
 54 
 55 				if (argc == 0) return 0;
 56 
 57-				for (int i = 0; i < (sizeof commands / sizeof commands[0]); i++) {			
 58-					if (strcmp(commands[i].name, argv[0]) == 0) {
 59-						commands[i].fn(argv + 1);
 60-						if (commands[i].config) reload_config();
 61-						return 0;
 62-					}
 63-				}
 64-				_wrn("no such command %s", argv[0]);
 65+				int cmd = atoi(argv[0]);
 66+				void *fn = cmd_handler[cmd];
 67+				if (!fn) _wrn("no such command %s", argv[0]);
 68+	
 69+				cmd_handler[cmd](argv);
 70 			}
 71 			close(afd);
 72 			return 0;
 73@@ -118,7 +144,7 @@ static void
 74 setup_ipc(void) {
 75 	struct sockaddr_un addr;
 76 
 77-	sfd = socket(AF_UNIX, SOCK_STREAM, 0);
 78+	sfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 79 	if (sfd == -1)
 80 		_err(1, "couldn't open IPC socket: %s", strerror(errno));
 81 
 82@@ -155,26 +181,6 @@ load_config(char *conf_path) {
 83 	}
 84 }
 85 
 86-static void
 87-reload_config(void) {
 88-	struct client *c;
 89-
 90-	wl_list_for_each(c, &wm.clients, link) {
 91-		if (c == wm.cur)
 92-			swc_window_set_border(
 93-				c->win,
 94-				config.focus_color, config.border_width,
 95-				0, 0
 96-			);
 97-		else
 98-			swc_window_set_border(
 99-				c->win,
100-				config.unfocus_color, config.border_width,
101-				0, 0
102-			);
103-	}
104-}
105-
106 static void
107 setup(void) {
108 	wm.dpy = wl_display_create();
+0, -4
1@@ -14,8 +14,4 @@ extern void _inf(const char *, ...);
2 extern void _wrn(const char *, ...);
3 extern void _err(int, const char *, ...);
4 
5-extern int      str_int(char *);
6-extern uint32_t str_uint(char *);
7-extern uint32_t str_color(char *);
8-
9 #endif /* HOWL_H */
+17, -38
 1@@ -1,44 +1,23 @@
 2 #ifndef IPC_H
 3 #define IPC_H
 4 
 5-#include "howl.h"
 6-#include "types.h"
 7-
 8-extern int do_move(char **);
 9-extern int do_resize(char **);
10-extern int do_teleport(char **);
11-extern int do_center(char **);
12-extern int do_hide(char **);
13-extern int do_show(char **);
14-extern int do_close(char **);
15-extern int do_title(char **);
16-
17-extern int get_geometry(char **);
18-extern int get_pid(char **);
19-extern int get_title(char **);
20-extern int get_app_id(char **);
21-
22-extern int ipc_focus_color(char **);
23-extern int ipc_unfocus_color(char **);
24-extern int ipc_border_width(char **);
25-
26-static const struct command commands[] = {
27-	{ "move",      2,  false,  do_move      },
28-	{ "resize",    2,  false,  do_resize    },
29-	{ "teleport",  4,  false,  do_teleport  },
30-	{ "center",    0,  false,  do_center    },
31-	{ "hide",      0,  false,  do_hide      },
32-	{ "show",      0,  false,  do_show      },
33-	{ "close",     0,  false,  do_close     },
34-	{ "geometry",  0,  false,  get_geometry },
35-	{ "pid",       0,  false,  get_pid      },
36-	{ "title",     0,  false,  get_title    },
37-	{ "app_id",    0,  false,  get_app_id   },
38-
39-	/* configuration */
40-	{ "focus_color",   1,  true,  ipc_focus_color   },
41-	{ "unfocus_color", 1,  true,  ipc_unfocus_color },
42-	{ "border_width",  1,  true,  ipc_border_width  }
43+enum cmd {
44+	cmd_move,
45+	cmd_resize,
46+	cmd_teleport,
47+	cmd_center,
48+	cmd_hide,
49+	cmd_show,
50+	cmd_close,
51+	cmd_geometry,
52+	cmd_pid,
53+	cmd_title,
54+	cmd_app_id,
55+	cmd_config,
56+	cmd_focus_color,
57+	cmd_unfocus_color,
58+	cmd_border_width,
59+	cmd_last
60 };
61 
62 #endif /* IPC_H */
+0, -7
 1@@ -7,13 +7,6 @@
 2 #include <wayland-server.h>
 3 #include <swc.h>
 4 
 5-struct command {
 6-	const char  *name;
 7-	int         argc;
 8-	bool        config;
 9-	int         (*fn)(char **);
10-};
11-
12 struct config {
13 	uint32_t  focus_color;
14 	uint32_t  unfocus_color;
M ipc.c
+91, -65
  1@@ -11,9 +11,26 @@
  2 struct wm wm;
  3 struct config config;
  4 
  5-int
  6-do_move(char **arg) {
  7-	if (arg[0] == NULL || arg[1] == NULL) return 1;
  8+static int
  9+fn_int(char *s) {
 10+	return atoi(s);
 11+}
 12+
 13+static uint32_t
 14+fn_uint(char *s) {
 15+	return strtoul(s, NULL, 10);
 16+}
 17+
 18+static uint32_t
 19+fn_hex(char *s) {
 20+	if (s[0] == '#') s++;
 21+	return strtoul(s, NULL, 16);
 22+}
 23+
 24+void
 25+ipc_move(char **arg) {
 26+	if (arg[1] == NULL || arg[2] == NULL || !wm.cur)
 27+		return;
 28 
 29 	struct swc_rectangle geom;
 30 	if (swc_window_get_geometry(wm.cur->win, &geom)) {
 31@@ -23,13 +40,12 @@ do_move(char **arg) {
 32 		wm.cur->height = geom.height;
 33 	}
 34 
 35-	swc_window_set_position(wm.cur->win, wm.cur->x + atoi(arg[0]), wm.cur->y + atoi(arg[1]));
 36-	return 0;
 37+	swc_window_set_position(wm.cur->win, wm.cur->x + atoi(arg[1]), wm.cur->y + atoi(arg[2]));
 38 }
 39 
 40-int
 41-do_resize(char **arg) {
 42-	if (arg[0] == NULL || arg[1] == NULL) return 1;
 43+void
 44+ipc_resize(char **arg) {
 45+	if (arg[1] == NULL || arg[2] == NULL || !wm.cur) return;
 46 
 47 	struct swc_rectangle geom;
 48 	if (swc_window_get_geometry(wm.cur->win, &geom)) {
 49@@ -39,29 +55,29 @@ do_resize(char **arg) {
 50 		wm.cur->height = geom.height;
 51 	}
 52 
 53-	swc_window_set_size(wm.cur->win, wm.cur->width + strtoul(arg[0], NULL, 0), wm.cur->height + strtoul(arg[1], NULL, 0));
 54-	return 0;
 55+	swc_window_set_size(wm.cur->win, wm.cur->width + strtoul(arg[1], NULL, 0), wm.cur->height + strtoul(arg[2], NULL, 0));
 56 }
 57 
 58-int
 59-do_teleport(char **arg) {
 60-	if (arg[0] == NULL || arg[1] == NULL ||
 61-	    arg[2] == NULL || arg[3] == NULL) return 1;
 62+void
 63+ipc_teleport(char **arg) {
 64+	if (arg[1] == NULL || arg[2] == NULL ||
 65+	    arg[3] == NULL || arg[4] == NULL || !wm.cur)
 66+		return;
 67 
 68 	struct swc_rectangle rect = {
 69-		.x      = atoi(arg[0]),
 70-		.y      = atoi(arg[1]),
 71-		.width  = strtoul(arg[2], NULL, 0),
 72-		.height = strtoul(arg[3], NULL, 0)
 73+		.x      = atoi(arg[1]),
 74+		.y      = atoi(arg[2]),
 75+		.width  = strtoul(arg[3], NULL, 0),
 76+		.height = strtoul(arg[4], NULL, 0)
 77 	};
 78 
 79 	swc_window_set_geometry(wm.cur->win, &rect);
 80-	return 0;
 81 }
 82 
 83-int
 84-do_center(char **arg) {
 85+void
 86+ipc_center(char **arg) {
 87 	UNUSED(arg);
 88+	if (!wm.cur) return;
 89 
 90 	struct swc_rectangle geom;
 91 	if (swc_window_get_geometry(wm.cur->win, &geom)) {
 92@@ -76,99 +92,109 @@ do_center(char **arg) {
 93 		wm.scr->width / 2 - wm.cur->width / 2,
 94 		wm.scr->height / 2 - wm.cur->height / 2
 95 	);
 96-	return 0;
 97 }
 98 
 99-int
100-do_hide(char **arg) {
101+void
102+ipc_hide(char **arg) {
103 	UNUSED(arg);
104+	if (!wm.cur) return;
105 
106 	swc_window_hide(wm.cur->win);
107-	return 0;
108 }
109 
110-int
111-do_show(char **arg) {
112+void
113+ipc_show(char **arg) {
114 	UNUSED(arg);
115+	if (!wm.cur) return;
116 
117 	swc_window_show(wm.cur->win);
118-	return 0;
119 }
120 
121-int
122-do_close(char **arg) {
123+void
124+ipc_close(char **arg) {
125 	UNUSED(arg);
126+	if (!wm.cur) return;
127 
128 	swc_window_close(wm.cur->win);
129-	return 0;
130 }
131 
132 /*
133  * window info
134  */
135 
136-int
137-get_geometry(char **arg) {
138+void
139+ipc_get_geometry(char **arg) {
140 	UNUSED(arg);
141+	if (!wm.cur) return;
142 
143 	struct swc_rectangle geom;
144 	if (swc_window_get_geometry(wm.cur->win, &geom)) {
145 		printf("%d %d %u %u\n", geom.x, geom.y, geom.width, geom.height);  
146 		fflush(stdout);
147-		return 0;
148 	}
149-	return 1;
150 }
151 
152-int
153-get_pid(char **arg) {
154+void
155+ipc_get_pid(char **arg) {
156 	UNUSED(arg);
157+	if (!wm.cur) return;
158 
159 	pid_t pid = swc_window_get_pid(wm.cur->win);
160 	printf("%d\n", pid);
161-	return 0;
162 }
163 
164-int
165-get_title(char **arg) {
166+void
167+ipc_get_title(char **arg) {
168 	UNUSED(arg);
169+	if (!wm.cur) return;
170 
171 	printf("%s\n", wm.cur->win->title);
172-	return 0;
173 }
174 
175-int
176-get_app_id(char **arg) {
177+void
178+ipc_get_app_id(char **arg) {
179 	UNUSED(arg);
180+	if (!wm.cur) return;
181 
182 	printf("%s\n", wm.cur->win->app_id);
183-	return 0;
184 }
185 
186 /*
187  * configuration
188  */
189 
190-int
191-ipc_focus_color(char **arg) {
192-	if (arg[0] == NULL) return 1;
193-
194-	config.focus_color = str_color(arg[0]);
195-	return 0;
196-}
197-
198-int
199-ipc_unfocus_color(char **arg) {
200-	if (arg[0] == NULL) return 1;
201-
202-	config.unfocus_color = str_color(arg[0]);
203-	return 0;
204-}
205-
206-int
207-ipc_border_width(char **arg) {
208-	if (arg[0] == NULL) return 1;
209+void
210+ipc_config(char **arg) {
211+	if (arg[0] == NULL || arg[1] == NULL) return;
212+
213+	enum cmd cmd = atoi(arg[0]);
214+	switch (cmd) {
215+		case cmd_focus_color:
216+			config.focus_color = fn_hex(arg[1]);
217+			break;
218+		case cmd_unfocus_color:
219+			config.unfocus_color = fn_hex(arg[1]);
220+			break;
221+		case cmd_border_width:
222+			config.border_width = fn_int(arg[1]);
223+			break;
224+		default:
225+			break;
226+	}
227 
228-	config.border_width = str_int(arg[0]);
229-	return 0;
230+	struct client *c;
231+	wl_list_for_each(c, &wm.clients, link) {
232+		if (c == wm.cur)
233+			swc_window_set_border(
234+				c->win,
235+				config.focus_color, config.border_width,
236+				0, 0
237+			);
238+		else
239+			swc_window_set_border(
240+				c->win,
241+				config.unfocus_color, config.border_width,
242+				0, 0
243+			);
244+	}
245 }
D util.c
+0, -19
 1@@ -1,19 +0,0 @@
 2-#include <stdlib.h>
 3-#include <stdint.h>
 4-#include <string.h>
 5-
 6-int
 7-str_int(char *s) {
 8-	return atoi(s);
 9-}
10-
11-uint32_t
12-str_uint(char *s) {
13-	return strtoul(s, NULL, 0);
14-}
15-
16-uint32_t
17-str_color(char *s) {
18-	if (s[0] == '#') s++;
19-	return strtoul(s, NULL, 16); /* 16 = base16 */
20-}