You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

439 lines
7.5 KiB

18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
  1. /*
  2. * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
  3. * See LICENSE file for license details.
  4. */
  5. #include "dwm.h"
  6. /* static */
  7. static Client *
  8. minclient(void) {
  9. Client *c, *min;
  10. if((clients && clients->isfloat) || arrange == dofloat)
  11. return clients; /* don't touch floating order */
  12. for(min = c = clients; c; c = c->next)
  13. if(c->weight < min->weight)
  14. min = c;
  15. return min;
  16. }
  17. static Client *
  18. nexttiled(Client *c) {
  19. for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
  20. return c;
  21. }
  22. static void
  23. reorder(void) {
  24. Client *c, *newclients, *tail;
  25. newclients = tail = NULL;
  26. while((c = minclient())) {
  27. detach(c);
  28. if(tail) {
  29. c->prev = tail;
  30. tail->next = c;
  31. tail = c;
  32. }
  33. else
  34. tail = newclients = c;
  35. }
  36. clients = newclients;
  37. }
  38. static void
  39. togglemax(Client *c)
  40. {
  41. XEvent ev;
  42. if((c->ismax = !c->ismax)) {
  43. c->rx = c->x; c->x = sx;
  44. c->ry = c->y; c->y = bh;
  45. c->rw = c->w; c->w = sw - 2 * BORDERPX;
  46. c->rh = c->h; c->h = sh - bh - 2 * BORDERPX;
  47. }
  48. else {
  49. c->x = c->rx;
  50. c->y = c->ry;
  51. c->w = c->rw;
  52. c->h = c->rh;
  53. }
  54. resize(c, True, TopLeft);
  55. while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  56. }
  57. /* extern */
  58. void (*arrange)(Arg *) = DEFMODE;
  59. Bool isvertical = VERTICALSTACK;
  60. StackPos stackpos = STACKPOS;
  61. void
  62. detach(Client *c) {
  63. if(c->prev)
  64. c->prev->next = c->next;
  65. if(c->next)
  66. c->next->prev = c->prev;
  67. if(c == clients)
  68. clients = c->next;
  69. c->next = c->prev = NULL;
  70. }
  71. void
  72. dofloat(Arg *arg) {
  73. Client *c;
  74. for(c = clients; c; c = c->next) {
  75. if(isvisible(c)) {
  76. resize(c, True, TopLeft);
  77. }
  78. else
  79. ban(c);
  80. }
  81. if(!sel || !isvisible(sel)) {
  82. for(c = stack; c && !isvisible(c); c = c->snext);
  83. focus(c);
  84. }
  85. restack();
  86. }
  87. /* This algorithm is based on a (M)aster area and a (S)tacking area.
  88. * It supports following arrangements:
  89. * SSMMM MMMMM MMMSS
  90. * SSMMM SSSSS MMMSS
  91. */
  92. void
  93. dotile(Arg *arg) {
  94. int i, n, stackw, stackh, tw, th;
  95. Client *c;
  96. for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
  97. n++;
  98. if(stackpos == StackBottom) {
  99. stackw = sw;
  100. stackh = sh - bh - master;
  101. }
  102. else {
  103. stackw = sw - master;
  104. stackh = sh - bh;
  105. }
  106. if(isvertical) {
  107. tw = stackw;
  108. if(n > 1)
  109. th = stackh / (n - 1);
  110. else
  111. th = stackh;
  112. }
  113. else {
  114. th = stackh;
  115. if(n > 1)
  116. tw = stackw / (n - 1);
  117. else
  118. tw = stackw;
  119. }
  120. for(i = 0, c = clients; c; c = c->next) {
  121. if(isvisible(c)) {
  122. if(c->isfloat) {
  123. resize(c, True, TopLeft);
  124. continue;
  125. }
  126. c->ismax = False;
  127. if(n == 1) { /* only 1 window */
  128. c->x = sx;
  129. c->y = sy + bh;
  130. c->w = sw - 2 * BORDERPX;
  131. c->h = sh - 2 * BORDERPX - bh;
  132. }
  133. else if(i == 0) { /* master window */
  134. switch(stackpos) {
  135. case StackLeft:
  136. c->x = sx + stackw;
  137. c->y = sy + bh;
  138. c->w = master - 2 * BORDERPX;
  139. c->h = sh - bh - 2 * BORDERPX;
  140. break;
  141. case StackBottom:
  142. c->x = sx;
  143. c->y = sy + bh;
  144. c->w = sw - 2 * BORDERPX;
  145. c->h = master - 2 * BORDERPX;
  146. break;
  147. case StackRight:
  148. c->x = sx;
  149. c->y = sy + bh;
  150. c->w = master - 2 * BORDERPX;
  151. c->h = sh - bh - 2 * BORDERPX;
  152. break;
  153. }
  154. }
  155. else if((isvertical && th > bh) || (!isvertical && tw > MINW)) {
  156. /* tile window */
  157. c->w = tw - 2 * BORDERPX;
  158. c->h = th - 2 * BORDERPX;
  159. switch(stackpos) {
  160. case StackLeft:
  161. if(isvertical) {
  162. c->x = sx;
  163. c->y = sy + (i - 1) * th + bh;
  164. if(i + 1 == n)
  165. c->h = sh - c->y - 2 * BORDERPX;
  166. }
  167. else {
  168. c->x = sx + (i - 1) * tw;
  169. c->y = sy + bh;
  170. if(i + 1 == n)
  171. c->w = sx + stackw - c->x - 2 * BORDERPX;
  172. }
  173. break;
  174. case StackBottom:
  175. if(isvertical) {
  176. c->x = sx;
  177. c->y = sy + master + (i - 1) * th + bh;
  178. if(i + 1 == n)
  179. c->h = sh - c->y - 2 * BORDERPX;
  180. }
  181. else {
  182. c->x = sx + (i - 1) * tw;
  183. c->y = sy + bh + master;
  184. if(i + 1 == n)
  185. c->w = sw - c->x - 2 * BORDERPX;
  186. }
  187. break;
  188. case StackRight:
  189. if(isvertical) {
  190. c->x = sx + master;
  191. c->y = sy + (i - 1) * th + bh;
  192. if(i + 1 == n)
  193. c->h = sh - c->y - 2 * BORDERPX;
  194. }
  195. else {
  196. c->x = sx + master + (i - 1) * tw;
  197. c->y = sy + bh;
  198. if(i + 1 == n)
  199. c->w = sw - c->x - 2 * BORDERPX;
  200. }
  201. break;
  202. }
  203. }
  204. else { /* fallback if th < bh resp. tw < MINW */
  205. c->w = stackw - 2 * BORDERPX;
  206. c->h = stackh - 2 * BORDERPX;
  207. switch(stackpos) {
  208. case StackLeft:
  209. c->x = sx;
  210. c->y = sy + bh;
  211. break;
  212. case StackBottom:
  213. c->x = sx;
  214. c->y = sy + master;
  215. break;
  216. case StackRight:
  217. c->x = sx + master;
  218. c->y = sy + bh;
  219. break;
  220. }
  221. }
  222. resize(c, False, TopLeft);
  223. i++;
  224. }
  225. else
  226. ban(c);
  227. }
  228. if(!sel || !isvisible(sel)) {
  229. for(c = stack; c && !isvisible(c); c = c->snext);
  230. focus(c);
  231. }
  232. restack();
  233. }
  234. void
  235. focusnext(Arg *arg) {
  236. Client *c;
  237. if(!sel)
  238. return;
  239. if(!(c = getnext(sel->next)))
  240. c = getnext(clients);
  241. if(c) {
  242. focus(c);
  243. restack();
  244. }
  245. }
  246. void
  247. focusprev(Arg *arg) {
  248. Client *c;
  249. if(!sel)
  250. return;
  251. if(!(c = getprev(sel->prev))) {
  252. for(c = clients; c && c->next; c = c->next);
  253. c = getprev(c);
  254. }
  255. if(c) {
  256. focus(c);
  257. restack();
  258. }
  259. }
  260. Bool
  261. isvisible(Client *c) {
  262. unsigned int i;
  263. for(i = 0; i < ntags; i++)
  264. if(c->tags[i] && seltag[i])
  265. return True;
  266. return False;
  267. }
  268. void
  269. resizecol(Arg *arg) {
  270. unsigned int n;
  271. Client *c;
  272. for(n = 0, c = clients; c; c = c->next)
  273. if(isvisible(c) && !c->isfloat)
  274. n++;
  275. if(!sel || sel->isfloat || n < 2 || (arrange == dofloat))
  276. return;
  277. if(sel == getnext(clients)) {
  278. if(master + arg->i > sw - MINW || master + arg->i < MINW)
  279. return;
  280. master += arg->i;
  281. }
  282. else {
  283. if(master - arg->i > sw - MINW || master - arg->i < MINW)
  284. return;
  285. master -= arg->i;
  286. }
  287. arrange(NULL);
  288. }
  289. void
  290. restack(void) {
  291. Client *c;
  292. XEvent ev;
  293. if(!sel) {
  294. drawstatus();
  295. return;
  296. }
  297. if(sel->isfloat || arrange == dofloat) {
  298. XRaiseWindow(dpy, sel->win);
  299. XRaiseWindow(dpy, sel->twin);
  300. }
  301. if(arrange != dofloat)
  302. for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
  303. XLowerWindow(dpy, c->twin);
  304. XLowerWindow(dpy, c->win);
  305. }
  306. drawall();
  307. XSync(dpy, False);
  308. while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  309. }
  310. void
  311. togglemode(Arg *arg) {
  312. arrange = (arrange == dofloat) ? dotile : dofloat;
  313. if(sel)
  314. arrange(NULL);
  315. else
  316. drawstatus();
  317. }
  318. void
  319. toggleview(Arg *arg) {
  320. unsigned int i;
  321. seltag[arg->i] = !seltag[arg->i];
  322. for(i = 0; i < ntags && !seltag[i]; i++);
  323. if(i == ntags)
  324. seltag[arg->i] = True; /* cannot toggle last view */
  325. reorder();
  326. arrange(NULL);
  327. }
  328. void
  329. togglestackdir(Arg *arg) {
  330. if(arrange == dofloat)
  331. return;
  332. isvertical = !isvertical;
  333. arrange(NULL);
  334. }
  335. void
  336. togglestackpos(Arg *arg) {
  337. if(arrange == dofloat)
  338. return;
  339. if(stackpos == StackBottom)
  340. stackpos = STACKPOS;
  341. else
  342. stackpos = StackBottom;
  343. updatemaster();
  344. arrange(NULL);
  345. }
  346. void
  347. updatemaster(void) {
  348. master = ((stackpos == StackBottom ? sh - bh : sw) * MASTER) / 100;
  349. }
  350. void
  351. view(Arg *arg) {
  352. unsigned int i;
  353. for(i = 0; i < ntags; i++)
  354. seltag[i] = False;
  355. seltag[arg->i] = True;
  356. reorder();
  357. arrange(NULL);
  358. }
  359. void
  360. viewall(Arg *arg) {
  361. unsigned int i;
  362. for(i = 0; i < ntags; i++)
  363. seltag[i] = True;
  364. reorder();
  365. arrange(NULL);
  366. }
  367. void
  368. zoom(Arg *arg) {
  369. unsigned int n;
  370. Client *c;
  371. if(!sel)
  372. return;
  373. if(sel->isfloat || (arrange == dofloat)) {
  374. togglemax(sel);
  375. return;
  376. }
  377. for(n = 0, c = clients; c; c = c->next)
  378. if(isvisible(c) && !c->isfloat)
  379. n++;
  380. if(n < 2 || (arrange == dofloat))
  381. return;
  382. if((c = sel) == nexttiled(clients))
  383. if(!(c = nexttiled(c->next)))
  384. return;
  385. detach(c);
  386. if(clients)
  387. clients->prev = c;
  388. c->next = clients;
  389. clients = c;
  390. focus(c);
  391. arrange(NULL);
  392. }