dwm-betterswallow-20250116-89eeca1.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dwm-betterswallow-20250116-89eeca1.diff (8161B)
       ---
            1 diff -up -x dwm -x '*.o' -x compile_commands.json dwm-6.3-orig/config.mk dwm-6.3/config.mk
            2 --- dwm-6.3-orig/config.mk        2024-06-25 01:55:26.769203813 +0200
            3 +++ dwm-6.3/config.mk        2024-12-15 01:12:39.132847648 +0100
            4 @@ -24,6 +24,8 @@ FREETYPEINC = /usr/include/freetype2
            5  INCS = -I${X11INC} -I${FREETYPEINC}
            6  LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
            7  
            8 +LIBS += -lXRes
            9 +
           10  # flags
           11  CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
           12  #CFLAGS   = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
           13 diff -up -x dwm -x '*.o' -x compile_commands.json dwm-6.3-orig/dwm.c dwm-6.3/dwm.c
           14 --- dwm-6.3-orig/dwm.c        2024-06-25 01:55:26.771203825 +0200
           15 +++ dwm-6.3/dwm.c        2025-01-16 21:07:02.942737362 +0100
           16 @@ -40,6 +40,7 @@
           17  #include <X11/extensions/Xinerama.h>
           18  #endif /* XINERAMA */
           19  #include <X11/Xft/Xft.h>
           20 +#include <X11/extensions/XRes.h>
           21  
           22  #include "drw.h"
           23  #include "util.h"
           24 @@ -49,7 +50,7 @@
           25  #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
           26  #define INTERSECT(x,y,w,h,m)    (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
           27                                 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
           28 -#define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
           29 +#define ISVISIBLE(C)            (C->swallowed == NULL && (C->tags & C->mon->tagset[C->mon->seltags]))
           30  #define LENGTH(X)               (sizeof X / sizeof X[0])
           31  #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
           32  #define WIDTH(X)                ((X)->w + 2 * (X)->bw)
           33 @@ -93,6 +94,11 @@ struct Client {
           34          int bw, oldbw;
           35          unsigned int tags;
           36          int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
           37 +
           38 +        Client *swallower;
           39 +        Client *swallowed;
           40 +        Client *next_swallowed;
           41 +
           42          Client *next;
           43          Client *snext;
           44          Monitor *mon;
           45 @@ -141,6 +147,12 @@ typedef struct {
           46          int monitor;
           47  } Rule;
           48  
           49 +typedef struct SwallowDef {
           50 +        pid_t pid;
           51 +        Client *swallower;
           52 +        struct SwallowDef *next;
           53 +} SwallowDef;
           54 +
           55  /* function declarations */
           56  static void applyrules(Client *c);
           57  static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
           58 @@ -260,6 +272,8 @@ static void (*handler[LASTEvent]) (XEven
           59          [PropertyNotify] = propertynotify,
           60          [UnmapNotify] = unmapnotify
           61  };
           62 +static Atom swallow_atom;
           63 +static SwallowDef *swallowlist;
           64  static Atom wmatom[WMLast], netatom[NetLast];
           65  static int running = 1;
           66  static Cur *cursor[CurLast];
           67 @@ -400,6 +414,69 @@ arrangemon(Monitor *m)
           68                  m->lt[m->sellt]->arrange(m);
           69  }
           70  
           71 +pid_t
           72 +wintopid(Window window) {
           73 +  XResClientIdSpec spec;
           74 +  spec.client = window;
           75 +  spec.mask = XRES_CLIENT_ID_XID;
           76 +
           77 +  long count;
           78 +  XResClientIdValue *output;
           79 +  XResQueryClientIds(dpy, 1, &spec, &count, &output);
           80 +
           81 +  pid_t pid = -1;
           82 +
           83 +  for (int i = 0; i < count; ++i)
           84 +    if (output[i].spec.mask == XRES_CLIENT_ID_PID_MASK) {
           85 +      pid = *(pid_t *)output[i].value;
           86 +      break;
           87 +    }
           88 +
           89 +  XResClientIdsDestroy(count, output);
           90 +
           91 +  return pid;
           92 +}
           93 +
           94 +void
           95 +copyclientpos(Client *dst, Client *src) {
           96 +        dst->bw = src->bw;
           97 +        resizeclient(dst, src->x, src->y, src->w, src->h);
           98 +        dst->oldx = src->oldx;
           99 +        dst->oldy = src->oldy;
          100 +        dst->oldw = src->oldw;
          101 +        dst->oldh = src->oldh;
          102 +        dst->oldbw = src->oldbw;
          103 +        dst->oldstate = src->oldstate;
          104 +        dst->isfullscreen = src->isfullscreen;
          105 +        dst->isfloating = src->isfloating;
          106 +        dst->tags = src->tags;
          107 +        dst->mon = src->mon;
          108 +}
          109 +
          110 +void
          111 +checkswallowed(Client *c) {
          112 +        pid_t pid = wintopid(c->win);
          113 +
          114 +        if(pid < 0) return;
          115 +        for(SwallowDef *sd = swallowlist; sd != NULL; sd = sd->next) {
          116 +                if(pid == sd->pid) {
          117 +                        c->swallower = sd->swallower;
          118 +                        copyclientpos(c, sd->swallower);
          119 +
          120 +                        c->next_swallowed = c->swallower->swallowed;
          121 +                        c->swallower->swallowed = c;
          122 +
          123 +                        c->next = c->swallower->next;
          124 +                        c->swallower->next = c;
          125 +
          126 +                        c->snext = c->swallower->snext;
          127 +                        c->swallower->snext = c;
          128 +
          129 +                        return;
          130 +                }
          131 +        }
          132 +}
          133 +
          134  void
          135  attach(Client *c)
          136  {
          137 @@ -526,7 +603,15 @@ clientmessage(XEvent *e)
          138          } else if (cme->message_type == netatom[NetActiveWindow]) {
          139                  if (c != selmon->sel && !c->isurgent)
          140                          seturgent(c, 1);
          141 +        } else if(cme->message_type == swallow_atom) {
          142 +                SwallowDef *node = ecalloc(1, sizeof(SwallowDef));
          143 +                node->pid = cme->data.l[0];
          144 +                node->swallower = c;
          145 +                node->next = swallowlist;
          146 +                swallowlist = node;
          147 +                return;
          148          }
          149 +
          150  }
          151  
          152  void
          153 @@ -1052,6 +1137,7 @@ manage(Window w, XWindowAttributes *wa)
          154          c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
          155                  && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
          156          c->bw = borderpx;
          157 +        checkswallowed(c);
          158  
          159          wc.border_width = c->bw;
          160          XConfigureWindow(dpy, w, CWBorderWidth, &wc);
          161 @@ -1066,8 +1152,10 @@ manage(Window w, XWindowAttributes *wa)
          162                  c->isfloating = c->oldstate = trans != None || c->isfixed;
          163          if (c->isfloating)
          164                  XRaiseWindow(dpy, c->win);
          165 -        attach(c);
          166 -        attachstack(c);
          167 +        if(!c->swallower) {
          168 +                attach(c);
          169 +                attachstack(c);
          170 +        }
          171          XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
          172                  (unsigned char *) &(c->win), 1);
          173          XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
          174 @@ -1164,6 +1252,10 @@ movemouse(const Arg *arg)
          175                  case Expose:
          176                  case MapRequest:
          177                          handler[ev.type](&ev);
          178 +
          179 +                        // A MapRequest could've caused the current window to swallow another one.
          180 +                        if(c->swallowed)
          181 +                                c = c->swallowed;
          182                          break;
          183                  case MotionNotify:
          184                          if ((ev.xmotion.time - lasttime) <= (1000 / 60))
          185 @@ -1318,6 +1410,9 @@ resizemouse(const Arg *arg)
          186                  case Expose:
          187                  case MapRequest:
          188                          handler[ev.type](&ev);
          189 +
          190 +                        if(c->swallowed)
          191 +                                c = c->swallowed;
          192                          break;
          193                  case MotionNotify:
          194                          if ((ev.xmotion.time - lasttime) <= (1000 / 60))
          195 @@ -1566,6 +1661,7 @@ setup(void)
          196          netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
          197          netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
          198          netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
          199 +        swallow_atom = XInternAtom(dpy, "_BETTER_SWALLOW", False);
          200          /* init cursors */
          201          cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
          202          cursor[CurResize] = drw_cur_create(drw, XC_sizing);
          203 @@ -1583,6 +1679,8 @@ setup(void)
          204                  PropModeReplace, (unsigned char *) &wmcheckwin, 1);
          205          XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
          206                  PropModeReplace, (unsigned char *) "dwm", 3);
          207 +        XChangeProperty(dpy, root, swallow_atom, utf8string, 8,
          208 +                PropModeReplace, (unsigned char *) "supported", 9);
          209          XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
          210                  PropModeReplace, (unsigned char *) &wmcheckwin, 1);
          211          /* EWMH support per view */
          212 @@ -1766,11 +1864,55 @@ unfocus(Client *c, int setfocus)
          213  }
          214  
          215  void
          216 +deleteswallower(Client *c) {
          217 +        SwallowDef **prevnext = &swallowlist;
          218 +        for(SwallowDef *sd = swallowlist; sd != NULL;) {
          219 +                if(sd->swallower == c) {
          220 +                        SwallowDef *next = sd->next;
          221 +                        *prevnext = next;
          222 +                        free(sd);
          223 +                        sd = next;
          224 +                } else {
          225 +                        prevnext = &sd->next;
          226 +                        sd = sd->next;
          227 +                }
          228 +        }
          229 +
          230 +        Client *sw = c->swallowed;
          231 +        while(sw) {
          232 +                sw->swallower = NULL;
          233 +                Client *next = sw->next_swallowed;
          234 +                 sw->next_swallowed = NULL;
          235 +                sw = next;
          236 +        }
          237 +}
          238 +
          239 +void
          240  unmanage(Client *c, int destroyed)
          241  {
          242          Monitor *m = c->mon;
          243          XWindowChanges wc;
          244  
          245 +        if(c->swallower) {
          246 +                Client **prev = &c->swallower->swallowed;
          247 +                for(; *prev != c; prev = &(*prev)->next_swallowed)
          248 +                        ;
          249 +                *prev = c->next_swallowed;
          250 +                c->next_swallowed = NULL;
          251 +
          252 +                if(c->swallower->swallowed == NULL) {
          253 +                        detach(c->swallower);
          254 +                        detachstack(c->swallower);
          255 +
          256 +                        c->swallower->next = c->next;
          257 +                        c->next = c->swallower;
          258 +                        c->swallower->snext = c->snext;
          259 +                        c->snext = c->swallower;
          260 +
          261 +                        copyclientpos(c->swallower, c);
          262 +                }
          263 +        }
          264 +
          265          detach(c);
          266          detachstack(c);
          267          if (!destroyed) {
          268 @@ -1783,9 +1925,10 @@ unmanage(Client *c, int destroyed)
          269                  XSync(dpy, False);
          270                  XSetErrorHandler(xerror);
          271                  XUngrabServer(dpy);
          272 -        }
          273 +        } else deleteswallower(c);
          274 +        if(c->swallower) focus(c->swallower);
          275 +        else focus(NULL);
          276          free(c);
          277 -        focus(NULL);
          278          updateclientlist();
          279          arrange(m);
          280  }