tabbed-unix-socket-control-20240319.diff - sites - public wiki contents of suckless.org
(HTM) git clone git://git.suckless.org/sites
(DIR) Log
(DIR) Files
(DIR) Refs
---
tabbed-unix-socket-control-20240319.diff (10135B)
---
1 diff --git a/Makefile b/Makefile
2 index 54ba350..049a086 100644
3 --- a/Makefile
4 +++ b/Makefile
5 @@ -10,7 +10,7 @@ DOCPREFIX = ${PREFIX}/share/doc/${NAME}
6
7 # use system flags.
8 TABBED_CFLAGS = -I/usr/X11R6/include -I/usr/include/freetype2 ${CFLAGS}
9 -TABBED_LDFLAGS = -L/usr/X11R6/lib -lX11 -lfontconfig -lXft ${LDFLAGS}
10 +TABBED_LDFLAGS = -L/usr/X11R6/lib -lX11 -lfontconfig -lXft -lpthread ${LDFLAGS}
11 TABBED_CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700L
12
13 # OpenBSD (uncomment)
14 diff --git a/config.def.h b/config.def.h
15 index 51bb13d..2c0f3fd 100644
16 --- a/config.def.h
17 +++ b/config.def.h
18 @@ -32,35 +32,3 @@ static Bool npisrelative = False;
19 p, winid, NULL \
20 } \
21 }
22 -
23 -#define MODKEY ControlMask
24 -static const Key keys[] = {
25 - /* modifier key function argument */
26 - { MODKEY|ShiftMask, XK_Return, focusonce, { 0 } },
27 - { MODKEY|ShiftMask, XK_Return, spawn, { 0 } },
28 -
29 - { MODKEY|ShiftMask, XK_l, rotate, { .i = +1 } },
30 - { MODKEY|ShiftMask, XK_h, rotate, { .i = -1 } },
31 - { MODKEY|ShiftMask, XK_j, movetab, { .i = -1 } },
32 - { MODKEY|ShiftMask, XK_k, movetab, { .i = +1 } },
33 - { MODKEY, XK_Tab, rotate, { .i = 0 } },
34 -
35 - { MODKEY, XK_grave, spawn, SETPROP("_TABBED_SELECT_TAB") },
36 - { MODKEY, XK_1, move, { .i = 0 } },
37 - { MODKEY, XK_2, move, { .i = 1 } },
38 - { MODKEY, XK_3, move, { .i = 2 } },
39 - { MODKEY, XK_4, move, { .i = 3 } },
40 - { MODKEY, XK_5, move, { .i = 4 } },
41 - { MODKEY, XK_6, move, { .i = 5 } },
42 - { MODKEY, XK_7, move, { .i = 6 } },
43 - { MODKEY, XK_8, move, { .i = 7 } },
44 - { MODKEY, XK_9, move, { .i = 8 } },
45 - { MODKEY, XK_0, move, { .i = 9 } },
46 -
47 - { MODKEY, XK_q, killclient, { 0 } },
48 -
49 - { MODKEY, XK_u, focusurgent, { 0 } },
50 - { MODKEY|ShiftMask, XK_u, toggle, { .v = (void*) &urgentswitch } },
51 -
52 - { 0, XK_F11, fullscreen, { 0 } },
53 -};
54 diff --git a/tabbed.c b/tabbed.c
55 index 81be5e4..47de28b 100644
56 --- a/tabbed.c
57 +++ b/tabbed.c
58 @@ -2,8 +2,12 @@
59 * See LICENSE file for copyright and license details.
60 */
61
62 +#include <sys/socket.h>
63 +#include <sys/un.h>
64 #include <sys/wait.h>
65 +#include <fcntl.h>
66 #include <locale.h>
67 +#include <pthread.h>
68 #include <signal.h>
69 #include <stdarg.h>
70 #include <stdio.h>
71 @@ -47,6 +51,10 @@
72 #define LENGTH(x) (sizeof((x)) / sizeof(*(x)))
73 #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
74 #define TEXTW(x) (textnw(x, strlen(x)) + dc.font.height)
75 +#define streq(s1, s2) (strcmp((s1), (s2)) == 0)
76 +
77 +/* UNIX Socket settings */
78 +#define SOCKET_PATH_TPL "/tmp/tabbed_%s-socket"
79
80 enum { ColFG, ColBG, ColLast }; /* color */
81 enum { WMProtocols, WMDelete, WMName, WMState, WMFullscreen,
82 @@ -57,13 +65,6 @@ typedef union {
83 const void *v;
84 } Arg;
85
86 -typedef struct {
87 - unsigned int mod;
88 - KeySym keysym;
89 - void (*func)(const Arg *);
90 - const Arg arg;
91 -} Key;
92 -
93 typedef struct {
94 int x, y, w, h;
95 XftColor norm[ColLast];
96 @@ -111,6 +112,7 @@ static int getclient(Window w);
97 static XftColor getcolor(const char *colstr);
98 static int getfirsttab(void);
99 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
100 +static void handle_message(char *msg, int msg_len, FILE *rsp, int sock_fd);
101 static void initfont(const char *fontstr);
102 static Bool isprotodel(int c);
103 static void keypress(const XEvent *e);
104 @@ -119,6 +121,7 @@ static void manage(Window win);
105 static void maprequest(const XEvent *e);
106 static void move(const Arg *arg);
107 static void movetab(const Arg *arg);
108 +static void process_message(char **args, int num, FILE *rsp, int sock_fd);
109 static void propertynotify(const XEvent *e);
110 static void resize(int c, int w, int h);
111 static void rotate(const Arg *arg);
112 @@ -148,7 +151,6 @@ static void (*handler[LASTEvent]) (const XEvent *) = {
113 [DestroyNotify] = destroynotify,
114 [Expose] = expose,
115 [FocusIn] = focusin,
116 - [KeyPress] = keypress,
117 [MapRequest] = maprequest,
118 [PropertyNotify] = propertynotify,
119 };
120 @@ -169,6 +171,8 @@ static char winid[64];
121 static char **cmd;
122 static char *wmname = "tabbed";
123 static const char *geometry;
124 +static int sock_fd = -1;
125 +static char socket_path[256];
126
127 char *argv0;
128
129 @@ -228,6 +232,9 @@ cleanup(void)
130 XDestroyWindow(dpy, win);
131 XSync(dpy, False);
132 free(cmd);
133 +
134 + close(sock_fd);
135 + unlink(socket_path);
136 }
137
138 void
139 @@ -657,22 +664,6 @@ isprotodel(int c)
140 return ret;
141 }
142
143 -void
144 -keypress(const XEvent *e)
145 -{
146 - const XKeyEvent *ev = &e->xkey;
147 - unsigned int i;
148 - KeySym keysym;
149 -
150 - keysym = XkbKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0, 0);
151 - for (i = 0; i < LENGTH(keys); i++) {
152 - if (keysym == keys[i].keysym &&
153 - CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) &&
154 - keys[i].func)
155 - keys[i].func(&(keys[i].arg));
156 - }
157 -}
158 -
159 void
160 killclient(const Arg *arg)
161 {
162 @@ -713,16 +704,6 @@ manage(Window w)
163 StructureNotifyMask | EnterWindowMask);
164 XSync(dpy, False);
165
166 - for (i = 0; i < LENGTH(keys); i++) {
167 - if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) {
168 - for (j = 0; j < LENGTH(modifiers); j++) {
169 - XGrabKey(dpy, code, keys[i].mod |
170 - modifiers[j], w, True,
171 - GrabModeAsync, GrabModeAsync);
172 - }
173 - }
174 - }
175 -
176 c = ecalloc(1, sizeof *c);
177 c->win = w;
178
179 @@ -919,6 +900,152 @@ rotate(const Arg *arg)
180 }
181 }
182
183 +void
184 +handle_message(char *msg, int msg_len, FILE *rsp, int sock_fd)
185 +{
186 + int cap = 8;
187 + int num = 0;
188 + char **args = calloc(cap, sizeof(char *));
189 +
190 + if (args == NULL) {
191 + perror("Handle message: calloc");
192 + return;
193 + }
194 +
195 + for (int i = 0, j = 0; i < msg_len; i++) {
196 + if (msg[i] == 0) {
197 + args[num++] = msg + j;
198 + j = i + 1;
199 + }
200 + if (num >= cap) {
201 + cap *= 2;
202 + char **new = realloc(args, cap * sizeof(char *));
203 + if (new == NULL) {
204 + free(args);
205 + perror("Handle message: realloc");
206 + return;
207 + } else {
208 + args = new;
209 + }
210 + }
211 + }
212 +
213 + if (num < 1) {
214 + free(args);
215 + perror("No arguments given.");
216 + return;
217 + }
218 +
219 + char **args_orig = args;
220 + process_message(args, num, rsp, sock_fd);
221 + free(args_orig);
222 +}
223 +
224 +void
225 +process_message(char **args, int num, FILE *rsp, int sock_fd)
226 +{
227 + char buf[256];
228 + Arg arg;
229 + if (streq("rotate", *args)) {
230 + if (num == 2) {
231 + args++;
232 + arg.i = atoi(*args);
233 + rotate(&arg);
234 + } else {
235 + arg.i = 1;
236 + rotate(&arg);
237 + }
238 + } else if (streq("movetab", *args)) {
239 + if (num == 2) {
240 + args++;
241 + arg.i = atoi(*args);
242 + movetab(&arg);
243 + }
244 + } else if (streq("move", *args)) {
245 + if (num == 2) {
246 + args++;
247 + arg.i = atoi(*args);
248 + move(&arg);
249 + }
250 + } else if (streq("toggle", *args)) {
251 + arg.v = (void*)&urgentswitch;
252 + toggle(&arg);
253 + } else if (streq("killclient", *args)) {
254 + arg.i = 0;
255 + killclient(&arg);
256 + } else if (streq("focusonce", *args)) {
257 + arg.i = 0;
258 + focusonce(&arg);
259 + } else if (streq("focusurgent", *args)) {
260 + arg.i = 0;
261 + focusurgent(&arg);
262 + } else if (streq("spawn", *args)) {
263 + arg.i = 0;
264 + spawn(&arg);
265 + } else if (streq("fullscreen", *args)) {
266 + arg.i = 0;
267 + fullscreen(&arg);
268 + } else if (streq("isfirst", *args)) {
269 + if (sel == 0) {
270 + write(sock_fd, "1", 1);
271 + } else {
272 + write(sock_fd, "0", 1);
273 + }
274 + } else if (streq("islast", *args)) {
275 + if (nclients > 0 && sel == (nclients-1)) {
276 + write(sock_fd, "1", 1);
277 + } else {
278 + write(sock_fd, "0", 1);
279 + }
280 + } else if (streq("isempty", *args)) {
281 + if (nclients == 0) {
282 + write(sock_fd, "1", 1);
283 + } else {
284 + write(sock_fd, "0", 1);
285 + }
286 + } else if (streq("totaltabs", *args)) {
287 + if (nclients > 0) {
288 + snprintf(buf, sizeof(buf), "%d", nclients);
289 + write(sock_fd, buf, strlen(buf));
290 + } else {
291 + write(sock_fd, "0", 1);
292 + }
293 + } else if (streq("tabnumber", *args)) {
294 + snprintf(buf, sizeof(buf), "%d", sel);
295 + write(sock_fd, buf, strlen(buf));
296 + }
297 + fflush(rsp);
298 + fclose(rsp);
299 +}
300 +
301 +void *
302 +socket_run(void *vargp)
303 +{
304 + fd_set descriptors;
305 + int cli_fd, n;
306 + char msg[BUFSIZ] = {0};
307 +
308 + while (running) {
309 + FD_ZERO(&descriptors);
310 + FD_SET(sock_fd, &descriptors);
311 +
312 + if (FD_ISSET(sock_fd, &descriptors)) {
313 + cli_fd = accept(sock_fd, NULL, 0);
314 + if (cli_fd > 0 && (n = recv(cli_fd, msg, sizeof(msg)-1, 0)) > 0) {
315 + msg[n] = '\0';
316 + FILE *rsp = fdopen(cli_fd, "w");
317 + if (rsp != NULL) {
318 + handle_message(msg, n, rsp, cli_fd);
319 + } else {
320 + fprintf(stderr, "warn: Can't open the client socket as file.\n");
321 + }
322 + close(cli_fd);
323 + }
324 + }
325 + }
326 + return NULL;
327 +}
328 +
329 void
330 run(void)
331 {
332 @@ -930,6 +1057,9 @@ run(void)
333 if (doinitspawn == True)
334 spawn(NULL);
335
336 + pthread_t thread_id;
337 + pthread_create(&thread_id, NULL, socket_run, NULL);
338 +
339 while (running) {
340 XNextEvent(dpy, &ev);
341 if (handler[ev.type])
342 @@ -1083,6 +1213,35 @@ setup(void)
343
344 nextfocus = foreground;
345 focus(-1);
346 +
347 + /* Setup UNIX socket */
348 + struct sockaddr_un sock_address;
349 + if (sock_fd == -1) {
350 + snprintf(socket_path, sizeof(socket_path), SOCKET_PATH_TPL, winid);
351 +
352 + sock_address.sun_family = AF_UNIX;
353 + if (snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", socket_path) < 0) {
354 + fprintf(stderr, "Couldn't write the socket path.\n");
355 + }
356 +
357 + sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
358 +
359 + if (sock_fd == -1) {
360 + fprintf(stderr, "Couldn't create the socket.\n");
361 + }
362 +
363 + unlink(socket_path);
364 +
365 + if (bind(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) {
366 + fprintf(stderr, "Couldn't bind a name to the socket.\n");
367 + }
368 +
369 + if (listen(sock_fd, SOMAXCONN) == -1) {
370 + fprintf(stderr, "Couldn't listen to the socket.\n");
371 + }
372 + }
373 +
374 + fcntl(sock_fd, F_SETFD, FD_CLOEXEC | fcntl(sock_fd, F_GETFD));
375 }
376
377 void
378 @@ -1286,6 +1445,8 @@ main(int argc, char *argv[])
379 int replace = 0;
380 char *pstr;
381
382 + XInitThreads();
383 +
384 ARGBEGIN {
385 case 'c':
386 closelastclient = True;