added QoL patches and improvements

This commit is contained in:
λmolinae 2025-06-14 23:59:26 -06:00
parent ffc2e2e241
commit f05276780b
6 changed files with 333 additions and 46 deletions

283
dwl.c
View file

@ -84,6 +84,7 @@
#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
#define BORDERPX(C) (borderpx + ((C)->swallowing ? (int)ceilf(swallowborder * (C)->swallowing->bw) : 0))
#define TEXTW(mon, text) (drwl_font_getwidth(mon->drw, text) + mon->lrpad)
#define PREFIX(str, prefix) !strncmp(str, prefix, strlen(prefix))
/* enums */
enum { SchemeNorm, SchemeSel, SchemeUrg }; /* color schemes */
@ -310,11 +311,13 @@ static void bufdataend(struct wlr_buffer *buffer);
static Buffer *bufmon(Monitor *m);
static void bufrelease(struct wl_listener *listener, void *data);
static void buttonpress(struct wl_listener *listener, void *data);
static void centeredmaster(Monitor *m);
static void chvt(const Arg *arg);
static void checkidleinhibitor(struct wlr_surface *exclude);
static void cleanup(void);
static void cleanupmon(struct wl_listener *listener, void *data);
static void closemon(Monitor *m);
static void col(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);
@ -349,6 +352,8 @@ static void destroykeyboardgroup(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
static void drawbar(Monitor *m);
static void drawbars(void);
static int drawstatus(Monitor *m);
static Client *firstfocused(void);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
@ -374,6 +379,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);
@ -410,6 +416,7 @@ static void setsel(struct wl_listener *listener, void *data);
static void setup(void);
static void spawn(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data);
static void switchxkbrule(const Arg *arg);
static void swallow(Client *c, Client *toswallow);
static int statusin(int fd, unsigned int mask, void *data);
static void tag(const Arg *arg);
@ -491,6 +498,7 @@ static struct wl_listener lock_listener = {.notify = locksession};
static struct wlr_seat *seat;
static KeyboardGroup *kb_group;
static unsigned int cursor_mode;
static unsigned int xkb_rule_index = 0;
static Client *grabc;
static int grabcx, grabcy; /* client-relative */
@ -499,7 +507,7 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
static char stext[256];
static char stext[512];
static struct wl_event_source *status_event_source;
static const struct wlr_buffer_impl buffer_impl = {
@ -723,8 +731,8 @@ arrangelayers(Monitor *m)
return;
if (m->scene_buffer->node.enabled) {
usable_area.height -= m->b.real_height;
usable_area.y += topbar ? m->b.real_height : 0;
usable_area.height -= m->b.real_height + vertpad;
usable_area.y += topbar ? m->b.real_height + vertpad : 0;
}
/* Arrange exclusive surfaces from top->bottom */
@ -876,7 +884,7 @@ buttonpress(struct wl_listener *listener, void *data)
struct wlr_scene_buffer *buffer;
uint32_t mods;
Arg arg = {0};
Client *c;
Client *c, *focused;
const Button *b;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
@ -886,6 +894,10 @@ buttonpress(struct wl_listener *listener, void *data)
if (c)
click = ClkClient;
focused = firstfocused();
if (focused && focused->isfullscreen)
goto skip_click;
switch (event->state) {
case WL_POINTER_BUTTON_STATE_PRESSED:
cursor_mode = CurPressed;
@ -896,7 +908,7 @@ buttonpress(struct wl_listener *listener, void *data)
if (!c && !exclusive_focus &&
(node = wlr_scene_node_at(&layers[LyrBottom]->node, cursor->x, cursor->y, NULL, NULL)) &&
(buffer = wlr_scene_buffer_from_node(node)) && buffer == selmon->scene_buffer) {
cx = (cursor->x - selmon->m.x) * selmon->wlr_output->scale;
cx = (cursor->x - selmon->m.x - sidepad) * selmon->wlr_output->scale;
wl_list_for_each(c, &clients, link) {
if (c->mon != selmon)
continue;
@ -949,10 +961,73 @@ buttonpress(struct wl_listener *listener, void *data)
}
/* If the event wasn't handled by the compositor, notify the client with
* pointer focus that a button press has occurred */
skip_click:
wlr_seat_pointer_notify_button(seat,
event->time_msec, event->button, event->state);
}
void
centeredmaster(Monitor *m)
{
int i, n, h, mw, mx, my, oty, ety, tw;
Client *c;
n = 0;
wl_list_for_each(c, &clients, link)
if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
n++;
if (n == 0)
return;
/* initialize areas */
mw = m->w.width;
mx = 0;
my = 0;
tw = mw;
if (n > m->nmaster) {
/* go mfact box in the center if more than nmaster clients */
mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0;
tw = m->w.width - mw;
if (n - m->nmaster > 1) {
/* only one client */
mx = (m->w.width - mw) / 2;
tw = (m->w.width - mw) / 2;
}
}
i = 0;
oty = 0;
ety = 0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
continue;
if (i < m->nmaster) {
/* nmaster clients are stacked vertically, in the center
* of the screen */
h = (m->w.height - my) / (MIN(n, m->nmaster) - i);
resize(c, (struct wlr_box){.x = m->w.x + mx, .y = m->w.y + my, .width = mw,
.height = h}, 0);
my += c->geom.height;
} else {
/* stack clients are stacked vertically */
if ((i - m->nmaster) % 2) {
h = (m->w.height - ety) / ( (1 + n - i) / 2);
resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + ety, .width = tw,
.height = h}, 0);
ety += c->geom.height;
} else {
h = (m->w.height - oty) / ((1 + n - i) / 2);
resize(c, (struct wlr_box){.x = m->w.x + mx + mw, .y = m->w.y + oty, .width = tw,
.height = h}, 0);
oty += c->geom.height;
}
}
i++;
}
}
void
chvt(const Arg *arg)
{
@ -1081,6 +1156,33 @@ closemon(Monitor *m)
drawbars();
}
void
col(Monitor *m)
{
Client *c;
unsigned int n = 0, i = 0;
wl_list_for_each(c, &clients, link)
if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
n++;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
continue;
resize(
c,
(struct wlr_box){
.x = m->w.x + i * m->w.width / n,
.y = m->w.y,
.width = m->w.width / n,
.height = m->w.height
},
0
);
i++;
}
}
void
commitlayersurfacenotify(struct wl_listener *listener, void *data)
{
@ -1222,7 +1324,7 @@ createkeyboardgroup(void)
/* Prepare an XKB keymap and assign it to the keyboard group. */
context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules,
if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules[xkb_rule_index],
XKB_KEYMAP_COMPILE_NO_FLAGS)))
die("failed to compile keymap");
@ -1738,11 +1840,8 @@ drawbar(Monitor *m)
return;
/* draw status first so it can be overdrawn by tags later */
if (m == selmon) { /* status is only drawn on selected monitor */
drwl_setscheme(m->drw, colors[SchemeNorm]);
tw = TEXTW(m, stext) - m->lrpad + 2; /* 2px right padding */
drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
}
if (m == selmon) /* status is only drawn on selected monitor */
tw = drawstatus(m);
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
@ -1779,8 +1878,8 @@ drawbar(Monitor *m)
wlr_scene_buffer_set_dest_size(m->scene_buffer,
m->b.real_width, m->b.real_height);
wlr_scene_node_set_position(&m->scene_buffer->node, m->m.x,
m->m.y + (topbar ? 0 : m->m.height - m->b.real_height));
wlr_scene_node_set_position(&m->scene_buffer->node, m->m.x + sidepad,
m->m.y + (topbar ? vertpad : m->m.height - m->b.real_height - vertpad));
wlr_scene_buffer_set_buffer(m->scene_buffer, &buf->base);
wlr_buffer_unlock(&buf->base);
}
@ -1794,6 +1893,95 @@ drawbars(void)
drawbar(m);
}
int
drawstatus(Monitor *m)
{
int x, tw, iw;
char rstext[512] = "";
char *p, *argstart, *argend, *itext;
uint32_t scheme[3], *color;
/* calculate real width of stext */
for (p = stext; *p; p++) {
if (PREFIX(p, "^^")) {
strncat(rstext, p, 2);
p++;
} else if (PREFIX(p, "^fg(") || PREFIX(p, "^bg(")) {
argend = strchr(p, ')');
if (!argend) { /* ignore this command */
argstart = strchr(p, '(') + 1;
strncat(rstext, p, argstart - p);
p = argstart - 1;
} else {
p = argend;
}
} else {
strncat(rstext, p, 1);
}
}
tw = TEXTW(m, rstext) - m->lrpad;
x = m->b.width - tw;
itext = stext;
scheme[0] = colors[SchemeNorm][0];
scheme[1] = colors[SchemeNorm][1];
drwl_setscheme(m->drw, scheme);
for (p = stext; *p; p++) {
if (PREFIX(p, "^^")) {
p++;
} else if (PREFIX(p, "^fg(") || PREFIX(p, "^bg(")) {
argstart = strchr(p, '(') + 1;
argend = strchr(argstart, ')');
if (!argend) { /* ignore this command */
p = argstart - 1;
continue;
}
*p = '\0';
iw = TEXTW(m, itext) - m->lrpad;
if (*itext) /* only draw text if there is something to draw */
x = drwl_text(m->drw, x, 0, iw, m->b.height, 0, itext, 0);
*p = '^';
if (PREFIX(p, "^fg("))
color = &scheme[0];
else
color = &scheme[1];
if (argend != argstart) {
*argend = '\0';
*color = strtoul(argstart, NULL, 16);
*color = *color << 8 | 0xff; /* add alpha channel */
*argend = ')';
} else {
*color = 0; /* reset */
}
/* reset color back to normal if none was provided */
if (!scheme[0])
scheme[0] = colors[SchemeNorm][0];
if (!scheme[1])
scheme[1] = colors[SchemeNorm][1];
itext = argend + 1;
drwl_setscheme(m->drw, scheme);
p = argend;
}
}
iw = TEXTW(m, itext) - m->lrpad;
if (*itext)
drwl_text(m->drw, x, 0, iw, m->b.height, 0, itext, 0);
return tw;
}
Client *
firstfocused(void)
{
Client *c = wl_container_of(fstack.next, c, flink);
return c;
}
void
focusclient(Client *c, int lift)
{
@ -2123,10 +2311,18 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
* processing keys, rather than passing them on to the client for its own
* processing.
*/
Client *c = firstfocused();
const Key *k;
for (k = keys; k < END(keys); k++) {
if (CLEANMASK(mods) == CLEANMASK(k->mod)
&& sym == k->keysym && k->func) {
if (c && c->isfullscreen) {
if (k->func == togglefullscreen) {
k->func(&k->arg);
return 1;
}
return 0;
}
k->func(&k->arg);
return 1;
}
@ -2363,6 +2559,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)
{
@ -3352,6 +3590,21 @@ swallow(Client *c, Client *toswallow)
}
}
void
switchxkbrule(const Arg *arg)
{
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
struct xkb_keymap *keymap;
xkb_rule_index = (xkb_rule_index + 1) % LENGTH(xkb_rules);
if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules[xkb_rule_index],
XKB_KEYMAP_COMPILE_NO_FLAGS)))
die("failed to compile keymap");
wlr_keyboard_set_keymap(&kb_group->wlr_group->keyboard, keymap);
xkb_keymap_unref(keymap);
xkb_context_unref(context);
}
void
tag(const Arg *arg)
{
@ -3746,8 +3999,8 @@ updatebar(Monitor *m)
char fontattrs[12];
wlr_output_transformed_resolution(m->wlr_output, &rw, &rh);
m->b.width = rw;
m->b.real_width = (int)((float)m->b.width / m->wlr_output->scale);
m->b.width = rw - (2 * sidepad);
m->b.real_width = (int)((float)rw / m->wlr_output->scale) - (2 * sidepad);
wlr_scene_node_set_enabled(&m->scene_buffer->node, m->wlr_output->enabled ? showbar : 0);