From 2e5748edfe1129f95c7bb1bf9dd590a897f55f57 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Mon, 3 Mar 2025 21:49:52 +0100 Subject: [PATCH] swallow: rewrite patch, update README.md --- patches/swallow/README.md | 79 +++--- patches/swallow/swallow-freebsd.patch | 27 +-- patches/swallow/swallow.patch | 330 +++++++++++++++++--------- 3 files changed, 284 insertions(+), 152 deletions(-) diff --git a/patches/swallow/README.md b/patches/swallow/README.md index 27c9ab9..29b5564 100644 --- a/patches/swallow/README.md +++ b/patches/swallow/README.md @@ -1,29 +1,52 @@ -### Description -Terminals swallow windows that they are the parent of. - -foot is the terminal by default, you can change it in client rules in config.h. - -2023-08-16 and up are made to also work with x windows: https://codeberg.org/dwl/dwl/issues/331 - -for freebsd users: apply swallow-freebsd.patch **on top of** swallow.patch - -### Download -- [git branch](https://codeberg.org/notchoc/dwl/src/branch/swallow) -- [2024-07-13](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swallow/swallow.patch) +### Description + +This patch adds "window swallowing" to dwl. + +If a user runs a graphical program from the terminal (e.g., `mpv`), the terminal +will be hidden and only a window of the newly spawned graphical program will +be visible. The terminal stays hidden until the graphical program is closed. +This patch helps users spawning a lot of graphical programs from their command +line by avoiding cluttering the screen with many unusable terminals. + +`foot` is the terminal by default, you can change it in client rules in config.h. + +In `2025-03-03 v0.7` version, the patch had been rewritten from scratch to make +it more robust and add a few more features: + +- "dynamically swallow" windows by pressing `Alt+a` (a focused window will + swallow/unswallow the previously focused one) +- toggle automatic swallowing by `Alt+Shift+a` +- if a window has swallowed another, it get thicker borders + +### Download + +#### swallow.patch + +- [git branch](https://codeberg.org/nikitaivanov/dwl/src/branch/swallow) +- [2025-03-03 v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swallow/swallow.patch) (added "dynamic swallowing support") +- [2024-07-13](https://codeberg.org/dwl/dwl-patches/raw/commit/f1ed83eaeba46108f4ee8164094cb431d64a3e68/patches/swallow/swallow.patch) - [2024-07-13](https://codeberg.org/dwl/dwl-patches/raw/commit/f64d701bab2f9f52d3637edd091684f920407d87/patches/swallow/swallow.patch) -- [2024-05-02](https://codeberg.org/dwl/dwl-patches/raw/commit/9c5d5d85f3ac780e7a14d5d0535e3349ce8b8f53/patches/swallow/swallow.patch) -- [2024-04-03](https://codeberg.org/dwl/dwl-patches/raw/commit/3c9a8e3232a8531871924484cef1ef0938730e15/swallow/swallow.patch) -- [2024-01-01](https://codeberg.org/dwl/dwl-patches/raw/commit/8a352a1b27a64821ba9fbfda52fe82463ac84c66/swallow/swallow.patch) -- [2023-10-26](https://github.com/djpohly/dwl/compare/main...youbitchoc:swallow.patch) -- [2023-08-16](https://github.com/djpohly/dwl/compare/main...mewkl:swallowx.patch) -- [2023-07-15](https://github.com/djpohly/dwl/compare/main...NikitaIvanovV:swallow.patch) -- [v0.4](https://github.com/djpohly/dwl/compare/main...dm1tz:04-swallow.patch) -- [2021-12-03](https://github.com/djpohly/dwl/compare/main...dm1tz:swallow.patch) - -### Authors -- [Dmitry Zakharchenko](https://github.com/dm1tz) -- [Palanix](https://codeberg.org/Palanix) -- [Nikita Ivanov](https://github.com/NikitaIvanovV) -- [Connor Worrell](https://github.com/ConnorWorrell) -- [Mewkl](https://github.com/mewkl) -- [Choc](https://codeberg.org/notchoc) +- [2024-05-02](https://codeberg.org/dwl/dwl-patches/raw/commit/9c5d5d85f3ac780e7a14d5d0535e3349ce8b8f53/patches/swallow/swallow.patch) +- [2024-04-03](https://codeberg.org/dwl/dwl-patches/raw/commit/3c9a8e3232a8531871924484cef1ef0938730e15/swallow/swallow.patch) +- [2024-01-01](https://codeberg.org/dwl/dwl-patches/raw/commit/8a352a1b27a64821ba9fbfda52fe82463ac84c66/swallow/swallow.patch) +- [2023-10-26](https://github.com/djpohly/dwl/compare/main...youbitchoc:swallow.patch) +- [2023-08-16](https://github.com/djpohly/dwl/compare/main...mewkl:swallowx.patch) (added XWayland support) +- [2023-07-15](https://github.com/djpohly/dwl/compare/main...NikitaIvanovV:swallow.patch) +- [v0.4](https://github.com/djpohly/dwl/compare/main...dm1tz:04-swallow.patch) +- [2021-12-03](https://github.com/djpohly/dwl/compare/main...dm1tz:swallow.patch) + +#### swallow-freebsd.patch + +Apply this patch on top of the swallow.patch if you use FreeBSD. + +- [2025-03-03 v0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/swallow/swallow-freebsd.patch) +- [2024-07-13](https://codeberg.org/dwl/dwl-patches/raw/commit/f1ed83eaeba46108f4ee8164094cb431d64a3e68/patches/swallow/swallow-freebsd.patch) + +### Authors + +- [Nikita Ivanov](https://codeberg.org/nikitaivanov) ([GitHub](https://github.com/NikitaIvanovV)) +- [Dmitry Zakharchenko](https://github.com/dm1tz) +- [Palanix](https://codeberg.org/Palanix) +- [Connor Worrell](https://github.com/ConnorWorrell) +- [Mewkl](https://github.com/mewkl) +- [Choc](https://codeberg.org/notchoc) diff --git a/patches/swallow/swallow-freebsd.patch b/patches/swallow/swallow-freebsd.patch index 3d56999..ee86799 100644 --- a/patches/swallow/swallow-freebsd.patch +++ b/patches/swallow/swallow-freebsd.patch @@ -1,17 +1,17 @@ -From 49dc947ba4c33324b969ef7179768c806910fffb Mon Sep 17 00:00:00 2001 -From: choc -Date: Sat, 22 Jun 2024 10:52:33 +0800 -Subject: [PATCH] swallow: add freebsd support +From 002e11e197cd254f06b65681ffd5bcf617d830b9 Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Mon, 3 Mar 2025 19:49:07 +0100 +Subject: [PATCH] swallow: add FreeBSD support --- dwl.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dwl.c b/dwl.c -index 3a3167b..ee9e965 100644 +index bbbbe6f..dc55319 100644 --- a/dwl.c +++ b/dwl.c -@@ -65,6 +65,14 @@ +@@ -67,6 +67,14 @@ #include #endif @@ -26,17 +26,17 @@ index 3a3167b..ee9e965 100644 #include "util.h" /* macros */ -@@ -1486,6 +1494,7 @@ handlesig(int signo) +@@ -2032,6 +2040,7 @@ outputmgrtest(struct wl_listener *listener, void *data) pid_t - getparentprocess(pid_t p) + parentpid(pid_t pid) { +#ifdef __linux__ unsigned int v = 0; - FILE *f; -@@ -1499,6 +1508,14 @@ getparentprocess(pid_t p) + char buf[256]; +@@ -2041,6 +2050,14 @@ parentpid(pid_t pid) + fscanf(f, "%*u %*s %*c %u", &v); fclose(f); - return (pid_t)v; +#elif defined(__FreeBSD__) + struct kinfo_proc kip; @@ -48,8 +48,7 @@ index 3a3167b..ee9e965 100644 +#endif } - int + void -- -2.43.0 - +2.48.1 diff --git a/patches/swallow/swallow.patch b/patches/swallow/swallow.patch index b4581c4..f976023 100644 --- a/patches/swallow/swallow.patch +++ b/patches/swallow/swallow.patch @@ -1,13 +1,13 @@ -From 4b80c425c9f414bc079a0e61f5a3ef42eea85476 Mon Sep 17 00:00:00 2001 -From: choc -Date: Fri, 15 Sep 2023 10:36:21 +0800 -Subject: [PATCH] implement swallow +From 7255d7e2e1b87c0583a202ea20c83fa75466c0fc Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov +Date: Wed, 5 Feb 2025 02:34:39 +0100 +Subject: [PATCH] Swallow: hide the terminal when it spawns a client --- - client.h | 12 ++++++ - config.def.h | 7 ++-- - dwl.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++--- - 3 files changed, 123 insertions(+), 8 deletions(-) + client.h | 12 ++++ + config.def.h | 10 +++- + dwl.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 167 insertions(+), 7 deletions(-) diff --git a/client.h b/client.h index 42f225f..bc9cad2 100644 @@ -33,29 +33,61 @@ index 42f225f..bc9cad2 100644 client_get_clip(Client *c, struct wlr_box *clip) { diff --git a/config.def.h b/config.def.h -index 22d2171..7e5fef1 100644 +index 22d2171..fb5f8fb 100644 --- a/config.def.h +++ b/config.def.h -@@ -22,10 +22,11 @@ static int log_level = WLR_ERROR; +@@ -13,6 +13,7 @@ static const float focuscolor[] = COLOR(0x005577ff); + static const float urgentcolor[] = COLOR(0xff0000ff); + /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ + static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */ ++static int enableautoswallow = 1; /* enables autoswallowing newly spawned clients */ + + /* tagging - TAGCOUNT must be no greater than 31 */ + #define TAGCOUNT (9) +@@ -22,10 +23,11 @@ static int log_level = WLR_ERROR; /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */ static const Rule rules[] = { - /* app_id title tags mask isfloating monitor */ -+ /* app_id title tags mask isfloating isterm noswallow monitor */ ++ /* app_id title tags mask isfloating isterm noswallow monitor */ /* examples: */ - { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ - { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ -+ { "Gimp_EXAMPLE", NULL, 0, 1, 0, 0, -1 }, /* Start on currently visible tags floating, not tiled */ -+ { "firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1 }, /* Start on ONLY tag "9" */ -+ { "foot", NULL, 0, 0, 1, 1, -1 }, /* make foot swallow clients that are not foot */ ++ { "foot", NULL, 0, 0, 1, 1, -1 }, ++ { "Gimp_EXAMPLE", NULL, 0, 1, 0, 0, -1 }, /* Start on currently visible tags floating, not tiled */ ++ { "firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1 }, /* Start on ONLY tag "9" */ }; /* layout(s) */ +@@ -142,6 +144,8 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, ++ { MODKEY, XKB_KEY_a, toggleswallow, {0} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow,{0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, + { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, diff --git a/dwl.c b/dwl.c -index dc0437e..c6a5e9d 100644 +index def2562..bbbbe6f 100644 --- a/dwl.c +++ b/dwl.c -@@ -103,7 +103,8 @@ typedef struct { +@@ -73,12 +73,13 @@ + #define MAX(A, B) ((A) > (B) ? (A) : (B)) + #define MIN(A, B) ((A) < (B) ? (A) : (B)) + #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) +-#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) ++#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]) && !(C)->swallowedby) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define END(A) ((A) + LENGTH(A)) + #define TAGMASK ((1u << TAGCOUNT) - 1) + #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) + #define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) ++#define BORDERPX(C) (borderpx + ((C)->swallowing ? (C)->swallowing->bw : 0)) + + /* enums */ + enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ +@@ -104,7 +105,8 @@ typedef struct { } Button; typedef struct Monitor Monitor; @@ -65,21 +97,21 @@ index dc0437e..c6a5e9d 100644 /* Must keep these three elements in this order */ unsigned int type; /* XDGShell or X11* */ struct wlr_box geom; /* layout-relative, includes border */ -@@ -138,9 +139,11 @@ typedef struct { - #endif +@@ -140,8 +142,12 @@ typedef struct { unsigned int bw; uint32_t tags; -- int isfloating, isurgent, isfullscreen; -+ int isfloating, isurgent, isfullscreen, isterm, noswallow; + int isfloating, isurgent, isfullscreen; ++ int isterm, noswallow; uint32_t resize; /* configure serial of a pending resize */ -} Client; + pid_t pid; -+ Client *swallowing, *swallowedby; ++ Client *swallowing; /* client being hidden */ ++ Client *swallowedby; +}; typedef struct { uint32_t mod; -@@ -229,6 +232,8 @@ typedef struct { +@@ -230,6 +236,8 @@ typedef struct { const char *title; uint32_t tags; int isfloating; @@ -88,18 +120,31 @@ index dc0437e..c6a5e9d 100644 int monitor; } Rule; -@@ -351,6 +356,10 @@ static Monitor *xytomon(double x, double y); - static void xytonode(double x, double y, struct wlr_surface **psurface, - Client **pc, LayerSurface **pl, double *nx, double *ny); - static void zoom(const Arg *arg); -+static pid_t getparentprocess(pid_t p); -+static int isdescprocess(pid_t p, pid_t c); -+static Client *termforwin(Client *w); -+static void swallow(Client *c, Client *w); - - /* variables */ - static const char broken[] = "broken"; -@@ -461,10 +470,14 @@ applyrules(Client *c) +@@ -311,6 +319,7 @@ static void moveresize(const Arg *arg); + static void outputmgrapply(struct wl_listener *listener, void *data); + static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); + static void outputmgrtest(struct wl_listener *listener, void *data); ++static pid_t parentpid(pid_t pid); + static void pointerfocus(Client *c, struct wlr_surface *surface, + double sx, double sy, uint32_t time); + static void printstatus(void); +@@ -335,11 +344,15 @@ static void setsel(struct wl_listener *listener, void *data); + static void setup(void); + static void spawn(const Arg *arg); + static void startdrag(struct wl_listener *listener, void *data); ++static void swallow(Client *c, Client *toswallow); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); ++static Client *termforwin(Client *c); + static void tile(Monitor *m); + static void togglefloating(const Arg *arg); + static void togglefullscreen(const Arg *arg); ++static void toggleswallow(const Arg *arg); ++static void toggleautoswallow(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unlocksession(struct wl_listener *listener, void *data); +@@ -466,11 +479,15 @@ applyrules(Client *c) if (!(title = client_get_title(c))) title = broken; @@ -109,132 +154,197 @@ index dc0437e..c6a5e9d 100644 if ((!r->title || strstr(title, r->title)) && (!r->id || strstr(appid, r->id))) { c->isfloating = r->isfloating; -+ c->isterm = r->isterm; -+ c->noswallow = r->noswallow; newtags |= r->tags; ++ c->isterm = r->isterm; ++ c->noswallow = r->noswallow; i = 0; wl_list_for_each(m, &mons, link) { -@@ -473,6 +486,21 @@ applyrules(Client *c) + if (r->monitor == i++) +@@ -478,6 +495,12 @@ applyrules(Client *c) } } } -+ if (!c->noswallow && !client_is_float_type(c) -+ && !c->surface.xdg->initial_commit) { ++ if (enableautoswallow && !c->noswallow && !c->isfloating && ++ !c->surface.xdg->initial_commit) { + Client *p = termforwin(c); -+ if (p) { -+ c->swallowedby = p; -+ p->swallowing = c; -+ wl_list_remove(&c->link); -+ wl_list_remove(&c->flink); ++ if (p) + swallow(c, p); -+ wl_list_remove(&p->link); -+ wl_list_remove(&p->flink); -+ mon = p->mon; -+ newtags = p->tags; -+ } + } setmon(c, mon, newtags); } -@@ -1467,6 +1495,63 @@ handlesig(int signo) - } +@@ -2006,6 +2029,20 @@ outputmgrtest(struct wl_listener *listener, void *data) + outputmgrapplyortest(config, 1); } +pid_t -+getparentprocess(pid_t p) ++parentpid(pid_t pid) +{ + unsigned int v = 0; -+ + FILE *f; + char buf[256]; -+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); -+ ++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)pid); + if (!(f = fopen(buf, "r"))) + return 0; -+ + fscanf(f, "%*u %*s %*c %u", &v); + fclose(f); -+ + return (pid_t)v; +} + -+int -+isdescprocess(pid_t p, pid_t c) -+{ -+ while (p != c && c != 0) -+ c = getparentprocess(c); + void + pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, + uint32_t time) +@@ -2326,7 +2363,7 @@ setfullscreen(Client *c, int fullscreen) + c->isfullscreen = fullscreen; + if (!c->mon || !client_surface(c)->mapped) + return; +- c->bw = fullscreen ? 0 : borderpx; ++ c->bw = fullscreen ? 0 : BORDERPX(c); + client_set_fullscreen(c, fullscreen); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); +@@ -2404,6 +2441,9 @@ setmon(Client *c, Monitor *m, uint32_t newtags) + setfloating(c, c->isfloating); + } + focusclient(focustop(selmon), 1); + -+ return (int)c; ++ if (c->swallowing) ++ setmon(c->swallowing, m, newtags); + } + + void +@@ -2669,6 +2709,44 @@ startdrag(struct wl_listener *listener, void *data) + LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); + } + ++void ++swallow(Client *c, Client *toswallow) ++{ ++ /* Do not allow a client to swallow itself */ ++ if (c == toswallow) ++ return; ++ ++ /* Swallow */ ++ if (toswallow && !c->swallowing) { ++ c->swallowing = toswallow; ++ toswallow->swallowedby = c; ++ toswallow->mon = c->mon; ++ toswallow->mon = c->mon; ++ wl_list_remove(&c->link); ++ wl_list_insert(&c->swallowing->link, &c->link); ++ wl_list_remove(&c->flink); ++ wl_list_insert(&c->swallowing->flink, &c->flink); ++ c->bw = BORDERPX(c); ++ c->tags = toswallow->tags; ++ c->isfloating = toswallow->isfloating; ++ c->geom = toswallow->geom; ++ setfullscreen(toswallow, 0); ++ } ++ ++ /* Unswallow */ ++ else if (c->swallowing) { ++ wl_list_remove(&c->swallowing->link); ++ wl_list_insert(&c->link, &c->swallowing->link); ++ wl_list_remove(&c->swallowing->flink); ++ wl_list_insert(&c->flink, &c->swallowing->flink); ++ c->swallowing->tags = c->tags; ++ c->swallowing->swallowedby = NULL; ++ c->swallowing = NULL; ++ c->bw = BORDERPX(c); ++ setfullscreen(c, 0); ++ } +} + + void + tag(const Arg *arg) + { +@@ -2690,6 +2768,40 @@ tagmon(const Arg *arg) + setmon(sel, dirtomon(arg->i), 0); + } + +Client * -+termforwin(Client *w) ++termforwin(Client *c) +{ -+ Client *c; ++ Client *p; ++ pid_t pid; ++ pid_t pids[32]; ++ size_t i, pids_len; + -+ if (!w->pid || w->isterm || w->noswallow) ++ if (!c->pid || c->isterm) + return NULL; + -+ wl_list_for_each(c, &fstack, flink) -+ if (c->isterm && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) -+ return c; ++ /* Get all parent pids */ ++ pids_len = 0; ++ pid = c->pid; ++ while (pids_len < LENGTH(pids)) { ++ pid = parentpid(pid); ++ if (!pid) ++ break; ++ pids[pids_len++] = pid; ++ } ++ ++ /* Find closest parent */ ++ for (i = 0; i < pids_len; i++) { ++ wl_list_for_each(p, &clients, link) { ++ if (!p->pid || !p->isterm || p->swallowedby) ++ continue; ++ if (pids[i] == p->pid) ++ return p; ++ } ++ } + + return NULL; +} + + void + tile(Monitor *m) + { +@@ -2741,6 +2853,32 @@ togglefullscreen(const Arg *arg) + setfullscreen(sel, !sel->isfullscreen); + } + +void -+swallow(Client *c, Client *w) ++toggleswallow(const Arg *arg) +{ -+ c->bw = w->bw; -+ c->isfloating = w->isfloating; -+ c->isurgent = w->isurgent; -+ c->isfullscreen = w->isfullscreen; -+ c->tags = w->tags; -+ c->geom = w->geom; -+ wl_list_insert(&w->link, &c->link); -+ wl_list_insert(&w->flink, &c->flink); -+ wlr_scene_node_set_enabled(&w->scene->node, 0); -+ wlr_scene_node_set_enabled(&c->scene->node, 1); ++ Client *c, *sel = focustop(selmon); ++ if (!sel) ++ return; ++ ++ if (sel->swallowing) { ++ swallow(sel, NULL); ++ } else { ++ wl_list_for_each(c, &sel->flink, flink) { ++ if (&c->flink == &fstack) ++ continue; /* wrap past the sentinel node */ ++ if (VISIBLEON(c, selmon)) ++ break; /* found it */ ++ } ++ swallow(sel, c); ++ } ++} ++ ++void ++toggleautoswallow(const Arg *arg) ++{ ++ enableautoswallow = !enableautoswallow; +} + void - incnmaster(const Arg *arg) + toggletag(const Arg *arg) { -@@ -2746,15 +2831,32 @@ unmapnotify(struct wl_listener *listener, void *data) +@@ -2801,6 +2939,12 @@ unmapnotify(struct wl_listener *listener, void *data) grabc = NULL; } -+ if (c->swallowedby) -+ swallow(c->swallowedby, c); ++ if (c->swallowing) { ++ swallow(c, NULL); ++ } else if (c->swallowedby) { ++ swallow(c->swallowedby, NULL); ++ } + if (client_is_unmanaged(c)) { if (c == exclusive_focus) { exclusive_focus = NULL; - focusclient(focustop(selmon), 1); - } - } else { -- wl_list_remove(&c->link); -+ if (!c->swallowing) -+ wl_list_remove(&c->link); - setmon(c, NULL, 0); -- wl_list_remove(&c->flink); -+ if (!c->swallowing) -+ wl_list_remove(&c->flink); -+ } -+ -+ if (c->swallowedby) { -+ c->swallowedby->prev = c->geom; -+ setfullscreen(c->swallowedby, c->isfullscreen); -+ c->swallowedby->swallowing = NULL; -+ c->swallowedby = NULL; -+ } -+ -+ if (c->swallowing) { -+ c->swallowing->swallowedby = NULL; -+ c->swallowing = NULL; - } - - wlr_scene_node_destroy(&c->scene->node); -- -2.43.0 +2.48.1