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.

380 lines
6.4 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
  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. #define MINDIM 100
  7. /* static */
  8. static Client *
  9. minclient(void) {
  10. Client *c, *min;
  11. if((clients && clients->isfloat) || arrange == dofloat)
  12. return clients; /* don't touch floating order */
  13. for(min = c = clients; c; c = c->next)
  14. if(c->weight < min->weight)
  15. min = c;
  16. return min;
  17. }
  18. static Client *
  19. nexttiled(Client *c) {
  20. for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
  21. return c;
  22. }
  23. static void
  24. reorder(void) {
  25. Client *c, *newclients, *tail;
  26. newclients = tail = NULL;
  27. while((c = minclient())) {
  28. detach(c);
  29. if(tail) {
  30. c->prev = tail;
  31. tail->next = c;
  32. tail = c;
  33. }
  34. else
  35. tail = newclients = c;
  36. }
  37. clients = newclients;
  38. }
  39. static void
  40. togglemax(Client *c)
  41. {
  42. XEvent ev;
  43. if((c->ismax = !c->ismax)) {
  44. c->rx = c->x; c->x = sx;
  45. c->ry = c->y; c->y = bh;
  46. c->rw = c->w; c->w = sw - 2 * BORDERPX;
  47. c->rh = c->h; c->h = sh - bh - 2 * BORDERPX;
  48. }
  49. else {
  50. c->x = c->rx;
  51. c->y = c->ry;
  52. c->w = c->rw;
  53. c->h = c->rh;
  54. }
  55. resize(c, True, TopLeft);
  56. while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  57. }
  58. /* extern */
  59. void (*arrange)(Arg *) = DEFMODE;
  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. tw = stackw;
  107. if(n > 1)
  108. th = stackh / (n - 1);
  109. else
  110. th = stackh;
  111. for(i = 0, c = clients; c; c = c->next) {
  112. if(isvisible(c)) {
  113. if(c->isfloat) {
  114. resize(c, True, TopLeft);
  115. continue;
  116. }
  117. c->ismax = False;
  118. c->x = sx;
  119. c->y = sy + bh;
  120. if(n == 1) { /* only 1 window */
  121. c->w = sw - 2 * BORDERPX;
  122. c->h = sh - 2 * BORDERPX - bh;
  123. }
  124. else if(i == 0) { /* master window */
  125. if(stackpos == StackLeft)
  126. c->x += stackw;
  127. switch(stackpos) {
  128. case StackLeft:
  129. case StackRight:
  130. c->w = master - 2 * BORDERPX;
  131. c->h = sh - bh - 2 * BORDERPX;
  132. break;
  133. case StackBottom:
  134. c->w = sw - 2 * BORDERPX;
  135. c->h = master - 2 * BORDERPX;
  136. break;
  137. }
  138. }
  139. else { /* tile window */
  140. if(stackpos == StackRight)
  141. c->x += master;
  142. if(th > bh) {
  143. switch(stackpos) {
  144. case StackLeft:
  145. case StackRight:
  146. c->y = sy + (i - 1) * th + bh;
  147. if(i + 1 == n)
  148. c->h = sh - c->y - 2 * BORDERPX;
  149. break;
  150. case StackBottom:
  151. c->y = sy + master + (i - 1) * th + bh;
  152. if(i + 1 == n)
  153. c->h = sh - c->y - 2 * BORDERPX;
  154. break;
  155. }
  156. c->w = tw - 2 * BORDERPX;
  157. c->h = th - 2 * BORDERPX;
  158. }
  159. else { /* fallback if th < bh */
  160. if(stackpos == StackBottom)
  161. c->y += master;
  162. c->w = stackw - 2 * BORDERPX;
  163. c->h = stackh - 2 * BORDERPX;
  164. }
  165. }
  166. resize(c, False, TopLeft);
  167. i++;
  168. }
  169. else
  170. ban(c);
  171. }
  172. if(!sel || !isvisible(sel)) {
  173. for(c = stack; c && !isvisible(c); c = c->snext);
  174. focus(c);
  175. }
  176. restack();
  177. }
  178. void
  179. focusnext(Arg *arg) {
  180. Client *c;
  181. if(!sel)
  182. return;
  183. if(!(c = getnext(sel->next)))
  184. c = getnext(clients);
  185. if(c) {
  186. focus(c);
  187. restack();
  188. }
  189. }
  190. void
  191. focusprev(Arg *arg) {
  192. Client *c;
  193. if(!sel)
  194. return;
  195. if(!(c = getprev(sel->prev))) {
  196. for(c = clients; c && c->next; c = c->next);
  197. c = getprev(c);
  198. }
  199. if(c) {
  200. focus(c);
  201. restack();
  202. }
  203. }
  204. Bool
  205. isvisible(Client *c) {
  206. unsigned int i;
  207. for(i = 0; i < ntags; i++)
  208. if(c->tags[i] && seltag[i])
  209. return True;
  210. return False;
  211. }
  212. void
  213. resizecol(Arg *arg) {
  214. int s;
  215. unsigned int n;
  216. Client *c;
  217. for(n = 0, c = clients; c; c = c->next)
  218. if(isvisible(c) && !c->isfloat)
  219. n++;
  220. if(!sel || sel->isfloat || n < 2 || (arrange == dofloat))
  221. return;
  222. s = stackpos == StackBottom ? sh - bh : sw;
  223. if(sel == getnext(clients)) {
  224. if(master + arg->i > s - MINDIM || master + arg->i < MINDIM)
  225. return;
  226. master += arg->i;
  227. }
  228. else {
  229. if(master - arg->i > s - MINDIM || master - arg->i < MINDIM)
  230. return;
  231. master -= arg->i;
  232. }
  233. arrange(NULL);
  234. }
  235. void
  236. restack(void) {
  237. Client *c;
  238. XEvent ev;
  239. if(!sel) {
  240. drawstatus();
  241. return;
  242. }
  243. if(sel->isfloat || arrange == dofloat) {
  244. XRaiseWindow(dpy, sel->win);
  245. XRaiseWindow(dpy, sel->twin);
  246. }
  247. if(arrange != dofloat) {
  248. if(!sel->isfloat) {
  249. XLowerWindow(dpy, sel->twin);
  250. XLowerWindow(dpy, sel->win);
  251. }
  252. for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
  253. if(c == sel)
  254. continue;
  255. XLowerWindow(dpy, c->twin);
  256. XLowerWindow(dpy, c->win);
  257. }
  258. }
  259. drawall();
  260. XSync(dpy, False);
  261. while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  262. }
  263. void
  264. togglemode(Arg *arg) {
  265. arrange = (arrange == dofloat) ? dotile : dofloat;
  266. if(sel)
  267. arrange(NULL);
  268. else
  269. drawstatus();
  270. }
  271. void
  272. toggleview(Arg *arg) {
  273. unsigned int i;
  274. seltag[arg->i] = !seltag[arg->i];
  275. for(i = 0; i < ntags && !seltag[i]; i++);
  276. if(i == ntags)
  277. seltag[arg->i] = True; /* cannot toggle last view */
  278. reorder();
  279. arrange(NULL);
  280. }
  281. void
  282. togglestackpos(Arg *arg) {
  283. if(arrange == dofloat)
  284. return;
  285. if(stackpos == StackBottom)
  286. stackpos = STACKPOS;
  287. else
  288. stackpos = StackBottom;
  289. master = ((stackpos == StackBottom ? sh - bh : sw) * MASTER) / 100;
  290. arrange(NULL);
  291. }
  292. void
  293. view(Arg *arg) {
  294. unsigned int i;
  295. for(i = 0; i < ntags; i++)
  296. seltag[i] = False;
  297. seltag[arg->i] = True;
  298. reorder();
  299. arrange(NULL);
  300. }
  301. void
  302. viewall(Arg *arg) {
  303. unsigned int i;
  304. for(i = 0; i < ntags; i++)
  305. seltag[i] = True;
  306. reorder();
  307. arrange(NULL);
  308. }
  309. void
  310. zoom(Arg *arg) {
  311. unsigned int n;
  312. Client *c;
  313. if(!sel)
  314. return;
  315. if(sel->isfloat || (arrange == dofloat)) {
  316. togglemax(sel);
  317. return;
  318. }
  319. for(n = 0, c = clients; c; c = c->next)
  320. if(isvisible(c) && !c->isfloat)
  321. n++;
  322. if(n < 2 || (arrange == dofloat))
  323. return;
  324. if((c = sel) == nexttiled(clients))
  325. if(!(c = nexttiled(c->next)))
  326. return;
  327. detach(c);
  328. if(clients)
  329. clients->prev = c;
  330. c->next = clients;
  331. clients = c;
  332. focus(c);
  333. arrange(NULL);
  334. }