Compare commits

...

12 commits

10 changed files with 184 additions and 335 deletions

6
.envrc Normal file
View file

@ -0,0 +1,6 @@
watch_file shell.nix
watch_file flake.lock
# try to use flakes, if it fails use normal nix (ie. shell.nix)
use flake || use nix
eval "$shellHook"

3
.gitignore vendored
View file

@ -4,3 +4,6 @@ dwl
*-protocol.h *-protocol.h
.ccls-cache .ccls-cache
config.h config.h
.direnv
custom_dwl.patch
.cache

View file

@ -4,7 +4,7 @@
include config.mk include config.mk
# flags for compiling # flags for compiling
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND) DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\"
DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wshadow -Wunused-macros\ DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wshadow -Wunused-macros\
-Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types -Wfloat-conversion -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types -Wfloat-conversion
@ -38,7 +38,7 @@ cursor-shape-v1-protocol.h:
config.h: config.h:
cp config.def.h $@ cp config.def.h $@
clean: clean:
rm -f dwl *.o *-protocol.h rm -f dwl *.o *-protocol.h config.h
dist: clean dist: clean
mkdir -p dwl-$(VERSION) mkdir -p dwl-$(VERSION)

127
client.h
View file

@ -9,19 +9,12 @@
static inline int static inline int
client_is_x11(Client *c) client_is_x11(Client *c)
{ {
#ifdef XWAYLAND
return c->type == X11;
#endif
return 0; return 0;
} }
static inline struct wlr_surface * static inline struct wlr_surface *
client_surface(Client *c) client_surface(Client *c)
{ {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->surface;
#endif
return c->surface.xdg->surface; return c->surface.xdg->surface;
} }
@ -34,22 +27,11 @@ toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
Client *c = NULL; Client *c = NULL;
LayerSurface *l = NULL; LayerSurface *l = NULL;
int type = -1; int type = -1;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
#endif
if (!s) if (!s)
return -1; return -1;
root_surface = wlr_surface_get_root_surface(s); root_surface = wlr_surface_get_root_surface(s);
#ifdef XWAYLAND
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
c = xsurface->data;
type = c->type;
goto end;
}
#endif
if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) { if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
l = layer_surface->data; l = layer_surface->data;
type = LayerShell; type = LayerShell;
@ -93,13 +75,6 @@ static inline void
client_activate_surface(struct wlr_surface *s, int activated) client_activate_surface(struct wlr_surface *s, int activated)
{ {
struct wlr_xdg_toplevel *toplevel; struct wlr_xdg_toplevel *toplevel;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
wlr_xwayland_surface_activate(xsurface, activated);
return;
}
#endif
if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s))) if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
wlr_xdg_toplevel_set_activated(toplevel, activated); wlr_xdg_toplevel_set_activated(toplevel, activated);
} }
@ -107,10 +82,6 @@ client_activate_surface(struct wlr_surface *s, int activated)
static inline uint32_t static inline uint32_t
client_set_bounds(Client *c, int32_t width, int32_t height) client_set_bounds(Client *c, int32_t width, int32_t height)
{ {
#ifdef XWAYLAND
if (client_is_x11(c))
return 0;
#endif
if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0 XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0
&& (c->bounds.width != width || c->bounds.height != height)) { && (c->bounds.width != width || c->bounds.height != height)) {
@ -124,10 +95,6 @@ client_set_bounds(Client *c, int32_t width, int32_t height)
static inline const char * static inline const char *
client_get_appid(Client *c) client_get_appid(Client *c)
{ {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->class;
#endif
return c->surface.xdg->toplevel->app_id; return c->surface.xdg->toplevel->app_id;
} }
@ -142,11 +109,6 @@ client_get_clip(Client *c, struct wlr_box *clip)
.height = c->geom.height - c->bw, .height = c->geom.height - c->bw,
}; };
#ifdef XWAYLAND
if (client_is_x11(c))
return;
#endif
wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom); wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom);
clip->x = xdg_geom.x; clip->x = xdg_geom.x;
clip->y = xdg_geom.y; clip->y = xdg_geom.y;
@ -155,15 +117,6 @@ client_get_clip(Client *c, struct wlr_box *clip)
static inline void static inline void
client_get_geometry(Client *c, struct wlr_box *geom) client_get_geometry(Client *c, struct wlr_box *geom)
{ {
#ifdef XWAYLAND
if (client_is_x11(c)) {
geom->x = c->surface.xwayland->x;
geom->y = c->surface.xwayland->y;
geom->width = c->surface.xwayland->width;
geom->height = c->surface.xwayland->height;
return;
}
#endif
wlr_xdg_surface_get_geometry(c->surface.xdg, geom); wlr_xdg_surface_get_geometry(c->surface.xdg, geom);
} }
@ -171,10 +124,6 @@ static inline Client *
client_get_parent(Client *c) client_get_parent(Client *c)
{ {
Client *p = NULL; Client *p = NULL;
#ifdef XWAYLAND
if (client_is_x11(c) && c->surface.xwayland->parent)
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
#endif
if (c->surface.xdg->toplevel->parent) if (c->surface.xdg->toplevel->parent)
toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
return p; return p;
@ -183,10 +132,6 @@ client_get_parent(Client *c)
static inline const char * static inline const char *
client_get_title(Client *c) client_get_title(Client *c)
{ {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->title;
#endif
return c->surface.xdg->toplevel->title; return c->surface.xdg->toplevel->title;
} }
@ -196,27 +141,6 @@ client_is_float_type(Client *c)
struct wlr_xdg_toplevel *toplevel; struct wlr_xdg_toplevel *toplevel;
struct wlr_xdg_toplevel_state state; struct wlr_xdg_toplevel_state state;
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
xcb_size_hints_t *size_hints = surface->size_hints;
size_t i;
if (surface->modal)
return 1;
for (i = 0; i < surface->window_type_len; i++)
if (surface->window_type[i] == netatom[NetWMWindowTypeDialog]
|| surface->window_type[i] == netatom[NetWMWindowTypeSplash]
|| surface->window_type[i] == netatom[NetWMWindowTypeToolbar]
|| surface->window_type[i] == netatom[NetWMWindowTypeUtility])
return 1;
return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
&& (size_hints->max_width == size_hints->min_width
|| size_hints->max_height == size_hints->min_height);
}
#endif
toplevel = c->surface.xdg->toplevel; toplevel = c->surface.xdg->toplevel;
state = toplevel->current; state = toplevel->current;
return toplevel->parent || (state.min_width != 0 && state.min_height != 0 return toplevel->parent || (state.min_width != 0 && state.min_height != 0
@ -245,10 +169,6 @@ client_is_stopped(Client *c)
{ {
int pid; int pid;
siginfo_t in = {0}; siginfo_t in = {0};
#ifdef XWAYLAND
if (client_is_x11(c))
return 0;
#endif
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) { if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
@ -269,10 +189,6 @@ client_is_stopped(Client *c)
static inline int static inline int
client_is_unmanaged(Client *c) client_is_unmanaged(Client *c)
{ {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->override_redirect;
#endif
return 0; return 0;
} }
@ -289,23 +205,12 @@ client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
static inline void static inline void
client_restack_surface(Client *c) client_restack_surface(Client *c)
{ {
#ifdef XWAYLAND
if (client_is_x11(c))
wlr_xwayland_surface_restack(c->surface.xwayland, NULL,
XCB_STACK_MODE_ABOVE);
#endif
return; return;
} }
static inline void static inline void
client_send_close(Client *c) client_send_close(Client *c)
{ {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_close(c->surface.xwayland);
return;
}
#endif
wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel); wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
} }
@ -320,25 +225,12 @@ client_set_border_color(Client *c, const float color[static 4])
static inline void static inline void
client_set_fullscreen(Client *c, int fullscreen) client_set_fullscreen(Client *c, int fullscreen)
{ {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
return;
}
#endif
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen); wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
} }
static inline uint32_t static inline uint32_t
client_set_size(Client *c, uint32_t width, uint32_t height) client_set_size(Client *c, uint32_t width, uint32_t height)
{ {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_configure(c->surface.xwayland,
c->geom.x, c->geom.y, width, height);
return 0;
}
#endif
if ((int32_t)width == c->surface.xdg->toplevel->current.width if ((int32_t)width == c->surface.xdg->toplevel->current.width
&& (int32_t)height == c->surface.xdg->toplevel->current.height) && (int32_t)height == c->surface.xdg->toplevel->current.height)
return 0; return 0;
@ -348,10 +240,6 @@ client_set_size(Client *c, uint32_t width, uint32_t height)
static inline void static inline void
client_set_tiled(Client *c, uint32_t edges) client_set_tiled(Client *c, uint32_t edges)
{ {
#ifdef XWAYLAND
if (client_is_x11(c))
return;
#endif
if (wl_resource_get_version(c->surface.xdg->toplevel->resource) if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
@ -363,12 +251,6 @@ client_set_tiled(Client *c, uint32_t edges)
static inline void static inline void
client_set_suspended(Client *c, int suspended) client_set_suspended(Client *c, int suspended)
{ {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_withdrawn(c->surface.xwayland, suspended);
return;
}
#endif
wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
} }
@ -376,20 +258,11 @@ client_set_suspended(Client *c, int suspended)
static inline int static inline int
client_wants_focus(Client *c) client_wants_focus(Client *c)
{ {
#ifdef XWAYLAND
return client_is_unmanaged(c)
&& wlr_xwayland_or_surface_wants_focus(c->surface.xwayland)
&& wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
#endif
return 0; return 0;
} }
static inline int static inline int
client_wants_fullscreen(Client *c) client_wants_fullscreen(Client *c)
{ {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->fullscreen;
#endif
return c->surface.xdg->toplevel->requested.fullscreen; return c->surface.xdg->toplevel->requested.fullscreen;
} }

View file

@ -14,6 +14,17 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
/* 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 */
/* Autostart */
static const char *const autostart[] = {
"gammastep-indicator", NULL,
"foot", NULL,
"todoodoo", NULL,
"firefox", NULL,
"somebar", NULL,
"someblocks", NULL,
NULL /* terminate */
};
/* tagging - TAGCOUNT must be no greater than 31 */ /* tagging - TAGCOUNT must be no greater than 31 */
#define TAGCOUNT (9) #define TAGCOUNT (9)
@ -25,7 +36,8 @@ static const Rule rules[] = {
/* examples: /* examples:
{ "Gimp", NULL, 0, 1, -1 }, { "Gimp", NULL, 0, 1, -1 },
*/ */
{ "firefox", NULL, 1 << 8, 0, -1 }, { "todoodoo", NULL, 1 << 1, 0, 1 },
{ "firefox", NULL, 1 << 8, 0, 0 },
}; };
/* layout(s) */ /* layout(s) */
@ -43,6 +55,7 @@ static const MonitorRule monrules[] = {
/* example of a HiDPI laptop monitor: /* example of a HiDPI laptop monitor:
{ "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, { "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
*/ */
{ "DP-3", 0.5, 1, 1.5, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
/* defaults */ /* defaults */
{ NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, { NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
}; };
@ -50,9 +63,10 @@ static const MonitorRule monrules[] = {
/* keyboard */ /* keyboard */
static const struct xkb_rule_names xkb_rules = { static const struct xkb_rule_names xkb_rules = {
/* can specify fields: rules, model, layout, variant, options */ /* can specify fields: rules, model, layout, variant, options */
/* example: .rules = NULL,
.options = "ctrl:nocaps", .model = NULL,
*/ .layout = "us",
.variant = "intl",
.options = NULL, .options = NULL,
}; };
@ -101,8 +115,8 @@ 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 alt key for MODKEY, use WLR_MODIFIER_ALT */
#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} }, \
@ -113,15 +127,12 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } #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 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, SHCMD("dmenu_path | wmenu | xargs -I_-_ /bin/sh -c \"exec _-_\"") },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_S, spawn, SHCMD("slurp | grim -g - - | wl-copy -t image/png") },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = (char*[]){ "foot", NULL } } },
{ 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} },

272
dwl.c
View file

@ -54,11 +54,6 @@
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#ifdef XWAYLAND
#include <wlr/xwayland.h>
#include <xcb/xcb.h>
#include <xcb/xcb_icccm.h>
#endif
#include "util.h" #include "util.h"
@ -78,10 +73,6 @@
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */ enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
#endif
typedef union { typedef union {
int i; int i;
@ -124,13 +115,6 @@ typedef struct {
struct wl_listener destroy_decoration; struct wl_listener destroy_decoration;
struct wlr_box prev; /* layout-relative, includes border */ struct wlr_box prev; /* layout-relative, includes border */
struct wlr_box bounds; struct wlr_box bounds;
#ifdef XWAYLAND
struct wl_listener activate;
struct wl_listener associate;
struct wl_listener dissociate;
struct wl_listener configure;
struct wl_listener set_hints;
#endif
unsigned int bw; unsigned int bw;
uint32_t tags; uint32_t tags;
int isfloating, isurgent, isfullscreen; int isfloating, isurgent, isfullscreen;
@ -232,6 +216,7 @@ typedef struct {
/* function declarations */ /* function declarations */
static void applybounds(Client *c, struct wlr_box *bbox); static void applybounds(Client *c, struct wlr_box *bbox);
static void autostartexec(void);
static void applyrules(Client *c); static void applyrules(Client *c);
static void arrange(Monitor *m); static void arrange(Monitor *m);
static void arrangelayer(Monitor *m, struct wl_list *list, static void arrangelayer(Monitor *m, struct wl_list *list,
@ -334,6 +319,7 @@ static void xytonode(double x, double y, struct wlr_surface **psurface,
static void zoom(const Arg *arg); static void zoom(const Arg *arg);
/* variables */ /* variables */
static char const* autostart_runtime[256] = {NULL};
static const char broken[] = "broken"; static const char broken[] = "broken";
static pid_t child_pid = -1; static pid_t child_pid = -1;
static int locked; static int locked;
@ -385,25 +371,15 @@ static struct wlr_box sgeom;
static struct wl_list mons; static struct wl_list mons;
static Monitor *selmon; static Monitor *selmon;
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
static void configurex11(struct wl_listener *listener, void *data);
static void createnotifyx11(struct wl_listener *listener, void *data);
static void dissociatex11(struct wl_listener *listener, void *data);
static xcb_atom_t getatom(xcb_connection_t *xc, const char *name);
static void sethints(struct wl_listener *listener, void *data);
static void xwaylandready(struct wl_listener *listener, void *data);
static struct wlr_xwayland *xwayland;
static xcb_atom_t netatom[NetLast];
#endif
/* configuration, allows nested code to access above variables */ /* configuration, allows nested code to access above variables */
#include "config.h" #include "config.h"
/* 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)
@ -422,6 +398,39 @@ applybounds(Client *c, struct wlr_box *bbox)
c->geom.y = bbox->y; c->geom.y = bbox->y;
} }
void
autostartexec(void) {
const char *const *p;
size_t i = 0;
/* count entries */
for (p = autostart; *p; autostart_len++, p++)
while (*++p);
/* count runtime entries */
for (p = autostart_runtime; *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);
}
for (p = autostart_runtime; *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
applyrules(Client *c) applyrules(Client *c)
{ {
@ -632,11 +641,17 @@ checkidleinhibitor(struct wlr_surface *exclude)
void void
cleanup(void) cleanup(void)
{ {
#ifdef XWAYLAND size_t i;
wlr_xwayland_destroy(xwayland);
xwayland = NULL;
#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);
@ -1111,20 +1126,9 @@ destroynotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->destroy.link); wl_list_remove(&c->destroy.link);
wl_list_remove(&c->set_title.link); wl_list_remove(&c->set_title.link);
wl_list_remove(&c->fullscreen.link); wl_list_remove(&c->fullscreen.link);
#ifdef XWAYLAND
if (c->type != XDGShell) {
wl_list_remove(&c->activate.link);
wl_list_remove(&c->associate.link);
wl_list_remove(&c->configure.link);
wl_list_remove(&c->dissociate.link);
wl_list_remove(&c->set_hints.link);
} else
#endif
{
wl_list_remove(&c->commit.link); wl_list_remove(&c->commit.link);
wl_list_remove(&c->map.link); wl_list_remove(&c->map.link);
wl_list_remove(&c->unmap.link); wl_list_remove(&c->unmap.link);
}
free(c); free(c);
} }
@ -1296,18 +1300,27 @@ 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)) pid_t *p, *lim;
waitpid(in.si_pid, NULL, 0); waitpid(in.si_pid, NULL, 0);
#else if (in.si_pid == child_pid)
while (waitpid(-1, NULL, WNOHANG) > 0); child_pid = -1;
#endif 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);
} }
@ -1963,6 +1976,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)
@ -2390,20 +2404,6 @@ setup(void)
* e.g when running in the x11 backend or the wayland backend and the * e.g when running in the x11 backend or the wayland backend and the
* compositor has Xwayland support */ * compositor has Xwayland support */
unsetenv("DISPLAY"); unsetenv("DISPLAY");
#ifdef XWAYLAND
/*
* Initialise the XWayland X server.
* It will be started when the first X client is started.
*/
if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) {
LISTEN_STATIC(&xwayland->events.ready, xwaylandready);
LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11);
setenv("DISPLAY", xwayland->display_name, 1);
} else {
fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");
}
#endif
} }
void void
@ -2798,140 +2798,27 @@ zoom(const Arg *arg)
arrange(selmon); arrange(selmon);
} }
#ifdef XWAYLAND
void
activatex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, activate);
/* Only "managed" windows can be activated */
if (!client_is_unmanaged(c))
wlr_xwayland_surface_activate(c->surface.xwayland, 1);
}
void
associatex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, associate);
LISTEN(&client_surface(c)->events.map, &c->map, mapnotify);
LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify);
}
void
configurex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, configure);
struct wlr_xwayland_surface_configure_event *event = data;
if (!c->mon)
return;
if (c->isfloating || client_is_unmanaged(c))
resize(c, (struct wlr_box){.x = event->x, .y = event->y,
.width = event->width, .height = event->height}, 0);
else
arrange(c->mon);
}
void
createnotifyx11(struct wl_listener *listener, void *data)
{
struct wlr_xwayland_surface *xsurface = data;
Client *c;
/* Allocate a Client for this surface */
c = xsurface->data = ecalloc(1, sizeof(*c));
c->surface.xwayland = xsurface;
c->type = X11;
c->bw = borderpx;
/* Listen to the various events it can emit */
LISTEN(&xsurface->events.associate, &c->associate, associatex11);
LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify);
LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11);
LISTEN(&xsurface->events.request_activate, &c->activate, activatex11);
LISTEN(&xsurface->events.request_configure, &c->configure, configurex11);
LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify);
LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints);
LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle);
}
void
dissociatex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, dissociate);
wl_list_remove(&c->map.link);
wl_list_remove(&c->unmap.link);
}
xcb_atom_t
getatom(xcb_connection_t *xc, const char *name)
{
xcb_atom_t atom = 0;
xcb_intern_atom_reply_t *reply;
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name);
if ((reply = xcb_intern_atom_reply(xc, cookie, NULL)))
atom = reply->atom;
free(reply);
return atom;
}
void
sethints(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, set_hints);
struct wlr_surface *surface = client_surface(c);
if (c == focustop(selmon))
return;
c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
printstatus();
if (c->isurgent && surface && surface->mapped)
client_set_border_color(c, urgentcolor);
}
void
xwaylandready(struct wl_listener *listener, void *data)
{
struct wlr_xcursor *xcursor;
xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL);
int err = xcb_connection_has_error(xc);
if (err) {
fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err);
return;
}
/* Collect atoms we are interested in. If getatom returns 0, we will
* not detect that window type. */
netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG");
netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH");
netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR");
netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY");
/* assign the one and only seat */
wlr_xwayland_set_seat(xwayland, seat);
/* Set the default XWayland cursor to match the rest of dwl. */
if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1)))
wlr_xwayland_set_cursor(xwayland,
xcursor->images[0]->buffer, xcursor->images[0]->width * 4,
xcursor->images[0]->width, xcursor->images[0]->height,
xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);
xcb_disconnect(xc);
}
#endif
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
char *startup_cmd = NULL; char *startup_cmd = NULL;
int c; int c;
char *path = calloc(8192, sizeof(char));
while ((c = getopt(argc, argv, "s:hdv")) != -1) { int autostart_runtime_idx = 0;
strcat(path, getenv("PATH"));
while ((c = getopt(argc, argv, "e:p:s:hdv")) != -1) {
if (c == 's') if (c == 's')
startup_cmd = optarg; startup_cmd = optarg;
else if (c == 'p') {
strcat(path, ":");
strcat(path, optarg);
}
else if (c == 'e') {
autostart_runtime[autostart_runtime_idx] = optarg;
autostart_runtime_idx++;
}
else if (c == 'd') else if (c == 'd')
log_level = WLR_DEBUG; log_level = WLR_DEBUG;
else if (c == 'v') else if (c == 'v')
@ -2945,11 +2832,14 @@ main(int argc, char *argv[])
/* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */
if (!getenv("XDG_RUNTIME_DIR")) if (!getenv("XDG_RUNTIME_DIR"))
die("XDG_RUNTIME_DIR must be set"); die("XDG_RUNTIME_DIR must be set");
if (setenv("PATH", path, 1))
die("Failed to set PATH");
free(path);
setup(); setup();
run(startup_cmd); run(startup_cmd);
cleanup(); cleanup();
return EXIT_SUCCESS; return EXIT_SUCCESS;
usage: usage:
die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); die("Usage: %s [-v] [-d] [-s startup command] [[-p path directory] ...] [[-e autostart file] ...]", argv[0]);
} }

27
flake.lock Normal file
View file

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1705856552,
"narHash": "sha256-JXfnuEf5Yd6bhMs/uvM67/joxYKoysyE3M2k6T3eWbg=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "612f97239e2cc474c13c9dafa0df378058c5ad8d",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

17
flake.nix Normal file
View file

@ -0,0 +1,17 @@
{
description = "ToDooDoo";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
supportedSystems = [ "x86_64-linux" ];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
pkgsFor = nixpkgs.legacyPackages;
in {
devShells = forAllSystems (system: {
default = pkgsFor.${system}.callPackage ./shell.nix { };
});
};
}

1
generate_patch.sh Executable file
View file

@ -0,0 +1 @@
git diff v0.5 > custom_dwl.patch

21
shell.nix Normal file
View file

@ -0,0 +1,21 @@
{ pkgs ? import <nixpkgs> { }, lib }:
let packages = with pkgs; [
pkg-config
wayland
wayland-protocols
wlroots
libxkbcommon
libinput
pixman
glibc
];
in
pkgs.mkShell {
inherit packages;
nativeBuildInputs = packages;
buildInputs = packages;
env = {
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
LD_LIBRARY_PATH = "${lib.makeLibraryPath packages}";
};
}