dwm-swallow-20200522-7accbcf.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dwm-swallow-20200522-7accbcf.diff (10221B)
       ---
            1 From 7accbcf7db35995d4c26c5cd69338aafa6feb89a Mon Sep 17 00:00:00 2001
            2 From: wtl <wtl144000@gmail.com>
            3 Date: Fri, 22 May 2020 22:38:38 +0300
            4 Subject: [PATCH] swallow X windows from the terminal
            5 
            6 ---
            7  config.def.h |   9 ++-
            8  config.mk    |   2 +-
            9  dwm.c        | 218 +++++++++++++++++++++++++++++++++++++++++++++++++--
           10  3 files changed, 220 insertions(+), 9 deletions(-)
           11 
           12 diff --git a/config.def.h b/config.def.h
           13 index 1c0b587..4c0b25c 100644
           14 --- a/config.def.h
           15 +++ b/config.def.h
           16 @@ -3,6 +3,7 @@
           17  /* appearance */
           18  static const unsigned int borderpx  = 1;        /* border pixel of windows */
           19  static const unsigned int snap      = 32;       /* snap pixel */
           20 +static const int swallowfloating    = 0;        /* 1 means swallow floating windows by default */
           21  static const int showbar            = 1;        /* 0 means no bar */
           22  static const int topbar             = 1;        /* 0 means bottom bar */
           23  static const char *fonts[]          = { "monospace:size=10" };
           24 @@ -26,9 +27,11 @@ static const Rule rules[] = {
           25           *        WM_CLASS(STRING) = instance, class
           26           *        WM_NAME(STRING) = title
           27           */
           28 -        /* class      instance    title       tags mask     isfloating   monitor */
           29 -        { "Gimp",     NULL,       NULL,       0,            1,           -1 },
           30 -        { "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },
           31 +        /* class     instance  title           tags mask  isfloating  isterminal  noswallow  monitor */
           32 +        { "Gimp",    NULL,     NULL,           0,         1,          0,           0,        -1 },
           33 +        { "Firefox", NULL,     NULL,           1 << 8,    0,          0,          -1,        -1 },
           34 +        { "st",      NULL,     NULL,           0,         0,          1,          -1,        -1 },
           35 +        { NULL,      NULL,     "Event Tester", 0,         1,          0,           1,        -1 }, /* xev */
           36  };
           37  
           38  /* layout(s) */
           39 diff --git a/config.mk b/config.mk
           40 index 7084c33..b77641d 100644
           41 --- a/config.mk
           42 +++ b/config.mk
           43 @@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2
           44  
           45  # includes and libs
           46  INCS = -I${X11INC} -I${FREETYPEINC}
           47 -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
           48 +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res
           49  
           50  # flags
           51  CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
           52 diff --git a/dwm.c b/dwm.c
           53 index 9fd0286..1befee4 100644
           54 --- a/dwm.c
           55 +++ b/dwm.c
           56 @@ -40,6 +40,8 @@
           57  #include <X11/extensions/Xinerama.h>
           58  #endif /* XINERAMA */
           59  #include <X11/Xft/Xft.h>
           60 +#include <X11/Xlib-xcb.h>
           61 +#include <xcb/res.h>
           62  
           63  #include "drw.h"
           64  #include "util.h"
           65 @@ -92,9 +94,11 @@ struct Client {
           66          int basew, baseh, incw, inch, maxw, maxh, minw, minh;
           67          int bw, oldbw;
           68          unsigned int tags;
           69 -        int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
           70 +        int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow;
           71 +        pid_t pid;
           72          Client *next;
           73          Client *snext;
           74 +        Client *swallowing;
           75          Monitor *mon;
           76          Window win;
           77  };
           78 @@ -138,6 +142,8 @@ typedef struct {
           79          const char *title;
           80          unsigned int tags;
           81          int isfloating;
           82 +        int isterminal;
           83 +        int noswallow;
           84          int monitor;
           85  } Rule;
           86  
           87 @@ -235,9 +241,16 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee);
           88  static int xerrorstart(Display *dpy, XErrorEvent *ee);
           89  static void zoom(const Arg *arg);
           90  
           91 +static pid_t getparentprocess(pid_t p);
           92 +static int isdescprocess(pid_t p, pid_t c);
           93 +static Client *swallowingclient(Window w);
           94 +static Client *termforwin(const Client *c);
           95 +static pid_t winpid(Window w);
           96 +
           97  /* variables */
           98  static const char broken[] = "broken";
           99  static char stext[256];
          100 +static int scanner;
          101  static int screen;
          102  static int sw, sh;           /* X display screen geometry width, height */
          103  static int bh, blw = 0;      /* bar geometry */
          104 @@ -269,6 +282,8 @@ static Drw *drw;
          105  static Monitor *mons, *selmon;
          106  static Window root, wmcheckwin;
          107  
          108 +static xcb_connection_t *xcon;
          109 +
          110  /* configuration, allows nested code to access above variables */
          111  #include "config.h"
          112  
          113 @@ -286,6 +301,7 @@ applyrules(Client *c)
          114          XClassHint ch = { NULL, NULL };
          115  
          116          /* rule matching */
          117 +        c->noswallow = -1;
          118          c->isfloating = 0;
          119          c->tags = 0;
          120          XGetClassHint(dpy, c->win, &ch);
          121 @@ -298,6 +314,8 @@ applyrules(Client *c)
          122                  && (!r->class || strstr(class, r->class))
          123                  && (!r->instance || strstr(instance, r->instance)))
          124                  {
          125 +                        c->isterminal = r->isterminal;
          126 +                        c->noswallow  = r->noswallow;
          127                          c->isfloating = r->isfloating;
          128                          c->tags |= r->tags;
          129                          for (m = mons; m && m->num != r->monitor; m = m->next);
          130 @@ -414,6 +432,61 @@ attachstack(Client *c)
          131          c->mon->stack = c;
          132  }
          133  
          134 +void
          135 +swallow(Client *p, Client *c)
          136 +{
          137 +        Client *s;
          138 +
          139 +        if (c->noswallow > 0 || c->isterminal)
          140 +                return;
          141 +        if (c->noswallow < 0 && !swallowfloating && c->isfloating)
          142 +                return;
          143 +
          144 +        detach(c);
          145 +        detachstack(c);
          146 +
          147 +        setclientstate(c, WithdrawnState);
          148 +        XUnmapWindow(dpy, p->win);
          149 +
          150 +        p->swallowing = c;
          151 +        c->mon = p->mon;
          152 +
          153 +        Window w = p->win;
          154 +        p->win = c->win;
          155 +        c->win = w;
          156 +
          157 +        XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace,
          158 +                (unsigned char *) &(p->win), 1);
          159 +
          160 +        updatetitle(p);
          161 +        s = scanner ? c : p;
          162 +        XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h);
          163 +        arrange(p->mon);
          164 +        configure(p);
          165 +        updateclientlist();
          166 +}
          167 +
          168 +void
          169 +unswallow(Client *c)
          170 +{
          171 +        c->win = c->swallowing->win;
          172 +
          173 +        free(c->swallowing);
          174 +        c->swallowing = NULL;
          175 +
          176 +        XDeleteProperty(dpy, c->win, netatom[NetClientList]);
          177 +
          178 +        /* unfullscreen the client */
          179 +        setfullscreen(c, 0);
          180 +        updatetitle(c);
          181 +        arrange(c->mon);
          182 +        XMapWindow(dpy, c->win);
          183 +        XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
          184 +        setclientstate(c, NormalState);
          185 +        focus(NULL);
          186 +        arrange(c->mon);
          187 +}
          188 +
          189  void
          190  buttonpress(XEvent *e)
          191  {
          192 @@ -653,6 +726,9 @@ destroynotify(XEvent *e)
          193  
          194          if ((c = wintoclient(ev->window)))
          195                  unmanage(c, 1);
          196 +
          197 +        else if ((c = swallowingclient(ev->window)))
          198 +                unmanage(c->swallowing, 1);
          199  }
          200  
          201  void
          202 @@ -1018,12 +1094,13 @@ killclient(const Arg *arg)
          203  void
          204  manage(Window w, XWindowAttributes *wa)
          205  {
          206 -        Client *c, *t = NULL;
          207 +        Client *c, *t = NULL, *term = NULL;
          208          Window trans = None;
          209          XWindowChanges wc;
          210  
          211          c = ecalloc(1, sizeof(Client));
          212          c->win = w;
          213 +        c->pid = winpid(w);
          214          /* geometry */
          215          c->x = c->oldx = wa->x;
          216          c->y = c->oldy = wa->y;
          217 @@ -1038,6 +1115,7 @@ manage(Window w, XWindowAttributes *wa)
          218          } else {
          219                  c->mon = selmon;
          220                  applyrules(c);
          221 +                term = termforwin(c);
          222          }
          223  
          224          if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
          225 @@ -1074,6 +1152,8 @@ manage(Window w, XWindowAttributes *wa)
          226          c->mon->sel = c;
          227          arrange(c->mon);
          228          XMapWindow(dpy, c->win);
          229 +        if (term)
          230 +                swallow(term, c);
          231          focus(NULL);
          232  }
          233  
          234 @@ -1384,7 +1464,9 @@ run(void)
          235  void
          236  scan(void)
          237  {
          238 +        scanner = 1;
          239          unsigned int i, num;
          240 +        char swin[256];
          241          Window d1, d2, *wins = NULL;
          242          XWindowAttributes wa;
          243  
          244 @@ -1395,6 +1477,8 @@ scan(void)
          245                                  continue;
          246                          if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
          247                                  manage(wins[i], &wa);
          248 +                        else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin))
          249 +                                manage(wins[i], &wa);
          250                  }
          251                  for (i = 0; i < num; i++) { /* now the transients */
          252                          if (!XGetWindowAttributes(dpy, wins[i], &wa))
          253 @@ -1406,6 +1490,7 @@ scan(void)
          254                  if (wins)
          255                          XFree(wins);
          256          }
          257 +        scanner = 0;
          258  }
          259  
          260  void
          261 @@ -1768,6 +1853,20 @@ unmanage(Client *c, int destroyed)
          262          Monitor *m = c->mon;
          263          XWindowChanges wc;
          264  
          265 +        if (c->swallowing) {
          266 +                unswallow(c);
          267 +                return;
          268 +        }
          269 +
          270 +        Client *s = swallowingclient(c->win);
          271 +        if (s) {
          272 +                free(s->swallowing);
          273 +                s->swallowing = NULL;
          274 +                arrange(m);
          275 +                focus(NULL);
          276 +                return;
          277 +        }
          278 +
          279          detach(c);
          280          detachstack(c);
          281          if (!destroyed) {
          282 @@ -1782,9 +1881,12 @@ unmanage(Client *c, int destroyed)
          283                  XUngrabServer(dpy);
          284          }
          285          free(c);
          286 -        focus(NULL);
          287 -        updateclientlist();
          288 -        arrange(m);
          289 +
          290 +        if (!s) {
          291 +                arrange(m);
          292 +                focus(NULL);
          293 +                updateclientlist();
          294 +        }
          295  }
          296  
          297  void
          298 @@ -2047,6 +2149,110 @@ view(const Arg *arg)
          299          arrange(selmon);
          300  }
          301  
          302 +pid_t
          303 +winpid(Window w)
          304 +{
          305 +        pid_t result = 0;
          306 +
          307 +        xcb_res_client_id_spec_t spec = {0};
          308 +        spec.client = w;
          309 +        spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID;
          310 +
          311 +        xcb_generic_error_t *e = NULL;
          312 +        xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec);
          313 +        xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e);
          314 +
          315 +        if (!r)
          316 +                return (pid_t)0;
          317 +
          318 +        xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r);
          319 +        for (; i.rem; xcb_res_client_id_value_next(&i)) {
          320 +                spec = i.data->spec;
          321 +                if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {
          322 +                        uint32_t *t = xcb_res_client_id_value_value(i.data);
          323 +                        result = *t;
          324 +                        break;
          325 +                }
          326 +        }
          327 +
          328 +        free(r);
          329 +
          330 +        if (result == (pid_t)-1)
          331 +                result = 0;
          332 +        return result;
          333 +}
          334 +
          335 +pid_t
          336 +getparentprocess(pid_t p)
          337 +{
          338 +        unsigned int v = 0;
          339 +
          340 +#if defined(__linux__)
          341 +        FILE *f;
          342 +        char buf[256];
          343 +        snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
          344 +
          345 +        if (!(f = fopen(buf, "r")))
          346 +                return (pid_t)0;
          347 +
          348 +        if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1)
          349 +                v = (pid_t)0;
          350 +        fclose(f);
          351 +#elif defined(__FreeBSD__)
          352 +        struct kinfo_proc *proc = kinfo_getproc(p);
          353 +        if (!proc)
          354 +                return (pid_t)0;
          355 +
          356 +        v = proc->ki_ppid;
          357 +        free(proc);
          358 +#endif
          359 +        return (pid_t)v;
          360 +}
          361 +
          362 +int
          363 +isdescprocess(pid_t p, pid_t c)
          364 +{
          365 +        while (p != c && c != 0)
          366 +                c = getparentprocess(c);
          367 +
          368 +        return (int)c;
          369 +}
          370 +
          371 +Client *
          372 +termforwin(const Client *w)
          373 +{
          374 +        Client *c;
          375 +        Monitor *m;
          376 +
          377 +        if (!w->pid || w->isterminal)
          378 +                return NULL;
          379 +
          380 +        for (m = mons; m; m = m->next) {
          381 +                for (c = m->clients; c; c = c->next) {
          382 +                        if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
          383 +                                return c;
          384 +                }
          385 +        }
          386 +
          387 +        return NULL;
          388 +}
          389 +
          390 +Client *
          391 +swallowingclient(Window w)
          392 +{
          393 +        Client *c;
          394 +        Monitor *m;
          395 +
          396 +        for (m = mons; m; m = m->next) {
          397 +                for (c = m->clients; c; c = c->next) {
          398 +                        if (c->swallowing && c->swallowing->win == w)
          399 +                                return c;
          400 +                }
          401 +        }
          402 +
          403 +        return NULL;
          404 +}
          405 +
          406  Client *
          407  wintoclient(Window w)
          408  {
          409 @@ -2138,6 +2344,8 @@ main(int argc, char *argv[])
          410                  fputs("warning: no locale support\n", stderr);
          411          if (!(dpy = XOpenDisplay(NULL)))
          412                  die("dwm: cannot open display");
          413 +        if (!(xcon = XGetXCBConnection(dpy)))
          414 +                die("dwm: cannot get xcb connection\n");
          415          checkotherwm();
          416          setup();
          417  #ifdef __OpenBSD__
          418 -- 
          419 2.26.2
          420