implement version 5 with x11 support

This commit is contained in:
sad 2024-02-09 20:16:24 -07:00
parent 8006e79200
commit b21a09cb06
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG Key ID: 28D3A882F3E6AD02
6 changed files with 640 additions and 26 deletions

View File

@ -7,10 +7,11 @@
static const int sloppyfocus = 1; /* focus follows mouse */ 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 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 unsigned int borderpx = 1; /* border pixel of windows */
static const float rootcolor[] = COLOR(0x222222ff); static const float rootcolor[] = COLOR(0x330044);
static const float bordercolor[] = COLOR(0x444444ff); static const float bordercolor[] = COLOR(0x32CD32); // Lime green
static const float focuscolor[] = COLOR(0x005577ff); static const float focuscolor[] = COLOR(0x330044); // Darker purple
static const float urgentcolor[] = COLOR(0xff0000ff); 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 */ /* 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 */ 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 */ /* logging */
static int log_level = WLR_ERROR; 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[] = { static const Rule rules[] = {
/* app_id title tags mask isfloating monitor */ /* app_id title tags mask isfloating isterm noswallow monitor */
/* examples: /* 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) */ /* 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; 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 */ /* 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) \ #define TAGKEYS(KEY,SKEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << 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 } } #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* commands */ /* commands */
static const char *termcmd[] = { "foot", NULL }; static const char *termcmd[] = { "kitty", NULL };
static const char *menucmd[] = { "bemenu-run", 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[] = { static const Key keys[] = {
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */ /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
/* modifier key function argument */ /* modifier key function argument */
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} }, { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, { 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_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, { MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} },
{ MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} }, { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} },
{ MODKEY, XKB_KEY_Return, zoom, {0} }, { MODKEY, XKB_KEY_Return, zoom, {0} },
{ MODKEY, XKB_KEY_Tab, view, {0} }, { MODKEY, XKB_KEY_Tab, view, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {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_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XKB_KEY_space, setlayout, {0} }, { MODKEY, XKB_KEY_space, setlayout, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {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_e, togglefullscreen, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} }, { MODKEY, XKB_KEY_0, view, {.ui = ~0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.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, 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_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} }, { 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_1, XKB_KEY_exclam, 0),
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),

View File

@ -8,8 +8,7 @@ PREFIX = /usr/local
MANDIR = $(PREFIX)/share/man MANDIR = $(PREFIX)/share/man
DATADIR = $(PREFIX)/share DATADIR = $(PREFIX)/share
XWAYLAND =
XLIBS =
# Uncomment to build XWayland support # Uncomment to build XWayland support
#XWAYLAND = -DXWAYLAND XWAYLAND = -DXWAYLAND
#XLIBS = xcb xcb-icccm XLIBS = xcb xcb-icccm

173
dwl.c
View File

@ -68,7 +68,7 @@
#define MIN(A, B) ((A) < (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B))
#define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5))) #define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5)))
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) #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 LENGTH(X) (sizeof X / sizeof X[0])
#define END(A) ((A) + LENGTH(A)) #define END(A) ((A) + LENGTH(A))
#define TAGMASK ((1u << TAGCOUNT) - 1) #define TAGMASK ((1u << TAGCOUNT) - 1)
@ -99,7 +99,8 @@ typedef struct {
} Button; } Button;
typedef struct Monitor Monitor; typedef struct Monitor Monitor;
typedef struct { typedef struct Client Client;
struct Client {
/* Must keep these three elements in this order */ /* Must keep these three elements in this order */
unsigned int type; /* XDGShell or X11* */ unsigned int type; /* XDGShell or X11* */
struct wlr_box geom; /* layout-relative, includes border */ struct wlr_box geom; /* layout-relative, includes border */
@ -134,9 +135,11 @@ typedef struct {
#endif #endif
unsigned int bw; unsigned int bw;
uint32_t tags; uint32_t tags;
int isfloating, isurgent, isfullscreen; int isfloating, isurgent, isfullscreen, issticky, isterm, noswallow;
uint32_t resize; /* configure serial of a pending resize */ uint32_t resize; /* configure serial of a pending resize */
} Client; pid_t pid;
Client *swallowing, *swallowedby;
};
typedef struct { typedef struct {
uint32_t mod; uint32_t mod;
@ -219,6 +222,8 @@ typedef struct {
const char *title; const char *title;
uint32_t tags; uint32_t tags;
int isfloating; int isfloating;
int isterm;
int noswallow;
int monitor; int monitor;
} Rule; } Rule;
@ -238,6 +243,7 @@ static void arrange(Monitor *m);
static void arrangelayer(Monitor *m, struct wl_list *list, static void arrangelayer(Monitor *m, struct wl_list *list,
struct wlr_box *usable_area, int exclusive); struct wlr_box *usable_area, int exclusive);
static void arrangelayers(Monitor *m); static void arrangelayers(Monitor *m);
static void autostartexec(void);
static void axisnotify(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data);
static void buttonpress(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data);
static void chvt(const Arg *arg); static void chvt(const Arg *arg);
@ -318,6 +324,7 @@ static void tag(const Arg *arg);
static void tagmon(const Arg *arg); static void tagmon(const Arg *arg);
static void tile(Monitor *m); static void tile(Monitor *m);
static void togglefloating(const Arg *arg); static void togglefloating(const Arg *arg);
static void togglesticky(const Arg *arg);
static void togglefullscreen(const Arg *arg); static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg); static void toggletag(const Arg *arg);
static void toggleview(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, static void xytonode(double x, double y, struct wlr_surface **psurface,
Client **pc, LayerSurface **pl, double *nx, double *ny); Client **pc, LayerSurface **pl, double *nx, double *ny);
static void zoom(const Arg *arg); 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 */ /* variables */
static const char broken[] = "broken"; static const char broken[] = "broken";
@ -407,6 +418,9 @@ static xcb_atom_t netatom[NetLast];
/* attempt to encapsulate suck into one file */ /* attempt to encapsulate suck into one file */
#include "client.h" #include "client.h"
static pid_t *autostart_pids;
static size_t autostart_len;
/* function implementations */ /* function implementations */
void void
applybounds(Client *c, struct wlr_box *bbox) applybounds(Client *c, struct wlr_box *bbox)
@ -445,6 +459,8 @@ applyrules(Client *c)
if ((!r->title || strstr(title, r->title)) if ((!r->title || strstr(title, r->title))
&& (!r->id || strstr(appid, r->id))) { && (!r->id || strstr(appid, r->id))) {
c->isfloating = r->isfloating; c->isfloating = r->isfloating;
c->isterm = r->isterm;
c->noswallow = r->noswallow;
newtags |= r->tags; newtags |= r->tags;
i = 0; i = 0;
wl_list_for_each(m, &mons, link) { 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 void
axisnotify(struct wl_listener *listener, void *data) axisnotify(struct wl_listener *listener, void *data)
{ {
@ -638,11 +675,21 @@ checkidleinhibitor(struct wlr_surface *exclude)
void void
cleanup(void) cleanup(void)
{ {
size_t i;
#ifdef XWAYLAND #ifdef XWAYLAND
wlr_xwayland_destroy(xwayland); wlr_xwayland_destroy(xwayland);
xwayland = NULL; xwayland = NULL;
#endif #endif
wl_display_destroy_clients(dpy); 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) { if (child_pid > 0) {
kill(child_pid, SIGTERM); kill(child_pid, SIGTERM);
waitpid(child_pid, NULL, 0); waitpid(child_pid, NULL, 0);
@ -957,6 +1004,7 @@ createnotify(struct wl_listener *listener, void *data)
c->surface.xdg = xdg_surface; c->surface.xdg = xdg_surface;
c->bw = borderpx; 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_set_wm_capabilities(xdg_surface->toplevel,
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
@ -1303,23 +1351,91 @@ void
handlesig(int signo) handlesig(int signo)
{ {
if (signo == SIGCHLD) { if (signo == SIGCHLD) {
#ifdef XWAYLAND
siginfo_t in; siginfo_t in;
/* wlroots expects to reap the XWayland process itself, so we /* wlroots expects to reap the XWayland process itself, so we
* use WNOWAIT to keep the child waitable until we know it's not * use WNOWAIT to keep the child waitable until we know it's not
* XWayland. * XWayland.
*/ */
while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid
&& (!xwayland || in.si_pid != xwayland->server->pid)) #ifdef XWAYLAND
waitpid(in.si_pid, NULL, 0); && (!xwayland || in.si_pid != xwayland->server->pid)
#else
while (waitpid(-1, NULL, WNOHANG) > 0);
#endif #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) { } else if (signo == SIGINT || signo == SIGTERM) {
quit(NULL); 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 void
incnmaster(const Arg *arg) incnmaster(const Arg *arg)
{ {
@ -1552,6 +1668,20 @@ mapnotify(struct wl_listener *listener, void *data)
} }
printstatus(); 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: unset_fullscreen:
m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y);
wl_list_for_each(w, &clients, link) { wl_list_for_each(w, &clients, link) {
@ -1972,6 +2102,7 @@ run(char *startup_cmd)
die("startup: backend_start"); die("startup: backend_start");
/* Now that the socket exists and the backend is started, run the startup command */ /* Now that the socket exists and the backend is started, run the startup command */
autostartexec();
if (startup_cmd) { if (startup_cmd) {
int piperw[2]; int piperw[2];
if (pipe(piperw) < 0) if (pipe(piperw) < 0)
@ -2506,6 +2637,16 @@ togglefloating(const Arg *arg)
setfloating(sel, !sel->isfloating); setfloating(sel, !sel->isfloating);
} }
void
togglesticky(const Arg *arg)
{
Client *sel = focustop(selmon);
if (!sel)
return;
sel->issticky = !sel->issticky;
arrange(selmon);
}
void void
togglefullscreen(const Arg *arg) togglefullscreen(const Arg *arg)
{ {
@ -2574,6 +2715,18 @@ unmapnotify(struct wl_listener *listener, void *data)
grabc = NULL; 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 (client_is_unmanaged(c)) {
if (c == exclusive_focus) { if (c == exclusive_focus) {
exclusive_focus = NULL; exclusive_focus = NULL;

154
patches/autostart.patch Normal file
View File

@ -0,0 +1,154 @@
From 51d56a433f23e13ac711b283a03c7903068febf6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?=
<leohdz172@proton.me>
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 <leohdz172@proton.me>
---
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

View File

@ -0,0 +1,69 @@
From 7ba760ab76353e9344a08902a5b12acb431d3843 Mon Sep 17 00:00:00 2001
From: Dmitry Zakharchenko <dmitz@disroot.org>
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)
{

View File

@ -0,0 +1,197 @@
From bc61a2cc74f65ab5bba51ba65edc1efd1269d510 Mon Sep 17 00:00:00 2001
From: Dmitry Zakharchenko <dmitz@disroot.org>
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;