dwm-cropwindows-20170709-ceac8c9.diff (9365B)
1 diff --git a/config.def.h b/config.def.h 2 index a9ac303..a9797ac 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -105,8 +105,10 @@ static Button buttons[] = { 6 { ClkWinTitle, 0, Button2, zoom, {0} }, 7 { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, 8 { ClkClientWin, MODKEY, Button1, movemouse, {0} }, 9 + { ClkClientWin, MODKEY|ShiftMask, Button1, movemouse, {.i = 1} }, 10 { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, 11 { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, 12 + { ClkClientWin, MODKEY|ShiftMask, Button3, resizemouse, {.i = 1} }, 13 { ClkTagBar, 0, Button1, view, {0} }, 14 { ClkTagBar, 0, Button3, toggleview, {0} }, 15 { ClkTagBar, MODKEY, Button1, tag, {0} }, 16 diff --git a/dwm.c b/dwm.c 17 index a5ce993..e922ef6 100644 18 --- a/dwm.c 19 +++ b/dwm.c 20 @@ -98,6 +98,7 @@ struct Client { 21 Client *snext; 22 Monitor *mon; 23 Window win; 24 + Client *crop; 25 }; 26 27 typedef struct { 28 @@ -276,6 +277,88 @@ static Window root, wmcheckwin; 29 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; 30 31 /* function implementations */ 32 +Client * 33 +cropwintoclient(Window w) 34 +{ 35 + Client *c; 36 + Monitor *m; 37 + 38 + for (m = mons; m; m = m->next) 39 + for (c = m->clients; c; c = c->next) 40 + if (c->crop && c->crop->win == w) 41 + return c; 42 + return NULL; 43 +} 44 + 45 +void 46 +cropwindow(Client *c) 47 +{ 48 + int x, y; 49 + XEvent ev; 50 + XSetWindowAttributes wa = { .event_mask = SubstructureRedirectMask }; 51 + 52 + if (!getrootptr(&x, &y)) 53 + return; 54 + if (!c->crop) { 55 + c->crop = ecalloc(1, sizeof(Client)); 56 + memcpy(c->crop, c, sizeof(Client)); 57 + c->crop->crop = NULL; 58 + c->crop->x = c->crop->y = c->crop->bw = 0; 59 + c->basew = c->baseh = c->mina = c->maxa = 0; 60 + c->maxw = c->maxh = c->incw = c->inch = 0; 61 + c->minw = c->minh = 1; 62 + if (!c->isfloating) 63 + togglefloating(NULL); 64 + c->win = XCreateWindow(dpy, root, x, y, 1, 1, c->bw, 65 + 0, 0, 0, CWEventMask, &wa); 66 + XReparentWindow(dpy, c->crop->win, c->win, 0, 0); 67 + XMapWindow(dpy, c->win); 68 + focus(c); 69 + XCheckTypedWindowEvent(dpy, c->crop->win, UnmapNotify, &ev); 70 + if (XCheckTypedWindowEvent(dpy, root, UnmapNotify, &ev) 71 + && ev.xunmap.window != c->crop->win) 72 + XPutBackEvent(dpy, &ev); 73 + } 74 + resizeclient(c->crop, c->crop->x + c->x - x, c->crop->y + c->y - y, 75 + c->crop->w, c->crop->h); 76 + resizeclient(c, x, y, 1, 1); 77 +} 78 + 79 +void 80 +cropdelete(Client *c) 81 +{ 82 + Client *crop; 83 + XEvent ev; 84 + 85 + c->crop->x += c->x; 86 + c->crop->y += c->y; 87 + c->crop->bw = c->bw; 88 + c->crop->next = c->next; 89 + c->crop->snext = c->snext; 90 + c->crop->tags = c->tags; 91 + c->crop->mon = c->mon; 92 + XReparentWindow(dpy, c->crop->win, root, c->crop->x, c->crop->y); 93 + XDestroyWindow(dpy, c->win); 94 + crop = c->crop; 95 + memcpy(c, c->crop, sizeof(Client)); 96 + free(crop); 97 + resize(c, c->x, c->y, c->w, c->h, 0); 98 + focus(c); 99 + XCheckTypedWindowEvent(dpy, c->win, UnmapNotify, &ev); 100 +} 101 + 102 +void 103 +cropresize(Client* c) 104 +{ 105 + resizeclient(c->crop, 106 + BETWEEN(c->crop->x, -(c->crop->w), 0) ? c->crop->x : 0, 107 + BETWEEN(c->crop->y, -(c->crop->h), 0) ? c->crop->y : 0, 108 + c->crop->w, c->crop->h); 109 + resize(c, c->x, c->y, 110 + MIN(c->w, c->crop->x + c->crop->w), 111 + MIN(c->h, c->crop->y + c->crop->h), 0); 112 +} 113 + 114 void 115 applyrules(Client *c) 116 { 117 @@ -516,7 +599,7 @@ clientmessage(XEvent *e) 118 XClientMessageEvent *cme = &e->xclient; 119 Client *c = wintoclient(cme->window); 120 121 - if (!c) 122 + if (!c && !(c = cropwintoclient(cme->window))) 123 return; 124 if (cme->message_type == netatom[NetWMState]) { 125 if (cme->data.l[1] == netatom[NetWMFullscreen] 126 @@ -579,16 +662,19 @@ configurenotify(XEvent *e) 127 void 128 configurerequest(XEvent *e) 129 { 130 - Client *c; 131 + Client *c, *cc = NULL; 132 Monitor *m; 133 XConfigureRequestEvent *ev = &e->xconfigurerequest; 134 XWindowChanges wc; 135 136 - if ((c = wintoclient(ev->window))) { 137 + if ((c = wintoclient(ev->window)) 138 + || (c = cc = cropwintoclient(ev->window))) { 139 if (ev->value_mask & CWBorderWidth) 140 c->bw = ev->border_width; 141 else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { 142 m = c->mon; 143 + if (c->crop) 144 + c = c->crop; 145 if (ev->value_mask & CWX) { 146 c->oldx = c->x; 147 c->x = m->mx + ev->x; 148 @@ -613,6 +699,8 @@ configurerequest(XEvent *e) 149 configure(c); 150 if (ISVISIBLE(c)) 151 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); 152 + if (cc) 153 + cropresize(cc); 154 } else 155 configure(c); 156 } else { 157 @@ -651,7 +739,7 @@ destroynotify(XEvent *e) 158 Client *c; 159 XDestroyWindowEvent *ev = &e->xdestroywindow; 160 161 - if ((c = wintoclient(ev->window))) 162 + if ((c = wintoclient(ev->window)) || (c = cropwintoclient(ev->window))) 163 unmanage(c, 1); 164 } 165 166 @@ -762,6 +850,8 @@ enternotify(XEvent *e) 167 if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) 168 return; 169 c = wintoclient(ev->window); 170 + if (!c) 171 + c = cropwintoclient(ev->window); 172 m = c ? c->mon : wintomon(ev->window); 173 if (m != selmon) { 174 unfocus(selmon->sel, 1); 175 @@ -1005,6 +1095,8 @@ killclient(const Arg *arg) 176 { 177 if (!selmon->sel) 178 return; 179 + if (selmon->sel->crop) 180 + cropdelete(selmon->sel); 181 if (!sendevent(selmon->sel, wmatom[WMDelete])) { 182 XGrabServer(dpy); 183 XSetErrorHandler(xerrordummy); 184 @@ -1150,6 +1242,10 @@ movemouse(const Arg *arg) 185 restack(selmon); 186 ocx = c->x; 187 ocy = c->y; 188 + if (arg->i == 1 && c->crop) { 189 + ocx = c->crop->x; 190 + ocy = c->crop->y; 191 + } 192 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 193 None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) 194 return; 195 @@ -1170,6 +1266,12 @@ movemouse(const Arg *arg) 196 197 nx = ocx + (ev.xmotion.x - x); 198 ny = ocy + (ev.xmotion.y - y); 199 + if (arg->i == 1 && c->crop) { 200 + c->crop->x = nx; 201 + c->crop->y = ny; 202 + cropresize(c); 203 + continue; 204 + } 205 if (abs(selmon->wx - nx) < snap) 206 nx = selmon->wx; 207 else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) 208 @@ -1221,7 +1323,10 @@ propertynotify(XEvent *e) 209 updatestatus(); 210 else if (ev->state == PropertyDelete) 211 return; /* ignore */ 212 - else if ((c = wintoclient(ev->window))) { 213 + else if ((c = wintoclient(ev->window)) 214 + || (c = cropwintoclient(ev->window))) { 215 + if (c->crop) 216 + c = c->crop; 217 switch(ev->atom) { 218 default: break; 219 case XA_WM_TRANSIENT_FOR: 220 @@ -1303,12 +1408,16 @@ resizemouse(const Arg *arg) 221 if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ 222 return; 223 restack(selmon); 224 + if (arg->i == 1) 225 + cropwindow(c); 226 ocx = c->x; 227 ocy = c->y; 228 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 229 None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) 230 return; 231 - XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); 232 + if (arg->i != 1) 233 + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, 234 + c->w + c->bw - 1, c->h + c->bw - 1); 235 do { 236 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); 237 switch(ev.type) { 238 @@ -1324,6 +1433,10 @@ resizemouse(const Arg *arg) 239 240 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); 241 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); 242 + if (c->crop) { 243 + nw = MIN(nw, c->crop->w + c->crop->x); 244 + nh = MIN(nh, c->crop->h + c->crop->y); 245 + } 246 if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww 247 && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) 248 { 249 @@ -1430,6 +1543,8 @@ setclientstate(Client *c, long state) 250 { 251 long data[] = { state, None }; 252 253 + if (c->crop) 254 + c = c->crop; 255 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, 256 PropModeReplace, (unsigned char *)data, 2); 257 } 258 @@ -1462,6 +1577,8 @@ sendevent(Client *c, Atom proto) 259 void 260 setfocus(Client *c) 261 { 262 + if (c->crop) 263 + c = c->crop; 264 if (!c->neverfocus) { 265 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); 266 XChangeProperty(dpy, root, netatom[NetActiveWindow], 267 @@ -1474,6 +1591,8 @@ setfocus(Client *c) 268 void 269 setfullscreen(Client *c, int fullscreen) 270 { 271 + if (c->crop) 272 + c = c->crop; 273 if (fullscreen && !c->isfullscreen) { 274 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, 275 PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); 276 @@ -1718,6 +1837,8 @@ togglefloating(const Arg *arg) 277 if (selmon->sel->isfloating) 278 resize(selmon->sel, selmon->sel->x, selmon->sel->y, 279 selmon->sel->w, selmon->sel->h, 0); 280 + if (!selmon->sel->isfloating && selmon->sel->crop) 281 + cropdelete(selmon->sel); 282 arrange(selmon); 283 } 284 285 @@ -1767,6 +1888,8 @@ unmanage(Client *c, int destroyed) 286 Monitor *m = c->mon; 287 XWindowChanges wc; 288 289 + if (c->crop) 290 + cropdelete(c); 291 detach(c); 292 detachstack(c); 293 if (!destroyed) { 294 @@ -1792,7 +1915,8 @@ unmapnotify(XEvent *e) 295 Client *c; 296 XUnmapEvent *ev = &e->xunmap; 297 298 - if ((c = wintoclient(ev->window))) { 299 + if ((c = wintoclient(ev->window)) 300 + || (c = cropwintoclient(ev->window))) { 301 if (ev->send_event) 302 setclientstate(c, WithdrawnState); 303 else 304 @@ -2070,7 +2194,7 @@ wintomon(Window w) 305 for (m = mons; m; m = m->next) 306 if (w == m->barwin) 307 return m; 308 - if ((c = wintoclient(w))) 309 + if ((c = wintoclient(w)) || (c = cropwintoclient(w))) 310 return c->mon; 311 return selmon; 312 }