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;