From b21a09cb064688702abcbb735860fe53daac2ae2 Mon Sep 17 00:00:00 2001 From: sad Date: Fri, 9 Feb 2024 20:16:24 -0700 Subject: [PATCH] implement version 5 with x11 support --- config.def.h | 66 +++++++-- config.mk | 7 +- dwl.c | 173 ++++++++++++++++++++-- patches/autostart.patch | 154 ++++++++++++++++++++ patches/main...dm1tz:04-sticky.patch | 69 +++++++++ patches/main...dm1tz:04-swallow.patch | 197 ++++++++++++++++++++++++++ 6 files changed, 640 insertions(+), 26 deletions(-) create mode 100644 patches/autostart.patch create mode 100644 patches/main...dm1tz:04-sticky.patch create mode 100644 patches/main...dm1tz:04-swallow.patch diff --git a/config.def.h b/config.def.h index 9009517..c1d276a 100644 --- a/config.def.h +++ b/config.def.h @@ -7,10 +7,11 @@ static const int sloppyfocus = 1; /* focus follows mouse */ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ static const unsigned int borderpx = 1; /* border pixel of windows */ -static const float rootcolor[] = COLOR(0x222222ff); -static const float bordercolor[] = COLOR(0x444444ff); -static const float focuscolor[] = COLOR(0x005577ff); -static const float urgentcolor[] = COLOR(0xff0000ff); +static const float rootcolor[] = COLOR(0x330044); +static const float bordercolor[] = COLOR(0x32CD32); // Lime green +static const float focuscolor[] = COLOR(0x330044); // Darker purple +static const float urgentcolor[] = COLOR(0x32CD32); // Changed from red to lime green + /* To conform 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 */ @@ -20,12 +21,27 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca /* logging */ static int log_level = WLR_ERROR; + +/* Autostart */ +static const char *const autostart[] = { + "exec", "dbus-update-activation-environment", "--systemd", "DISPLAY", "I3SOCK", "SWAYSOCK", "WAYLAND_DISPLAY", "XDG_CURRENT_DESKTOP=sway", NULL, + "/usr/bin/wbg", "/home/s4d/.config/lain.jpg", NULL, + "/usr/libexec/kdeconnectd", NULL, + "/usr/bin/pipewire", NULL, + "/usr/bin/dunst", NULL, + "/usr/local/bin/someblocks", NULL, + "/usr/bin/swayidle", "-w", "idle", "timeout", "600", "\"/usr/local/bin/swaylock -f\"", NULL, + "/usr/bin/spotifyd", "--no-daemon", NULL, + "/usr/libexec/xdg-desktop-portal", "-r", NULL, + NULL /* terminate */ +}; + static const Rule rules[] = { - /* app_id title tags mask isfloating monitor */ + /* app_id title tags mask isfloating isterm noswallow monitor */ /* examples: - { "Gimp", NULL, 0, 1, -1 }, + { "Gimp", NULL, 0, 1, 0, 1, -1 }, */ - { "firefox", NULL, 1 << 8, 0, -1 }, + { "firefox", NULL, 1 << 8, 0, 0, 1, -1 }, }; /* layout(s) */ @@ -102,7 +118,7 @@ LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; /* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ -#define MODKEY WLR_MODIFIER_ALT +#define MODKEY WLR_MODIFIER_LOGO #define TAGKEYS(KEY,SKEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ @@ -114,20 +130,37 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } /* commands */ -static const char *termcmd[] = { "foot", NULL }; -static const char *menucmd[] = { "bemenu-run", NULL }; +static const char *termcmd[] = { "kitty", NULL }; +/*static const char *menucmd[] = { "dmenu-wl_run", "-fn", "hack_mono:13", "-sb", "#550077", NULL };*/ +static const char *menucmd[] = { "/bin/sh", "-c", + "dmenu-wl_path | wmenu -S \"#550077\" -N \"#000000\" -n \"#32CD32\" -s \"#000000\" -f \"Hack Mono Bold 13\" | xargs -I_-_ /bin/sh -c \"exec _-_\"", + NULL }; + +/* volume control */ +static const char *volup[] = {"/usr/bin/pactl", "set-sink-volume", "@DEFAULT_SINK@", "+5%", NULL}; +static const char *voldown[] = {"/usr/bin/pactl", "set-sink-volume", "@DEFAULT_SINK@", "-5%", NULL}; +static const char *volmute[] = {"/usr/bin/pactl", "set-sink-mute", "@DEFAULT_SINK@", "toggle", NULL}; + +/* volume input */ +static const char *mutemic[] = { "/usr/bin/pactl", "set-source-mute", "@DEFAULT_SOURCE@", "toggle", NULL }; + +/* brightness control */ +static const char *brightnessup[] = { "/usr/bin/brightnessctl", "s", "3%+", NULL }; +static const char *brightnessdown[] = { "/usr/bin/brightnessctl", "s", "3%-", NULL }; + static const Key keys[] = { /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ /* modifier key function argument */ { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, + /*{ MODKEY, XKB_KEY_b, togglebar, {0}},*/ { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, - { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, - { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} }, + { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} }, { MODKEY, XKB_KEY_Return, zoom, {0} }, { MODKEY, XKB_KEY_Tab, view, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} }, @@ -136,6 +169,7 @@ static const Key keys[] = { { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, { MODKEY, XKB_KEY_space, setlayout, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_s, togglesticky, {0} }, { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, @@ -143,6 +177,14 @@ static const Key keys[] = { { MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} }, + { 0, XKB_KEY_XF86AudioRaiseVolume, spawn, {.v = volup} }, + { 0, XKB_KEY_XF86AudioLowerVolume, spawn, {.v = voldown} }, + { 0, XKB_KEY_XF86AudioMute, spawn, {.v = volmute} }, + { 0, XKB_KEY_XF86MonBrightnessUp, spawn, {.v = brightnessup} }, + { 0, XKB_KEY_XF86MonBrightnessDown, spawn, {.v = brightnessdown} }, + { 0, XKB_KEY_XF86AudioMicMute, spawn, {.v = mutemic} }, + { 0, XKB_KEY_Print, spawn, SHCMD("grim -g \"$(slurp)\" ~/media/screenshots/$(date +'%h%d-%H%M-ss.png')") }, + { MODKEY, XKB_KEY_q, quit, {0} }, TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0), TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), diff --git a/config.mk b/config.mk index 906f403..248a5dc 100644 --- a/config.mk +++ b/config.mk @@ -8,8 +8,7 @@ PREFIX = /usr/local MANDIR = $(PREFIX)/share/man DATADIR = $(PREFIX)/share -XWAYLAND = -XLIBS = + # Uncomment to build XWayland support -#XWAYLAND = -DXWAYLAND -#XLIBS = xcb xcb-icccm +XWAYLAND = -DXWAYLAND +XLIBS = xcb xcb-icccm diff --git a/dwl.c b/dwl.c index fa76db2..b04bc62 100644 --- a/dwl.c +++ b/dwl.c @@ -68,7 +68,7 @@ #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5))) #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)->issticky)) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1u << TAGCOUNT) - 1) @@ -99,7 +99,8 @@ typedef struct { } Button; 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* */ struct wlr_box geom; /* layout-relative, includes border */ @@ -134,9 +135,11 @@ typedef struct { #endif unsigned int bw; uint32_t tags; - int isfloating, isurgent, isfullscreen; - uint32_t resize; /* configure serial of a pending resize */ -} Client; + int isfloating, isurgent, isfullscreen, issticky, isterm, noswallow; + uint32_t resize; /* configure serial of a pending resize */ + pid_t pid; + Client *swallowing, *swallowedby; +}; typedef struct { uint32_t mod; @@ -219,6 +222,8 @@ typedef struct { const char *title; uint32_t tags; int isfloating; + int isterm; + int noswallow; int monitor; } Rule; @@ -238,6 +243,7 @@ static void arrange(Monitor *m); static void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive); static void arrangelayers(Monitor *m); +static void autostartexec(void); static void axisnotify(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data); static void chvt(const Arg *arg); @@ -318,6 +324,7 @@ static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *m); static void togglefloating(const Arg *arg); +static void togglesticky(const Arg *arg); static void togglefullscreen(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); @@ -334,6 +341,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"; @@ -407,6 +418,9 @@ static xcb_atom_t netatom[NetLast]; /* attempt to encapsulate suck into one file */ #include "client.h" +static pid_t *autostart_pids; +static size_t autostart_len; + /* function implementations */ void applybounds(Client *c, struct wlr_box *bbox) @@ -445,6 +459,8 @@ applyrules(Client *c) 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; i = 0; wl_list_for_each(m, &mons, link) { @@ -541,6 +557,27 @@ arrangelayers(Monitor *m) } } +void +autostartexec(void) { + const char *const *p; + size_t i = 0; + + /* count entries */ + for (p = autostart; *p; autostart_len++, p++) + while (*++p); + + autostart_pids = calloc(autostart_len, sizeof(pid_t)); + for (p = autostart; *p; i++, p++) { + if ((autostart_pids[i] = fork()) == 0) { + setsid(); + execvp(*p, (char *const *)p); + die("dwl: execvp %s:", *p); + } + /* skip arguments */ + while (*++p); + } +} + void axisnotify(struct wl_listener *listener, void *data) { @@ -638,11 +675,21 @@ checkidleinhibitor(struct wlr_surface *exclude) void cleanup(void) { + size_t i; #ifdef XWAYLAND wlr_xwayland_destroy(xwayland); xwayland = NULL; #endif wl_display_destroy_clients(dpy); + + /* kill child processes */ + for (i = 0; i < autostart_len; i++) { + if (0 < autostart_pids[i]) { + kill(autostart_pids[i], SIGTERM); + waitpid(autostart_pids[i], NULL, 0); + } + } + if (child_pid > 0) { kill(child_pid, SIGTERM); waitpid(child_pid, NULL, 0); @@ -957,6 +1004,7 @@ createnotify(struct wl_listener *listener, void *data) c->surface.xdg = xdg_surface; c->bw = borderpx; + wl_client_get_credentials(c->surface.xdg->client->client, &c->pid, NULL, NULL); wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); @@ -1303,23 +1351,91 @@ void handlesig(int signo) { if (signo == SIGCHLD) { -#ifdef XWAYLAND siginfo_t in; /* wlroots expects to reap the XWayland process itself, so we * use WNOWAIT to keep the child waitable until we know it's not * XWayland. */ while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); -#else - while (waitpid(-1, NULL, WNOHANG) > 0); +#ifdef XWAYLAND + && (!xwayland || in.si_pid != xwayland->server->pid) #endif + ) { + pid_t *p, *lim; + waitpid(in.si_pid, NULL, 0); + if (in.si_pid == child_pid) + child_pid = -1; + if (!(p = autostart_pids)) + continue; + lim = &p[autostart_len]; + + for (; p < lim; p++) { + if (*p == in.si_pid) { + *p = -1; + break; + } + } + } } else if (signo == SIGINT || signo == SIGTERM) { quit(NULL); } } +pid_t +getparentprocess(pid_t p) +{ + unsigned int v = 0; + + FILE *f; + char buf[256]; + snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); + + 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); + + return (int)c; +} + +Client * +termforwin(Client *w) +{ + Client *c; + + if (!w->pid || w->isterm || w->noswallow) + return NULL; + + wl_list_for_each(c, &clients, link) + if (c->isterm && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) + return c; + + return NULL; +} + +void +swallow(Client *c, Client *w) { + c->bw = w->bw; + c->isfloating = w->isfloating; + c->isurgent = w->isurgent; + c->isfullscreen = w->isfullscreen; + resize(c, w->geom, 0); + 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); +} + void incnmaster(const Arg *arg) { @@ -1552,6 +1668,20 @@ mapnotify(struct wl_listener *listener, void *data) } printstatus(); + if (!c->noswallow) { + Client *p = termforwin(c); + if (p) { + c->swallowedby = p; + p->swallowing = c; + wl_list_remove(&c->link); + wl_list_remove(&c->flink); + swallow(c,p); + wl_list_remove(&p->link); + wl_list_remove(&p->flink); + arrange(c->mon); + } + } + unset_fullscreen: m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); wl_list_for_each(w, &clients, link) { @@ -1972,6 +2102,7 @@ run(char *startup_cmd) die("startup: backend_start"); /* Now that the socket exists and the backend is started, run the startup command */ + autostartexec(); if (startup_cmd) { int piperw[2]; if (pipe(piperw) < 0) @@ -2506,6 +2637,16 @@ togglefloating(const Arg *arg) setfloating(sel, !sel->isfloating); } +void +togglesticky(const Arg *arg) +{ + Client *sel = focustop(selmon); + if (!sel) + return; + sel->issticky = !sel->issticky; + arrange(selmon); +} + void togglefullscreen(const Arg *arg) { @@ -2574,6 +2715,18 @@ unmapnotify(struct wl_listener *listener, void *data) grabc = NULL; } + if (c->swallowing) { + c->swallowing->swallowedby = NULL; + c->swallowing = NULL; + } + + if (c->swallowedby) { + setfullscreen(c->swallowedby, 0); + swallow(c->swallowedby, c); + c->swallowedby->swallowing = NULL; + c->swallowedby = NULL; + } + if (client_is_unmanaged(c)) { if (c == exclusive_focus) { exclusive_focus = NULL; diff --git a/patches/autostart.patch b/patches/autostart.patch new file mode 100644 index 0000000..e16b294 --- /dev/null +++ b/patches/autostart.patch @@ -0,0 +1,154 @@ +From 51d56a433f23e13ac711b283a03c7903068febf6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= + +Date: Sat, 8 Jul 2023 17:11:36 -0600 +Subject: [PATCH] port autostart patch from dwm +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +https://dwm.suckless.org/patches/cool_autostart/ +Signed-off-by: Leonardo Hernández Hernández +--- + config.def.h | 7 +++++++ + dwl.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++----- + 2 files changed, 61 insertions(+), 5 deletions(-) + +diff --git a/config.def.h b/config.def.h +index a8ed61d..3585711 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -20,6 +20,13 @@ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can al + /* logging */ + static int log_level = WLR_ERROR; + ++/* Autostart */ ++static const char *const autostart[] = { ++ "wbg", "/path/to/your/image", NULL, ++ NULL /* terminate */ ++}; ++ ++ + static const Rule rules[] = { + /* app_id title tags mask isfloating monitor */ + /* examples: +diff --git a/dwl.c b/dwl.c +index 10d5a5b..bbbef2b 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -236,6 +236,7 @@ static void arrange(Monitor *m); + static void arrangelayer(Monitor *m, struct wl_list *list, + struct wlr_box *usable_area, int exclusive); + static void arrangelayers(Monitor *m); ++static void autostartexec(void); + static void axisnotify(struct wl_listener *listener, void *data); + static void buttonpress(struct wl_listener *listener, void *data); + static void chvt(const Arg *arg); +@@ -403,6 +404,9 @@ static xcb_atom_t netatom[NetLast]; + /* attempt to encapsulate suck into one file */ + #include "client.h" + ++static pid_t *autostart_pids; ++static size_t autostart_len; ++ + /* function implementations */ + void + applybounds(Client *c, struct wlr_box *bbox) +@@ -533,6 +537,27 @@ arrangelayers(Monitor *m) + } + } + ++void ++autostartexec(void) { ++ const char *const *p; ++ size_t i = 0; ++ ++ /* count entries */ ++ for (p = autostart; *p; autostart_len++, p++) ++ while (*++p); ++ ++ autostart_pids = calloc(autostart_len, sizeof(pid_t)); ++ for (p = autostart; *p; i++, p++) { ++ if ((autostart_pids[i] = fork()) == 0) { ++ setsid(); ++ execvp(*p, (char *const *)p); ++ die("dwl: execvp %s:", *p); ++ } ++ /* skip arguments */ ++ while (*++p); ++ } ++} ++ + void + axisnotify(struct wl_listener *listener, void *data) + { +@@ -630,11 +655,21 @@ checkidleinhibitor(struct wlr_surface *exclude) + void + cleanup(void) + { ++ size_t i; + #ifdef XWAYLAND + wlr_xwayland_destroy(xwayland); + xwayland = NULL; + #endif + wl_display_destroy_clients(dpy); ++ ++ /* kill child processes */ ++ for (i = 0; i < autostart_len; i++) { ++ if (0 < autostart_pids[i]) { ++ kill(autostart_pids[i], SIGTERM); ++ waitpid(autostart_pids[i], NULL, 0); ++ } ++ } ++ + if (child_pid > 0) { + kill(child_pid, SIGTERM); + waitpid(child_pid, NULL, 0); +@@ -1294,18 +1329,31 @@ void + handlesig(int signo) + { + if (signo == SIGCHLD) { +-#ifdef XWAYLAND + siginfo_t in; + /* wlroots expects to reap the XWayland process itself, so we + * use WNOWAIT to keep the child waitable until we know it's not + * XWayland. + */ + while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid +- && (!xwayland || in.si_pid != xwayland->server->pid)) +- waitpid(in.si_pid, NULL, 0); +-#else +- while (waitpid(-1, NULL, WNOHANG) > 0); ++#ifdef XWAYLAND ++ && (!xwayland || in.si_pid != xwayland->server->pid) + #endif ++ ) { ++ pid_t *p, *lim; ++ waitpid(in.si_pid, NULL, 0); ++ if (in.si_pid == child_pid) ++ child_pid = -1; ++ if (!(p = autostart_pids)) ++ continue; ++ lim = &p[autostart_len]; ++ ++ for (; p < lim; p++) { ++ if (*p == in.si_pid) { ++ *p = -1; ++ break; ++ } ++ } ++ } + } else if (signo == SIGINT || signo == SIGTERM) { + quit(NULL); + } +@@ -1965,6 +2013,7 @@ run(char *startup_cmd) + die("startup: backend_start"); + + /* Now that the socket exists and the backend is started, run the startup command */ ++ autostartexec(); + if (startup_cmd) { + int piperw[2]; + if (pipe(piperw) < 0) +-- +2.43.0 + diff --git a/patches/main...dm1tz:04-sticky.patch b/patches/main...dm1tz:04-sticky.patch new file mode 100644 index 0000000..18022f3 --- /dev/null +++ b/patches/main...dm1tz:04-sticky.patch @@ -0,0 +1,69 @@ +From 7ba760ab76353e9344a08902a5b12acb431d3843 Mon Sep 17 00:00:00 2001 +From: Dmitry Zakharchenko +Date: Wed, 4 Jan 2023 00:25:55 +0200 +Subject: [PATCH] sticky: sync with 0.4 + +--- + config.def.h | 1 + + dwl.c | 15 +++++++++++++-- + 2 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index a4f7c13d0..120c27aa1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -126,6 +126,7 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, ++ { MODKEY, XKB_KEY_s, togglesticky, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, +diff --git a/dwl.c b/dwl.c +index 19bb6ce34..ec8c4282d 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -64,7 +64,7 @@ + #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)->issticky)) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define END(A) ((A) + LENGTH(A)) + #define TAGMASK ((1 << LENGTH(tags)) - 1) +@@ -124,7 +124,7 @@ typedef struct { + #endif + unsigned int bw; + unsigned int tags; +- int isfloating, isurgent, isfullscreen; ++ int isfloating, isurgent, isfullscreen, issticky; + uint32_t resize; /* configure serial of a pending resize */ + } Client; + +@@ -295,6 +295,7 @@ static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *m); + static void togglefloating(const Arg *arg); ++static void togglesticky(const Arg *arg); + static void togglefullscreen(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); +@@ -2337,6 +2338,16 @@ togglefloating(const Arg *arg) + setfloating(sel, !sel->isfloating); + } + ++void ++togglesticky(const Arg *arg) ++{ ++ Client *sel = focustop(selmon); ++ if (!sel) ++ return; ++ sel->issticky = !sel->issticky; ++ arrange(selmon); ++} ++ + void + togglefullscreen(const Arg *arg) + { diff --git a/patches/main...dm1tz:04-swallow.patch b/patches/main...dm1tz:04-swallow.patch new file mode 100644 index 0000000..dd81b47 --- /dev/null +++ b/patches/main...dm1tz:04-swallow.patch @@ -0,0 +1,197 @@ +From bc61a2cc74f65ab5bba51ba65edc1efd1269d510 Mon Sep 17 00:00:00 2001 +From: Dmitry Zakharchenko +Date: Thu, 5 Jan 2023 14:57:48 +0200 +Subject: [PATCH] swallow: sync with 0.4 + +--- + config.def.h | 6 ++-- + dwl.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 100 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index a4f7c13d0..9dcedacd4 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -12,11 +12,11 @@ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + + static const Rule rules[] = { +- /* app_id title tags mask isfloating monitor */ ++ /* app_id title tags mask isfloating isterm noswallow monitor */ + /* examples: +- { "Gimp", NULL, 0, 1, -1 }, ++ { "Gimp", NULL, 0, 1, 0, 1, -1 }, + */ +- { "firefox", NULL, 1 << 8, 0, -1 }, ++ { "firefox", NULL, 1 << 8, 0, 0, 1, -1 }, + }; + + /* layout(s) */ +diff --git a/dwl.c b/dwl.c +index 19bb6ce34..262fa62c7 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -95,7 +95,8 @@ typedef struct { + } Button; + + 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* */ + struct wlr_box geom; /* layout-relative, includes border */ +@@ -124,9 +125,11 @@ typedef struct { + #endif + unsigned int bw; + unsigned int tags; +- int isfloating, isurgent, isfullscreen; ++ int isfloating, isurgent, isfullscreen, isterm, noswallow; + uint32_t resize; /* configure serial of a pending resize */ +-} Client; ++ pid_t pid; ++ Client *swallowing, *swallowedby; ++}; + + typedef struct { + uint32_t mod; +@@ -201,6 +204,8 @@ typedef struct { + const char *title; + unsigned int tags; + int isfloating; ++ int isterm; ++ int noswallow; + int monitor; + } Rule; + +@@ -310,6 +315,10 @@ static Monitor *xytomon(double x, double y); + static struct wlr_scene_node *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"; +@@ -453,6 +462,8 @@ applyrules(Client *c) + 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; + i = 0; + wl_list_for_each(m, &mons, link) +@@ -990,6 +1001,8 @@ createnotify(struct wl_listener *listener, void *data) + c->surface.xdg = xdg_surface; + c->bw = borderpx; + ++ wl_client_get_credentials(c->surface.xdg->client->client, &c->pid, NULL, NULL); ++ + LISTEN(&xdg_surface->events.map, &c->map, mapnotify); + LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); +@@ -1308,6 +1321,61 @@ fullscreennotify(struct wl_listener *listener, void *data) + setfullscreen(c, client_wants_fullscreen(c)); + } + ++pid_t ++getparentprocess(pid_t p) ++{ ++ unsigned int v = 0; ++ ++ FILE *f; ++ char buf[256]; ++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); ++ ++ 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); ++ ++ return (int)c; ++} ++ ++Client * ++termforwin(Client *w) ++{ ++ Client *c; ++ ++ if (!w->pid || w->isterm || w->noswallow) ++ return NULL; ++ ++ wl_list_for_each(c, &clients, link) ++ if (c->isterm && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) ++ return c; ++ ++ return NULL; ++} ++ ++void ++swallow(Client *c, Client *w) { ++ c->bw = w->bw; ++ c->isfloating = w->isfloating; ++ c->isurgent = w->isurgent; ++ c->isfullscreen = w->isfullscreen; ++ resize(c, w->geom, 0); ++ 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); ++} ++ + void + incnmaster(const Arg *arg) + { +@@ -1528,6 +1596,20 @@ mapnotify(struct wl_listener *listener, void *data) + } + printstatus(); + ++ if (!c->noswallow) { ++ Client *p = termforwin(c); ++ if (p) { ++ c->swallowedby = p; ++ p->swallowing = c; ++ wl_list_remove(&c->link); ++ wl_list_remove(&c->flink); ++ swallow(c,p); ++ wl_list_remove(&p->link); ++ wl_list_remove(&p->flink); ++ arrange(c->mon); ++ } ++ } ++ + unset_fullscreen: + m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); + wl_list_for_each(w, &clients, link) +@@ -2409,6 +2491,18 @@ unmapnotify(struct wl_listener *listener, void *data) + grabc = NULL; + } + ++ if (c->swallowing) { ++ c->swallowing->swallowedby = NULL; ++ c->swallowing = NULL; ++ } ++ ++ if (c->swallowedby) { ++ setfullscreen(c->swallowedby, 0); ++ swallow(c->swallowedby, c); ++ c->swallowedby->swallowing = NULL; ++ c->swallowedby = NULL; ++ } ++ + if (client_is_unmanaged(c)) { + if (c == exclusive_focus) + exclusive_focus = NULL;