Compare commits

...

21 Commits

Author SHA1 Message Date
gitea-runner[bot] f95e729c48 Merge remote-tracking branch 'upstream/master' 2026-03-22 12:23:05 +00: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
gitea-runner[bot] 02bd09ff29 Merge remote-tracking branch 'upstream/master' 2026-01-16 14:20:18 +00: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
eeeck 0a93955264 Implement lightmode/darkmode patch 2026-01-15 12:40:37 +01:00
eeeck 5bbe65082c Add antialias and autohint to font 2026-01-14 09:37:33 +01:00
eeeck b14af08e9e Use Catppuccin Mocha color pallette 2026-01-13 22:24:51 +01:00
eeeck 4537c87ba0 Use Firacode Nerd Fonts 2026-01-13 22:12:39 +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
eeeck 2c260c333d Adjust border pixel, framerate 2025-12-30 15:05:25 +01:00
eeeck 96a91904a5 Change prefix to install package system-wide 2025-12-07 10:48:24 +01:00
eeeck 018d1f362f Sync regularly with upstream 2025-11-11 15:40:05 +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
8 changed files with 302 additions and 50 deletions
+31
View File
@@ -0,0 +1,31 @@
name: Sync Upstream
on:
schedule:
- cron: "0 0 * * 0"
workflow_dispatch:
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout fork
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: master
- name: Add upstream remote
run: |
git remote add upstream https://git.suckless.org/dwm || true
git fetch upstream
- name: Merge upstream into master
run: |
git config user.name "gitea-runner[bot]"
git config user.email "gitea-runner[bot]@noreply.erickahmed.com"
git merge upstream/master --strategy-option ours --no-edit || true
- name: Push merged branch
run: |
git push origin master
+1 -1
View File
@@ -1,5 +1,6 @@
MIT/X Consortium License
© 2010-2026 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
@@ -11,7 +12,6 @@ MIT/X Consortium License
© 2008 Martin Hurton <martin dot hurton at gmail dot com>
© 2008 Neale Pickett <neale dot woozle dot org>
© 2009 Mate Nagy <mnagy at port70 dot net>
© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
© 2011 Christoph Lohmann <20h@r-36.net>
© 2015-2016 Quentin Rameau <quinq@fifth.space>
+37 -20
View File
@@ -1,21 +1,36 @@
/* See LICENSE file for copyright and license details. */
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
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 char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
static const char col_gray4[] = "#eeeeee";
static const char col_cyan[] = "#005577";
static const char *colors[][3] = {
#define FONT "FiraCodeNerdFont:size=11:antialias=true:autohint=true"
/* appearance */
static const unsigned int borderpx = 3; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const char *fonts[] = { FONT };
static const char dmenufont[] = FONT;
// Dark colors
static const char col_dark1[] = "#11111b";
static const char col_dark2[] = "#45475a";
static const char col_dark3[] = "#7f849c";
static const char col_dark4[] = "#cdd6f4"; //text
static const char col_lavender_dark[] = "#b4befe";
// Light colors
static const char col_light1[] = "#dce0e8";
static const char col_light2[] = "#bcc0cc";
static const char col_light3[] = "#8c8fa1";
static const char col_light4[] = "#4c4f69"; //text
static const char col_lavender_light[] = "#7287fd";
static const char *colorslight[][3] = {
/* fg bg border */
[SchemeNorm] = { col_light3, col_light1, col_light2 },
[SchemeSel] = { col_light4, col_light2, col_lavender_light },
};
static const char *colorsdark[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
[SchemeNorm] = { col_dark1, col_dark3, col_dark2 },
[SchemeSel] = { col_dark4, col_dark2, col_lavender_dark },
};
/* tagging */
@@ -27,8 +42,8 @@ static const Rule rules[] = {
* WM_NAME(STRING) = title
*/
/* class instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
{ "Terminal", NULL, NULL, 0, 1, -1 },
{ "Reader", NULL, NULL, 1 << 8, 0, -1 },
};
/* layout(s) */
@@ -36,6 +51,7 @@ static const float mfact = 0.55; /* factor of master area size [0.05..0.95]
static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
static const int refreshrate = 60; /* refresh rate (per second) for client move/resize */
static const Layout layouts[] = {
/* symbol arrange function */
@@ -56,13 +72,14 @@ static const Layout layouts[] = {
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
/* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static char dmenumon[2] = "0"; /* component of dmenu{dark,light}, manipulated in spawndmenu() */
static const char *dmenudark[] = { "dmenu_run", "-m", dmenumon, "-i", "-fn", dmenufont, "-nb", col_dark1, "-nf", col_dark3, "-sb", col_lavender_dark, "-sf", col_dark4, NULL };
static const char *dmenulight[] = { "dmenu_run", "-m", dmenumon, "-i", "-fn", dmenufont, "-nb", col_light1, "-nf", col_light3, "-sb", col_lavender_light, "-sf", col_light4, NULL };
static const char *termcmd[] = { "st", NULL };
static const Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY, XK_p, spawndmenu, {0} },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
+120
View File
@@ -0,0 +1,120 @@
/* See LICENSE file for copyright and license details. */
#define FONT "FiraCodeNerdFont:size=11:antialias=true:autohint=true"
/* appearance */
static const unsigned int borderpx = 3; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const char *fonts[] = { FONT };
static const char dmenufont[] = FONT;
static const char col_gray1[] = "#1e1e2e";
static const char col_gray2[] = "#45475a";
static const char col_gray3[] = "#6c7086";
static const char col_gray4[] = "#a6adc8";
static const char col_lavender[] = "#b4befe";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray1, col_lavender, col_lavender },
};
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask isfloating monitor */
{ "Terminal", NULL, NULL, 0, 1, -1 },
{ "Reader", NULL, NULL, 1 << 8, 0, -1 },
};
/* layout(s) */
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
static const int refreshrate = 60; /* refresh rate (per second) for client move/resize */
static const Layout layouts[] = {
/* symbol arrange function */
{ "[]=", tile }, /* first entry is default */
{ "><>", NULL }, /* no layout function means floating behavior */
{ "[M]", monocle },
};
/* key definitions */
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask|ShiftMask, KEY, 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 char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_lavender, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };
static const Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
{ MODKEY, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XK_space, setlayout, {0} },
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
{ MODKEY, XK_0, view, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
{ MODKEY, XK_period, focusmon, {.i = +1 } },
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2)
TAGKEYS( XK_4, 3)
TAGKEYS( XK_5, 4)
TAGKEYS( XK_6, 5)
TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
{ MODKEY|ShiftMask, XK_q, quit, {0} },
};
/* button definitions */
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static const Button buttons[] = {
/* click event mask button function argument */
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
{ ClkTagBar, 0, Button1, view, {0} },
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
};
+2 -2
View File
@@ -1,10 +1,10 @@
# dwm version
VERSION = 6.6
VERSION = 6.8
# Customize below to fit your system
# paths
PREFIX = /usr/local
PREFIX = /usr
MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
+26 -3
View File
@@ -178,8 +178,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
die("error, cannot allocate color '%s'", clrname);
}
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */
/* Create color schemes. */
Clr *
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
{
@@ -187,7 +186,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
Clr *ret;
/* need at least two colors for a scheme */
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(Clr))))
return NULL;
for (i = 0; i < clrcount; i++)
@@ -195,6 +194,30 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
return ret;
}
void
drw_clr_free(Drw *drw, Clr *c)
{
if (!drw || !c)
return;
/* c is typedef XftColor Clr */
XftColorFree(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen), c);
}
void
drw_scm_free(Drw *drw, Clr *scm, size_t clrcount)
{
size_t i;
if (!drw || !scm)
return;
for (i = 0; i < clrcount; i++)
drw_clr_free(drw, &scm[i]);
free(scm);
}
void
drw_setfontset(Drw *drw, Fnt *set)
{
+2
View File
@@ -40,7 +40,9 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in
/* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
void drw_clr_free(Drw *drw, Clr *c);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
void drw_scm_free(Drw *drw, Clr *scm, size_t clrcount);
/* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape);
+83 -24
View File
@@ -152,6 +152,7 @@ static void checkotherwm(void);
static void cleanup(void);
static void cleanupmon(Monitor *mon);
static void clientmessage(XEvent *e);
static void colormodehandler(int sig);
static void configure(Client *c);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
@@ -197,6 +198,7 @@ static void scan(void);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
static void setcolormode(void);
static void setfocus(Client *c);
static void setfullscreen(Client *c, int fullscreen);
static void setlayout(const Arg *arg);
@@ -205,6 +207,7 @@ static void setup(void);
static void seturgent(Client *c, int urg);
static void showhide(Client *c);
static void spawn(const Arg *arg);
static void spawndmenu(const Arg *arg);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *m);
@@ -261,11 +264,13 @@ static void (*handler[LASTEvent]) (XEvent *) = {
static Atom wmatom[WMLast], netatom[NetLast];
static int running = 1;
static Cur *cursor[CurLast];
static Clr **scheme;
static Clr **scheme, **schemedark, **schemelight;
static Display *dpy;
static Drw *drw;
static Monitor *mons, *selmon;
static Window root, wmcheckwin;
static const char **dmenucmd;
static int colormodechanged;
/* configuration, allows nested code to access above variables */
#include "config.h"
@@ -440,7 +445,7 @@ buttonpress(XEvent *e)
arg.ui = 1 << i;
} else if (ev->x < x + TEXTW(selmon->ltsymbol))
click = ClkLtSymbol;
else if (ev->x > selmon->ww - (int)TEXTW(stext))
else if (ev->x > selmon->ww - (int)TEXTW(stext) + lrpad - 2)
click = ClkStatusText;
else
click = ClkWinTitle;
@@ -485,9 +490,12 @@ cleanup(void)
cleanupmon(mons);
for (i = 0; i < CurLast; i++)
drw_cur_free(drw, cursor[i]);
for (i = 0; i < LENGTH(colors); i++)
free(scheme[i]);
free(scheme);
for (i = 0; i < LENGTH(colorsdark); i++) {
free(schemedark[i]);
free(schemelight[i]);
}
free(schemedark);
free(schemelight);
XDestroyWindow(dpy, wmcheckwin);
drw_free(drw);
XSync(dpy, False);
@@ -530,6 +538,12 @@ clientmessage(XEvent *e)
}
}
void
colormodehandler(int sig)
{
colormodechanged = 1;
}
void
configure(Client *c)
{
@@ -863,14 +877,15 @@ focusstack(const Arg *arg)
Atom
getatomprop(Client *c, Atom prop)
{
int di;
unsigned long dl;
int format;
unsigned long nitems, dl;
unsigned char *p = NULL;
Atom da, atom = None;
if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
&da, &di, &dl, &dl, &p) == Success && p) {
atom = *(Atom *)p;
&da, &format, &nitems, &dl, &p) == Success && p) {
if (nitems > 0 && format == 32)
atom = *(long *)p;
XFree(p);
}
return atom;
@@ -896,10 +911,10 @@ getstate(Window w)
Atom real;
if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
&real, &format, &n, &extra, (unsigned char **)&p) != Success)
&real, &format, &n, &extra, &p) != Success)
return -1;
if (n != 0)
result = *p;
if (n != 0 && format == 32)
result = *(long *)p;
XFree(p);
return result;
}
@@ -1171,7 +1186,7 @@ movemouse(const Arg *arg)
handler[ev.type](&ev);
break;
case MotionNotify:
if ((ev.xmotion.time - lasttime) <= (1000 / 60))
if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate))
continue;
lasttime = ev.xmotion.time;
@@ -1224,6 +1239,10 @@ propertynotify(XEvent *e)
Window trans;
XPropertyEvent *ev = &e->xproperty;
if (colormodechanged) {
setcolormode();
colormodechanged = 0;
}
if ((ev->window == root) && (ev->atom == XA_WM_NAME))
updatestatus();
else if (ev->state == PropertyDelete)
@@ -1325,7 +1344,7 @@ resizemouse(const Arg *arg)
handler[ev.type](&ev);
break;
case MotionNotify:
if ((ev.xmotion.time - lasttime) <= (1000 / 60))
if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate))
continue;
lasttime = ev.xmotion.time;
@@ -1428,6 +1447,8 @@ sendmon(Client *c, Monitor *m)
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
attach(c);
attachstack(c);
if (c->isfullscreen)
resizeclient(c, m->mx, m->my, m->mw, m->mh);
focus(NULL);
arrange(NULL);
}
@@ -1441,6 +1462,32 @@ setclientstate(Client *c, long state)
PropModeReplace, (unsigned char *)data, 2);
}
void
setcolormode(void)
{
static const char *file = ".lightmode";
static char *path = NULL;
const char *home;
size_t size;
if (!path && (home = getenv("HOME"))) {
size = strlen(home) + 1 + strlen(file) + 1;
path = malloc(size);
if (!path)
die("dwm: malloc failed");
snprintf(path, size, "%s/%s", home, file);
}
if (access(path, F_OK) == 0) {
scheme = schemelight;
dmenucmd = dmenulight;
} else {
scheme = schemedark;
dmenucmd = dmenudark;
}
}
int
sendevent(Client *c, Atom proto)
{
@@ -1469,12 +1516,10 @@ sendevent(Client *c, Atom proto)
void
setfocus(Client *c)
{
if (!c->neverfocus) {
if (!c->neverfocus)
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
XChangeProperty(dpy, root, netatom[NetActiveWindow],
XA_WINDOW, 32, PropModeReplace,
(unsigned char *) &(c->win), 1);
}
XChangeProperty(dpy, root, netatom[NetActiveWindow], XA_WINDOW, 32,
PropModeReplace, (unsigned char *)&c->win, 1);
sendevent(c, wmatom[WMTakeFocus]);
}
@@ -1549,6 +1594,11 @@ setup(void)
sa.sa_handler = SIG_IGN;
sigaction(SIGCHLD, &sa, NULL);
/* set color mode on SIGHUP */
sigemptyset(&sa.sa_mask);
sa.sa_handler = colormodehandler;
sigaction(SIGHUP, &sa, NULL);
/* clean up any zombies (inherited from .xinitrc etc) immediately */
while (waitpid(-1, NULL, WNOHANG) > 0);
@@ -1583,9 +1633,13 @@ setup(void)
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
/* init appearance */
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
for (i = 0; i < LENGTH(colors); i++)
scheme[i] = drw_scm_create(drw, colors[i], 3);
schemedark = ecalloc(LENGTH(colorsdark), sizeof(Clr *));
schemelight = ecalloc(LENGTH(colorslight), sizeof(Clr *));
for (i = 0; i < LENGTH(colorsdark); i++) {
schemedark[i] = drw_scm_create(drw, colorsdark[i], 3);
schemelight[i] = drw_scm_create(drw, colorslight[i], 3);
}
setcolormode();
/* init bars */
updatebars();
updatestatus();
@@ -1648,8 +1702,6 @@ spawn(const Arg *arg)
{
struct sigaction sa;
if (arg->v == dmenucmd)
dmenumon[0] = '0' + selmon->num;
if (fork() == 0) {
if (dpy)
close(ConnectionNumber(dpy));
@@ -1665,6 +1717,13 @@ spawn(const Arg *arg)
}
}
void
spawndmenu(const Arg *arg)
{
dmenumon[0] = '0' + selmon->num;
spawn(&(const Arg){.v = dmenucmd});
}
void
tag(const Arg *arg)
{