Compare commits

..

No commits in common. "47a1135b594c0b61a15c8ac6ebf8e38b8adab7cb" and "9837ea5729c01bbbec10f6200509146a1b7bd28c" have entirely different histories.

20 changed files with 204 additions and 7638 deletions

View file

@ -12,7 +12,7 @@ DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
-Wfloat-conversion
# CFLAGS / LDFLAGS
PKGS = wayland-server xkbcommon libinput pixman-1 fcft $(XLIBS)
PKGS = wayland-server xkbcommon libinput $(XLIBS)
DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)

View file

@ -1,8 +1,15 @@
# dwl - dwm for Wayland
Join us on our [Discord server]
Or Matrix: [#dwl-official:matrix.org]
Or on our IRC channel: [#dwl on Libera Chat]
2025-08-16:
dwl IS CURRENTLY UN-MAINTAINED.
AT THE PRESENT TIME, I (@fauxmight) DO NOT HAVE
THE TIME OR CAPACITY TO KEEP UP WITH [wlroots] CHANGES.
IF YOU ARE INTERESTED IN TAKING ON LEAD DEVELOPER RESPONSIBILITIES,
SEE ISSUE [#1166](https://codeberg.org/dwl/dwl/issues/1166).
---
Join us on our IRC channel: [#dwl on Libera Chat]
Or on the community-maintained [Discord server].
dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is
intended to fill the same space in the Wayland world that [dwm] does in X11,
@ -24,14 +31,12 @@ with each release on the [release] page
### Development branch [main]
Active development progresses on the `main` branch. The `main` branch is built
against the latest release of [wlroots]. PRs should target this branch unless they
depend on functionality that is not in the current release of `wlroots`.
### Preview branch [wlroots-next]
The `wlroots-next` branch is built against the git version of [wlroots], which
is unstable and changes frequently. PRs requiring functionality from the git
version of `wlroots` should target this branch.
against a late (and often changing) git commit of wlroots. While the adventurous
are welcome to use `main`, it is a rocky road. Using `main` requires that the
user be willing to chase git commits of wlroots. Testing development pull
requests may involve merging unmerged pull requests in [wlroots]' git repository
and/or git commits of wayland.
### Building dwl
dwl has the following dependencies:
- libinput
@ -205,7 +210,6 @@ inspiration, and to the various contributors to the project, including:
[dwl-patches]: https://codeberg.org/dwl/dwl-patches
[list of useful resources on our wiki]: https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x
[main]: https://codeberg.org/dwl/dwl/src/branch/main
[wlroots-next]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next
[release]: https://codeberg.org/dwl/dwl/releases
[runit]: http://smarden.org/runit/faq.html#userservices
[s6]: https://skarnet.org/software/s6/
@ -213,4 +217,3 @@ inspiration, and to the various contributors to the project, including:
[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars
[Discord server]: https://discord.gg/jJxZnrGPWN
[Wayland]: https://wayland.freedesktop.org/
[#dwl-official:matrix.org]: https://matrix.to/#/#dwl-official:matrix.org

View file

@ -318,12 +318,6 @@ client_set_border_color(Client *c, const float color[static 4])
wlr_scene_rect_set_color(c->border[i], color);
}
static inline void
client_set_dimmer_state(Client *c, const int dim)
{
wlr_scene_node_set_enabled(&c->dimmer->node, DIMOPT && !c->neverdim && dim);
}
static inline void
client_set_fullscreen(Client *c, int fullscreen)
{

View file

@ -1,404 +0,0 @@
/*
* Attempt to consolidate unavoidable suck into one file, away from dwl.c. This
* file is not meant to be pretty. We use a .h file with static inline
* functions instead of a separate .c module, or function pointers like sway, so
* that they will simply compile out if the chosen #defines leave them unused.
*/
/* Leave these functions first; they're used in the others */
static inline int
client_is_x11(Client *c)
{
#ifdef XWAYLAND
return c->type == X11;
#endif
return 0;
}
static inline struct wlr_surface *
client_surface(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->surface;
#endif
return c->surface.xdg->surface;
}
static inline int
toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
{
struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
struct wlr_surface *root_surface;
struct wlr_layer_surface_v1 *layer_surface;
Client *c = NULL;
LayerSurface *l = NULL;
int type = -1;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
#endif
if (!s)
return -1;
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))) {
l = layer_surface->data;
type = LayerShell;
goto end;
}
xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
while (xdg_surface) {
tmp_xdg_surface = NULL;
switch (xdg_surface->role) {
case WLR_XDG_SURFACE_ROLE_POPUP:
if (!xdg_surface->popup || !xdg_surface->popup->parent)
return -1;
tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
if (!tmp_xdg_surface)
return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
xdg_surface = tmp_xdg_surface;
break;
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
c = xdg_surface->data;
type = c->type;
goto end;
case WLR_XDG_SURFACE_ROLE_NONE:
return -1;
}
}
end:
if (pl)
*pl = l;
if (pc)
*pc = c;
return type;
}
/* The others */
static inline void
client_activate_surface(struct wlr_surface *s, int activated)
{
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)))
wlr_xdg_toplevel_set_activated(toplevel, activated);
}
static inline uint32_t
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) >=
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;
return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
}
return 0;
}
static inline const char *
client_get_appid(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->class ? c->surface.xwayland->class : "broken";
#endif
return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id : "broken";
}
static inline void
client_get_clip(Client *c, struct wlr_box *clip)
{
*clip = (struct wlr_box){
.x = 0,
.y = 0,
.width = c->geom.width - c->bw,
.height = c->geom.height - c->bw,
};
#ifdef XWAYLAND
if (client_is_x11(c))
return;
#endif
clip->x = c->surface.xdg->geometry.x;
clip->y = c->surface.xdg->geometry.y;
}
static inline void
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
*geom = c->surface.xdg->geometry;
}
static inline Client *
client_get_parent(Client *c)
{
Client *p = NULL;
#ifdef XWAYLAND
if (client_is_x11(c)) {
if (c->surface.xwayland->parent)
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
return p;
}
#endif
if (c->surface.xdg->toplevel->parent)
toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
return p;
}
static inline int
client_has_children(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return !wl_list_empty(&c->surface.xwayland->children);
#endif
/* surface.xdg->link is never empty because it always contains at least the
* surface itself. */
return wl_list_length(&c->surface.xdg->link) > 1;
}
static inline const char *
client_get_title(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->title ? c->surface.xwayland->title : "broken";
#endif
return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title : "broken";
}
static inline int
client_is_float_type(Client *c)
{
struct wlr_xdg_toplevel *toplevel;
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;
if (surface->modal)
return 1;
if (wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG)
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH)
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR)
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
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;
state = toplevel->current;
return toplevel->parent || (state.min_width != 0 && state.min_height != 0
&& (state.min_width == state.max_width
|| state.min_height == state.max_height));
}
static inline int
client_is_rendered_on_mon(Client *c, Monitor *m)
{
/* This is needed for when you don't want to check formal assignment,
* but rather actual displaying of the pixels.
* Usually VISIBLEON suffices and is also faster. */
struct wlr_surface_output *s;
int unused_lx, unused_ly;
if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
return 0;
wl_list_for_each(s, &client_surface(c)->current_outputs, link)
if (s->output == m->wlr_output)
return 1;
return 0;
}
static inline int
client_is_stopped(Client *c)
{
int pid;
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);
if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
/* This process is not our child process, while is very unlikely that
* it is stopped, in order to do not skip frames, assume that it is. */
if (errno == ECHILD)
return 1;
} else if (in.si_pid) {
if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
return 1;
if (in.si_code == CLD_CONTINUED)
return 0;
}
return 0;
}
static inline int
client_is_unmanaged(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->override_redirect;
#endif
return 0;
}
static inline void
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
{
if (kb)
wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
kb->num_keycodes, &kb->modifiers);
else
wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
}
static inline void
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);
}
static inline void
client_set_border_color(Client *c, const float color[static 4])
{
int i;
for (i = 0; i < 4; i++)
wlr_scene_rect_set_color(c->border[i], color);
}
static inline void
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);
}
static inline void
client_set_scale(struct wlr_surface *s, float scale)
{
wlr_fractional_scale_v1_notify_scale(s, scale);
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
}
static inline uint32_t
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->bw, c->geom.y + c->bw, width, height);
return 0;
}
#endif
if ((int32_t)width == c->surface.xdg->toplevel->current.width
&& (int32_t)height == c->surface.xdg->toplevel->current.height)
return 0;
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
}
static inline void
client_set_tiled(Client *c, uint32_t edges)
{
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_maximized(c->surface.xwayland,
edges != WLR_EDGE_NONE, edges != WLR_EDGE_NONE);
return;
}
#endif
if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
} else {
wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE);
}
}
static inline void
client_set_suspended(Client *c, int suspended)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return;
#endif
wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
}
static inline int
client_wants_focus(Client *c)
{
#ifdef XWAYLAND
return client_is_unmanaged(c)
&& wlr_xwayland_surface_override_redirect_wants_focus(c->surface.xwayland)
&& wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
#endif
return 0;
}
static inline int
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;
}

View file

@ -6,42 +6,26 @@
/* appearance */
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 smartgaps = 0; /* 1 means no outer gap when there is only one window */
static int gaps = 1; /* 1 means gaps between windows are added */
static const unsigned int gappx = 10; /* gap pixel between windows */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const char *fonts[] = {"monospace:size=10"};
static const float rootcolor[] = COLOR(0x000000ff);
static const float unfocuseddim[] = COLOR(0x00000088);
static const float rootcolor[] = COLOR(0x222222ff);
static const float bordercolor[] = COLOR(0x444444ff);
static const float focuscolor[] = COLOR(0x005577ff);
static const float urgentcolor[] = COLOR(0xff0000ff);
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
static uint32_t colors[][3] = {
/* fg bg border */
[SchemeNorm] = { 0xbbbbbbff, 0x222222ff, 0x444444ff },
[SchemeSel] = { 0xeeeeeeff, 0x005577ff, 0x005577ff },
[SchemeUrg] = { 0, 0, 0x770000ff },
};
/* tagging */
static char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
/* tagging - TAGCOUNT must be no greater than 31 */
#define TAGCOUNT (9)
/* logging */
static int log_level = WLR_ERROR;
/* Autostart */
static const char *const autostart[] = {
"wbg", "/path/to/your/image", NULL,
NULL /* terminate */
};
/* 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 neverdim monitor */
/* examples:
{ "Gimp_example", NULL, 0, 1, 0, -1 },
*/
{ "firefox_example", NULL, 1 << 8, 0, 1, -1 },
/* 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" */
};
/* layout(s) */
@ -54,14 +38,17 @@ static const Layout layouts[] = {
/* monitors */
/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator
* WARNING: negative values other than (-1, -1) cause problems with Xwayland clients due to
* https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 */
* WARNING: negative values other than (-1, -1) cause problems with Xwayland clients
* https://gitlab.freedesktop.org/xorg/xserver/-/issues/899
*/
/* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */
static const MonitorRule monrules[] = {
/* name mfact nmaster scale layout rotate/reflect x y
* example of a HiDPI laptop monitor:
{ "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, */
/* name mfact nmaster scale layout rotate/reflect x y */
/* example of a HiDPI laptop monitor:
{ "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
*/
/* defaults */
{ NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
/* default monitor rule: can be changed but cannot be eliminated; at least one monitor rule must exist */
};
/* keyboard */
@ -119,8 +106,6 @@ 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 int cursor_timeout = 5;
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
#define MODKEY WLR_MODIFIER_ALT
@ -139,43 +124,40 @@ static const char *menucmd[] = { "wmenu-run", NULL };
static const Key keys[] = {
/* Note that Shift changes certain key codes: 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|WLR_MODIFIER_SHIFT, XKB_KEY_J, movestack, {.i = +1} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, movestack, {.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_Return, zoom, {0} },
{ MODKEY, XKB_KEY_Tab, view, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} },
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
{ 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_e, togglefullscreen, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
{ 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} },
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3),
TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4),
TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5),
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q, quit, {0} },
/* modifier key function argument */
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
{ 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_Return, zoom, {0} },
{ MODKEY, XKB_KEY_Tab, view, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} },
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
{ 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_e, togglefullscreen, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
{ 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} },
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3),
TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4),
TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5),
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q, quit, {0} },
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
@ -188,15 +170,7 @@ static const Key keys[] = {
};
static const Button buttons[] = {
{ ClkLtSymbol, 0, BTN_LEFT, setlayout, {.v = &layouts[0]} },
{ ClkLtSymbol, 0, BTN_RIGHT, setlayout, {.v = &layouts[2]} },
{ ClkTitle, 0, BTN_MIDDLE, zoom, {0} },
{ ClkStatus, 0, BTN_MIDDLE, spawn, {.v = termcmd} },
{ ClkClient, MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
{ ClkClient, MODKEY, BTN_MIDDLE, togglefloating, {0} },
{ ClkClient, MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
{ ClkTagBar, 0, BTN_LEFT, view, {0} },
{ ClkTagBar, 0, BTN_RIGHT, toggleview, {0} },
{ ClkTagBar, MODKEY, BTN_LEFT, tag, {0} },
{ ClkTagBar, MODKEY, BTN_RIGHT, toggletag, {0} },
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
};

View file

@ -1,200 +0,0 @@
/* Taken from https://github.com/djpohly/dwl/issues/466 */
#define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \
((hex >> 16) & 0xFF) / 255.0f, \
((hex >> 8) & 0xFF) / 255.0f, \
(hex & 0xFF) / 255.0f }
/* appearance */
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 smartgaps = 0; /* 1 means no outer gap when there is only one window */
static int gaps = 1; /* 1 means gaps between windows are added */
static const unsigned int gappx = 10; /* gap pixel between windows */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
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.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
static uint32_t colors[][3] = {
/* fg bg border */
[SchemeNorm] = { 0xbbbbbbff, 0x222222ff, 0x444444ff },
[SchemeSel] = { 0xeeeeeeff, 0x005577ff, 0x005577ff },
[SchemeUrg] = { 0, 0, 0x770000ff },
};
/* tagging */
static char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
/* 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 */
{ "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" */
/* default/example rule: can be changed but cannot be eliminated; at least one rule must exist */
};
/* layout(s) */
static const Layout layouts[] = {
/* symbol arrange function */
{ "[]=", tile },
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
};
/* monitors */
/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator
* WARNING: negative values other than (-1, -1) cause problems with Xwayland clients due to
* https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 */
static const MonitorRule monrules[] = {
/* name mfact nmaster scale layout rotate/reflect x y
* example of a HiDPI laptop monitor:
{ "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, */
{ NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
/* default monitor rule: can be changed but cannot be eliminated; at least one monitor rule must exist */
};
/* keyboard */
static const struct xkb_rule_names xkb_rules = {
/* can specify fields: rules, model, layout, variant, options */
/* example:
.options = "ctrl:nocaps",
*/
.options = NULL,
};
static const int repeat_rate = 25;
static const int repeat_delay = 600;
/* Trackpad */
static const int tap_to_click = 1;
static const int tap_and_drag = 1;
static const int drag_lock = 1;
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;
/* You can choose between:
LIBINPUT_CONFIG_SCROLL_NO_SCROLL
LIBINPUT_CONFIG_SCROLL_2FG
LIBINPUT_CONFIG_SCROLL_EDGE
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN
*/
static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
/* You can choose between:
LIBINPUT_CONFIG_CLICK_METHOD_NONE
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER
*/
static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
/* You can choose between:
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE
*/
static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
/* You can choose between:
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
*/
static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
static const double accel_speed = 0.0;
/* You can choose between:
LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
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 int cursor_timeout = 5;
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
#define MODKEY WLR_MODIFIER_ALT
#define TAGKEYS(KEY,SKEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* commands */
static const char *termcmd[] = { "foot", NULL };
static const char *menucmd[] = { "wmenu-run", NULL };
static const Key keys[] = {
/* Note that Shift changes certain key codes: 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|WLR_MODIFIER_SHIFT, XKB_KEY_J, movestack, {.i = +1} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, movestack, {.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_Return, zoom, {0} },
{ MODKEY, XKB_KEY_Tab, view, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} },
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
{ 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_e, togglefullscreen, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
{ 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} },
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3),
TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4),
TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5),
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q, quit, {0} },
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
* do not remove them.
*/
#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
};
static const Button buttons[] = {
{ ClkLtSymbol, 0, BTN_LEFT, setlayout, {.v = &layouts[0]} },
{ ClkLtSymbol, 0, BTN_RIGHT, setlayout, {.v = &layouts[2]} },
{ ClkTitle, 0, BTN_MIDDLE, zoom, {0} },
{ ClkStatus, 0, BTN_MIDDLE, spawn, {.v = termcmd} },
{ ClkClient, MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
{ ClkClient, MODKEY, BTN_MIDDLE, togglefloating, {0} },
{ ClkClient, MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
{ ClkTagBar, 0, BTN_LEFT, view, {0} },
{ ClkTagBar, 0, BTN_RIGHT, toggleview, {0} },
{ ClkTagBar, MODKEY, BTN_LEFT, tag, {0} },
{ ClkTagBar, MODKEY, BTN_RIGHT, toggletag, {0} },
};

View file

@ -1,11 +0,0 @@
--- config.def.h
+++ config.def.h
@@ -129,6 +129,8 @@ static const Key keys[] = {
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_J, movestack, {.i = +1} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, movestack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },

310
drwl.h
View file

@ -1,310 +0,0 @@
/*
* drwl - https://codeberg.org/sewn/drwl
*
* Copyright (c) 2023-2025 sewn <sewn@disroot.org>
* Copyright (c) 2024 notchoc <notchoc@disroot.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The UTF-8 Decoder included is from Bjoern Hoehrmann:
* Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
* See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
*/
#pragma once
#include <stdlib.h>
#include <fcft/fcft.h>
#include <pixman-1/pixman.h>
enum { ColFg, ColBg, ColBorder }; /* colorscheme index */
typedef struct fcft_font Fnt;
typedef pixman_image_t Img;
typedef struct {
Img *image;
Fnt *font;
uint32_t *scheme;
} Drwl;
#define UTF8_ACCEPT 0
#define UTF8_REJECT 12
#define UTF8_INVALID 0xFFFD
static const uint8_t utf8d[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
12,36,12,12,12,12,12,12,12,12,12,12,
};
static inline uint32_t
utf8decode(uint32_t *state, uint32_t *codep, uint8_t byte)
{
uint32_t type = utf8d[byte];
*codep = (*state != UTF8_ACCEPT) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8d[256 + *state + type];
return *state;
}
static int
drwl_init(void)
{
return fcft_init(FCFT_LOG_COLORIZE_AUTO, 0, FCFT_LOG_CLASS_ERROR);
}
static Drwl *
drwl_create(void)
{
Drwl *drwl;
if (!(drwl = calloc(1, sizeof(Drwl))))
return NULL;
return drwl;
}
static void
drwl_setfont(Drwl *drwl, Fnt *font)
{
if (drwl)
drwl->font = font;
}
static void
drwl_setimage(Drwl *drwl, Img *image)
{
if (drwl)
drwl->image = image;
}
static Fnt *
drwl_font_create(Drwl *drwl, size_t count,
const char *names[static count], const char *attributes)
{
Fnt *font = fcft_from_name(count, names, attributes);
if (drwl)
drwl_setfont(drwl, font);
return font;
}
static void
drwl_font_destroy(Fnt *font)
{
fcft_destroy(font);
}
static inline pixman_color_t
convert_color(uint32_t clr)
{
return (pixman_color_t){
((clr >> 24) & 0xFF) * 0x101 * (clr & 0xFF) / 0xFF,
((clr >> 16) & 0xFF) * 0x101 * (clr & 0xFF) / 0xFF,
((clr >> 8) & 0xFF) * 0x101 * (clr & 0xFF) / 0xFF,
(clr & 0xFF) * 0x101
};
}
static void
drwl_setscheme(Drwl *drwl, uint32_t *scm)
{
if (drwl)
drwl->scheme = scm;
}
static Img *
drwl_image_create(Drwl *drwl, unsigned int w, unsigned int h, uint32_t *bits)
{
Img *image;
pixman_region32_t clip;
image = pixman_image_create_bits_no_clear(
PIXMAN_a8r8g8b8, w, h, bits, w * 4);
if (!image)
return NULL;
pixman_region32_init_rect(&clip, 0, 0, w, h);
pixman_image_set_clip_region32(image, &clip);
pixman_region32_fini(&clip);
if (drwl)
drwl_setimage(drwl, image);
return image;
}
static void
drwl_rect(Drwl *drwl,
int x, int y, unsigned int w, unsigned int h,
int filled, int invert)
{
pixman_color_t clr;
if (!drwl || !drwl->scheme || !drwl->image)
return;
clr = convert_color(drwl->scheme[invert ? ColBg : ColFg]);
if (filled)
pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->image, &clr, 1,
&(pixman_rectangle16_t){x, y, w, h});
else
pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->image, &clr, 4,
(pixman_rectangle16_t[4]){
{ x, y, w, 1 },
{ x, y + h - 1, w, 1 },
{ x, y, 1, h },
{ x + w - 1, y, 1, h }});
}
static int
drwl_text(Drwl *drwl,
int x, int y, unsigned int w, unsigned int h,
unsigned int lpad, const char *text, int invert)
{
int ty;
int render = x || y || w || h;
long x_kern;
uint32_t cp = 0, last_cp = 0, state;
pixman_color_t clr;
pixman_image_t *fg_pix = NULL;
int noellipsis = 0;
const struct fcft_glyph *glyph, *eg = NULL;
int fcft_subpixel_mode = FCFT_SUBPIXEL_DEFAULT;
if (!drwl || (render && (!drwl->scheme || !w || !drwl->image)) || !text || !drwl->font)
return 0;
if (!render) {
w = invert ? invert : ~invert;
} else {
clr = convert_color(drwl->scheme[invert ? ColBg : ColFg]);
fg_pix = pixman_image_create_solid_fill(&clr);
drwl_rect(drwl, x, y, w, h, 1, !invert);
x += lpad;
w -= lpad;
}
if (render && (drwl->scheme[ColBg] & 0xFF) != 0xFF)
fcft_subpixel_mode = FCFT_SUBPIXEL_NONE;
if (render)
eg = fcft_rasterize_char_utf32(drwl->font, 0x2026 /* … */, fcft_subpixel_mode);
for (const char *p = text, *pp; pp = p, *p; p++) {
for (state = UTF8_ACCEPT; *p &&
utf8decode(&state, &cp, *p) > UTF8_REJECT; p++)
;
if (!*p || state == UTF8_REJECT) {
cp = UTF8_INVALID;
if (p > pp)
p--;
}
glyph = fcft_rasterize_char_utf32(drwl->font, cp, fcft_subpixel_mode);
if (!glyph)
continue;
x_kern = 0;
if (last_cp)
fcft_kerning(drwl->font, last_cp, cp, &x_kern, NULL);
last_cp = cp;
ty = y + (h - drwl->font->height) / 2 + drwl->font->ascent;
if (render && !noellipsis && x_kern + glyph->advance.x + eg->advance.x > w &&
*(p + 1) != '\0') {
/* cannot fit ellipsis after current codepoint */
if (drwl_text(drwl, 0, 0, 0, 0, 0, pp, 0) + x_kern <= w) {
noellipsis = 1;
} else {
w -= eg->advance.x;
pixman_image_composite32(
PIXMAN_OP_OVER, fg_pix, eg->pix, drwl->image, 0, 0, 0, 0,
x + eg->x, ty - eg->y, eg->width, eg->height);
}
}
if ((x_kern + glyph->advance.x) > w)
break;
x += x_kern;
if (render && pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8)
/* pre-rendered glyphs (eg. emoji) */
pixman_image_composite32(
PIXMAN_OP_OVER, glyph->pix, NULL, drwl->image, 0, 0, 0, 0,
x + glyph->x, ty - glyph->y, glyph->width, glyph->height);
else if (render)
pixman_image_composite32(
PIXMAN_OP_OVER, fg_pix, glyph->pix, drwl->image, 0, 0, 0, 0,
x + glyph->x, ty - glyph->y, glyph->width, glyph->height);
x += glyph->advance.x;
w -= glyph->advance.x;
}
if (render)
pixman_image_unref(fg_pix);
return x + (render ? w : 0);
}
static unsigned int
drwl_font_getwidth(Drwl *drwl, const char *text)
{
if (!drwl || !drwl->font || !text)
return 0;
return drwl_text(drwl, 0, 0, 0, 0, 0, text, 0);
}
static void
drwl_image_destroy(Img *image)
{
pixman_image_unref(image);
}
static void
drwl_destroy(Drwl *drwl)
{
if (drwl->font)
drwl_font_destroy(drwl->font);
if (drwl->image)
drwl_image_destroy(drwl->image);
free(drwl);
}
static void
drwl_fini(void)
{
fcft_fini();
}

740
dwl.c

File diff suppressed because it is too large Load diff

3658
dwl.c.orig

File diff suppressed because it is too large Load diff

View file

@ -1,32 +0,0 @@
--- dwl.c
+++ dwl.c
@@ -340,6 +342,8 @@ static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *m);
+static void toggledimming(const Arg *arg);
+static void toggledimmingclient(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
@@ -1369,8 +1375,10 @@ focusclient(Client *c, int lift)
/* Don't change border color if there is an exclusive focus or we are
* handling a drag operation */
- if (!exclusive_focus && !seat->drag)
+ if (!exclusive_focus && !seat->drag) {
client_set_border_color(c, focuscolor);
+ client_set_dimmer_state(c, 0);
+ }
}
/* Deactivate old client if focus is changing */
@@ -1388,7 +1396,7 @@ focusclient(Client *c, int lift)
* and probably other clients */
} else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
client_set_border_color(old_c, bordercolor);
-
+ client_set_dimmer_state(old_c, 1);
client_activate_surface(old, 0);
}
}

View file

@ -1,141 +0,0 @@
From e8932f159793012a54047c48b3710703a63c07fb Mon Sep 17 00:00:00 2001
From: A Frederick Christensen <dwl@ivories.org>
Date: Fri, 27 Feb 2026 12:29:02 -0600
Subject: [PATCH] Applied autostart patch
---
config.def.h | 6 ++++++
dwl.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/config.def.h b/config.def.h
index 8a6eda0..6eb0db4 100644
--- a/config.def.h
+++ b/config.def.h
@@ -20,6 +20,12 @@ static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You ca
/* 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 */
{ "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */
diff --git a/dwl.c b/dwl.c
index 8a9715d..3450817 100644
--- a/dwl.c
+++ b/dwl.c
@@ -248,6 +248,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);
@@ -451,6 +452,9 @@ static struct wl_listener xwayland_ready = {.notify = xwaylandready};
static struct wlr_xwayland *xwayland;
#endif
+static pid_t *autostart_pids;
+static size_t autostart_len;
+
/* configuration, allows nested code to access above variables */
#include "config.h"
@@ -605,6 +609,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)
{
@@ -701,12 +726,23 @@ checkidleinhibitor(struct wlr_surface *exclude)
void
cleanup(void)
{
+ size_t i;
+
cleanuplisteners();
#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);
@@ -1562,10 +1598,25 @@ gpureset(struct wl_listener *listener, void *data)
void
handlesig(int signo)
{
- if (signo == SIGCHLD)
- while (waitpid(-1, NULL, WNOHANG) > 0);
- else if (signo == SIGINT || signo == SIGTERM)
+ if (signo == SIGCHLD) {
+ pid_t pid, *p, *lim;
+ while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
+ if (pid == child_pid)
+ child_pid = -1;
+ if (!(p = autostart_pids))
+ continue;
+ lim = &p[autostart_len];
+
+ for (; p < lim; p++) {
+ if (*p == pid) {
+ *p = -1;
+ break;
+ }
+ }
+ }
+ } else if (signo == SIGINT || signo == SIGTERM) {
quit(NULL);
+ }
}
void
@@ -2252,6 +2303,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.52.0

File diff suppressed because it is too large Load diff

View file

@ -1,132 +0,0 @@
From e0cecc228d436425c0d921a1eec5e0370d24613d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Desgualdo=20Pereira?= <desgua@gmail.com>
Date: Thu, 13 Nov 2025 09:09:22 -0300
Subject: [PATCH] controlled fullscreen fix
---
dwl.c | 32 ++++++++++++--------------------
1 file changed, 12 insertions(+), 20 deletions(-)
diff --git a/dwl.c b/dwl.c
index 12f441e..4f124eb 100644
--- a/dwl.c
+++ b/dwl.c
@@ -518,9 +518,6 @@ arrange(Monitor *m)
}
}
- wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
- (c = focustop(m)) && c->isfullscreen);
-
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
/* We move all clients (except fullscreen and unmanaged) to LyrTile while
@@ -878,7 +875,7 @@ commitnotify(struct wl_listener *listener, void *data)
return;
}
- resize(c, c->geom, (c->isfloating && !c->isfullscreen));
+ resize(c, c->geom, (c->isfloating));
/* mark a pending resize as completed */
if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
@@ -1490,7 +1487,7 @@ focusstack(const Arg *arg)
{
/* Focus the next or previous client (in tiling order) on selmon */
Client *c, *sel = focustop(selmon);
- if (!sel || (sel->isfullscreen && !client_has_children(sel)))
+ if (!sel)
return;
if (arg->i > 0) {
wl_list_for_each(c, &sel->link, link) {
@@ -1826,7 +1823,7 @@ monocle(Monitor *m)
int n = 0;
wl_list_for_each(c, &clients, link) {
- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ if (!VISIBLEON(c, m) || c->isfloating)
continue;
resize(c, m->w, 0);
n++;
@@ -1957,7 +1954,7 @@ moveresize(const Arg *arg)
if (cursor_mode != CurNormal && cursor_mode != CurPressed)
return;
xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);
- if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
+ if (!grabc || client_is_unmanaged(grabc))
return;
/* Float the window and tell motionnotify to grab it */
@@ -2332,14 +2329,12 @@ setcursorshape(struct wl_listener *listener, void *data)
void
setfloating(Client *c, int floating)
{
- Client *p = client_get_parent(c);
c->isfloating = floating;
/* If in floating layout do not change the client's layer */
if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
return;
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
- (p && p->isfullscreen) ? LyrFS
- : c->isfloating ? LyrFloat : LyrTile]);
+ wlr_scene_node_reparent(&c->scene->node,
+ layers[c->isfloating ? LyrFloat : LyrTile]);
arrange(c->mon);
printstatus();
}
@@ -2352,12 +2347,12 @@ setfullscreen(Client *c, int fullscreen)
return;
c->bw = fullscreen ? 0 : borderpx;
client_set_fullscreen(c, fullscreen);
- wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
- ? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
+ wlr_scene_node_reparent(&c->scene->node,
+ layers[c->isfloating ? LyrFloat : LyrTile]);
if (fullscreen) {
c->prev = c->geom;
- resize(c, c->mon->m, 0);
+ resize(c, c->mon->w, 0);
} else {
/* restore previous size instead of arrange for floating windows since
* client positions are set by the user and cannot be recalculated */
@@ -2716,7 +2711,7 @@ tile(Monitor *m)
Client *c;
wl_list_for_each(c, &clients, link)
- if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
+ if (VISIBLEON(c, m) && !c->isfloating)
n++;
if (n == 0)
return;
@@ -2727,7 +2722,7 @@ tile(Monitor *m)
mw = m->w.width;
i = my = ty = 0;
wl_list_for_each(c, &clients, link) {
- if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ if (!VISIBLEON(c, m) || c->isfloating)
continue;
if (i < m->nmaster) {
resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
@@ -2747,7 +2742,7 @@ togglefloating(const Arg *arg)
{
Client *sel = focustop(selmon);
/* return if fullscreen */
- if (sel && !sel->isfullscreen)
+ if (sel)
setfloating(sel, !sel->isfloating);
}
@@ -2902,9 +2897,6 @@ updatemons(struct wl_listener *listener, void *data)
arrangelayers(m);
/* Don't move clients to the left output when plugging monitors */
arrange(m);
- /* make sure fullscreen clients have the right size */
- if ((c = focustop(m)) && c->isfullscreen)
- resize(c, m->m, 0);
/* Try to re-set the gamma LUT when updating monitors,
* it's only really needed when enabling a disabled output, but meh. */
--
2.51.0

View file

@ -1,216 +0,0 @@
diff --git a/client.h b/client.h
index dabea35..3a31c25 100644
--- a/client.h
+++ b/client.h
@@ -319,6 +319,12 @@ client_set_border_color(Client *c, const float color[static 4])
wlr_scene_rect_set_color(c->border[i], color);
}
+static inline void
+client_set_dimmer_state(Client *c, const int dim)
+{
+ wlr_scene_node_set_enabled(&c->dimmer->node, DIMOPT && !c->neverdim && dim);
+}
+
static inline void
client_set_fullscreen(Client *c, int fullscreen)
{
diff --git a/config.def.h b/config.def.h
index 22d2171..4ca21c9 100644
--- a/config.def.h
+++ b/config.def.h
@@ -10,6 +10,7 @@ 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 unfocuseddim[] = COLOR(0x00000088);
static const float urgentcolor[] = COLOR(0xff0000ff);
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
@@ -22,10 +23,11 @@ static int log_level = WLR_ERROR;
/* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
static const Rule rules[] = {
- /* app_id title tags mask isfloating monitor */
- /* 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 neverdim monitor */
+ /* examples:
+ { "Gimp_example", NULL, 0, 1, 0, -1 },
+ */
+ { "firefox_example", NULL, 1 << 8, 0, 1, -1 },
};
/* layout(s) */
@@ -140,8 +142,9 @@ static const Key keys[] = {
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XKB_KEY_space, setlayout, {0} },
+ { MODKEY, XKB_KEY_apostrophe, toggledimming, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
- { MODKEY, XKB_KEY_e, togglefullscreen, {0} },
+ { MODKEY, XKB_KEY_e, togglefullscreen, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
@@ -172,5 +175,6 @@ static const Key keys[] = {
static const Button buttons[] = {
{ MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
+ { MODKEY|ShiftMask, BTN_MIDDLE, toggledimmingclient, {0} },
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
};
diff --git a/dwl.c b/dwl.c
index dc0c861..dcc3ece 100644
--- a/dwl.c
+++ b/dwl.c
@@ -112,6 +112,7 @@ typedef struct {
Monitor *mon;
struct wlr_scene_tree *scene;
struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
+ struct wlr_scene_rect *dimmer;
struct wlr_scene_tree *scene_surface;
struct wl_list link;
struct wl_list flink;
@@ -141,7 +142,7 @@ typedef struct {
#endif
unsigned int bw;
uint32_t tags;
- int isfloating, isurgent, isfullscreen;
+ int isfloating, isurgent, isfullscreen, neverdim;
uint32_t resize; /* configure serial of a pending resize */
} Client;
@@ -231,6 +232,7 @@ typedef struct {
const char *title;
uint32_t tags;
int isfloating;
+ int neverdim;
int monitor;
} Rule;
@@ -338,6 +340,8 @@ static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *m);
+static void toggledimming(const Arg *arg);
+static void toggledimmingclient(const Arg *arg);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
@@ -410,6 +414,7 @@ static struct wlr_output_layout *output_layout;
static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static int DIMOPT = 1;
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
@@ -466,6 +471,7 @@ applyrules(Client *c)
if ((!r->title || strstr(title, r->title))
&& (!r->id || strstr(appid, r->id))) {
c->isfloating = r->isfloating;
+ c->neverdim = r-> neverdim;
newtags |= r->tags;
i = 0;
wl_list_for_each(m, &mons, link) {
@@ -1365,8 +1371,10 @@ focusclient(Client *c, int lift)
/* Don't change border color if there is an exclusive focus or we are
* handling a drag operation */
- if (!exclusive_focus && !seat->drag)
+ if (!exclusive_focus && !seat->drag) {
client_set_border_color(c, focuscolor);
+ client_set_dimmer_state(c, 0);
+ }
}
/* Deactivate old client if focus is changing */
@@ -1384,7 +1392,7 @@ focusclient(Client *c, int lift)
* and probably other clients */
} else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
client_set_border_color(old_c, bordercolor);
-
+ client_set_dimmer_state(old_c, 1);
client_activate_surface(old, 0);
}
}
@@ -1681,8 +1689,7 @@ void
mapnotify(struct wl_listener *listener, void *data)
{
/* Called when the surface is mapped, or ready to display on-screen. */
- Client *p = NULL;
- Client *w, *c = wl_container_of(listener, c, map);
+ Client *p, *w, *d, *c = wl_container_of(listener, c, map);
Monitor *m;
int i;
@@ -1716,6 +1723,10 @@ mapnotify(struct wl_listener *listener, void *data)
c->border[i]->node.data = c;
}
+ c->dimmer = wlr_scene_rect_create(c->scene, 0, 0, unfocuseddim);
+ c->dimmer->node.data = c;
+ client_set_dimmer_state(c, 1);
+
/* Initialize client geometry with room for border */
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
c->geom.width += 2 * c->bw;
@@ -1734,6 +1745,10 @@ mapnotify(struct wl_listener *listener, void *data)
setmon(c, p->mon, p->tags);
} else {
applyrules(c);
+ d = focustop(selmon);
+ if (d) {
+ client_set_dimmer_state(d, 0);
+ }
}
printstatus();
@@ -2160,7 +2175,7 @@ resize(Client *c, struct wlr_box geo, int interact)
c->geom = geo;
applybounds(c, bbox);
- /* Update scene-graph, including borders */
+ /* Update scene-graph, including borders and dimmer*/
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
@@ -2170,6 +2185,8 @@ resize(Client *c, struct wlr_box geo, int interact)
wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
+ wlr_scene_rect_set_size(c->dimmer, c->geom.width - 2*c->bw, c-> geom.height - 2*c->bw);
+ wlr_scene_node_set_position(&c->dimmer->node, c->bw, c->bw);
/* this is a no-op if size hasn't changed */
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
@@ -2681,6 +2698,27 @@ tile(Monitor *m)
}
}
+void toggledimming(const Arg *arg)
+{
+ Client *c;
+ DIMOPT ^= 1;
+ wl_list_for_each(c, &clients, link)
+ {
+ client_set_dimmer_state(c, 1);
+ }
+ c = focustop(selmon);
+ if (c)
+ client_set_dimmer_state(c, 0);
+}
+
+void
+toggledimmingclient(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+ if (sel)
+ sel -> neverdim ^= 1;
+}
+
void
togglefloating(const Arg *arg)
{

View file

@ -1,127 +0,0 @@
From 50e3dd4746b6cb719efb9f8213b94ac52a5320d9 Mon Sep 17 00:00:00 2001
From: peesock <kcormn@gmail.com>
Date: Mon, 24 Jun 2024 20:06:42 -0700
Subject: [PATCH] gaps!
Co-authored-by: sewn <sewn@disroot.org>
Co-authored-by: serenevoid <ajuph9224@gmail.com>
---
config.def.h | 4 ++++
dwl.c | 34 ++++++++++++++++++++++++++--------
2 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..b388b4e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -6,6 +6,9 @@
/* appearance */
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 smartgaps = 0; /* 1 means no outer gap when there is only one window */
+static int gaps = 1; /* 1 means gaps between windows are added */
+static const unsigned int gappx = 10; /* gap pixel between windows */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const float rootcolor[] = COLOR(0x222222ff);
static const float bordercolor[] = COLOR(0x444444ff);
@@ -135,6 +138,7 @@ static const Key keys[] = {
{ MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },
{ MODKEY, XKB_KEY_Return, zoom, {0} },
{ MODKEY, XKB_KEY_Tab, view, {0} },
+ { MODKEY, XKB_KEY_g, togglegaps, {0} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
diff --git a/dwl.c b/dwl.c
index dc0437e..dc851df 100644
--- a/dwl.c
+++ b/dwl.c
@@ -199,6 +199,7 @@ struct Monitor {
struct wlr_box w; /* window area, layout-relative */
struct wl_list layers[4]; /* LayerSurface.link */
const Layout *lt[2];
+ int gaps;
unsigned int seltags;
unsigned int sellt;
uint32_t tagset[2];
@@ -336,6 +337,7 @@ static void tagmon(const Arg *arg);
static void tile(Monitor *m);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
+static void togglegaps(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unlocksession(struct wl_listener *listener, void *data);
@@ -949,6 +951,8 @@ createmon(struct wl_listener *listener, void *data)
wlr_output_state_init(&state);
/* Initialize monitor state using configured rules */
+ m->gaps = gaps;
+
m->tagset[0] = m->tagset[1] = 1;
for (r = monrules; r < END(monrules); r++) {
if (!r->name || strstr(wlr_output->name, r->name)) {
@@ -2638,7 +2642,7 @@ tagmon(const Arg *arg)
void
tile(Monitor *m)
{
- unsigned int mw, my, ty;
+ unsigned int h, r, e = m->gaps, mw, my, ty;
int i, n = 0;
Client *c;
@@ -2647,23 +2651,30 @@ tile(Monitor *m)
n++;
if (n == 0)
return;
+ if (smartgaps == n)
+ e = 0;
if (n > m->nmaster)
- mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0;
+ mw = m->nmaster ? (int)roundf((m->w.width + gappx*e) * m->mfact) : 0;
else
mw = m->w.width;
- i = my = ty = 0;
+ i = 0;
+ my = ty = gappx*e;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
continue;
if (i < m->nmaster) {
- resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
- .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
- my += c->geom.height;
+ r = MIN(n, m->nmaster) - i;
+ h = (m->w.height - my - gappx*e - gappx*e * (r - 1)) / r;
+ resize(c, (struct wlr_box){.x = m->w.x + gappx*e, .y = m->w.y + my,
+ .width = mw - 2*gappx*e, .height = h}, 0);
+ my += c->geom.height + gappx*e;
} else {
+ r = n - i;
+ h = (m->w.height - ty - gappx*e - gappx*e * (r - 1)) / r;
resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
- .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
- ty += c->geom.height;
+ .width = m->w.width - mw - gappx*e, .height = h}, 0);
+ ty += c->geom.height + gappx*e;
}
i++;
}
@@ -2686,6 +2697,13 @@ togglefullscreen(const Arg *arg)
setfullscreen(sel, !sel->isfullscreen);
}
+void
+togglegaps(const Arg *arg)
+{
+ selmon->gaps = !selmon->gaps;
+ arrange(selmon);
+}
+
void
toggletag(const Arg *arg)
{
--
2.45.2

View file

@ -1,87 +0,0 @@
From 08230817bd3926e29d9897657eb1852cb27d461f Mon Sep 17 00:00:00 2001
From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
Date: Tue, 4 Feb 2025 23:21:19 +0100
Subject: [PATCH] Allows you to move a window up and down the stack
---
config.def.h | 2 ++
dwl.c | 43 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/config.def.h b/config.def.h
index 22d2171..2c129f2 100644
--- a/config.def.h
+++ b/config.def.h
@@ -129,6 +129,8 @@ static const Key keys[] = {
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_J, movestack, {.i = +1} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, movestack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
diff --git a/dwl.c b/dwl.c
index def2562..045d6fa 100644
--- a/dwl.c
+++ b/dwl.c
@@ -303,6 +303,7 @@ static void locksession(struct wl_listener *listener, void *data);
static void mapnotify(struct wl_listener *listener, void *data);
static void maximizenotify(struct wl_listener *listener, void *data);
static void monocle(Monitor *m);
+static void movestack(const Arg *arg);
static void motionabsolute(struct wl_listener *listener, void *data);
static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
double sy, double sx_unaccel, double sy_unaccel);
@@ -1786,6 +1787,48 @@ monocle(Monitor *m)
wlr_scene_node_raise_to_top(&c->scene->node);
}
+void
+movestack(const Arg *arg)
+{
+ Client *c, *sel = focustop(selmon);
+
+ if (!sel) {
+ return;
+ }
+
+ if (wl_list_length(&clients) <= 1) {
+ return;
+ }
+
+ if (arg->i > 0) {
+ wl_list_for_each(c, &sel->link, link) {
+ if (&c->link == &clients) {
+ c = wl_container_of(&clients, c, link);
+ break; /* wrap past the sentinel node */
+ }
+ if (VISIBLEON(c, selmon) || &c->link == &clients) {
+ break; /* found it */
+ }
+ }
+ } else {
+ wl_list_for_each_reverse(c, &sel->link, link) {
+ if (&c->link == &clients) {
+ c = wl_container_of(&clients, c, link);
+ break; /* wrap past the sentinel node */
+ }
+ if (VISIBLEON(c, selmon) || &c->link == &clients) {
+ break; /* found it */
+ }
+ }
+ /* backup one client */
+ c = wl_container_of(c->link.prev, c, link);
+ }
+
+ wl_list_remove(&sel->link);
+ wl_list_insert(&c->link, &sel->link);
+ arrange(selmon);
+}
+
void
motionabsolute(struct wl_listener *listener, void *data)
{
--
2.48.1

View file

@ -1,73 +0,0 @@
From 09759c3ef75158c366e9fc63814485fbb31a3ccf Mon Sep 17 00:00:00 2001
From: Ben Collerson <benc@benc.cc>
Date: Sat, 30 Dec 2023 13:39:31 +1000
Subject: [PATCH] simpleborders
---
dwl.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/dwl.c b/dwl.c
index a2711f67..415fe1a0 100644
--- a/dwl.c
+++ b/dwl.c
@@ -259,6 +259,7 @@ static void closemon(Monitor *m);
static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
static void commitnotify(struct wl_listener *listener, void *data);
static void commitpopup(struct wl_listener *listener, void *data);
+static int countclients(Monitor *m);
static void createdecoration(struct wl_listener *listener, void *data);
static void createidleinhibitor(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_keyboard *keyboard);
@@ -308,6 +309,7 @@ static void motionnotify(uint32_t time, struct wlr_input_device *device, double
double sy, double sx_unaccel, double sy_unaccel);
static void motionrelative(struct wl_listener *listener, void *data);
static void moveresize(const Arg *arg);
+static int needsborder(Client *c);
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);
@@ -849,6 +851,17 @@ commitpopup(struct wl_listener *listener, void *data)
wl_list_remove(&listener->link);
}
+int
+countclients(Monitor *m)
+{
+ unsigned int n = 0;
+ Client *c;
+ wl_list_for_each(c, &clients, link)
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
+ n++;
+ return n;
+}
+
void
createdecoration(struct wl_listener *listener, void *data)
{
@@ -1927,6 +1940,14 @@ moveresize(const Arg *arg)
}
}
+int
+needsborder(Client *c) {
+ return ((countclients(c->mon) > 1
+ && c->mon->lt[c->mon->sellt]->arrange != monocle)
+ || c->isfloating)
+ && !c->isfullscreen;
+}
+
void
outputmgrapply(struct wl_listener *listener, void *data)
{
@@ -2190,6 +2211,7 @@ resize(Client *c, struct wlr_box geo, int interact)
client_set_bounds(c, geo.width, geo.height);
c->geom = geo;
+ c->bw = needsborder(c) ? borderpx : 0;
applybounds(c, bbox);
/* Update scene-graph, including borders */
--
2.45.2

View file

@ -1,192 +0,0 @@
From 68914f40359ebccc7b684a1f74d82419b1796cdf Mon Sep 17 00:00:00 2001
From: Guido Cella <guido@guidocella.xyz>
Date: Thu, 25 Jul 2024 17:59:05 +0200
Subject: [PATCH] =?UTF-8?q?hide=20the=20mouse=20cursor=20if=20it=20isn?=
=?UTF-8?q?=E2=80=99t=20being=20used?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
config.def.h | 2 ++
dwl.c | 74 +++++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 67 insertions(+), 9 deletions(-)
diff --git a/config.def.h b/config.def.h
index 22d2171..790c73d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -106,6 +106,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 int cursor_timeout = 5;
+
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
#define MODKEY WLR_MODIFIER_ALT
diff --git a/dwl.c b/dwl.c
index 775dadf..621779e 100644
--- a/dwl.c
+++ b/dwl.c
@@ -288,6 +288,8 @@ static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m);
static void fullscreennotify(struct wl_listener *listener, void *data);
static void gpureset(struct wl_listener *listener, void *data);
+static void handlecursoractivity(void);
+static int hidecursor(void *data);
static void handlesig(int signo);
static void incnmaster(const Arg *arg);
static void inputdevice(struct wl_listener *listener, void *data);
@@ -389,6 +391,14 @@ static struct wlr_pointer_constraint_v1 *active_constraint;
static struct wlr_cursor *cursor;
static struct wlr_xcursor_manager *cursor_mgr;
+static struct wl_event_source *hide_source;
+static bool cursor_hidden = false;
+static struct {
+ enum wp_cursor_shape_device_v1_shape shape;
+ struct wlr_surface *surface;
+ int hotspot_x;
+ int hotspot_y;
+} last_cursor;
static struct wlr_scene_rect *root_bg;
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
@@ -609,8 +619,9 @@ axisnotify(struct wl_listener *listener, void *data)
* for example when you move the scroll wheel. */
struct wlr_pointer_axis_event *event = data;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
- /* TODO: allow usage of scroll wheel for mousebindings, it can be implemented
- * by checking the event's orientation and the delta of the event */
+ handlecursoractivity();
+ /* TODO: allow usage of scroll wheel for mousebindings, it can be implemented
+ * checking the event's orientation and the delta of the event */
/* Notify the client with pointer focus of the axis event. */
wlr_seat_pointer_notify_axis(seat,
event->time_msec, event->orientation, event->delta,
@@ -627,6 +638,7 @@ buttonpress(struct wl_listener *listener, void *data)
const Button *b;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+ handlecursoractivity();
switch (event->state) {
case WL_POINTER_BUTTON_STATE_PRESSED:
@@ -1563,6 +1575,32 @@ handlesig(int signo)
quit(NULL);
}
+void
+handlecursoractivity(void)
+{
+ wl_event_source_timer_update(hide_source, cursor_timeout * 1000);
+
+ if (!cursor_hidden)
+ return;
+
+ cursor_hidden = false;
+
+ if (last_cursor.shape)
+ wlr_cursor_set_xcursor(cursor, cursor_mgr,
+ wlr_cursor_shape_v1_name(last_cursor.shape));
+ else
+ wlr_cursor_set_surface(cursor, last_cursor.surface,
+ last_cursor.hotspot_x, last_cursor.hotspot_y);
+}
+
+int
+hidecursor(void *data)
+{
+ wlr_cursor_unset_image(cursor);
+ cursor_hidden = true;
+ return 1;
+}
+
void
incnmaster(const Arg *arg)
{
@@ -1903,6 +1941,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
wlr_cursor_move(cursor, device, dx, dy);
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+ handlecursoractivity();
/* Update selmon (even while dragging a window) */
if (sloppyfocus)
@@ -1927,7 +1966,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
/* If there's no client surface under the cursor, set the cursor image to a
* default. This is what makes the cursor image appear when you move it
* off of a client or over its border. */
- if (!surface && !seat->drag)
+ if (!surface && !seat->drag && !cursor_hidden)
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
pointerfocus(c, surface, sx, sy, time);
@@ -2284,6 +2323,7 @@ run(char *startup_cmd)
* monitor when displayed here */
wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y);
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
+ handlecursoractivity();
/* Run the Wayland event loop. This does not return until you exit the
* compositor. Starting the backend rigged up all of the necessary event
@@ -2307,9 +2347,16 @@ setcursor(struct wl_listener *listener, void *data)
* use the provided surface as the cursor image. It will set the
* hardware cursor on the output that it's currently on and continue to
* do so as the cursor moves between outputs. */
- if (event->seat_client == seat->pointer_state.focused_client)
- wlr_cursor_set_surface(cursor, event->surface,
- event->hotspot_x, event->hotspot_y);
+ if (event->seat_client == seat->pointer_state.focused_client) {
+ last_cursor.shape = 0;
+ last_cursor.surface = event->surface;
+ last_cursor.hotspot_x = event->hotspot_x;
+ last_cursor.hotspot_y = event->hotspot_y;
+
+ if (!cursor_hidden)
+ wlr_cursor_set_surface(cursor, event->surface,
+ event->hotspot_x, event->hotspot_y);
+ }
}
void
@@ -2321,9 +2368,14 @@ setcursorshape(struct wl_listener *listener, void *data)
/* This can be sent by any client, so we check to make sure this one
* actually has pointer focus first. If so, we can tell the cursor to
* use the provided cursor shape. */
- if (event->seat_client == seat->pointer_state.focused_client)
- wlr_cursor_set_xcursor(cursor, cursor_mgr,
- wlr_cursor_shape_v1_name(event->shape));
+ if (event->seat_client == seat->pointer_state.focused_client) {
+ last_cursor.shape = event->shape;
+ last_cursor.surface = NULL;
+
+ if (!cursor_hidden)
+ wlr_cursor_set_xcursor(cursor, cursor_mgr,
+ wlr_cursor_shape_v1_name(event->shape));
+ }
}
void
@@ -2614,6 +2666,9 @@ setup(void)
cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
+ hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
+ hidecursor, cursor);
+
/*
* Configures a seat, which is a single "seat" at which a user sits and
* operates the computer. This conceptually includes up to one keyboard,
@@ -2998,6 +3053,7 @@ virtualpointer(struct wl_listener *listener, void *data)
wlr_cursor_attach_input_device(cursor, device);
if (event->suggested_output)
wlr_cursor_map_input_to_output(cursor, device, event->suggested_output);
+ handlecursoractivity();
}
Monitor *
--
2.49.0

View file

@ -1,71 +0,0 @@
From 4951ccc89dac2b557994b2f6c3aacb2398e2d1b1 Mon Sep 17 00:00:00 2001
From: Ben Collerson <benc@benc.cc>
Date: Thu, 4 Jan 2024 20:30:01 +1000
Subject: [PATCH] warpcursor
---
dwl.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/dwl.c b/dwl.c
index 145fd018..f7ad6c13 100644
--- a/dwl.c
+++ b/dwl.c
@@ -347,6 +347,7 @@ static void urgent(struct wl_listener *listener, void *data);
static void view(const Arg *arg);
static void virtualkeyboard(struct wl_listener *listener, void *data);
static void virtualpointer(struct wl_listener *listener, void *data);
+static void warpcursor(const Client *c);
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);
@@ -514,6 +515,7 @@ arrange(Monitor *m)
m->lt[m->sellt]->arrange(m);
motionnotify(0, NULL, 0, 0, 0, 0);
checkidleinhibitor(NULL);
+ warpcursor(focustop(selmon));
}
void
@@ -1323,6 +1325,10 @@ focusclient(Client *c, int lift)
if (locked)
return;
+ /* Warp cursor to center of client if it is outside */
+ if (lift)
+ warpcursor(c);
+
/* Raise client in stacking order if requested */
if (c && lift)
wlr_scene_node_raise_to_top(&c->scene->node);
@@ -2927,6 +2933,27 @@ virtualpointer(struct wl_listener *listener, void *data)
wlr_cursor_map_input_to_output(cursor, &pointer.base, event->suggested_output);
}
+void
+warpcursor(const Client *c) {
+ if (cursor_mode != CurNormal) {
+ return;
+ }
+ if (!c && selmon) {
+ wlr_cursor_warp_closest(cursor,
+ NULL,
+ selmon->w.x + selmon->w.width / 2.0 ,
+ selmon->w.y + selmon->w.height / 2.0);
+ }
+ else if ( c && (cursor->x < c->geom.x ||
+ cursor->x > c->geom.x + c->geom.width ||
+ cursor->y < c->geom.y ||
+ cursor->y > c->geom.y + c->geom.height))
+ wlr_cursor_warp_closest(cursor,
+ NULL,
+ c->geom.x + c->geom.width / 2.0,
+ c->geom.y + c->geom.height / 2.0);
+}
+
Monitor *
xytomon(double x, double y)
{
--
2.45.2