dwm-canvas-6.2.diff (13152B)
1 diff --git a/config.def.h b/config.def.h 2 index 81c3fc0..9154d29 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -18,6 +18,9 @@ static const char *colors[][3] = { 6 [SchemeSel] = { col_gray4, col_cyan, col_cyan }, 7 }; 8 9 +#define MOVE_CANVAS_STEP 120 10 +#define COORDINATES_DIVISOR 10 11 + 12 /* tagging */ 13 static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; 14 15 @@ -86,6 +89,12 @@ static const Key keys[] = { 16 { MODKEY, XK_period, focusmon, {.i = +1 } }, 17 { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, 18 { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, 19 + { MODKEY, XK_r, homecanvas, {0} }, // Return to x:0, y:0 position 20 + { MODKEY|ShiftMask, XK_Left, movecanvas, {.i = 0} }, // Move your position to left 21 + { MODKEY|ShiftMask, XK_Right, movecanvas, {.i = 1} }, // Move your position to right 22 + { MODKEY|ShiftMask, XK_Up, movecanvas, {.i = 2} }, // Move your position up 23 + { MODKEY|ShiftMask, XK_Down, movecanvas, {.i = 3} }, // Move your position down 24 + { MODKEY|ShiftMask, XK_d, centerwindow, {0} }, 25 TAGKEYS( XK_1, 0) 26 TAGKEYS( XK_2, 1) 27 TAGKEYS( XK_3, 2) 28 @@ -113,5 +122,7 @@ static const Button buttons[] = { 29 { ClkTagBar, 0, Button3, toggleview, {0} }, 30 { ClkTagBar, MODKEY, Button1, tag, {0} }, 31 { ClkTagBar, MODKEY, Button3, toggletag, {0} }, 32 + { ClkRootWin, MODKEY|ShiftMask, Button1, manuallymovecanvas, {0} }, 33 + { ClkClientWin, MODKEY|ShiftMask, Button1, manuallymovecanvas, {0} } 34 }; 35 36 diff --git a/dwm.c b/dwm.c 37 index ab3a84c..c70ff19 100644 38 --- a/dwm.c 39 +++ b/dwm.c 40 @@ -56,6 +56,11 @@ 41 #define TAGMASK ((1 << LENGTH(tags)) - 1) 42 #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) 43 44 +#if !WINDOWMAP 45 + #undef WINDOWMAP 46 + #define WINDOWMAP 1 47 +#endif 48 + 49 /* enums */ 50 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ 51 enum { SchemeNorm, SchemeSel }; /* color schemes */ 52 @@ -96,6 +101,10 @@ struct Client { 53 Client *snext; 54 Monitor *mon; 55 Window win; 56 + int saved_cx, saved_cy; 57 + int saved_cw, saved_ch; 58 + int was_on_canvas; 59 + int ismapped; 60 }; 61 62 typedef struct { 63 @@ -110,6 +119,11 @@ typedef struct { 64 void (*arrange)(Monitor *); 65 } Layout; 66 67 +typedef struct { 68 + int cx, cy; 69 + int saved_cx, saved_cy; 70 +} CanvasOffset; 71 + 72 struct Monitor { 73 char ltsymbol[16]; 74 float mfact; 75 @@ -129,6 +143,7 @@ struct Monitor { 76 Monitor *next; 77 Window barwin; 78 const Layout *lt[2]; 79 + CanvasOffset *canvas; 80 }; 81 82 typedef struct { 83 @@ -267,8 +282,11 @@ static Drw *drw; 84 static Monitor *mons, *selmon; 85 static Window root, wmcheckwin; 86 87 +#include "infinitetags.h" 88 + 89 /* configuration, allows nested code to access above variables */ 90 #include "config.h" 91 +#include "infinitetags.c" 92 93 /* compile-time check if all tags fit into an unsigned int bit array. */ 94 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; 95 @@ -643,6 +661,12 @@ createmon(void) 96 m->lt[0] = &layouts[0]; 97 m->lt[1] = &layouts[1 % LENGTH(layouts)]; 98 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); 99 + m->canvas = ecalloc(LENGTH(tags), sizeof(CanvasOffset)); 100 + unsigned int i; 101 + for (i = 0; i < LENGTH(tags); i++){ 102 + m->canvas[i].cx = 0; 103 + m->canvas[i].cy = 0; 104 + } 105 return m; 106 } 107 108 @@ -719,6 +743,7 @@ drawbar(Monitor *m) 109 urg |= c->tags; 110 } 111 x = 0; 112 + 113 for (i = 0; i < LENGTH(tags); i++) { 114 w = TEXTW(tags[i]); 115 drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); 116 @@ -732,6 +757,20 @@ drawbar(Monitor *m) 117 w = TEXTW(m->ltsymbol); 118 drw_setscheme(drw, scheme[SchemeNorm]); 119 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); 120 + 121 + /* Draw the coordinates in canvas mode */ 122 + if (selmon->lt[selmon->sellt]->arrange == NULL){ 123 + int tagidx = getcurrenttag(m); 124 + char coords[64]; 125 + snprintf(coords, sizeof(coords), "[x%d y%d]", 126 + m->canvas[tagidx].cx / COORDINATES_DIVISOR, 127 + m->canvas[tagidx].cy / COORDINATES_DIVISOR); 128 + w = TEXTW(coords); 129 + drw_setscheme(drw, scheme[SchemeNorm]); 130 + drw_text(drw, x, 0, w, bh, lrpad / 2, coords, 0); 131 + x += w; 132 + } 133 + 134 135 if ((w = m->ww - tw - x) > bh) { 136 if (m->sel) { 137 @@ -744,6 +783,7 @@ drawbar(Monitor *m) 138 drw_rect(drw, x, 0, w, bh, 1, 1); 139 } 140 } 141 + 142 drw_map(drw, m->barwin, 0, 0, m->ww, bh); 143 } 144 145 @@ -856,7 +896,7 @@ focusstack(const Arg *arg) 146 } 147 if (c) { 148 focus(c); 149 - restack(selmon); 150 + centerwindow(NULL); 151 } 152 } 153 154 @@ -1510,10 +1550,32 @@ setfullscreen(Client *c, int fullscreen) 155 void 156 setlayout(const Arg *arg) 157 { 158 + const Layout *temp_new_layout = (arg && arg->v) ? (Layout *)arg->v : selmon->lt[selmon->sellt ^ 1]; 159 + if (temp_new_layout == selmon->lt[selmon->sellt]) return; 160 + 161 + const Layout *old_layout = selmon->lt[selmon->sellt]; 162 + 163 if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) 164 selmon->sellt ^= 1; 165 if (arg && arg->v) 166 selmon->lt[selmon->sellt] = (Layout *)arg->v; 167 + 168 + const Layout *new_layout = selmon->lt[selmon->sellt]; 169 + if (old_layout->arrange == NULL && new_layout->arrange != NULL) { 170 + save_canvas_positions(selmon); 171 + homecanvas(NULL); 172 + Client *c; 173 + for (c = selmon->clients; c; c = c->next) 174 + if (!c->isfixed) c->isfloating = 0; 175 + } 176 + 177 + if (new_layout->arrange == NULL) { 178 + restore_canvas_positions(selmon); 179 + Client *c; 180 + for (c = selmon->clients; c; c = c->next) 181 + c->isfloating = 1; 182 + } 183 + 184 strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); 185 if (selmon->sel) 186 arrange(selmon); 187 @@ -1670,6 +1732,21 @@ void 188 tag(const Arg *arg) 189 { 190 if (selmon->sel && arg->ui & TAGMASK) { 191 + Client *c = selmon->sel; 192 + unsigned int target_tag_mask = arg->ui & TAGMASK; 193 + int i; 194 + 195 + for (i = 0; i < LENGTH(tags); i++) { 196 + if (target_tag_mask & (1 << i)) { 197 + c->saved_cx = selmon->canvas[i].cx + (selmon->ww - WIDTH(c)) / 2; 198 + c->saved_cy = selmon->canvas[i].cy + (selmon->wh - HEIGHT(c)) / 2; 199 + c->saved_cw = c->w; 200 + c->saved_ch = c->h; 201 + c->was_on_canvas = 1; 202 + break; 203 + } 204 + } 205 + 206 selmon->sel->tags = arg->ui & TAGMASK; 207 focus(NULL); 208 arrange(selmon); 209 @@ -2053,11 +2130,26 @@ updatewmhints(Client *c) 210 void 211 view(const Arg *arg) 212 { 213 + if (selmon->lt[selmon->sellt]->arrange == NULL) 214 + save_canvas_positions(selmon); 215 + 216 if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) 217 return; 218 selmon->seltags ^= 1; /* toggle sel tagset */ 219 if (arg->ui & TAGMASK) 220 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; 221 + 222 + int newtag = getcurrenttag(selmon); 223 + if (selmon->lt[selmon->sellt]->arrange != NULL){ 224 + selmon->canvas[newtag].cx = 0; 225 + selmon->canvas[newtag].cy = 0; 226 + } else { 227 + restore_canvas_positions(selmon); 228 + Client *c; 229 + for (c = selmon->clients;c; c = c->next) 230 + if (ISVISIBLE(c)) 231 + c->isfloating = 1; 232 + } 233 focus(NULL); 234 arrange(selmon); 235 } 236 diff --git a/infinitetags.c b/infinitetags.c 237 new file mode 100644 238 index 0000000..46267ee 239 --- /dev/null 240 +++ b/infinitetags.c 241 @@ -0,0 +1,206 @@ 242 +int 243 +getcurrenttag(Monitor *m) { 244 + unsigned int i; 245 + for (i = 0; i < LENGTH(tags) && !(m->tagset[m->seltags] & (1 << i)); i++); 246 + return i < LENGTH(tags) ? i : 0; 247 +} 248 + 249 +void 250 +homecanvas(const Arg *arg) { 251 + Client *c; 252 + int tagidx = getcurrenttag(selmon); 253 + int cx = selmon->canvas[tagidx].cx; 254 + int cy = selmon->canvas[tagidx].cy; 255 + 256 + for (c = selmon->clients; c; c = c->next) { 257 + if (c->tags & (1 << tagidx)) { 258 + c->x -= cx; 259 + c->y -= cy; 260 + XMoveWindow(dpy, c->win, c->x, c->y); 261 + } 262 + } 263 + 264 + selmon->canvas[tagidx].cx = 0; 265 + selmon->canvas[tagidx].cy = 0; 266 + drawbar(selmon); 267 + XFlush(dpy); 268 +} 269 + 270 +void 271 +movecanvas(const Arg *arg) 272 +{ 273 + if (selmon->lt[selmon->sellt]->arrange != NULL) 274 + return; 275 + if (selmon->sel && selmon->sel->isfullscreen) 276 + return; 277 + 278 + int tagidx = getcurrenttag(selmon); 279 + int dx = 0, dy = 0; 280 + 281 +#ifndef MOVE_CANVAS_STEP 282 +#define MOVE_CANVAS_STEP 120 283 +#endif 284 + 285 + switch(arg->i) { 286 + case 0: dx = -MOVE_CANVAS_STEP; break; 287 + case 1: dx = MOVE_CANVAS_STEP; break; 288 + case 2: dy = -MOVE_CANVAS_STEP; break; 289 + case 3: dy = MOVE_CANVAS_STEP; break; 290 + } 291 + 292 + selmon->canvas[tagidx].cx -= dx; 293 + selmon->canvas[tagidx].cy -= dy; 294 + 295 + Client *c; 296 + for (c = selmon->clients; c; c = c->next) { 297 + if (ISVISIBLE(c)) { 298 + c->x -= dx; 299 + c->y -= dy; 300 + XMoveWindow(dpy, c->win, c->x, c->y); 301 + } 302 + } 303 + 304 + drawbar(selmon); 305 +} 306 + 307 +void 308 +manuallymovecanvas(const Arg *arg) { 309 + if (selmon->lt[selmon->sellt]->arrange != NULL) 310 + return; 311 + if (selmon->sel && selmon->sel->isfullscreen) 312 + return; 313 + int start_x, start_y; 314 + Window dummy; 315 + int di; 316 + unsigned int dui; 317 + int tagidx = getcurrenttag(selmon); 318 +#if LOCK_MOVE_RESIZE_REFRESH_RATE 319 + Time lasttime = 0; 320 +#endif 321 + 322 + if (!XQueryPointer(dpy, root, &dummy, &dummy, &start_x, &start_y, &di, &di, &dui)) 323 + return; 324 + 325 + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 326 + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) 327 + return; 328 + 329 + XEvent ev; 330 + do { 331 + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); 332 + 333 + switch (ev.type) { 334 + case MotionNotify: 335 + { 336 +#if LOCK_MOVE_RESIZE_REFRESH_RATE 337 + if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) 338 + continue; 339 + lasttime = ev.xmotion.time; 340 +#endif 341 + int nx = ev.xmotion.x - start_x; 342 + int ny = ev.xmotion.y - start_y; 343 + 344 + for (Client *c = selmon->clients; c; c = c->next) { 345 + if (c->tags & (1 << tagidx)) { 346 + c->x += nx; 347 + c->y += ny; 348 + XMoveWindow(dpy, c->win, c->x, c->y); 349 + } 350 + } 351 + 352 + selmon->canvas[tagidx].cx += nx; 353 + selmon->canvas[tagidx].cy += ny; 354 + drawbar(selmon); 355 + start_x = ev.xmotion.x; 356 + start_y = ev.xmotion.y; 357 + } break; 358 + } 359 + } while (ev.type != ButtonRelease); 360 + 361 + XUngrabPointer(dpy, CurrentTime); 362 +} 363 + 364 +void 365 +save_canvas_positions(Monitor *m) { 366 + Client *c; 367 + int tagidx = getcurrenttag(m); 368 + 369 + m->canvas[tagidx].saved_cx = m->canvas[tagidx].cx; 370 + m->canvas[tagidx].saved_cy = m->canvas[tagidx].cy; 371 + 372 + for (c = m->clients; c; c = c->next) { 373 + if (ISVISIBLE(c)) { 374 + c->saved_cx = c->x + m->canvas[tagidx].cx; 375 + c->saved_cy = c->y + m->canvas[tagidx].cy; 376 + c->saved_cw = c->w; 377 + c->saved_ch = c->h; 378 + c->was_on_canvas = 1; 379 + } 380 + } 381 +} 382 + 383 +void 384 +restore_canvas_positions(Monitor *m) { 385 + Client *c; 386 + int tagidx = getcurrenttag(m); 387 + 388 + m->canvas[tagidx].cx = m->canvas[tagidx].saved_cx; 389 + m->canvas[tagidx].cy = m->canvas[tagidx].saved_cy; 390 + 391 + for (c = m->clients; c; c = c->next) { 392 + if (ISVISIBLE(c) && c->was_on_canvas) { 393 + c->isfloating = 1; 394 + 395 + int target_x = c->saved_cx - m->canvas[tagidx].cx; 396 + int target_y = c->saved_cy - m->canvas[tagidx].cy; 397 + 398 + c->x = target_x; 399 + c->y = target_y; 400 + c->w = c->saved_cw; 401 + c->h = c->saved_ch; 402 + 403 + XMoveResizeWindow(dpy, c->win, target_x, target_y, c->w, c->h); 404 + 405 + configure(c); 406 + } 407 + } 408 + XSync(dpy, False); 409 +} 410 + 411 +void 412 +centerwindow(const Arg *arg) 413 +{ 414 + Client *c = (arg && arg->v) ? (Client *)arg->v : selmon->sel; 415 + 416 + if (!c || !c->mon || c->mon->lt[c->mon->sellt]->arrange != NULL) 417 + return; 418 + 419 + Monitor *m = c->mon; 420 + int tagidx = getcurrenttag(m); 421 + 422 + int screen_center_x = m->wx + (m->ww / 2); 423 + int screen_center_y = m->wy + (m->wh / 2); 424 + 425 + int win_center_x = c->x + (c->w + 2 * c->bw) / 2; 426 + int win_center_y = c->y + (c->h + 2 * c->bw) / 2; 427 + 428 + int dx = screen_center_x - win_center_x; 429 + int dy = screen_center_y - win_center_y; 430 + 431 + if (dx == 0 && dy == 0) 432 + return; 433 + 434 + Client *tmp; 435 + for (tmp = m->clients; tmp; tmp = tmp->next) { 436 + if (ISVISIBLE(tmp)) { 437 + tmp->x += dx; 438 + tmp->y += dy; 439 + XMoveWindow(dpy, tmp->win, tmp->x, tmp->y); 440 + } 441 + } 442 + 443 + m->canvas[tagidx].cx += dx; 444 + m->canvas[tagidx].cy += dy; 445 + 446 + drawbar(m); 447 +} 448 diff --git a/infinitetags.h b/infinitetags.h 449 new file mode 100644 450 index 0000000..adcb69e 451 --- /dev/null 452 +++ b/infinitetags.h 453 @@ -0,0 +1,7 @@ 454 +static void movecanvas(const Arg *arg); 455 +static void manuallymovecanvas(const Arg *arg); 456 +static void homecanvas(const Arg *arg); 457 +static int getcurrenttag(Monitor *m); 458 +static void save_canvas_positions(Monitor *m); 459 +static void restore_canvas_positions(Monitor *m); 460 +static void centerwindow(const Arg *arg);