dwm

my heavily-patched and customized dwm build
git clone git://git.kocotian.pl/dwm.git
Log | Files | Refs | README | LICENSE

commit 1d93d83d3a85d99902c318ed5900531dcdd938a5
parent 46bfa0175ecb2b0c7e410ab490a63111af2f5b16
Author: kocotian <kocotian@kocotian.pl>
Date:   Wed, 23 Dec 2020 11:16:20 +0100

color changes

Diffstat:
Mconfig.def.h | 9+++++++--
Mdrw.c | 11+++++++++--
Mdwm.c | 148++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Apatches/dwm-cropwindows-20170709-ceac8c9.diff | 312+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apatches/dwm-freespace-20180109-db22360.diff | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 529 insertions(+), 16 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -21,10 +21,13 @@ static const char *colors[][3] = { [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, [SchemeSel] = { col_gray4, col_cyan, col_cyan }, [SchemeStatus] = { col_gray3, col_gray1, "#000000" }, /* Status */ - [SchemeTagsSel] = { col_gray4, col_gray1, "#000000" }, /* Tagbar l selected */ [SchemeTagsNorm] = { col_gray3, col_gray1, "#000000" }, /* Tagbar l unselected */ - [SchemeInfoSel] = { col_gray3, col_gray1, "#000000" }, /* Infbar m selected */ + [SchemeTagsSel] = { col_gray4, col_gray1, "#000000" }, /* Tagbar l selected */ [SchemeInfoNorm] = { col_gray3, col_gray1, "#000000" }, /* Infbar m unselected */ + [SchemeInfoSel] = { col_gray3, col_gray1, "#000000" }, /* Infbar m selected */ + [SchemeTermNorm] = { col_gray3, col_gray1, "@term" }, + [SchemeTermSel] = { col_gray4, col_cyan, col_cyan }, + /* Terminal colors, see drw.c for customizing @term */ }; /* tagging */ @@ -211,8 +214,10 @@ static Button buttons[] = { { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY|ShiftMask, Button1, movemouse, {.i = 1} }, { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkClientWin, MODKEY|ShiftMask, Button3, resizemouse, {.i = 1} }, { ClkTagBar, 0, Button1, view, {0} }, { ClkTagBar, 0, Button3, toggleview, {0} }, { ClkTagBar, MODKEY, Button1, tag, {0} }, diff --git a/drw.c b/drw.c @@ -11,6 +11,9 @@ #define UTF_INVALID 0xFFFD #define UTF_SIZ 4 +/* @term color */ +static const char *termclr = "#000000"; + static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; @@ -202,10 +205,14 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname) if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen), - clrname, dest)) + strcmp(clrname, "@term") ? clrname : termclr, + dest)) die("error, cannot allocate color '%s'", clrname); - dest->pixel |= 0xff << 24; + if (!strcmp(clrname, "@term")) + dest->pixel |= 0xd9 << 24; + else + dest->pixel |= 0xff << 24; } /* Wrapper to create color schemes. The caller has to call free(3) on the diff --git a/dwm.c b/dwm.c @@ -66,7 +66,7 @@ /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */ +enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm, SchemeTermSel, SchemeTermNorm }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ @@ -107,6 +107,7 @@ struct Client { Client *swallowing; Monitor *mon; Window win; + Client *crop; }; typedef struct { @@ -342,6 +343,88 @@ struct Pertag { struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; /* function implementations */ +Client * +cropwintoclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + if (c->crop && c->crop->win == w) + return c; + return NULL; +} + +void +cropwindow(Client *c) +{ + int x, y; + XEvent ev; + XSetWindowAttributes wa = { .event_mask = SubstructureRedirectMask }; + + if (!getrootptr(&x, &y)) + return; + if (!c->crop) { + c->crop = ecalloc(1, sizeof(Client)); + memcpy(c->crop, c, sizeof(Client)); + c->crop->crop = NULL; + c->crop->x = c->crop->y = c->crop->bw = 0; + c->basew = c->baseh = c->mina = c->maxa = 0; + c->maxw = c->maxh = c->incw = c->inch = 0; + c->minw = c->minh = 1; + if (!c->isfloating) + togglefloating(NULL); + c->win = XCreateWindow(dpy, root, x, y, 1, 1, c->bw, + 0, 0, 0, CWEventMask, &wa); + XReparentWindow(dpy, c->crop->win, c->win, 0, 0); + XMapWindow(dpy, c->win); + focus(c); + XCheckTypedWindowEvent(dpy, c->crop->win, UnmapNotify, &ev); + if (XCheckTypedWindowEvent(dpy, root, UnmapNotify, &ev) + && ev.xunmap.window != c->crop->win) + XPutBackEvent(dpy, &ev); + } + resizeclient(c->crop, c->crop->x + c->x - x, c->crop->y + c->y - y, + c->crop->w, c->crop->h); + resizeclient(c, x, y, 1, 1); +} + +void +cropdelete(Client *c) +{ + Client *crop; + XEvent ev; + + c->crop->x += c->x; + c->crop->y += c->y; + c->crop->bw = c->bw; + c->crop->next = c->next; + c->crop->snext = c->snext; + c->crop->tags = c->tags; + c->crop->mon = c->mon; + XReparentWindow(dpy, c->crop->win, root, c->crop->x, c->crop->y); + XDestroyWindow(dpy, c->win); + crop = c->crop; + memcpy(c, c->crop, sizeof(Client)); + free(crop); + resize(c, c->x, c->y, c->w, c->h, 0); + focus(c); + XCheckTypedWindowEvent(dpy, c->win, UnmapNotify, &ev); +} + +void +cropresize(Client* c) +{ + resizeclient(c->crop, + BETWEEN(c->crop->x, -(c->crop->w), 0) ? c->crop->x : 0, + BETWEEN(c->crop->y, -(c->crop->h), 0) ? c->crop->y : 0, + c->crop->w, c->crop->h); + resize(c, c->x, c->y, + MIN(c->w, c->crop->x + c->crop->w), + MIN(c->h, c->crop->y + c->crop->h), 0); +} + void applyrules(Client *c) { @@ -717,7 +800,7 @@ clientmessage(XEvent *e) XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); - if (!c) + if (!c && !(c = cropwintoclient(cme->window))) return; if (cme->message_type == netatom[NetWMState]) { if (cme->data.l[1] == netatom[NetWMFullscreen] @@ -781,16 +864,19 @@ configurenotify(XEvent *e) void configurerequest(XEvent *e) { - Client *c; + Client *c, *cc = NULL; Monitor *m; XConfigureRequestEvent *ev = &e->xconfigurerequest; XWindowChanges wc; - if ((c = wintoclient(ev->window))) { + if ((c = wintoclient(ev->window)) + || (c = cc = cropwintoclient(ev->window))) { if (ev->value_mask & CWBorderWidth) c->bw = ev->border_width; else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { m = c->mon; + if (c->crop) + c = c->crop; if (ev->value_mask & CWX) { c->oldx = c->x; c->x = m->mx + ev->x; @@ -815,6 +901,8 @@ configurerequest(XEvent *e) configure(c); if (ISVISIBLE(c)) XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + if (cc) + cropresize(cc); } else configure(c); } else { @@ -885,7 +973,7 @@ destroynotify(XEvent *e) Client *c; XDestroyWindowEvent *ev = &e->xdestroywindow; - if ((c = wintoclient(ev->window))) + if ((c = wintoclient(ev->window)) || (c = cropwintoclient(ev->window))) unmanage(c, 1); else if ((c = swallowingclient(ev->window))) @@ -1021,6 +1109,8 @@ enternotify(XEvent *e) if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) return; c = wintoclient(ev->window); + if (!c) + c = cropwintoclient(ev->window); m = c ? c->mon : wintomon(ev->window); if (m != selmon) { unfocus(selmon->sel, 1); @@ -1055,7 +1145,7 @@ focus(Client *c) detachstack(c); attachstack(c); grabbuttons(c, 1); - XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + XSetWindowBorder(dpy, c->win, scheme[c->isterminal ? SchemeTermSel : SchemeSel][ColBorder].pixel); setfocus(c); } else { XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); @@ -1275,6 +1365,8 @@ killclient(const Arg *arg) { if (!selmon->sel) return; + if (selmon->sel->crop) + cropdelete(selmon->sel); if (!sendevent(selmon->sel, wmatom[WMDelete])) { XGrabServer(dpy); XSetErrorHandler(xerrordummy); @@ -1326,7 +1418,7 @@ manage(Window w, XWindowAttributes *wa) wc.border_width = c->bw; XConfigureWindow(dpy, w, CWBorderWidth, &wc); - XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); + XSetWindowBorder(dpy, w, scheme[c->isterminal ? SchemeTermNorm : SchemeNorm][ColBorder].pixel); configure(c); /* propagates border_width, if size doesn't change */ updatewindowtype(c); updatesizehints(c); @@ -1448,6 +1540,10 @@ movemouse(const Arg *arg) restack(selmon); ocx = c->x; ocy = c->y; + if (arg->i == 1 && c->crop) { + ocx = c->crop->x; + ocy = c->crop->y; + } if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) return; @@ -1468,6 +1564,12 @@ movemouse(const Arg *arg) nx = ocx + (ev.xmotion.x - x); ny = ocy + (ev.xmotion.y - y); + if (arg->i == 1 && c->crop) { + c->crop->x = nx; + c->crop->y = ny; + cropresize(c); + continue; + } if (abs(selmon->wx - nx) < snap) nx = selmon->wx; else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) @@ -1529,7 +1631,10 @@ propertynotify(XEvent *e) updatestatus(); else if (ev->state == PropertyDelete) return; /* ignore */ - else if ((c = wintoclient(ev->window))) { + else if ((c = wintoclient(ev->window)) + || (c = cropwintoclient(ev->window))) { + if (c->crop) + c = c->crop; switch(ev->atom) { default: break; case XA_WM_TRANSIENT_FOR: @@ -1662,12 +1767,16 @@ resizemouse(const Arg *arg) if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ return; restack(selmon); + if (arg->i == 1) + cropwindow(c); ocx = c->x; ocy = c->y; if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) return; - XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + if (arg->i != 1) + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, + c->w + c->bw - 1, c->h + c->bw - 1); do { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); switch(ev.type) { @@ -1683,6 +1792,10 @@ resizemouse(const Arg *arg) nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); + if (c->crop) { + nw = MIN(nw, c->crop->w + c->crop->x); + nh = MIN(nh, c->crop->h + c->crop->y); + } if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) { @@ -1807,6 +1920,8 @@ setclientstate(Client *c, long state) { long data[] = { state, None }; + if (c->crop) + c = c->crop; XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, PropModeReplace, (unsigned char *)data, 2); } @@ -1839,6 +1954,8 @@ sendevent(Client *c, Atom proto) void setfocus(Client *c) { + if (c->crop) + c = c->crop; if (!c->neverfocus) { XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); XChangeProperty(dpy, root, netatom[NetActiveWindow], @@ -1851,6 +1968,8 @@ setfocus(Client *c) void setfullscreen(Client *c, int fullscreen) { + if (c->crop) + c = c->crop; if (fullscreen && !c->isfullscreen) { XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); @@ -2191,6 +2310,8 @@ togglefloating(const Arg *arg) if (selmon->sel->isfloating) resize(selmon->sel, selmon->sel->x, selmon->sel->y, selmon->sel->w, selmon->sel->h, 0); + if (!selmon->sel->isfloating && selmon->sel->crop) + cropdelete(selmon->sel); arrange(selmon); } @@ -2258,7 +2379,7 @@ unfocus(Client *c, int setfocus) if (!c) return; grabbuttons(c, 0); - XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + XSetWindowBorder(dpy, c->win, scheme[c->isterminal ? SchemeTermNorm : SchemeNorm][ColBorder].pixel); if (setfocus) { XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XDeleteProperty(dpy, root, netatom[NetActiveWindow]); @@ -2285,6 +2406,8 @@ unmanage(Client *c, int destroyed) return; } + if (c->crop) + cropdelete(c); detach(c); detachstack(c); if (!destroyed) { @@ -2313,7 +2436,8 @@ unmapnotify(XEvent *e) Client *c; XUnmapEvent *ev = &e->xunmap; - if ((c = wintoclient(ev->window))) { + if ((c = wintoclient(ev->window)) + || (c = cropwintoclient(ev->window))) { if (ev->send_event) setclientstate(c, WithdrawnState); else @@ -2800,7 +2924,7 @@ wintomon(Window w) for (m = mons; m; m = m->next) if (w == m->barwin || w == m->extrabarwin) return m; - if ((c = wintoclient(w))) + if ((c = wintoclient(w)) || (c = cropwintoclient(w))) return c->mon; return selmon; } diff --git a/patches/dwm-cropwindows-20170709-ceac8c9.diff b/patches/dwm-cropwindows-20170709-ceac8c9.diff @@ -0,0 +1,312 @@ +diff --git a/config.def.h b/config.def.h +index a9ac303..a9797ac 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -105,8 +105,10 @@ static Button buttons[] = { + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, ++ { ClkClientWin, MODKEY|ShiftMask, Button1, movemouse, {.i = 1} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, ++ { ClkClientWin, MODKEY|ShiftMask, Button3, resizemouse, {.i = 1} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, +diff --git a/dwm.c b/dwm.c +index a5ce993..e922ef6 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -98,6 +98,7 @@ struct Client { + Client *snext; + Monitor *mon; + Window win; ++ Client *crop; + }; + + typedef struct { +@@ -276,6 +277,88 @@ static Window root, wmcheckwin; + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + + /* function implementations */ ++Client * ++cropwintoclient(Window w) ++{ ++ Client *c; ++ Monitor *m; ++ ++ for (m = mons; m; m = m->next) ++ for (c = m->clients; c; c = c->next) ++ if (c->crop && c->crop->win == w) ++ return c; ++ return NULL; ++} ++ ++void ++cropwindow(Client *c) ++{ ++ int x, y; ++ XEvent ev; ++ XSetWindowAttributes wa = { .event_mask = SubstructureRedirectMask }; ++ ++ if (!getrootptr(&x, &y)) ++ return; ++ if (!c->crop) { ++ c->crop = ecalloc(1, sizeof(Client)); ++ memcpy(c->crop, c, sizeof(Client)); ++ c->crop->crop = NULL; ++ c->crop->x = c->crop->y = c->crop->bw = 0; ++ c->basew = c->baseh = c->mina = c->maxa = 0; ++ c->maxw = c->maxh = c->incw = c->inch = 0; ++ c->minw = c->minh = 1; ++ if (!c->isfloating) ++ togglefloating(NULL); ++ c->win = XCreateWindow(dpy, root, x, y, 1, 1, c->bw, ++ 0, 0, 0, CWEventMask, &wa); ++ XReparentWindow(dpy, c->crop->win, c->win, 0, 0); ++ XMapWindow(dpy, c->win); ++ focus(c); ++ XCheckTypedWindowEvent(dpy, c->crop->win, UnmapNotify, &ev); ++ if (XCheckTypedWindowEvent(dpy, root, UnmapNotify, &ev) ++ && ev.xunmap.window != c->crop->win) ++ XPutBackEvent(dpy, &ev); ++ } ++ resizeclient(c->crop, c->crop->x + c->x - x, c->crop->y + c->y - y, ++ c->crop->w, c->crop->h); ++ resizeclient(c, x, y, 1, 1); ++} ++ ++void ++cropdelete(Client *c) ++{ ++ Client *crop; ++ XEvent ev; ++ ++ c->crop->x += c->x; ++ c->crop->y += c->y; ++ c->crop->bw = c->bw; ++ c->crop->next = c->next; ++ c->crop->snext = c->snext; ++ c->crop->tags = c->tags; ++ c->crop->mon = c->mon; ++ XReparentWindow(dpy, c->crop->win, root, c->crop->x, c->crop->y); ++ XDestroyWindow(dpy, c->win); ++ crop = c->crop; ++ memcpy(c, c->crop, sizeof(Client)); ++ free(crop); ++ resize(c, c->x, c->y, c->w, c->h, 0); ++ focus(c); ++ XCheckTypedWindowEvent(dpy, c->win, UnmapNotify, &ev); ++} ++ ++void ++cropresize(Client* c) ++{ ++ resizeclient(c->crop, ++ BETWEEN(c->crop->x, -(c->crop->w), 0) ? c->crop->x : 0, ++ BETWEEN(c->crop->y, -(c->crop->h), 0) ? c->crop->y : 0, ++ c->crop->w, c->crop->h); ++ resize(c, c->x, c->y, ++ MIN(c->w, c->crop->x + c->crop->w), ++ MIN(c->h, c->crop->y + c->crop->h), 0); ++} ++ + void + applyrules(Client *c) + { +@@ -516,7 +599,7 @@ clientmessage(XEvent *e) + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + +- if (!c) ++ if (!c && !(c = cropwintoclient(cme->window))) + return; + if (cme->message_type == netatom[NetWMState]) { + if (cme->data.l[1] == netatom[NetWMFullscreen] +@@ -579,16 +662,19 @@ configurenotify(XEvent *e) + void + configurerequest(XEvent *e) + { +- Client *c; ++ Client *c, *cc = NULL; + Monitor *m; + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + +- if ((c = wintoclient(ev->window))) { ++ if ((c = wintoclient(ev->window)) ++ || (c = cc = cropwintoclient(ev->window))) { + if (ev->value_mask & CWBorderWidth) + c->bw = ev->border_width; + else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + m = c->mon; ++ if (c->crop) ++ c = c->crop; + if (ev->value_mask & CWX) { + c->oldx = c->x; + c->x = m->mx + ev->x; +@@ -613,6 +699,8 @@ configurerequest(XEvent *e) + configure(c); + if (ISVISIBLE(c)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); ++ if (cc) ++ cropresize(cc); + } else + configure(c); + } else { +@@ -651,7 +739,7 @@ destroynotify(XEvent *e) + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + +- if ((c = wintoclient(ev->window))) ++ if ((c = wintoclient(ev->window)) || (c = cropwintoclient(ev->window))) + unmanage(c, 1); + } + +@@ -762,6 +850,8 @@ enternotify(XEvent *e) + if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) + return; + c = wintoclient(ev->window); ++ if (!c) ++ c = cropwintoclient(ev->window); + m = c ? c->mon : wintomon(ev->window); + if (m != selmon) { + unfocus(selmon->sel, 1); +@@ -1005,6 +1095,8 @@ killclient(const Arg *arg) + { + if (!selmon->sel) + return; ++ if (selmon->sel->crop) ++ cropdelete(selmon->sel); + if (!sendevent(selmon->sel, wmatom[WMDelete])) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); +@@ -1150,6 +1242,10 @@ movemouse(const Arg *arg) + restack(selmon); + ocx = c->x; + ocy = c->y; ++ if (arg->i == 1 && c->crop) { ++ ocx = c->crop->x; ++ ocy = c->crop->y; ++ } + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; +@@ -1170,6 +1266,12 @@ movemouse(const Arg *arg) + + nx = ocx + (ev.xmotion.x - x); + ny = ocy + (ev.xmotion.y - y); ++ if (arg->i == 1 && c->crop) { ++ c->crop->x = nx; ++ c->crop->y = ny; ++ cropresize(c); ++ continue; ++ } + if (abs(selmon->wx - nx) < snap) + nx = selmon->wx; + else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) +@@ -1221,7 +1323,10 @@ propertynotify(XEvent *e) + updatestatus(); + else if (ev->state == PropertyDelete) + return; /* ignore */ +- else if ((c = wintoclient(ev->window))) { ++ else if ((c = wintoclient(ev->window)) ++ || (c = cropwintoclient(ev->window))) { ++ if (c->crop) ++ c = c->crop; + switch(ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: +@@ -1303,12 +1408,16 @@ resizemouse(const Arg *arg) + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; + restack(selmon); ++ if (arg->i == 1) ++ cropwindow(c); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + return; +- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); ++ if (arg->i != 1) ++ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, ++ c->w + c->bw - 1, c->h + c->bw - 1); + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { +@@ -1324,6 +1433,10 @@ resizemouse(const Arg *arg) + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); ++ if (c->crop) { ++ nw = MIN(nw, c->crop->w + c->crop->x); ++ nh = MIN(nh, c->crop->h + c->crop->y); ++ } + if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww + && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) + { +@@ -1430,6 +1543,8 @@ setclientstate(Client *c, long state) + { + long data[] = { state, None }; + ++ if (c->crop) ++ c = c->crop; + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); + } +@@ -1462,6 +1577,8 @@ sendevent(Client *c, Atom proto) + void + setfocus(Client *c) + { ++ if (c->crop) ++ c = c->crop; + if (!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], +@@ -1474,6 +1591,8 @@ setfocus(Client *c) + void + setfullscreen(Client *c, int fullscreen) + { ++ if (c->crop) ++ c = c->crop; + if (fullscreen && !c->isfullscreen) { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); +@@ -1718,6 +1837,8 @@ togglefloating(const Arg *arg) + if (selmon->sel->isfloating) + resize(selmon->sel, selmon->sel->x, selmon->sel->y, + selmon->sel->w, selmon->sel->h, 0); ++ if (!selmon->sel->isfloating && selmon->sel->crop) ++ cropdelete(selmon->sel); + arrange(selmon); + } + +@@ -1767,6 +1888,8 @@ unmanage(Client *c, int destroyed) + Monitor *m = c->mon; + XWindowChanges wc; + ++ if (c->crop) ++ cropdelete(c); + detach(c); + detachstack(c); + if (!destroyed) { +@@ -1792,7 +1915,8 @@ unmapnotify(XEvent *e) + Client *c; + XUnmapEvent *ev = &e->xunmap; + +- if ((c = wintoclient(ev->window))) { ++ if ((c = wintoclient(ev->window)) ++ || (c = cropwintoclient(ev->window))) { + if (ev->send_event) + setclientstate(c, WithdrawnState); + else +@@ -2070,7 +2194,7 @@ wintomon(Window w) + for (m = mons; m; m = m->next) + if (w == m->barwin) + return m; +- if ((c = wintoclient(w))) ++ if ((c = wintoclient(w)) || (c = cropwintoclient(w))) + return c->mon; + return selmon; + } diff --git a/patches/dwm-freespace-20180109-db22360.diff b/patches/dwm-freespace-20180109-db22360.diff @@ -0,0 +1,65 @@ +diff --git a/config.def.h b/config.def.h +index a9ac303..eb22d92 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -1,6 +1,7 @@ + /* See LICENSE file for copyright and license details. */ + + /* appearance */ ++static const unsigned int panel[] = {30, 0, 0, 0};//positions: 0-top panel, 1-bottom panel, 2-left panel, 3-right panel + 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 */ +diff --git a/dwm.c b/dwm.c +index ec6a27c..91be0cc 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -1113,7 +1113,7 @@ monocle(Monitor *m) + if (n > 0) /* override layout symbol */ + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); + for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) +- resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); ++ resize(c, m->wx + panel[2], m->wy + panel[1] , m->ww - 2 * c->bw - panel[3] - panel[2], m->wh - 2 * c->bw - panel[0] - panel[1], 0); + } + + void +@@ -1169,14 +1169,14 @@ movemouse(const Arg *arg) + + nx = ocx + (ev.xmotion.x - x); + ny = ocy + (ev.xmotion.y - y); +- if (abs(selmon->wx - nx) < snap) +- nx = selmon->wx; +- else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) +- nx = selmon->wx + selmon->ww - WIDTH(c); +- if (abs(selmon->wy - ny) < snap) +- ny = selmon->wy; +- else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) +- ny = selmon->wy + selmon->wh - HEIGHT(c); ++ if (abs(selmon->wx + panel[2] - nx) < snap) ++ nx = selmon->wx + panel[2]; ++ else if (abs((selmon->wx + selmon->ww - panel[3]) - (nx + WIDTH(c))) < snap) ++ nx = selmon->wx + selmon->ww - WIDTH(c) - panel[3]; ++ if (abs(selmon->wy + panel[1] - ny) < snap) ++ ny = selmon->wy + panel[1]; ++ else if (abs((selmon->wy + selmon->wh - panel[0]) - (ny + HEIGHT(c))) < snap) ++ ny = selmon->wy + selmon->wh - HEIGHT(c) - panel[0]; + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); +@@ -1687,12 +1687,12 @@ tile(Monitor *m) + mw = m->ww; + for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { +- h = (m->wh - my) / (MIN(n, m->nmaster) - i); +- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - panel[0]; ++ resize(c, m->wx + panel[2], m->wy + my + panel[1], mw - (c->bw), h - (c->bw) - panel[1], 0); + my += HEIGHT(c); + } else { +- h = (m->wh - ty) / (n - i); +- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); ++ h = (m->wh - ty) / (n - i) - panel[0]; ++ resize(c, m->wx + mw + panel[2] , m->wy + ty + panel[1], m->ww - mw - (c->bw) - panel[2] - panel[3], h - (c->bw) - panel[1], 0); + ty += HEIGHT(c); + } + }