layout_flextile-deluxe.c (24588B)
1 typedef struct { 2 void (*arrange)(Monitor *, int, int, int, int, int, int, int); 3 } LayoutArranger; 4 5 typedef struct { 6 void (*arrange)(Monitor *, int, int, int, int, int, int, int, int, int); 7 } TileArranger; 8 9 static const LayoutArranger flexlayouts[] = { 10 { layout_no_split }, 11 { layout_split_vertical }, 12 { layout_split_horizontal }, 13 { layout_split_centered_vertical }, 14 { layout_split_centered_horizontal }, 15 { layout_split_vertical_dual_stack }, 16 { layout_split_horizontal_dual_stack }, 17 { layout_floating_master }, 18 { layout_split_vertical_fixed }, 19 { layout_split_horizontal_fixed }, 20 { layout_split_centered_vertical_fixed }, 21 { layout_split_centered_horizontal_fixed }, 22 { layout_split_vertical_dual_stack_fixed }, 23 { layout_split_horizontal_dual_stack_fixed }, 24 { layout_floating_master_fixed }, 25 }; 26 27 static const TileArranger flextiles[] = { 28 { arrange_top_to_bottom }, 29 { arrange_left_to_right }, 30 { arrange_monocle }, 31 { arrange_gapplessgrid }, 32 { arrange_gapplessgrid_alt1 }, 33 { arrange_gapplessgrid_alt2 }, 34 { arrange_gridmode }, 35 { arrange_horizgrid }, 36 { arrange_dwindle }, 37 { arrange_spiral }, 38 { arrange_tatami }, 39 }; 40 41 static void 42 getfactsforrange(Monitor *m, int an, int ai, int size, int *rest, float *fact) 43 { 44 int i; 45 float facts; 46 Client *c; 47 int total = 0; 48 49 facts = 0; 50 for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) 51 if (i >= ai && i < (ai + an)) 52 #if CFACTS_PATCH 53 facts += c->cfact; 54 #else 55 facts += 1; 56 #endif // CFACTS_PATCH 57 58 for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) 59 if (i >= ai && i < (ai + an)) 60 #if CFACTS_PATCH 61 total += size * (c->cfact / facts); 62 #else 63 total += size / facts; 64 #endif // CFACTS_PATCH 65 66 *rest = size - total; 67 *fact = facts; 68 } 69 70 #if IPC_PATCH || DWMC_PATCH 71 static void 72 setlayoutaxisex(const Arg *arg) 73 { 74 int axis, arr; 75 76 axis = arg->i & 0x3; // lower two bytes indicates layout, master or stack1-2 77 arr = ((arg->i & 0xFC) >> 2); // remaining six upper bytes indicate arrangement 78 79 if ((axis == 0 && abs(arr) > LAYOUT_LAST) 80 || (axis > 0 && (arr > AXIS_LAST || arr < 0))) 81 arr = 0; 82 83 selmon->ltaxis[axis] = arr; 84 #if PERTAG_PATCH 85 selmon->pertag->ltaxis[selmon->pertag->curtag][axis] = selmon->ltaxis[axis]; 86 #endif // PERTAG_PATCH 87 arrange(selmon); 88 } 89 #endif // IPC_PATCH | DWMC_PATCH 90 91 static void 92 layout_no_split(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 93 { 94 (&flextiles[m->ltaxis[m->nmaster >= n ? MASTER : STACK]])->arrange(m, x, y, h, w, ih, iv, n, n, 0); 95 } 96 97 static void 98 layout_split_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 99 { 100 /* Split master into master + stack if we have enough clients */ 101 if (m->nmaster && n > m->nmaster) { 102 layout_split_vertical_fixed(m, x, y, h, w, ih, iv, n); 103 } else { 104 layout_no_split(m, x, y, h, w, ih, iv, n); 105 } 106 } 107 108 static void 109 layout_split_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 110 { 111 int sw, sx; 112 113 sw = (w - iv) * (1 - m->mfact); 114 w = (w - iv) * m->mfact; 115 if (m->ltaxis[LAYOUT] < 0) { // mirror 116 sx = x; 117 x += sw + iv; 118 } else { 119 sx = x + w + iv; 120 } 121 122 (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); 123 (&flextiles[m->ltaxis[STACK]])->arrange(m, sx, y, h, sw, ih, iv, n, n - m->nmaster, m->nmaster); 124 } 125 126 static void 127 layout_split_vertical_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 128 { 129 /* Split master into master + stack if we have enough clients */ 130 if (!m->nmaster || n <= m->nmaster) { 131 layout_no_split(m, x, y, h, w, ih, iv, n); 132 } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) { 133 layout_split_vertical(m, x, y, h, w, ih, iv, n); 134 } else { 135 layout_split_vertical_dual_stack_fixed(m, x, y, h, w, ih, iv, n); 136 } 137 } 138 139 static void 140 layout_split_vertical_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 141 { 142 int sh, sw, sx, oy, sc; 143 144 if (m->nstack) 145 sc = m->nstack; 146 else 147 sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0); 148 149 sw = (w - iv) * (1 - m->mfact); 150 sh = (h - ih) / 2; 151 w = (w - iv) * m->mfact; 152 oy = y + sh + ih; 153 if (m->ltaxis[LAYOUT] < 0) { // mirror 154 sx = x; 155 x += sw + iv; 156 } else { 157 sx = x + w + iv; 158 } 159 160 (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); 161 (&flextiles[m->ltaxis[STACK]])->arrange(m, sx, y, sh, sw, ih, iv, n, sc, m->nmaster); 162 (&flextiles[m->ltaxis[STACK2]])->arrange(m, sx, oy, sh, sw, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc); 163 } 164 165 static void 166 layout_split_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 167 { 168 /* Split master into master + stack if we have enough clients */ 169 if (m->nmaster && n > m->nmaster) { 170 layout_split_horizontal_fixed(m, x, y, h, w, ih, iv, n); 171 } else { 172 layout_no_split(m, x, y, h, w, ih, iv, n); 173 } 174 } 175 176 static void 177 layout_split_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 178 { 179 int sh, sy; 180 181 sh = (h - ih) * (1 - m->mfact); 182 h = (h - ih) * m->mfact; 183 if (m->ltaxis[LAYOUT] < 0) { // mirror 184 sy = y; 185 y += sh + ih; 186 } else { 187 sy = y + h + ih; 188 } 189 190 (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); 191 (&flextiles[m->ltaxis[STACK]])->arrange(m, x, sy, sh, w, ih, iv, n, n - m->nmaster, m->nmaster); 192 } 193 194 static void 195 layout_split_horizontal_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 196 { 197 /* Split master into master + stack if we have enough clients */ 198 if (!m->nmaster || n <= m->nmaster) { 199 layout_no_split(m, x, y, h, w, ih, iv, n); 200 } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) { 201 layout_split_horizontal(m, x, y, h, w, ih, iv, n); 202 } else { 203 layout_split_horizontal_dual_stack_fixed(m, x, y, h, w, ih, iv, n); 204 } 205 } 206 207 static void 208 layout_split_horizontal_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 209 { 210 int sh, sy, ox, sc; 211 212 if (m->nstack) 213 sc = m->nstack; 214 else 215 sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0); 216 217 sh = (h - ih) * (1 - m->mfact); 218 h = (h - ih) * m->mfact; 219 sw = (w - iv) / 2; 220 ox = x + sw + iv; 221 if (m->ltaxis[LAYOUT] < 0) { // mirror 222 sy = y; 223 y += sh + ih; 224 } else { 225 sy = y + h + ih; 226 } 227 228 (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); 229 (&flextiles[m->ltaxis[STACK]])->arrange(m, x, sy, sh, sw, ih, iv, n, sc, m->nmaster); 230 (&flextiles[m->ltaxis[STACK2]])->arrange(m, ox, sy, sh, sw, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc); 231 } 232 233 static void 234 layout_split_centered_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 235 { 236 /* Split master into master + stack if we have enough clients */ 237 if (!m->nmaster || n <= m->nmaster) { 238 layout_no_split(m, x, y, h, w, ih, iv, n); 239 } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) { 240 layout_split_vertical(m, x, y, h, w, ih, iv, n); 241 } else { 242 layout_split_centered_vertical_fixed(m, x, y, h, w, ih, iv, n); 243 } 244 } 245 246 static void 247 layout_split_centered_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 248 { 249 int sw, sx, ox, sc; 250 251 if (m->nstack) 252 sc = m->nstack; 253 else 254 sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0); 255 256 sw = (w - 2*iv) * (1 - m->mfact) / 2; 257 w = (w - 2*iv) * m->mfact; 258 if (m->ltaxis[LAYOUT] < 0) { // mirror 259 sx = x; 260 x += sw + iv; 261 ox = x + w + iv; 262 } else { 263 ox = x; 264 x += sw + iv; 265 sx = x + w + iv; 266 } 267 268 (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); 269 (&flextiles[m->ltaxis[STACK]])->arrange(m, sx, y, h, sw, ih, iv, n, sc, m->nmaster); 270 (&flextiles[m->ltaxis[STACK2]])->arrange(m, ox, y, h, sw, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc); 271 } 272 273 static void 274 layout_split_centered_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 275 { 276 /* Split master into master + stack if we have enough clients */ 277 if (!m->nmaster || n <= m->nmaster) { 278 layout_no_split(m, x, y, h, w, ih, iv, n); 279 } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) { 280 layout_split_horizontal(m, x, y, h, w, ih, iv, n); 281 } else { 282 layout_split_centered_horizontal_fixed(m, x, y, h, w, ih, iv, n); 283 } 284 } 285 286 static void 287 layout_split_centered_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 288 { 289 int sh, sy, oy, sc; 290 291 if (m->nstack) 292 sc = m->nstack; 293 else 294 sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0); 295 296 sh = (h - 2*ih) * (1 - m->mfact) / 2; 297 h = (h - 2*ih) * m->mfact; 298 if (m->ltaxis[LAYOUT] < 0) { // mirror 299 sy = y; 300 y += sh + ih; 301 oy = y + h + ih; 302 } else { 303 oy = y; 304 y += sh + ih; 305 sy = y + h + ih; 306 } 307 308 (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); 309 (&flextiles[m->ltaxis[STACK]])->arrange(m, x, sy, sh, w, ih, iv, n, sc, m->nmaster); 310 (&flextiles[m->ltaxis[STACK2]])->arrange(m, x, oy, sh, w, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc); 311 } 312 313 static void 314 layout_floating_master(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 315 { 316 /* Split master into master + stack if we have enough clients */ 317 if (!m->nmaster || n <= m->nmaster) { 318 layout_no_split(m, x, y, h, w, ih, iv, n); 319 } else { 320 layout_floating_master_fixed(m, x, y, h, w, ih, iv, n); 321 } 322 } 323 324 static void 325 layout_floating_master_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) 326 { 327 int mh, mw; 328 329 /* Draw stack area first */ 330 (&flextiles[m->ltaxis[STACK]])->arrange(m, x, y, h, w, ih, iv, n, n - m->nmaster, m->nmaster); 331 332 if (w > h) { 333 mw = w * m->mfact; 334 mh = h * 0.9; 335 } else { 336 mw = w * 0.9; 337 mh = h * m->mfact; 338 } 339 x = x + (w - mw) / 2; 340 y = y + (h - mh) / 2; 341 342 (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, mh, mw, ih, iv, n, m->nmaster, 0); 343 } 344 345 static void 346 arrange_left_to_right(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 347 { 348 int i, rest; 349 float facts, fact = 1; 350 Client *c; 351 352 if (ai + an > n) 353 an = n - ai; 354 355 w -= iv * (an - 1); 356 getfactsforrange(m, an, ai, w, &rest, &facts); 357 for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { 358 if (i >= ai && i < (ai + an)) { 359 #if CFACTS_PATCH 360 fact = c->cfact; 361 #endif // CFACTS_PATCH 362 resize(c, x, y, w * (fact / facts) + ((i - ai) < rest ? 1 : 0) - (2*c->bw), h - (2*c->bw), 0); 363 x += WIDTH(c) + iv; 364 } 365 } 366 } 367 368 static void 369 arrange_top_to_bottom(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 370 { 371 int i, rest; 372 float facts, fact = 1; 373 Client *c; 374 375 if (ai + an > n) 376 an = n - ai; 377 378 h -= ih * (an - 1); 379 getfactsforrange(m, an, ai, h, &rest, &facts); 380 for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { 381 if (i >= ai && i < (ai + an)) { 382 #if CFACTS_PATCH 383 fact = c->cfact; 384 #endif // CFACTS_PATCH 385 resize(c, x, y, w - (2*c->bw), h * (fact / facts) + ((i - ai) < rest ? 1 : 0) - (2*c->bw), 0); 386 y += HEIGHT(c) + ih; 387 } 388 } 389 } 390 391 static void 392 arrange_monocle(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 393 { 394 int i; 395 Client *c; 396 397 for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) 398 if (i >= ai && i < (ai + an)) 399 resize(c, x, y, w - (2*c->bw), h - (2*c->bw), 0); 400 } 401 402 static void 403 arrange_gridmode(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 404 { 405 int i, cols, rows, ch, cw, cx, cy, cc, cr, chrest, cwrest; // counters 406 Client *c; 407 408 /* grid dimensions */ 409 for (rows = 0; rows <= an/2; rows++) 410 if (rows*rows >= an) 411 break; 412 cols = (rows && (rows - 1) * rows >= an) ? rows - 1 : rows; 413 414 /* window geoms (cell height/width) */ 415 ch = (h - ih * (rows - 1)) / (rows ? rows : 1); 416 cw = (w - iv * (cols - 1)) / (cols ? cols : 1); 417 chrest = h - ih * (rows - 1) - ch * rows; 418 cwrest = w - iv * (cols - 1) - cw * cols; 419 for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { 420 if (i >= ai && i < (ai + an)) { 421 cc = ((i - ai) / rows); // client column number 422 cr = ((i - ai) % rows); // client row number 423 cx = x + cc * (cw + iv) + MIN(cc, cwrest); 424 cy = y + cr * (ch + ih) + MIN(cr, chrest); 425 resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False); 426 } 427 } 428 } 429 430 static void 431 arrange_horizgrid(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 432 { 433 int ntop, nbottom, rh, rest; 434 435 /* Exception when there is only one client; don't split into two rows */ 436 if (an == 1) { 437 arrange_monocle(m, x, y, h, w, ih, iv, n, an, ai); 438 return; 439 } 440 441 ntop = an / 2; 442 nbottom = an - ntop; 443 rh = (h - ih) / 2; 444 rest = h - ih - rh * 2; 445 arrange_left_to_right(m, x, y, rh + rest, w, ih, iv, n, ntop, ai); 446 arrange_left_to_right(m, x, y + rh + ih + rest, rh, w, ih, iv, n, nbottom, ai + ntop); 447 } 448 449 static void 450 arrange_gapplessgrid(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 451 { 452 int i, cols, rows, ch, cw, cn, rn, cc, rrest, crest; // counters 453 Client *c; 454 455 /* grid dimensions */ 456 for (cols = 1; cols <= an/2; cols++) 457 if (cols*cols >= an) 458 break; 459 if (an == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */ 460 cols = 2; 461 rows = an/cols; 462 cn = rn = cc = 0; // reset column no, row no, client count 463 464 ch = (h - ih * (rows - 1)) / rows; 465 rrest = (h - ih * (rows - 1)) - ch * rows; 466 cw = (w - iv * (cols - 1)) / cols; 467 crest = (w - iv * (cols - 1)) - cw * cols; 468 469 for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { 470 if (i >= ai && i < (ai + an)) { 471 if (cc/rows + 1 > cols - an%cols) { 472 rows = an/cols + 1; 473 ch = (h - ih * (rows - 1)) / rows; 474 rrest = (h - ih * (rows - 1)) - ch * rows; 475 } 476 resize(c, 477 x, 478 y + rn*(ch + ih) + MIN(rn, rrest), 479 cw + (cn < crest ? 1 : 0) - 2*c->bw, 480 ch + (rn < rrest ? 1 : 0) - 2*c->bw, 481 0); 482 rn++; 483 cc++; 484 if (rn >= rows) { 485 rn = 0; 486 x += cw + ih + (cn < crest ? 1 : 0); 487 cn++; 488 } 489 } 490 } 491 } 492 493 /* This version of gappless grid fills rows first */ 494 static void 495 arrange_gapplessgrid_alt1(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 496 { 497 int i, cols, rows, rest, ch; 498 499 /* grid dimensions */ 500 for (cols = 1; cols <= an/2; cols++) 501 if (cols*cols >= an) 502 break; 503 rows = (cols && (cols - 1) * cols >= an) ? cols - 1 : cols; 504 ch = (h - ih * (rows - 1)) / (rows ? rows : 1); 505 rest = (h - ih * (rows - 1)) - ch * rows; 506 507 for (i = 0; i < rows; i++) { 508 arrange_left_to_right(m, x, y, ch + (i < rest ? 1 : 0), w, ih, iv, n, MIN(cols, an - i*cols), ai + i*cols); 509 y += ch + (i < rest ? 1 : 0) + ih; 510 } 511 } 512 513 /* This version of gappless grid fills columns first */ 514 static void 515 arrange_gapplessgrid_alt2(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 516 { 517 int i, cols, rows, rest, cw; 518 519 /* grid dimensions */ 520 for (rows = 0; rows <= an/2; rows++) 521 if (rows*rows >= an) 522 break; 523 cols = (rows && (rows - 1) * rows >= an) ? rows - 1 : rows; 524 cw = (w - iv * (cols - 1)) / (cols ? cols : 1); 525 rest = (w - iv * (cols - 1)) - cw * cols; 526 527 for (i = 0; i < cols; i++) { 528 arrange_top_to_bottom(m, x, y, h, cw + (i < rest ? 1 : 0), ih, iv, n, MIN(rows, an - i*rows), ai + i*rows); 529 x += cw + (i < rest ? 1 : 0) + iv; 530 } 531 } 532 533 static void 534 arrange_fibonacci(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai, int s) 535 { 536 int i, j, nv, hrest = 0, wrest = 0, nx = x, ny = y, nw = w, nh = h, r = 1; 537 Client *c; 538 539 for (i = 0, j = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), j++) { 540 if (j >= ai && j < (ai + an)) { 541 if (r) { 542 if ((i % 2 && ((nh - ih) / 2) <= (bh + 2*c->bw)) || (!(i % 2) && ((nw - iv) / 2) <= (bh + 2*c->bw))) { 543 r = 0; 544 } 545 if (r && i < an - 1) { 546 if (i % 2) { 547 nv = (nh - ih) / 2; 548 hrest = nh - 2*nv - ih; 549 nh = nv; 550 } else { 551 nv = (nw - iv) / 2; 552 wrest = nw - 2*nv - iv; 553 nw = nv; 554 } 555 556 if ((i % 4) == 2 && !s) 557 nx += nw + iv; 558 else if ((i % 4) == 3 && !s) 559 ny += nh + ih; 560 } 561 if ((i % 4) == 0) { 562 if (s) { 563 ny += nh + ih; 564 nh += hrest; 565 } else { 566 nh -= hrest; 567 ny -= nh + ih; 568 } 569 } else if ((i % 4) == 1) { 570 nx += nw + iv; 571 nw += wrest; 572 } else if ((i % 4) == 2) { 573 ny += nh + ih; 574 nh += hrest; 575 if (i < n - 1) 576 nw += wrest; 577 } else if ((i % 4) == 3) { 578 if (s) { 579 nx += nw + iv; 580 nw -= wrest; 581 } else { 582 nw -= wrest; 583 nx -= nw + iv; 584 nh += hrest; 585 } 586 } 587 if (i == 0) { 588 if (an != 1) { 589 nw = (w - iv) - (w - iv) * (1 - m->mfact); 590 wrest = 0; 591 } 592 ny = y; 593 } else if (i == 1) 594 nw = w - nw - iv; 595 i++; 596 } 597 598 resize(c, nx, ny, nw - 2 * c->bw, nh - 2*c->bw, False); 599 } 600 } 601 } 602 603 static void 604 arrange_dwindle(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 605 { 606 arrange_fibonacci(m, x, y, h, w, ih, iv, n, an, ai, 1); 607 } 608 609 static void 610 arrange_spiral(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 611 { 612 arrange_fibonacci(m, x, y, h, w, ih, iv, n, an, ai, 0); 613 } 614 615 static void 616 arrange_tatami(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) 617 { 618 unsigned int i, j, nx, ny, nw, nh, tnx, tny, tnw, tnh, nhrest, hrest, wrest, areas, mats, cats; 619 Client *c; 620 621 nx = x; 622 ny = y; 623 nw = w; 624 nh = h; 625 626 mats = an / 5; 627 cats = an % 5; 628 hrest = 0; 629 wrest = 0; 630 631 areas = mats + (cats > 0); 632 nh = (h - ih * (areas - 1)) / areas; 633 nhrest = (h - ih * (areas - 1)) % areas; 634 635 for (i = 0, j = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), j++) { 636 if (j >= ai && j < (ai + an)) { 637 638 tnw = nw; 639 tnx = nx; 640 tnh = nh; 641 tny = ny; 642 643 if (j < ai + cats) { 644 /* Arrange cats (all excess clients that can't be tiled as mats). Cats sleep on mats. */ 645 646 switch (cats) { 647 case 1: // fill 648 break; 649 case 2: // up and down 650 if ((i % 5) == 0) //up 651 tnh = (nh - ih) / 2 + (nh - ih) % 2; 652 else if ((i % 5) == 1) { //down 653 tny += (nh - ih) / 2 + (nh - ih) % 2 + ih; 654 tnh = (nh - ih) / 2; 655 } 656 break; 657 case 3: //bottom, up-left and up-right 658 if ((i % 5) == 0) { // up-left 659 tnw = (nw - iv) / 2 + (nw - iv) % 2; 660 tnh = (nh - ih) * 2 / 3 + (nh - ih) * 2 % 3; 661 } else if ((i % 5) == 1) { // up-right 662 tnx += (nw - iv) / 2 + (nw - iv) % 2 + iv; 663 tnw = (nw - iv) / 2; 664 tnh = (nh - ih) * 2 / 3 + (nh - ih) * 2 % 3; 665 } else if ((i % 5) == 2) { //bottom 666 tnh = (nh - ih) / 3; 667 tny += (nh - ih) * 2 / 3 + (nh - ih) * 2 % 3 + ih; 668 } 669 break; 670 case 4: // bottom, left, right and top 671 if ((i % 5) == 0) { //top 672 hrest = (nh - 2 * ih) % 4; 673 tnh = (nh - 2 * ih) / 4 + (hrest ? 1 : 0); 674 } else if ((i % 5) == 1) { // left 675 tnw = (nw - iv) / 2 + (nw - iv) % 2; 676 tny += (nh - 2 * ih) / 4 + (hrest ? 1 : 0) + ih; 677 tnh = (nh - 2 * ih) * 2 / 4 + (hrest > 1 ? 1 : 0); 678 } else if ((i % 5) == 2) { // right 679 tnx += (nw - iv) / 2 + (nw - iv) % 2 + iv; 680 tnw = (nw - iv) / 2; 681 tny += (nh - 2 * ih) / 4 + (hrest ? 1 : 0) + ih; 682 tnh = (nh - 2 * ih) * 2 / 4 + (hrest > 1 ? 1 : 0); 683 } else if ((i % 5) == 3) { // bottom 684 tny += (nh - 2 * ih) / 4 + (hrest ? 1 : 0) + (nh - 2 * ih) * 2 / 4 + (hrest > 1 ? 1 : 0) + 2 * ih; 685 tnh = (nh - 2 * ih) / 4 + (hrest > 2 ? 1 : 0); 686 } 687 break; 688 } 689 690 } else { 691 /* Arrange mats. One mat is a collection of five clients arranged tatami style */ 692 693 if (((i - cats) % 5) == 0) { 694 if ((cats > 0) || ((i - cats) >= 5)) { 695 tny = ny = ny + nh + (nhrest > 0 ? 1 : 0) + ih; 696 --nhrest; 697 } 698 } 699 700 switch ((i - cats) % 5) { 701 case 0: // top-left-vert 702 wrest = (nw - 2 * iv) % 3; 703 hrest = (nh - 2 * ih) % 3; 704 tnw = (nw - 2 * iv) / 3 + (wrest ? 1 : 0); 705 tnh = (nh - 2 * ih) * 2 / 3 + hrest + iv; 706 break; 707 case 1: // top-right-hor 708 tnx += (nw - 2 * iv) / 3 + (wrest ? 1 : 0) + iv; 709 tnw = (nw - 2 * iv) * 2 / 3 + (wrest > 1 ? 1 : 0) + iv; 710 tnh = (nh - 2 * ih) / 3 + (hrest ? 1 : 0); 711 break; 712 case 2: // center 713 tnx += (nw - 2 * iv) / 3 + (wrest ? 1 : 0) + iv; 714 tnw = (nw - 2 * iv) / 3 + (wrest > 1 ? 1 : 0); 715 tny += (nh - 2 * ih) / 3 + (hrest ? 1 : 0) + ih; 716 tnh = (nh - 2 * ih) / 3 + (hrest > 1 ? 1 : 0); 717 break; 718 case 3: // bottom-right-vert 719 tnx += (nw - 2 * iv) * 2 / 3 + wrest + 2 * iv; 720 tnw = (nw - 2 * iv) / 3; 721 tny += (nh - 2 * ih) / 3 + (hrest ? 1 : 0) + ih; 722 tnh = (nh - 2 * ih) * 2 / 3 + hrest + iv; 723 break; 724 case 4: // (oldest) bottom-left-hor 725 tnw = (nw - 2 * iv) * 2 / 3 + wrest + iv; 726 tny += (nh - 2 * ih) * 2 / 3 + hrest + 2 * iv; 727 tnh = (nh - 2 * ih) / 3; 728 break; 729 } 730 731 } 732 733 resize(c, tnx, tny, tnw - 2 * c->bw, tnh - 2 * c->bw, False); 734 ++i; 735 } 736 } 737 } 738 739 static void 740 flextile(Monitor *m) 741 { 742 unsigned int n; 743 int oh = 0, ov = 0, ih = 0, iv = 0; // gaps outer/inner horizontal/vertical 744 745 #if VANITYGAPS_PATCH 746 getgaps(m, &oh, &ov, &ih, &iv, &n); 747 #else 748 Client *c; 749 for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); 750 #endif // VANITYGAPS_PATCH 751 752 if (m->lt[m->sellt]->preset.layout != m->ltaxis[LAYOUT] || 753 m->lt[m->sellt]->preset.masteraxis != m->ltaxis[MASTER] || 754 m->lt[m->sellt]->preset.stack1axis != m->ltaxis[STACK] || 755 m->lt[m->sellt]->preset.stack2axis != m->ltaxis[STACK2]) 756 setflexsymbols(m, n); 757 else if (m->lt[m->sellt]->preset.symbolfunc != NULL) 758 m->lt[m->sellt]->preset.symbolfunc(m, n); 759 760 if (n == 0) 761 return; 762 763 #if VANITYGAPS_PATCH && !VANITYGAPS_MONOCLE_PATCH 764 /* No outer gap if full screen monocle */ 765 if (abs(m->ltaxis[MASTER]) == MONOCLE && (abs(m->ltaxis[LAYOUT]) == NO_SPLIT || n <= m->nmaster)) { 766 oh = 0; 767 ov = 0; 768 } 769 #endif // VANITYGAPS_PATCH && !VANITYGAPS_MONOCLE_PATCH 770 771 (&flexlayouts[abs(m->ltaxis[LAYOUT])])->arrange(m, m->wx + ov, m->wy + oh, m->wh - 2*oh, m->ww - 2*ov, ih, iv, n); 772 return; 773 } 774 775 static void 776 setflexsymbols(Monitor *m, unsigned int n) 777 { 778 int l; 779 char sym1, sym2, sym3; 780 Client *c; 781 782 if (n == 0) 783 for (c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); 784 785 l = abs(m->ltaxis[LAYOUT]); 786 if (m->ltaxis[MASTER] == MONOCLE && (l == NO_SPLIT || !m->nmaster || n <= m->nmaster)) { 787 monoclesymbols(m, n); 788 return; 789 } 790 791 if (m->ltaxis[STACK] == MONOCLE && (l == SPLIT_VERTICAL || l == SPLIT_HORIZONTAL_FIXED)) { 792 decksymbols(m, n); 793 return; 794 } 795 796 /* Layout symbols */ 797 if (l == NO_SPLIT || !m->nmaster) { 798 sym1 = sym2 = sym3 = (int)tilesymb[m->ltaxis[MASTER]]; 799 } else { 800 sym2 = layoutsymb[l]; 801 if (m->ltaxis[LAYOUT] < 0) { 802 sym1 = tilesymb[m->ltaxis[STACK]]; 803 sym3 = tilesymb[m->ltaxis[MASTER]]; 804 } else { 805 sym1 = tilesymb[m->ltaxis[MASTER]]; 806 sym3 = tilesymb[m->ltaxis[STACK]]; 807 } 808 } 809 810 snprintf(m->ltsymbol, sizeof m->ltsymbol, "%c%c%c", sym1, sym2, sym3); 811 } 812 813 static void 814 monoclesymbols(Monitor *m, unsigned int n) 815 { 816 if (n > 0) 817 snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); 818 else 819 snprintf(m->ltsymbol, sizeof m->ltsymbol, "[M]"); 820 } 821 822 static void 823 decksymbols(Monitor *m, unsigned int n) 824 { 825 if (n > m->nmaster) 826 snprintf(m->ltsymbol, sizeof m->ltsymbol, "[]%d", n); 827 else 828 snprintf(m->ltsymbol, sizeof m->ltsymbol, "[D]"); 829 } 830 831 /* Mirror layout axis for flextile */ 832 void 833 mirrorlayout(const Arg *arg) 834 { 835 if (!selmon->lt[selmon->sellt]->arrange) 836 return; 837 selmon->ltaxis[LAYOUT] *= -1; 838 #if PERTAG_PATCH 839 selmon->pertag->ltaxis[selmon->pertag->curtag][0] = selmon->ltaxis[LAYOUT]; 840 #endif // PERTAG_PATCH 841 arrange(selmon); 842 } 843 844 /* Rotate layout axis for flextile */ 845 void 846 rotatelayoutaxis(const Arg *arg) 847 { 848 int incr = (arg->i > 0 ? 1 : -1); 849 int axis = abs(arg->i) - 1; 850 851 if (!selmon->lt[selmon->sellt]->arrange) 852 return; 853 if (axis == LAYOUT) { 854 if (selmon->ltaxis[LAYOUT] >= 0) { 855 selmon->ltaxis[LAYOUT] += incr; 856 if (selmon->ltaxis[LAYOUT] >= LAYOUT_LAST) 857 selmon->ltaxis[LAYOUT] = 0; 858 else if (selmon->ltaxis[LAYOUT] < 0) 859 selmon->ltaxis[LAYOUT] = LAYOUT_LAST - 1; 860 } else { 861 selmon->ltaxis[LAYOUT] -= incr; 862 if (selmon->ltaxis[LAYOUT] <= -LAYOUT_LAST) 863 selmon->ltaxis[LAYOUT] = 0; 864 else if (selmon->ltaxis[LAYOUT] > 0) 865 selmon->ltaxis[LAYOUT] = -LAYOUT_LAST + 1; 866 } 867 } else { 868 selmon->ltaxis[axis] += incr; 869 if (selmon->ltaxis[axis] >= AXIS_LAST) 870 selmon->ltaxis[axis] = 0; 871 else if (selmon->ltaxis[axis] < 0) 872 selmon->ltaxis[axis] = AXIS_LAST - 1; 873 } 874 #if PERTAG_PATCH 875 selmon->pertag->ltaxis[selmon->pertag->curtag][axis] = selmon->ltaxis[axis]; 876 #endif // PERTAG_PATCH 877 arrange(selmon); 878 setflexsymbols(selmon, 0); 879 } 880 881 void 882 incnstack(const Arg *arg) 883 { 884 #if PERTAG_PATCH 885 selmon->nstack = selmon->pertag->nstacks[selmon->pertag->curtag] = MAX(selmon->nstack + arg->i, 0); 886 #else 887 selmon->nstack = MAX(selmon->nstack + arg->i, 0); 888 #endif // PERTAG_PATCH 889 arrange(selmon); 890 } 891