diff --git a/config.def.h b/config.def.h index 1bd0c3b..81f2d32 100644 --- a/config.def.h +++ b/config.def.h @@ -5,6 +5,9 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ static const unsigned int gappx = 0; /* gaps between windows */ +static const int rainbow_border = 0; /* 1 = animated rainbow border on focused window */ +static const int rainbow_interval = 50; /* ms between animation frames */ +static const float rainbow_step = 3.0; /* hue degrees to shift per frame */ 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" }; @@ -88,6 +91,7 @@ static const Key keys[] = { { MODKEY, XK_minus, setgaps, {.i = -5 } }, { MODKEY, XK_equal, setgaps, {.i = +5 } }, { MODKEY|ShiftMask, XK_minus, setgaps, {.i = 0 } }, + { MODKEY, XK_F5, togglerainbow, {0} }, { MODKEY, XK_0, view, {.ui = ~0 } }, { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, { MODKEY, XK_comma, focusmon, {.i = -1 } }, diff --git a/config.mk b/config.mk index 982dc21..433e544 100644 --- a/config.mk +++ b/config.mk @@ -23,13 +23,13 @@ FREETYPEINC = /usr/include/freetype2 # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lm # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} #CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} -CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} -LDFLAGS = ${LIBS} +CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE ${INCS} ${CPPFLAGS} +LDFLAGS = -pie -Wl,-z,relro,-z,now ${LIBS} # Solaris #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" diff --git a/dwm.c b/dwm.c index b4e350f..34fe9a5 100644 --- a/dwm.c +++ b/dwm.c @@ -23,12 +23,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include @@ -167,6 +170,8 @@ static void detachstack(Client *c); static Monitor *dirtomon(int dir); static void drawbar(Monitor *m); static void drawbars(void); +static void drawrainbowborder(Client *c); +static unsigned long hsvtorgb(float h, float s, float v); static void enternotify(XEvent *e); static void expose(XEvent *e); static void focus(Client *c); @@ -218,6 +223,7 @@ static void tagmon(const Arg *arg); static void tile(Monitor *m); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); +static void togglerainbow(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); @@ -278,6 +284,10 @@ static Drw *drw; static Monitor *mons, *selmon; static Window root, wmcheckwin; +/* rainbow border state */ +static float rainbow_hue = 0; +static int rainbow_enabled; + /* configuration, allows nested code to access above variables */ #include "config.h" @@ -374,7 +384,7 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) *h -= c->baseh; } /* adjust for aspect limits */ - if (c->mina > 0 && c->maxa > 0) { + if (c->mina > 0 && c->maxa > 0 && *w > 0 && *h > 0) { if (c->maxa < (float)*w / *h) *w = *h * c->maxa + 0.5; else if (c->mina < (float)*h / *w) @@ -630,7 +640,7 @@ configurerequest(XEvent *e) if ((c = wintoclient(ev->window))) { if (ev->value_mask & CWBorderWidth) c->bw = ev->border_width; - else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + else if (c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { m = c->mon; if (ev->value_mask & CWX) { c->oldx = c->x; @@ -829,6 +839,37 @@ drawbars(void) drawbar(m); } +unsigned long +hsvtorgb(float h, float s, float v) +{ + float c = v * s; + float x = c * (1.0f - fabsf(fmodf(h / 60.0f, 2.0f) - 1.0f)); + float m = v - c; + float r, g, b; + + if (h < 60) { r = c; g = x; b = 0; } + else if (h < 120) { r = x; g = c; b = 0; } + else if (h < 180) { r = 0; g = c; b = x; } + else if (h < 240) { r = 0; g = x; b = c; } + else if (h < 300) { r = x; g = 0; b = c; } + else { r = c; g = 0; b = x; } + + unsigned char R = (unsigned char)((r + m) * 255); + unsigned char G = (unsigned char)((g + m) * 255); + unsigned char B = (unsigned char)((b + m) * 255); + + return (R << 16) | (G << 8) | B; +} + +void +drawrainbowborder(Client *c) +{ + if (!c || c->isfullscreen || !c->bw) + return; + + XSetWindowBorder(dpy, c->win, hsvtorgb(rainbow_hue, 1.0f, 1.0f)); +} + void enternotify(XEvent *e) { @@ -873,7 +914,10 @@ focus(Client *c) detachstack(c); attachstack(c); grabbuttons(c, 1); - XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + if (rainbow_enabled) + drawrainbowborder(c); + else + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); setfocus(c); } else { XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); @@ -1025,7 +1069,7 @@ getstate(Window w) &real, &format, &n, &extra, (unsigned char **)&p) != Success) return -1; if (n != 0) - result = *p; + result = *(long *)p; XFree(p); return result; } @@ -1056,7 +1100,7 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size) void grabbuttons(Client *c, int focused) { - updatenumlockmask(); + /* numlockmask is updated by grabkeys() on MappingNotify */ { unsigned int i, j; unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; @@ -1290,8 +1334,10 @@ movemouse(const Arg *arg) if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) return; - if (!getrootptr(&x, &y)) + if (!getrootptr(&x, &y)) { + XUngrabPointer(dpy, CurrentTime); return; + } do { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); switch(ev.type) { @@ -1423,7 +1469,6 @@ resizeclient(Client *c, int x, int y, int w, int h) wc.border_width = c->bw; XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); configure(c); - XSync(dpy, False); } void @@ -1512,11 +1557,41 @@ void run(void) { XEvent ev; + int xfd; + fd_set rfds; + struct timeval tv, now; + long long now_ms, last_rainbow_ms = 0; + /* main event loop */ XSync(dpy, False); - while (running && !XNextEvent(dpy, &ev)) - if (handler[ev.type]) - handler[ev.type](&ev); /* call handler */ + xfd = ConnectionNumber(dpy); + + while (running) { + FD_ZERO(&rfds); + FD_SET(xfd, &rfds); + tv.tv_sec = 0; + tv.tv_usec = rainbow_interval * 1000L; + + if (select(xfd + 1, &rfds, NULL, NULL, rainbow_enabled ? &tv : NULL) > 0) { + while (XPending(dpy)) { + XNextEvent(dpy, &ev); + if (handler[ev.type]) + handler[ev.type](&ev); + } + } + + if (rainbow_enabled) { + gettimeofday(&now, NULL); + now_ms = now.tv_sec * 1000LL + now.tv_usec / 1000; + if (now_ms - last_rainbow_ms >= rainbow_interval) { + last_rainbow_ms = now_ms; + rainbow_hue = fmodf(rainbow_hue + rainbow_step, 360.0f); + if (selmon && selmon->sel) + drawrainbowborder(selmon->sel); + XFlush(dpy); + } + } + } } void @@ -1577,7 +1652,7 @@ sendevent(Client *c, Atom proto) int n; Atom *protocols; int exists = 0; - XEvent ev; + XEvent ev = {0}; if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { while (!exists && n--) @@ -1683,6 +1758,8 @@ setup(void) Atom utf8string; struct sigaction sa; + rainbow_enabled = rainbow_border; + /* do not transform children into zombies when they terminate */ sigemptyset(&sa.sa_mask); sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; @@ -1801,10 +1878,13 @@ void spawn(const Arg *arg) { struct sigaction sa; + pid_t pid; - if (arg->v == dmenucmd) - dmenumon[0] = '0' + selmon->num; - if (fork() == 0) { + if ((pid = fork()) < 0) { + fprintf(stderr, "dwm: fork failed: %s\n", strerror(errno)); + return; + } + if (pid == 0) { if (dpy) close(ConnectionNumber(dpy)); setsid(); @@ -1888,6 +1968,14 @@ togglefloating(const Arg *arg) arrange(selmon); } +void +togglerainbow(const Arg *arg) +{ + rainbow_enabled = !rainbow_enabled; + if (!rainbow_enabled && selmon && selmon->sel) + XSetWindowBorder(dpy, selmon->sel->win, scheme[SchemeSel][ColBorder].pixel); +} + void toggletag(const Arg *arg) {