Compare commits

...

17 commits

Author SHA1 Message Date
fb2c6e791c
add missing type annotation 2024-01-22 20:33:48 +01:00
4f960ea4f2
update flake.lock 2024-01-22 20:33:34 +01:00
33d910d1a4
add keybinds for screenshot and wmenu 2024-01-22 19:41:54 +01:00
906fc903ab
set up more Rules 2024-01-22 19:41:54 +01:00
5ac1aa67fa
add autostart 2024-01-22 19:41:54 +01:00
45f7c1a685
change monitor scaling 2024-01-22 19:41:54 +01:00
14292964fa
set keyboard layout to us(intl) 2024-01-22 19:41:53 +01:00
da0afb34ea
Set modkey to LOGO 2024-01-22 19:41:53 +01:00
c6185373e2
clangd setup 2024-01-22 19:41:53 +01:00
56363b548c
setup for nix 2024-01-22 19:41:53 +01:00
Devin J. Pohly
26d7c9689f
No need to call updatemons ourselves
The output manager in wlroots emits an output_layout.change event when
anything changes, so updatemons will be called anyway.

ΔSLOC: -1
2024-01-20 21:51:20 -06:00
Leonardo Hernández Hernández
6c8be38ec4
drop unused variable 2024-01-15 02:19:02 +00:00
Leonardo Hernández Hernández
417e37f988
request description before logs 2024-01-15 02:15:54 +00:00
Leonardo Hernández Hernández
a1f3e25c35
turn on -Wfloat-conversion 2024-01-15 02:09:18 +00:00
Leonardo Hernández Hernández
0151bd48dd
turn on -Wsign-compare 2024-01-15 02:09:18 +00:00
A Frederick Christensen
337d6ba3fb
acknowledgements refactoring 2024-01-14 09:01:49 -06:00
Leonardo Hernández Hernández
ec557f253b
clarify the code will be kept as small as possible 2024-01-12 22:34:09 -06:00
12 changed files with 194 additions and 60 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"

View file

@ -33,6 +33,14 @@ body:
validations:
required: false
- type: textarea
attributes:
label: Description
value: |
The steps you took to reproduce the problem.
validations:
required: false
- type: textarea
id: debug_log
attributes:
@ -52,11 +60,3 @@ body:
- If the lines mentioning dwl or wlroots have `??`. Please compile both dwl and wlroots from source (enabling debug symbols) and try to reproduce.
validations:
required: false
- type: textarea
attributes:
label: Description
value: |
The steps you took to reproduce the problem.
validations:
required: false

3
.gitignore vendored
View file

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

View file

@ -5,8 +5,8 @@ include config.mk
# flags for compiling
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND)
DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\
-Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types
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
# CFLAGS / LDFLAGS
PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS)
@ -38,7 +38,7 @@ cursor-shape-v1-protocol.h:
config.h:
cp config.def.h $@
clean:
rm -f dwl *.o *-protocol.h
rm -f dwl *.o *-protocol.h config.h
dist: clean
mkdir -p dwl-$(VERSION)

View file

@ -34,8 +34,10 @@ given the base on which it is built. Implemented default features are:
- Damage tracking provided by scenegraph API
Given the Wayland architecture, dwl has to implement features from dwm **and**
the xorg-server. Because of this, it is impossible to maintain the original project goal of 2000
SLOC and have a reasonably complete compositor with features comparable to dwm.
the xorg-server. Because of this, it is impossible to maintain the original
project goal of 2000 SLOC and have a reasonably complete compositor with
features comparable to dwm. However, this does not mean that the code will grow
indiscriminately. We will try to keep the code as small as possible.
Features under consideration (possibly as patches) are:
@ -155,8 +157,8 @@ possible.
Many thanks to suckless.org and the dwm developers and community for the
inspiration, and to the various contributors to the project, including:
- **Devin J. Pohly for creating and nurturing the fledgling project**
- Alexander Courtis for the XWayland implementation
- Devin J. Pohly for creating and nurturing the fledgling project
- Guido Cella for the layer-shell protocol implementation, patch maintenance,
and for helping to keep the project running
- Stivvo for output management and fullscreen support, and patch maintenance

View file

@ -339,10 +339,10 @@ client_set_size(Client *c, uint32_t width, uint32_t height)
return 0;
}
#endif
if (width == c->surface.xdg->toplevel->current.width
&& height ==c->surface.xdg->toplevel->current.height)
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, width, height);
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
}
static inline void

View file

@ -12,7 +12,16 @@ static const float bordercolor[] = COLOR(0x444444ff);
static const float focuscolor[] = COLOR(0x005577ff);
static const float urgentcolor[] = COLOR(0xff0000ff);
/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */
static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* 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,
NULL /* terminate */
};
/* tagging - TAGCOUNT must be no greater than 31 */
#define TAGCOUNT (9)
@ -25,7 +34,8 @@ static const Rule rules[] = {
/* examples:
{ "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) */
@ -41,18 +51,20 @@ static const Layout layouts[] = {
static const MonitorRule monrules[] = {
/* name mfact nmaster scale layout rotate/reflect x y */
/* example of a HiDPI laptop monitor:
{ "eDP-1", 0.5, 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 */
{ NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
{ NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
};
/* keyboard */
static const struct xkb_rule_names xkb_rules = {
/* can specify fields: rules, model, layout, variant, options */
/* example:
.options = "ctrl:nocaps",
*/
.rules = NULL,
.model = NULL,
.layout = "us",
.variant = "intl",
.options = NULL,
};
@ -101,8 +113,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;
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
#define MODKEY WLR_MODIFIER_ALT
/* If you want to use the alt key for MODKEY, use WLR_MODIFIER_ALT */
#define MODKEY WLR_MODIFIER_LOGO
#define TAGKEYS(KEY,SKEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
@ -113,21 +125,18 @@ 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 */
#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[] = {
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
/* modifier key function argument */
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
{ MODKEY, XKB_KEY_p, spawn, SHCMD("dmenu_path | wmenu | xargs -I_-_ /bin/sh -c \"exec _-_\"") },
{ 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_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.05} },
{ MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} },
{ 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} },

98
dwl.c
View file

@ -65,6 +65,7 @@
/* macros */
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5)))
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
@ -196,7 +197,7 @@ struct Monitor {
unsigned int seltags;
unsigned int sellt;
uint32_t tagset[2];
double mfact;
float mfact;
int gamma_lut_changed;
int nmaster;
char ltsymbol[16];
@ -231,6 +232,7 @@ typedef struct {
/* function declarations */
static void applybounds(Client *c, struct wlr_box *bbox);
static void autostartexec(void);
static void applyrules(Client *c);
static void arrange(Monitor *m);
static void arrangelayer(Monitor *m, struct wl_list *list,
@ -403,6 +405,9 @@ static xcb_atom_t netatom[NetLast];
/* attempt to encapsulate suck into one file */
#include "client.h"
static pid_t *autostart_pids;
static size_t autostart_len;
/* function implementations */
void
applybounds(Client *c, struct wlr_box *bbox)
@ -415,18 +420,40 @@ applybounds(Client *c, struct wlr_box *bbox)
c->geom.x = bbox->x + bbox->width - c->geom.width;
if (c->geom.y >= bbox->y + bbox->height)
c->geom.y = bbox->y + bbox->height - c->geom.height;
if (c->geom.x + c->geom.width + 2 * c->bw <= bbox->x)
if (c->geom.x + c->geom.width + 2 * (int)c->bw <= bbox->x)
c->geom.x = bbox->x;
if (c->geom.y + c->geom.height + 2 * c->bw <= bbox->y)
if (c->geom.y + c->geom.height + 2 * (int)c->bw <= 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);
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
applyrules(Client *c)
{
/* rule matching */
const char *appid, *title;
uint32_t i, newtags = 0;
uint32_t newtags = 0;
int i;
const Rule *r;
Monitor *mon = selmon, *m;
@ -520,7 +547,7 @@ arrangelayers(Monitor *m)
arrangelayer(m, &m->layers[i], &usable_area, 0);
/* Find topmost keyboard interactive layer, if such a layer exists */
for (i = 0; i < LENGTH(layers_above_shell); i++) {
for (i = 0; i < (int)LENGTH(layers_above_shell); i++) {
wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) {
if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped)
continue;
@ -630,11 +657,21 @@ checkidleinhibitor(struct wlr_surface *exclude)
void
cleanup(void)
{
size_t i;
#ifdef XWAYLAND
wlr_xwayland_destroy(xwayland);
xwayland = NULL;
#endif
wl_display_destroy_clients(dpy);
/* kill child processes */
for (i = 0; i < autostart_len; i++) {
if (0 < autostart_pids[i]) {
kill(autostart_pids[i], SIGTERM);
waitpid(autostart_pids[i], NULL, 0);
}
}
if (child_pid > 0) {
kill(child_pid, SIGTERM);
waitpid(child_pid, NULL, 0);
@ -657,7 +694,7 @@ cleanupmon(struct wl_listener *listener, void *data)
{
Monitor *m = wl_container_of(listener, m, destroy);
LayerSurface *l, *tmp;
int i;
size_t i;
/* m->layers[i] are intentionally not unlinked */
for (i = 0; i < LENGTH(m->layers); i++) {
@ -1294,18 +1331,31 @@ void
handlesig(int signo)
{
if (signo == SIGCHLD) {
#ifdef XWAYLAND
siginfo_t in;
/* wlroots expects to reap the XWayland process itself, so we
* use WNOWAIT to keep the child waitable until we know it's not
* XWayland.
*/
while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid
&& (!xwayland || in.si_pid != xwayland->server->pid))
waitpid(in.si_pid, NULL, 0);
#else
while (waitpid(-1, NULL, WNOHANG) > 0);
#ifdef XWAYLAND
&& (!xwayland || in.si_pid != xwayland->server->pid)
#endif
) {
pid_t *p, *lim;
waitpid(in.si_pid, NULL, 0);
if (in.si_pid == child_pid)
child_pid = -1;
if (!(p = autostart_pids))
continue;
lim = &p[autostart_len];
for (; p < lim; p++) {
if (*p == in.si_pid) {
*p = -1;
break;
}
}
}
} else if (signo == SIGINT || signo == SIGTERM) {
quit(NULL);
}
@ -1481,7 +1531,6 @@ locksession(struct wl_listener *listener, void *data)
void
maplayersurfacenotify(struct wl_listener *listener, void *data)
{
LayerSurface *l = wl_container_of(listener, l, map);
motionnotify(0);
}
@ -1620,17 +1669,17 @@ motionnotify(uint32_t time)
}
/* Update drag icon's position */
wlr_scene_node_set_position(&drag_icon->node, cursor->x, cursor->y);
wlr_scene_node_set_position(&drag_icon->node, ROUND(cursor->x), ROUND(cursor->y));
/* If we are currently grabbing the mouse, handle and return */
if (cursor_mode == CurMove) {
/* Move the grabbed client to the new position. */
resize(grabc, (struct wlr_box){.x = cursor->x - grabcx, .y = cursor->y - grabcy,
resize(grabc, (struct wlr_box){.x = ROUND(cursor->x) - grabcx, .y = ROUND(cursor->y) - grabcy,
.width = grabc->geom.width, .height = grabc->geom.height}, 1);
return;
} else if (cursor_mode == CurResize) {
resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
.width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1);
.width = ROUND(cursor->x) - grabc->geom.x, .height = ROUND(cursor->y) - grabc->geom.y}, 1);
return;
}
@ -1682,8 +1731,8 @@ moveresize(const Arg *arg)
setfloating(grabc, 1);
switch (cursor_mode = arg->ui) {
case CurMove:
grabcx = cursor->x - grabc->geom.x;
grabcy = cursor->y - grabc->geom.y;
grabcx = ROUND(cursor->x) - grabc->geom.x;
grabcy = ROUND(cursor->y) - grabc->geom.y;
wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
break;
case CurResize:
@ -1756,9 +1805,6 @@ apply_or_test:
else
wlr_output_configuration_v1_send_failed(config);
wlr_output_configuration_v1_destroy(config);
/* TODO: use a wrapper function? */
updatemons(NULL, NULL);
}
void
@ -1965,6 +2011,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)
@ -2104,7 +2151,7 @@ setmfact(const Arg *arg)
if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange)
return;
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f;
if (f < 0.1 || f > 0.9)
return;
selmon->mfact = f;
@ -2166,7 +2213,7 @@ setup(void)
struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
sigemptyset(&sa.sa_mask);
for (i = 0; i < LENGTH(sig); i++)
for (i = 0; i < (int)LENGTH(sig); i++)
sigaction(sig[i], &sa, NULL);
wlr_log_init(log_level, NULL);
@ -2276,7 +2323,7 @@ setup(void)
wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener);
LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr);
locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
(float [4]){0.1, 0.1, 0.1, 1.0});
(float [4]){0.1f, 0.1f, 0.1f, 1.0f});
wlr_scene_node_set_enabled(&locked_bg->node, 0);
/* Use decoration protocols to negotiate server-side decorations */
@ -2454,7 +2501,8 @@ tagmon(const Arg *arg)
void
tile(Monitor *m)
{
unsigned int i, n = 0, mw, my, ty;
unsigned int mw, my, ty;
int i, n = 0;
Client *c;
wl_list_for_each(c, &clients, link)
@ -2464,7 +2512,7 @@ tile(Monitor *m)
return;
if (n > m->nmaster)
mw = m->nmaster ? m->w.width * m->mfact : 0;
mw = m->nmaster ? ROUND(m->w.width * m->mfact) : 0;
else
mw = m->w.width;
i = my = ty = 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}";
};
}