1765 Commits
Author SHA1 Message Date
lupan b0cc093917 use alacritty term 2026-10-19 09:29:09 +02:00
lupan 2adf18bee6 local: letter tags and mod semicolon chords 2026-10-19 09:26:06 +02:00
Lukasz Kasprzak 9610f461c2 keychord: bind a sequence of keys, and dispatch events while waiting
Original keychord patch by Hai Nguyen <hhai2105@gmail.com>, updated for
dwm 6.4+ grabkeys() by Aaron Zueger <contact@azureorange.xyz>. This
revision rebases onto dwm 6.8 and fixes an event-loss bug in the chord
wait loop.

The wait loop used to discard every event that was not a KeyPress:

    while (running && !XNextEvent(dpy, &event) && !ran)
            if(event.type == KeyPress)
                    break;

Two consequences, both reproduced on Xephyr:

1. Unrecoverable input freeze. grabbuttons() grabs unfocused clients
   GrabModeSync/GrabModeSync, so clicking one freezes pointer AND
   keyboard until the grabbing client calls XAllowEvents. dwm does that
   in buttonpress() -- but if the ButtonPress is discarded here,
   buttonpress() never runs. The grab stays frozen forever and the loop
   can never exit, because a frozen keyboard cannot deliver the KeyPress
   it is waiting for. Only killing dwm ends it; XSendEvent is discarded
   by this same loop and XTEST queues behind the frozen device.
   Repro: press a chord prefix, then click any unfocused client.
   Observed: XGrabKeyboard -> GrabFrozen, XQueryPointer -> Button1 held.

2. Orphaned windows. A MapRequest arriving mid-chord is dropped, so a
   window opening during a chord is never managed. DestroyNotify,
   Expose and ConfigureRequest are lost the same way.

Dispatch through handler[] as run() does, breaking on KeyPress before
dispatch so keypress() cannot recurse. The `&& !ran` term is dropped:
ran is always 0 on entry and nothing in the body can set it.
2026-10-19 09:10:49 +02:00
lupan 636dcaf763 WIP my local config changes 2026-10-19 08:10:10 +02:00
BrunoCooper17 239b74dcb2 MoveStack patch
This plugin allows you to move clients around in the stack and swap them
with the master. It emulates the behavior off mod+shift+j and mod+shift+k
in Xmonad. movestack(+1) will swap the client with the current focus with
the next client. movestack(-1) will swap the client with the current focus
with the previous client.
2026-10-19 08:08:58 +02:00
lupan b6ed779125 apply patch dwm-winview-gaplessgrid-gridall-6.5.diff 2026-10-19 08:08:58 +02:00
explosion-mental f8024479de shift-tools - shifttag, moves the current selected client to the adjacent tag - shifttagclients, moves the current selected client to the adjacent tag that has at least one client else acts as shifttag - shiftview, view adjacent tag - shiftviewclients, view the closes tag that has a client. If none acts as shiftview - shiftboth, shifttag and shiftview. Basically moves the window to the next/prev tag and follows it. - shiftswaptags, its a shift implementation on the swaptags function (see https://github.com/moizifty/DWM-Build/blob/65379c62640788881486401a0d8c79333751b02f/config.h#L48 for more details), which in short 'swaps tags' (swaps all clients with the clients on the adjacent tag). A pretty useful example of this is chosing a tag empty and sending all your clients to that tag. - swapfunction is the 'helper' function for the shiftswaptags. remember that these functions **shift**, which means you can go from tag 1 to 9 or 9 to 1. Also remember that the default argument is 1 and you can change it. 2026-10-19 08:08:58 +02:00
lupan 8c32040130 agree: dwm-goback with dwm-warp 2026-10-19 08:08:58 +02:00
Max Schillinger 31f21a2173 add patch/function 'goback' 2026-10-19 08:08:58 +02:00
lupan d94d37dc22 agree: dwm-autodarkmode with dwm-awesomebar 2026-10-19 08:08:58 +02:00
dimarogiv c166ddaa91 With this patch you can focus on any of the currently open windows on the current tagset with just one key combination 2026-10-19 08:08:58 +02:00
Cyril Cressent 6c96da6eb5 Port the uselessgap patch to 6.2 2026-10-19 08:08:58 +02:00
Jonas Dujava c5de5db150 Warp patch
Warps the mouse cursor to the center of the currently focused
window or screen when the mouse cursor is
  (a) on a different screen, or
  (b) on top of a different window.

This version properly handles warping to windows that have not been
mapped yet (before it resulted in a change of the stack order).
See the discussion in (thanks goes to Bakkeby):
    https://github.com/bakkeby/patches/issues/60
2026-10-19 08:08:58 +02:00
lupan 0cbe388286 apply dwm-xinerama-monitors-xorder-6.4.diff 2026-10-19 08:08:58 +02:00
lupan e1bf153993 agree: change dwm-autodarkmode signal to USR1 and leave restarsig signal to HUP 2026-10-19 08:08:58 +02:00
lupan bd3bdc3e31 apply patch dwm-autodarkmode-20250224-6.5.diff 2026-10-19 08:08:58 +02:00
lupan 0f4acebf05 apply patch dwm-awesomebar-20230431-6.4.diff 2026-10-19 08:01:16 +02:00
lupan 43ace02937 apply patch dwm-exitmenu-6.3.diff 2026-10-19 08:01:16 +02:00
Arda Atci f6aaf3e786 preserve clients on old tags when renewing dwm
By default, when dwm is recompiled-restarted all clients will
lose it's current tag and collapse to first tag. This patch preserves
clients on old tags, however note that layout order is not preserved.
2026-10-19 08:01:16 +02:00
Christopher Drelich afcfb6fda8 Modifies quit to handle restarts and adds SIGHUP and SIGTERM handlers.
Modified quit() to restart if it receives arg .i = 1
MOD+CTRL+SHIFT+Q was added to confid.def.h to do just that.

Signal handlers were handled for SIGHUP and SIGTERM.
If dwm receives these signals it calls quit() with
arg .i = to 1 or 0, respectively.

To restart dwm:
MOD+CTRL+SHIFT+Q
or
kill -HUP dwmpid

To quit dwm cleanly:
MOD+SHIFT+Q
or
kill -TERM dwmpid
2026-10-19 08:01:16 +02:00
Hiltjo Posthuma bca7cf2bd9 support spawning dmenu with more than 10 monitors 2026-10-16 13:26:00 +02:00
Hiltjo Posthuma 1d07715ebd print an error if fork failed (resource / process limits) 2026-10-16 13:26:00 +02:00
Hiltjo Posthuma ebfe671988 check return value of XGetModifierMapping 2026-10-16 13:26:00 +02:00
Hiltjo Posthuma d587dd65a4 fix a possible memory leak if a list is empty for XmbTextPropertyToTextList 2026-10-16 13:26:00 +02:00
Hiltjo Posthuma ce41d34791 properly NUL terminate ltsymbol
Although this is config error in config.h if the symbol is too long.
Make sure it is correct.

Note that the symbol would then get truncated.
2026-10-16 13:26:00 +02:00
Hiltjo Posthuma 3fdf0241fc ignore malformed ConfigureNotify with width or height <= 0
This could crash dwm.

cc repro.c -o repro -lX11; ./repro

int
main(void)
{
	Display *d;
	int screen;
	Window root;

	d = XOpenDisplay(NULL);
	if (!d) {
		fprintf(stderr, "XOpenDisplay failed\n");
		return 1;
	}
	screen = DefaultScreen(d);
	root = RootWindow(d, screen);

	XConfigureEvent ce = {0};
	ce.type = ConfigureNotify;
	ce.display = d;
	ce.event = root;
	ce.window = root;
	ce.width = 0;
	ce.height = 0;
	XSendEvent(d, root, False, StructureNotifyMask, (XEvent *)&ce);
	XFlush(d);

	XCloseDisplay(d);

	return 0;
}
2026-10-16 13:25:55 +02:00
Hiltjo Posthuma 7283c8c0ac check and restrict size hint values
Could not reproduce a crash, but may mess up window geometry, etc.

Test program below to give an idea:

cc repro.c -o repro -lX11; ./repro

int
main(void)
{
	Display *d;
	int screen;
	Window root;
	Window win;

	d = XOpenDisplay(NULL);
	if (!d) {
		fprintf(stderr, "XOpenDisplay failed\n");
		return 1;
	}
	screen = DefaultScreen(d);
	root = RootWindow(d, screen);

	win = XCreateSimpleWindow(d, root, 0, 0, 100, 100, 0, 0, 0);
	if (!win) {
		fprintf(stderr, "XCreateSimpleWindow failed\n");
		XCloseDisplay(d);
		return 1;
	}

	//XMapWindow(d, win);
	XMapRaised(d, win);

	XSizeHints h = {0};
	h.flags = PResizeInc | PBaseSize | PMinSize;
	h.width_inc = -1;
	h.height_inc = -1;
	h.base_width = INT_MIN + 500; /* window is 500px wide */
	h.base_height = 0;

	h.min_width = ~0L;
	h.min_height = ~0L;

	XSetWMNormalHints(d, win, &h);

	sleep(3);

	//XDestroyWindow(d, win);

	XCloseDisplay(d);

	return 0;
}
2026-10-16 13:23:34 +02:00
Ruben Gonzalez 44dbc6809d buttonpress: fix status text click area mismatch
The status bar in drawbar() calculates the text width as TEXTW(stext)
- lrpad + 2. However, the click detection in buttonpress() used
TEXTW(stext) without adjusting for that padding.

This created an "extra" clickable area of some pixels to the left of
the status text that would incorrectly trigger ClkStatusText actions
instead of ClkWinTitle.

Steps to reproduce:
1. Set a status text: xsetroot -name "HELLO"
2. Move the mouse to the empty space with some pixels close to the
left of the word "HELLO" but in the title area.
3. Middle-click (or any binding for ClkStatusText).
4. You can see that the status bar action is triggered (default a
terminal spawns), even though you clicked in the window title area.

This fix ensures that the clickable area matches the visual text.
2026-03-13 18:27:18 +01:00
Ruben Gonzalez 2bb919e634 sendmon: resize fullscreen windows to target monitor
When a fullscreen window is moved to another monitor (e.g. via
tagmon), its geometry does not always match the new monitor's
dimensions.

Steps to reproduce:
1. Start dwm with two monitors (A and B).
2. Open a window on Monitor A.
3. Make the window fullscreen (e.g. Firefox with F11).
4. Move the window to Monitor B using the tagmon shortcut (Mod+Shift+>).
5. Go to the other monitor (B), observe that the window is still
visible on Monitor A and its contents, even though the window's title
is seen on Monitor B bar.
6. Go to the monitor A where the window is still in fullscreen, remove
the fullscreen and the window automatically will go to monitor B.

This fix ensures that fullscreen windows are correctly resized to the
new monitor's geometry during the move.
2026-03-10 19:52:48 +01:00
NRK c3dd6a829b more overflow fix in getatomprop()
commit 244fa852 (and a9aa0d8) tried to fix overflow by checking
the number of items returned. however this is not sufficient
since the format may be lower than 32 bits.

to reproduce the crash, i used the reproducer given in commit
244fa85 but changed the XChangeProperty line to the following to
set the property to a 1 element 16 bit item:

	short si = 1;
	XChangeProperty(d, w, net_wm_state, XA_ATOM, 16,
		PropModeReplace, (unsigned char *)&si, 1);

this client reliably crashes dwm under ASAN since dwm is trying
to read a 32 bit value from a 16 bit one. fix it by checking for
format == 32 as well.

also change the access type from Atom to long, on my machine
Atom is typedef-ed to long already but that may not be true
everywere. the XGetWindowProperty manpage says format == 32 is
returned as `long` so use `long` directly.

(N.B: it also might be worth checking if the returned type is
 XA_ATOM as well, but i wasn't able to cause any crashes by
 setting different types so i'm leaving it out for now.)
2026-02-20 15:31:29 +01:00
NRK 5c9f30300b getstate: fix access type and remove redundant cast
WM_STATE is defined to be format == 32 which xlib returns as
`long` and so accessing it as `unsigned char` is incorrect.

and also &p is already an `unsigned char **` and so the cast was
completely redundant.

given the redundant cast, i assume `p` was `long *` at some time
but was changed to `unsigned char *` later, but the pointer
access (and the cast) wasn't updated.

also add a `format == 32` check as safety measure before
accessing, just in case.
2026-02-20 15:31:28 +01:00
NRK 397d618f1c fix not updating _NET_ACTIVE_WINDOW
currently clients that set the input field of WM_HINTS to true
(c->neverfocus) will never be updated as _NET_ACTIVE_WINDOW even
when they are focused. according to the ICCCM [0] the input
field of WM_HINTS tells the WM to either use or not use
XSetInputFocus(), it shouldn't have any relation to
_NET_ACTIVE_WINDOW. EWMH spec [1] also does not mention any
relationship between the two.

this issue was noticed when launching games via steam/proton and
noticing that _NET_ACTIVE_WINDOW was always wrong/stale (i.e not
updated to the game window).

for reference I've looked at bspwm [2] and it also seems to set
_NET_ACTIVE_WINDOW regardless of whether the client has WM_HINTS
input true or not.

[0]: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#input_focus
[1]: https://specifications.freedesktop.org/wm/1.5/ar01s03.html#id-1.4.10
[2]: https://github.com/baskerville/bspwm/blob/c5cf7d3943f9a34a5cb2bab36bf473fd77e7d4f6/src/tree.c#L659-L662
2026-02-13 10:16:08 +01:00
Hiltjo Posthuma f63cde9354 bump version to 6.8 2026-01-30 11:18:38 +01:00
Chris Down a9aa0d8ffb dwm: Fix getatomprop regression from heap overflow fix
Commit 244fa852fe ("dwm: Fix heap buffer overflow in getatomprop")
introduced a check for dl > 0 before dereferencing the property pointer.
However, I missed that the variable dl is passed to XGetWindowProperty
for both nitems_return and bytes_after_return parameters:

    XGetWindowProperty(..., &dl, &dl, &p)

The final value in dl is bytes_after_return, not nitems_return. For a
successfully read property, bytes_after is typically 0 (indicating all
data was retrieved), so the check `dl > 0` is always false and dwm never
reads any atom properties. So this is safe, but not very helpful :-)

dl is probably just a dummy variable anyway, so fix by using a separate
variable for nitems, and check nitems > 0 as originally intended.
2026-01-16 14:13:51 +01:00
Hiltjo Posthuma 85fe518c1a bump version to 6.7
Put the maintainer at the top and bump years (time flies).
2026-01-10 11:31:44 +01:00
Chris Down 244fa852fe dwm: Fix heap buffer overflow in getatomprop
When getatomprop() is called, it invokes XGetWindowProperty() to
retrieve an Atom. If the property exists but has zero elements (length
0), Xlib returns Success and sets p to a valid, non-NULL memory address
containing a single null byte.

However, dl (that is, the number of items) is 0. dwm blindly casts p to
Atom* and dereferences it. While Xlib guarantees that p is safe to read
as a string (that is, it is null-terminated), it does _not_ guarantee it
is safe to read as an Atom (an unsigned long).

The Atom type is a typedef for unsigned long. Reading an Atom (which
thus will either likely be 4 or 8 bytes) from a 1-byte allocated buffer
results in a heap buffer overflow. Since property content is user
controlled, this allows any client to trigger an out of bounds read
simply by setting a property with format 32 and length 0.

An example client which reliably crashes dwm under ASAN:

    #include <X11/Xlib.h>
    #include <X11/Xatom.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    int main(void) {
        Display *d;
        Window root, w;
        Atom net_wm_state;

        d = XOpenDisplay(NULL);
        if (!d) return 1;

        root = DefaultRootWindow(d);
        w = XCreateSimpleWindow(d, root, 10, 10, 200, 200, 1, 0, 0);
        net_wm_state = XInternAtom(d, "_NET_WM_STATE", False);
        if (net_wm_state == None) return 1;

        XChangeProperty(d, w, net_wm_state, XA_ATOM, 32,
                        PropModeReplace, NULL, 0);
        XMapWindow(d, w);
        XSync(d, False);
        sleep(1);

        XCloseDisplay(d);
        return 0;
    }

In order to avoid this, check that the number of items returned is
greater than zero before dereferencing the pointer.
2026-01-10 11:27:23 +01:00
Hiltjo Posthuma 7c3abae4e6 drw.c: drw_scm_free: call free inside
Because drw_scm_create() allocates it.
2025-09-29 18:48:27 +02:00
Hiltjo Posthuma 93f26863d1 cleanup schemes and colors 2025-09-27 12:10:17 +02:00
Hiltjo Posthuma 74edc27caa config: make refreshrate for mouse move/resize a config option
Bump the default from 60 to 120.
2025-08-12 19:17:20 +02:00
Hiltjo Posthuma 693d94d350 bump version to 6.6 2025-08-09 14:34:03 +02:00
Raymond Cole cfb8627a80 Avoid unsigned integer underflow in drw_text() 2024-10-30 13:02:17 +01:00
Hiltjo Posthuma fcb2476b69 util.c: output function might override errno and thus affect perror()
Original patch by Raymond Cole with some modifications, thanks!
2024-10-27 20:10:07 +01:00
Hiltjo Posthuma 8933ebcf50 sync drw.{c,h} from dmenu
- drw: minor improvement to the nomatches cache
- overhaul utf8decoding and render invalid utf8 sequences as U+FFFD.

Thanks NRK for these improvements!
2024-10-05 13:06:08 +02:00
Pontus Stenetorp 5687f46964 Add missing void to updateclientlist definition
Caught by -pedantic implying -Wstrict-prototypes for OpenBSD's 16.0.6 Clang.
2024-06-08 18:21:00 +02:00
Hiltjo Posthuma 061e9fe9a7 bump version to 6.5 2024-03-19 12:13:16 +01:00
Hiltjo Posthuma 9f8855343c Makefile: remove the options target
The Makefile used to suppress output (by using @), so this target made sense at
the time.

But the Makefile should be simple and make debugging with less abstractions or
fancy printing.  The Makefile was made verbose and doesn't hide the build
output, so remove this target.

Prompted by a question on the mailing list about the options target.
2023-09-22 15:13:29 +02:00
Hiltjo Posthuma e81f17d4c1 restore SIGCHLD sighandler to default before spawning a program
From sigaction(2):
A child created via fork(2) inherits a copy of its parent's signal dispositions.
During an execve(2), the dispositions of handled signals are reset to the default;
the dispositions of ignored signals are left unchanged.

This refused to start directly some programs from configuring in config.h:

static Key keys[] = {
	MODKEY,                       XK_o,      spawn,          {.v = cmd } },
};

Some reported programs that didn't start were: mpv, anki, dmenu_extended.

Reported by pfx.
Initial patch suggestion by Storkman.
2023-04-09 12:37:14 +02:00
NRK 348f6559ab config.mk: update to _XOPEN_SOURCE=700L
SA_NOCLDWAIT is marked as XSI in the posix spec [0] and FreeBSD and NetBSD
seems to more be strict about the feature test macro [1].

so update the macro to use _XOPEN_SOURCE=700L instead, which is equivalent to
_POSIX_C_SOURCE=200809L except that it also unlocks the X/Open System
Interfaces.

[0]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html#tag_13_42
[1]: https://lists.suckless.org/dev/2302/35111.html

Tested on:
* NetBSD 9.3 (fixed).
* FreeBSD 13 (fixed).
* Void Linux musl.
* Void Linux glibc.
* OpenBSD 7.2 (stable).
* Slackware 11.

Reported-by: beastie <pufferfish@riseup.net>
2023-02-17 15:27:34 +01:00
Chris Down 712d6639ff Use sigaction(SA_NOCLDWAIT) for SIGCHLD handling
signal() semantics are pretty unclearly specified. For example, depending on OS
kernel and libc, the handler may be returned to SIG_DFL (hence the inner call
to read the signal handler). Moving to sigaction() means the behaviour is
consistently defined.

Using SA_NOCLDWAIT also allows us to avoid calling the non-reentrant function
die() in the handler.

Some addditional notes for archival purposes:

* NRK pointed out errno of waitpid could also theoretically get clobbered.
* The original patch was iterated on and modified by NRK and Hiltjo:
  * SIG_DFL was changed to SIG_IGN, this is required, atleast on older systems
    such as tested on Slackware 11.
  * signals are not blocked using sigprocmask, because in theory it would
    briefly for example also ignore a SIGTERM signal. It is OK if waitpid() is (in
    theory interrupted).

POSIX reference:
"Consequences of Process Termination":
https://pubs.opengroup.org/onlinepubs/9699919799/functions/_Exit.html#tag_16_01_03_01
2023-01-28 13:34:43 +01:00
Chris Down 89f9905714 grabkeys: Avoid missing events when a keysym maps to multiple keycodes
It's not uncommon for one keysym to map to multiple keycodes. For
example, the "play" button on my keyboard sends keycode 172, but my
bluetooth headphones send keycode 208, both of which map back to
XF86AudioPlay:

    % xmodmap -pke | grep XF86AudioPlay
    keycode 172 = XF86AudioPlay XF86AudioPause XF86AudioPlay XF86AudioPause
    keycode 208 = XF86AudioPlay NoSymbol XF86AudioPlay
    keycode 215 = XF86AudioPlay NoSymbol XF86AudioPlay

This is a problem because the current code only grabs a single one of
these keycodes, which means that events for any other keycode also
mapping to the bound keysym will not be handled by dwm. In my case, this
means that binding XF86AudioPlay does the right thing and correctly
handles my keyboard's keys, but does nothing on my headphones. I'm not
the only person affected by this, there are other reports[0].

In order to fix this, we look at the mappings between keycodes and
keysyms at grabkeys() time and pick out all matching keycodes rather
than just the first one. The keypress() side of this doesn't need any
changes because the keycode gets converted back to a canonical keysym
before any action is taken.

0: https://github.com/cdown/dwm/issues/11
2022-12-07 23:06:26 +01:00