diff --git a/README.md b/README.md index 307ff6d..ac7d095 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,12 @@ philosophy. Like dwm, dwl is: - [inputdevicerules](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/inputdevicerules) - [nextlayout](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/nextlayout) - [pertag](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/pertag) +- [primaryselection](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/primaryselection) - [rotatetags](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/rotatetags) - [setupenv](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/setupenv) - [sticky](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/sticky) +- [swallow](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/swallow) +- [swallow-freebsd](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/swallow) - [xkb-rules-switcher](https://codeberg.org/wochap/dwl/src/branch/v0.6-b/xkb-rules-switcher/xkb-rules-switcher.patch) ## Getting Started: diff --git a/client.h b/client.h index 42f225f..bc9cad2 100644 --- a/client.h +++ b/client.h @@ -131,6 +131,18 @@ client_get_appid(Client *c) return c->surface.xdg->toplevel->app_id; } +static inline int +client_get_pid(Client *c) +{ + pid_t pid; +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->pid; +#endif + wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); + return pid; +} + static inline void client_get_clip(Client *c, struct wlr_box *clip) { diff --git a/config.def.h b/config.def.h index c0b7de7..592d3c3 100644 --- a/config.def.h +++ b/config.def.h @@ -14,6 +14,7 @@ static const char *fonts[] = {"monospace:size=10"}; static const float rootcolor[] = COLOR(0x000000ff); /* 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 */ static const char *cursor_theme = NULL; static const char cursor_size[] = "24"; /* Make sure it's a valid integer, otherwise things will break */ static uint32_t colors[][3] = { @@ -51,10 +52,11 @@ static const char *const autostart[] = { /* 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 */ /* 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" */ + { "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) */ @@ -120,6 +122,7 @@ static const int natural_scrolling = 0; static const int disable_while_typing = 1; static const int left_handed = 0; static const int middle_button_emulation = 0; +static const int enable_primary_selection = 0; /* You can choose between: LIBINPUT_CONFIG_SCROLL_NO_SCROLL LIBINPUT_CONFIG_SCROLL_2FG @@ -215,7 +218,9 @@ static const Key keys[] = { { MODKEY, XKB_KEY_space, setlayout, {0} }, { MODKEY, XKB_KEY_n, nextlayout, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, - { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, + { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT, XKB_KEY_a, toggleswallow, {0} }, + { WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow,{0} }, { MODKEY, XKB_KEY_u, togglepointer, {0} }, { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, diff --git a/config.h b/config.h index 4573e59..91ff392 100644 --- a/config.h +++ b/config.h @@ -10,12 +10,13 @@ static const unsigned int gappih = 4; /* horiz inner gap between windo static const unsigned int gappiv = 4; /* vert inner gap between windows */ static const unsigned int gappoh = 1; /* horiz outer gap between windows and screen edge */ static const unsigned int gappov = 1; /* vert outer gap between windows and screen edge */ +static int enableautoswallow = 1; /* enables autoswallowing newly spawned clients */ static const char *cursor_theme = "macOS"; static const char cursor_size[] = "28"; /* Make sure it's a valid integer, otherwise things will break */ static const int user_bh = 30; /* 0 means that dwl will calculate barheight, >= 1 means dwl will use user_bh as the bar height. */ static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ -static const char *fonts[] = {"inconsolata:size=11"}; +static const char *fonts[] = {"Inconsolata:size=11"}; /* 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 */ @@ -34,8 +35,9 @@ static int log_level = WLR_ERROR; /* Environment variables */ static const Env envs[] = { - /* variable value */ + /* variable value */ { "XDG_CURRENT_DESKTOP", "wlroots" }, + { "XCURSOR_THEME", "macOS" }, { "SDL_VIDEODRIVER", "wayland" }, }; @@ -52,10 +54,12 @@ static const char *const autostart[] = { /* 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 */ - /* 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" */ + /* app_id title tags mask isfloating isterm noswallow monitor */ + /* examples: */ + { "foot", NULL, 0, 0, 1, 1, -1 }, /* make foot swallow clients that are not foot */ + { "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" */ + { "mpv", "webcam", 0, 1, 0, 0, -1 }, /* Launch camera as floating only*/ }; /* layout(s) */ @@ -121,6 +125,7 @@ static const int natural_scrolling = 0; static const int disable_while_typing = 1; static const int left_handed = 0; static const int middle_button_emulation = 0; +static const int enable_primary_selection = 0; /* You can choose between: LIBINPUT_CONFIG_SCROLL_NO_SCROLL LIBINPUT_CONFIG_SCROLL_2FG @@ -170,14 +175,18 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA /* commands */ static const char *termcmd[] = { "footclient", NULL }; // Terminal -static const char *menucmd[] = { "tofi-drun", NULL }; // Application launcher +static const char *menucmd[] = { "fuzzel", NULL }; // Application launcher static const char *fmgrcmd[] = { "footclient", "--title", "lf", "lf", NULL }; // File manager static const char *sptfcmd[] = { "footclient", "--title", "Spotify", "spotify_player", NULL }; // Spotify client static const char *ncmxcmd[] = { "footclient", "--title", "ncpamixer", "ncpamixer", NULL }; // Volume control static const char *blthcmd[] = { "footclient", "--title", "bluetui", "bluetui", NULL }; // Bluetooth manager static const char *lockcmd[] = { "swaylock", NULL }; // Launch swaylock +static const char *camrcmd[] = { "camera", NULL }; // Launch mpv window showing my camera +static const char *recscmd[] = { "recordscreen", NULL }; // Launch recording menu static const char *pwmncmd[] = { "powermenu", NULL }; // Launch powermenu static const char *emojcmd[] = { "tofiunicode", NULL }; // Launch emoji menu +static const char *btopcmd[] = { "footclient", "--title", "btop", "btop", NULL }; // Launch btop +static const char *musicmd[] = { "footclient", "--title", "cmus", "cmus", NULL }; // cmus player static const Key keys[] = { /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ @@ -189,17 +198,21 @@ static const Key keys[] = { { MODKEY, XKB_KEY_b, spawn, {.v = blthcmd} }, { MODKEY, XKB_KEY_v, spawn, {.v = ncmxcmd} }, { MODKEY, XKB_KEY_l, spawn, {.v = lockcmd} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, spawn, {.v = camrcmd} }, + { WLR_MODIFIER_SHIFT, XKB_KEY_Print, spawn, {.v = recscmd} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_E, spawn, {.v = emojcmd} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, spawn, {.v = pwmncmd} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, spawn, SHCMD("slurp | grim -g- - | wl-copy") }, - { 0, XKB_KEY_XF86AudioMicMute, spawn,SHCMD("setvol -m mute") }, - { WLR_MODIFIER_SHIFT, XKB_KEY_XF86AudioLowerVolume, spawn,SHCMD("setvol -m down") }, - { WLR_MODIFIER_SHIFT, XKB_KEY_XF86AudioRaiseVolume, spawn,SHCMD("setvol -m up") }, - { 0, XKB_KEY_XF86AudioMute, spawn,SHCMD("setvol mute") }, - { 0, XKB_KEY_XF86AudioLowerVolume, spawn,SHCMD("setvol down") }, - { 0, XKB_KEY_XF86AudioRaiseVolume, spawn,SHCMD("setvol up") }, - { 0, XKB_KEY_XF86MonBrightnessUp, spawn,SHCMD("setbrightness increase")}, - { 0, XKB_KEY_XF86MonBrightnessDown,spawn,SHCMD("setbrightness decrease")}, + { MODKEY, XKB_KEY_Delete, spawn, {.v = btopcmd} }, + { MODKEY, XKB_KEY_m, spawn, {.v = musicmd} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, spawn, SHCMD("slurp -d | grim -g- - | wl-copy") }, + { 0, XKB_KEY_XF86AudioMicMute, spawn,SHCMD("wpctl set-mute @DEFAULT_SOURCE@ toggle && pkill -RTMIN+3 slstatus") }, + { WLR_MODIFIER_SHIFT, XKB_KEY_XF86AudioLowerVolume, spawn,SHCMD("wpctl set-volume -l 1.0 @DEFAULT_SOURCE@ 5%- && pkill -RTMIN+3 slstatus") }, + { WLR_MODIFIER_SHIFT, XKB_KEY_XF86AudioRaiseVolume, spawn,SHCMD("wpctl set-volume -l 1.0 @DEFAULT_SOURCE@ 5%+ && pkill -RTMIN+3 slstatus") }, + { 0, XKB_KEY_XF86AudioMute, spawn,SHCMD("wpctl set-mute @DEFAULT_SINK@ toggle && pkill -RTMIN+2 slstatus") }, + { 0, XKB_KEY_XF86AudioLowerVolume, spawn,SHCMD("wpctl set-volume -l 1.0 @DEFAULT_SINK@ 5%- && pkill -RTMIN+3 slstatus") }, + { 0, XKB_KEY_XF86AudioRaiseVolume, spawn,SHCMD("wpctl set-volume -l 1.0 @DEFAULT_SINK@ 5%+ && pkill -RTMIN+2 slstatus") }, + { 0, XKB_KEY_XF86MonBrightnessUp, spawn,SHCMD("brillo -a -u 125000 -q -A 5")}, + { 0, XKB_KEY_XF86MonBrightnessDown,spawn,SHCMD("brillo -a -u 125000 -q -U 5")}, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_B, togglebar, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_S, togglesticky, {0} }, { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, @@ -250,6 +263,8 @@ static const Key keys[] = { */ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_F, togglefullscreen, {0} }, + { MODKEY, XKB_KEY_g, toggleswallow, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_G, toggleautoswallow,{0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_U, togglepointer, {0} }, /* { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, diff --git a/config.mk b/config.mk index 153e80d..1e0b810 100644 --- a/config.mk +++ b/config.mk @@ -8,10 +8,10 @@ PREFIX = /usr/local MANDIR = $(PREFIX)/share/man DATADIR = $(PREFIX)/share -#XWAYLAND = -#XLIBS = +XWAYLAND = +XLIBS = # Uncomment to build XWayland support -XWAYLAND = -DXWAYLAND -XLIBS = xcb xcb-icccm +#XWAYLAND = -DXWAYLAND +#XLIBS = xcb xcb-icccm CC = gcc diff --git a/dwl.c b/dwl.c index 8fd0480..68891c1 100644 --- a/dwl.c +++ b/dwl.c @@ -69,6 +69,14 @@ #include #endif +#ifdef __FreeBSD__ +#define __BSD_VISIBLE +#include +#include +#include +#include +#endif + #include "util.h" #include "drwl.h" @@ -76,12 +84,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]) || C->issticky)) +#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]) && !(C)->swallowedby || C->issticky) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1u << LENGTH(tags)) - 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)) #define TEXTW(mon, text) (drwl_font_getwidth(mon->drw, text) + mon->lrpad) /* enums */ @@ -112,7 +121,8 @@ typedef struct { typedef struct Pertag Pertag; typedef struct Monitor Monitor; -typedef struct { +typedef struct Client Client; +struct Client { /* Must keep these three elements in this order */ unsigned int type; /* XDGShell or X11* */ int interact; @@ -148,9 +158,13 @@ typedef struct { #endif unsigned int bw; uint32_t tags; - int isfloating, isurgent, isfullscreen, issticky; - uint32_t resize; /* configure serial of a pending resize */ -} Client; + int isfloating, isurgent, isfullscreen, issticky; + int isterm, noswallow; + uint32_t resize; /* configure serial of a pending resize */ + pid_t pid; + Client *swallowing; /* client being hidden */ + Client *swallowedby; +}; typedef struct { const char *name; @@ -267,6 +281,8 @@ typedef struct { const char *title; uint32_t tags; int isfloating; + int isterm; + int noswallow; int monitor; } Rule; @@ -377,6 +393,7 @@ static void nextlayout(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 powermgrsetmode(struct wl_listener *listener, void *data); @@ -401,17 +418,21 @@ static void setmon(Client *c, Monitor *m, uint32_t newtags); static void setpsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data); static void setup(void); +static void swallow(Client *c, Client *toswallow); static void spawn(const Arg *arg); static void startdrag(struct wl_listener *listener, void *data); static int statusin(int fd, unsigned int mask, void *data); static void switchxkbrule(const Arg *arg); static void tag(const Arg *arg); static void tagmon(const Arg *arg); +static Client *termforwin(Client *c); static void tile(Monitor *m); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); static void togglesticky(const Arg *arg); static void togglefullscreen(const Arg *arg); +static void toggleswallow(const Arg *arg); +static void toggleautoswallow(const Arg *arg); static void togglepointer(const Arg *arg); static void togglegaps(const Arg *arg); static void toggletag(const Arg *arg); @@ -577,11 +598,15 @@ applyrules(Client *c) if (!(title = client_get_title(c))) title = broken; + c->pid = client_get_pid(c); + for (r = rules; r < END(rules); r++) { if ((!r->title || strstr(title, r->title)) && (!r->id || strstr(appid, r->id))) { c->isfloating = r->isfloating; newtags |= r->tags; + c->isterm = r->isterm; + c->noswallow = r->noswallow; i = 0; wl_list_for_each(m, &mons, link) { if (r->monitor == i++) @@ -593,6 +618,12 @@ applyrules(Client *c) c->geom.x = (mon->w.width - c->geom.width) / 2 + mon->m.x; c->geom.y = (mon->w.height - c->geom.height) / 2 + mon->m.y; } + if (enableautoswallow && !c->noswallow && !c->isfloating && + !c->surface.xdg->initial_commit) { + Client *p = termforwin(c); + if (p) + swallow(c, p); + } setmon(c, mon, newtags); } @@ -2697,6 +2728,29 @@ outputmgrtest(struct wl_listener *listener, void *data) outputmgrapplyortest(config, 1); } +pid_t +parentpid(pid_t pid) +{ +#ifdef __linux__ + unsigned int v = 0; + FILE *f; + char buf[256]; + 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; +#elif defined(__FreeBSD__) + struct kinfo_proc kip; + size_t len = sizeof(struct kinfo_proc); + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, p }; + if (sysctl(mib, 4, &kip, &len, NULL, 0) < 0 || len == 0) + return 0; + return kip.ki_ppid; +#endif +} + void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time) @@ -2974,7 +3028,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]); @@ -3073,6 +3127,9 @@ setmon(Client *c, Monitor *m, uint32_t newtags) setfloating(c, c->isfloating); } focusclient(focustop(selmon), 1); + + if (c->swallowing) + setmon(c->swallowing, m, newtags); } void @@ -3170,7 +3227,8 @@ setup(void) wlr_export_dmabuf_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy); wlr_data_control_manager_v1_create(dpy); - wlr_primary_selection_v1_device_manager_create(dpy); + if (enable_primary_selection) + wlr_primary_selection_v1_device_manager_create(dpy); wlr_viewporter_create(dpy); wlr_single_pixel_buffer_manager_v1_create(dpy); wlr_fractional_scale_manager_v1_create(dpy, 1); @@ -3294,7 +3352,8 @@ setup(void) seat = wlr_seat_create(dpy, "seat0"); LISTEN_STATIC(&seat->events.request_set_cursor, setcursor); LISTEN_STATIC(&seat->events.request_set_selection, setsel); - LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); + if (enable_primary_selection) + LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel); LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag); LISTEN_STATIC(&seat->events.start_drag, startdrag); @@ -3392,6 +3451,44 @@ switchxkbrule(const Arg *arg) xkb_context_unref(context); } +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) { @@ -3413,6 +3510,40 @@ tagmon(const Arg *arg) setmon(sel, dirtomon(arg->i), 0); } +Client * +termforwin(Client *c) +{ + Client *p; + pid_t pid; + pid_t pids[32]; + size_t i, pids_len; + + if (!c->pid || c->isterm) + return NULL; + + /* 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) { @@ -3501,6 +3632,32 @@ togglesticky(const Arg *arg) setsticky(c, !c->issticky); } +void +toggleswallow(const Arg *arg) +{ + 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 toggletag(const Arg *arg) { @@ -3581,6 +3738,12 @@ unmapnotify(struct wl_listener *listener, void *data) grabc = NULL; } + 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;