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.

320 lines
5.9 KiB

  1. /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
  2. * See LICENSE file for license details.
  3. */
  4. #include "dwm.h"
  5. #include <regex.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/types.h>
  10. #include <X11/Xutil.h>
  11. unsigned int master = MASTER;
  12. unsigned int nmaster = NMASTER;
  13. unsigned int blw = 0;
  14. Layout *lt = NULL;
  15. /* static */
  16. typedef struct {
  17. const char *prop;
  18. const char *tags;
  19. Bool isfloat;
  20. } Rule;
  21. typedef struct {
  22. regex_t *propregex;
  23. regex_t *tagregex;
  24. } Regs;
  25. LAYOUTS
  26. TAGS
  27. RULES
  28. static Regs *regs = NULL;
  29. static unsigned int nrules = 0;
  30. static unsigned int nlayouts = 0;
  31. /* extern */
  32. void
  33. compileregs(void) {
  34. unsigned int i;
  35. regex_t *reg;
  36. if(regs)
  37. return;
  38. nrules = sizeof rule / sizeof rule[0];
  39. regs = emallocz(nrules * sizeof(Regs));
  40. for(i = 0; i < nrules; i++) {
  41. if(rule[i].prop) {
  42. reg = emallocz(sizeof(regex_t));
  43. if(regcomp(reg, rule[i].prop, REG_EXTENDED))
  44. free(reg);
  45. else
  46. regs[i].propregex = reg;
  47. }
  48. if(rule[i].tags) {
  49. reg = emallocz(sizeof(regex_t));
  50. if(regcomp(reg, rule[i].tags, REG_EXTENDED))
  51. free(reg);
  52. else
  53. regs[i].tagregex = reg;
  54. }
  55. }
  56. }
  57. void
  58. dofloat(void) {
  59. Client *c;
  60. for(c = clients; c; c = c->next) {
  61. if(isvisible(c)) {
  62. if(c->isbanned)
  63. XMoveWindow(dpy, c->win, c->x, c->y);
  64. c->isbanned = False;
  65. resize(c, c->x, c->y, c->w, c->h, True);
  66. }
  67. else {
  68. c->isbanned = True;
  69. XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
  70. }
  71. }
  72. if(!sel || !isvisible(sel)) {
  73. for(c = stack; c && !isvisible(c); c = c->snext);
  74. focus(c);
  75. }
  76. restack();
  77. }
  78. void
  79. dotile(void) {
  80. unsigned int i, n, nx, ny, nw, nh, mw, mh, tw, th;
  81. Client *c;
  82. for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
  83. n++;
  84. /* window geoms */
  85. mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
  86. mw = (n > nmaster) ? (waw * master) / 1000 : waw;
  87. th = (n > nmaster) ? wah / (n - nmaster) : 0;
  88. tw = waw - mw;
  89. for(i = 0, c = clients; c; c = c->next)
  90. if(isvisible(c)) {
  91. if(c->isbanned)
  92. XMoveWindow(dpy, c->win, c->x, c->y);
  93. c->isbanned = False;
  94. if(c->isfloat)
  95. continue;
  96. c->ismax = False;
  97. nx = wax;
  98. ny = way;
  99. if(i < nmaster) {
  100. ny += i * mh;
  101. nw = mw - 2 * BORDERPX;
  102. nh = mh - 2 * BORDERPX;
  103. }
  104. else { /* tile window */
  105. nx += mw;
  106. nw = tw - 2 * BORDERPX;
  107. if(th > 2 * BORDERPX) {
  108. ny += (i - nmaster) * th;
  109. nh = th - 2 * BORDERPX;
  110. }
  111. else /* fallback if th <= 2 * BORDERPX */
  112. nh = wah - 2 * BORDERPX;
  113. }
  114. resize(c, nx, ny, nw, nh, False);
  115. i++;
  116. }
  117. else {
  118. c->isbanned = True;
  119. XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
  120. }
  121. if(!sel || !isvisible(sel)) {
  122. for(c = stack; c && !isvisible(c); c = c->snext);
  123. focus(c);
  124. }
  125. restack();
  126. }
  127. void
  128. incnmaster(Arg *arg) {
  129. if((lt->arrange == dofloat) || (nmaster + arg->i < 1)
  130. || (wah / (nmaster + arg->i) <= 2 * BORDERPX))
  131. return;
  132. nmaster += arg->i;
  133. if(sel)
  134. lt->arrange();
  135. else
  136. drawstatus();
  137. }
  138. void
  139. initlayouts(void) {
  140. unsigned int i, w;
  141. lt = &layout[0];
  142. nlayouts = sizeof layout / sizeof layout[0];
  143. for(blw = i = 0; i < nlayouts; i++) {
  144. w = textw(layout[i].symbol);
  145. if(w > blw)
  146. blw = w;
  147. }
  148. }
  149. Bool
  150. isvisible(Client *c) {
  151. unsigned int i;
  152. for(i = 0; i < ntags; i++)
  153. if(c->tags[i] && seltag[i])
  154. return True;
  155. return False;
  156. }
  157. void
  158. resizemaster(Arg *arg) {
  159. if(lt->arrange != dotile)
  160. return;
  161. if(arg->i == 0)
  162. master = MASTER;
  163. else {
  164. if(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX
  165. || waw * (master + arg->i) / 1000 <= 2 * BORDERPX)
  166. return;
  167. master += arg->i;
  168. }
  169. lt->arrange();
  170. }
  171. void
  172. restack(void) {
  173. Client *c;
  174. XEvent ev;
  175. drawstatus();
  176. if(!sel)
  177. return;
  178. if(sel->isfloat || lt->arrange == dofloat)
  179. XRaiseWindow(dpy, sel->win);
  180. if(lt->arrange != dofloat) {
  181. if(!sel->isfloat)
  182. XLowerWindow(dpy, sel->win);
  183. for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
  184. if(c == sel)
  185. continue;
  186. XLowerWindow(dpy, c->win);
  187. }
  188. }
  189. XSync(dpy, False);
  190. while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  191. }
  192. void
  193. settags(Client *c, Client *trans) {
  194. char prop[512];
  195. unsigned int i, j;
  196. regmatch_t tmp;
  197. Bool matched = trans != NULL;
  198. XClassHint ch = { 0 };
  199. if(matched)
  200. for(i = 0; i < ntags; i++)
  201. c->tags[i] = trans->tags[i];
  202. else {
  203. XGetClassHint(dpy, c->win, &ch);
  204. snprintf(prop, sizeof prop, "%s:%s:%s",
  205. ch.res_class ? ch.res_class : "",
  206. ch.res_name ? ch.res_name : "", c->name);
  207. for(i = 0; i < nrules; i++)
  208. if(regs[i].propregex && !regexec(regs[i].propregex, prop, 1, &tmp, 0)) {
  209. c->isfloat = rule[i].isfloat;
  210. for(j = 0; regs[i].tagregex && j < ntags; j++) {
  211. if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
  212. matched = True;
  213. c->tags[j] = True;
  214. }
  215. }
  216. }
  217. if(ch.res_class)
  218. XFree(ch.res_class);
  219. if(ch.res_name)
  220. XFree(ch.res_name);
  221. }
  222. if(!matched)
  223. for(i = 0; i < ntags; i++)
  224. c->tags[i] = seltag[i];
  225. }
  226. void
  227. tag(Arg *arg) {
  228. unsigned int i;
  229. if(!sel)
  230. return;
  231. for(i = 0; i < ntags; i++)
  232. sel->tags[i] = (arg->i == -1) ? True : False;
  233. if(arg->i >= 0 && arg->i < ntags)
  234. sel->tags[arg->i] = True;
  235. lt->arrange();
  236. }
  237. void
  238. togglefloat(Arg *arg) {
  239. if(!sel || lt->arrange == dofloat)
  240. return;
  241. sel->isfloat = !sel->isfloat;
  242. lt->arrange();
  243. }
  244. void
  245. toggletag(Arg *arg) {
  246. unsigned int i;
  247. if(!sel)
  248. return;
  249. sel->tags[arg->i] = !sel->tags[arg->i];
  250. for(i = 0; i < ntags && !sel->tags[i]; i++);
  251. if(i == ntags)
  252. sel->tags[arg->i] = True;
  253. lt->arrange();
  254. }
  255. void
  256. togglelayout(Arg *arg) {
  257. unsigned int i;
  258. for(i = 0; i < nlayouts && lt != &layout[i]; i++);
  259. if(i == nlayouts - 1)
  260. lt = &layout[0];
  261. else
  262. lt = &layout[++i];
  263. if(sel)
  264. lt->arrange();
  265. else
  266. drawstatus();
  267. }
  268. void
  269. toggleview(Arg *arg) {
  270. unsigned int i;
  271. seltag[arg->i] = !seltag[arg->i];
  272. for(i = 0; i < ntags && !seltag[i]; i++);
  273. if(i == ntags)
  274. seltag[arg->i] = True; /* cannot toggle last view */
  275. lt->arrange();
  276. }
  277. void
  278. view(Arg *arg) {
  279. unsigned int i;
  280. for(i = 0; i < ntags; i++)
  281. seltag[i] = (arg->i == -1) ? True : False;
  282. if(arg->i >= 0 && arg->i < ntags)
  283. seltag[arg->i] = True;
  284. lt->arrange();
  285. }