Configuration of dwm for Mac Computers
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.

426 lines
9.6 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
  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 <stdlib.h>
  6. #include <string.h>
  7. #include <X11/Xatom.h>
  8. #include <X11/Xutil.h>
  9. /* static */
  10. static void
  11. attachstack(Client *c) {
  12. c->snext = stack;
  13. stack = c;
  14. }
  15. static void
  16. detachstack(Client *c) {
  17. Client **tc;
  18. for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
  19. *tc = c->snext;
  20. }
  21. static void
  22. grabbuttons(Client *c, Bool focused) {
  23. XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  24. if(focused) {
  25. XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
  26. GrabModeAsync, GrabModeSync, None, None);
  27. XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
  28. GrabModeAsync, GrabModeSync, None, None);
  29. XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
  30. GrabModeAsync, GrabModeSync, None, None);
  31. XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
  32. GrabModeAsync, GrabModeSync, None, None);
  33. XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
  34. GrabModeAsync, GrabModeSync, None, None);
  35. XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
  36. GrabModeAsync, GrabModeSync, None, None);
  37. XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
  38. GrabModeAsync, GrabModeSync, None, None);
  39. XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
  40. GrabModeAsync, GrabModeSync, None, None);
  41. XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
  42. GrabModeAsync, GrabModeSync, None, None);
  43. XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
  44. GrabModeAsync, GrabModeSync, None, None);
  45. XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
  46. GrabModeAsync, GrabModeSync, None, None);
  47. XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
  48. GrabModeAsync, GrabModeSync, None, None);
  49. }
  50. else
  51. XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
  52. GrabModeAsync, GrabModeSync, None, None);
  53. }
  54. static Bool
  55. isprotodel(Client *c) {
  56. int i, n;
  57. Atom *protocols;
  58. Bool ret = False;
  59. if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
  60. for(i = 0; !ret && i < n; i++)
  61. if(protocols[i] == wmatom[WMDelete])
  62. ret = True;
  63. XFree(protocols);
  64. }
  65. return ret;
  66. }
  67. static void
  68. setclientstate(Client *c, long state) {
  69. long data[] = {state, None};
  70. XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  71. PropModeReplace, (unsigned char *)data, 2);
  72. }
  73. static void
  74. togglemax(Client *c) {
  75. XEvent ev;
  76. if(c->isfixed)
  77. return;
  78. if((c->ismax = !c->ismax)) {
  79. c->rx = c->x;
  80. c->ry = c->y;
  81. c->rw = c->w;
  82. c->rh = c->h;
  83. resize(c, wax, way, waw - 2 * BORDERPX, wah - 2 * BORDERPX, True);
  84. }
  85. else
  86. resize(c, c->rx, c->ry, c->rw, c->rh, True);
  87. while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  88. }
  89. static int
  90. xerrordummy(Display *dsply, XErrorEvent *ee) {
  91. return 0;
  92. }
  93. /* extern */
  94. void
  95. attach(Client *c) {
  96. if(clients)
  97. clients->prev = c;
  98. c->next = clients;
  99. clients = c;
  100. }
  101. void
  102. configure(Client *c) {
  103. XConfigureEvent ce;
  104. ce.type = ConfigureNotify;
  105. ce.display = dpy;
  106. ce.event = c->win;
  107. ce.window = c->win;
  108. ce.x = c->x;
  109. ce.y = c->y;
  110. ce.width = c->w;
  111. ce.height = c->h;
  112. ce.border_width = c->border;
  113. ce.above = None;
  114. ce.override_redirect = False;
  115. XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
  116. }
  117. void
  118. detach(Client *c) {
  119. if(c->prev)
  120. c->prev->next = c->next;
  121. if(c->next)
  122. c->next->prev = c->prev;
  123. if(c == clients)
  124. clients = c->next;
  125. c->next = c->prev = NULL;
  126. }
  127. void
  128. focus(Client *c) {
  129. if(c && !isvisible(c))
  130. return;
  131. if(sel && sel != c) {
  132. grabbuttons(sel, False);
  133. XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
  134. }
  135. if(c) {
  136. detachstack(c);
  137. attachstack(c);
  138. grabbuttons(c, True);
  139. }
  140. sel = c;
  141. drawstatus();
  142. if(!selscreen)
  143. return;
  144. if(c) {
  145. XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
  146. XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
  147. }
  148. else
  149. XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
  150. }
  151. void
  152. killclient(Arg *arg) {
  153. if(!sel)
  154. return;
  155. if(isprotodel(sel))
  156. sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
  157. else
  158. XKillClient(dpy, sel->win);
  159. }
  160. void
  161. manage(Window w, XWindowAttributes *wa) {
  162. Client *c, *t;
  163. Window trans;
  164. XWindowChanges wc;
  165. c = emallocz(sizeof(Client));
  166. c->tags = emallocz(ntags * sizeof(Bool));
  167. c->win = w;
  168. c->x = wa->x;
  169. c->y = wa->y;
  170. c->w = wa->width;
  171. c->h = wa->height;
  172. if(c->w == sw && c->h == sh) {
  173. c->border = 0;
  174. c->x = sx;
  175. c->y = sy;
  176. }
  177. else {
  178. c->border = BORDERPX;
  179. if(c->x + c->w + 2 * c->border > wax + waw)
  180. c->x = wax + waw - c->w - 2 * c->border;
  181. if(c->y + c->h + 2 * c->border > way + wah)
  182. c->y = way + wah - c->h - 2 * c->border;
  183. if(c->x < wax)
  184. c->x = wax;
  185. if(c->y < way)
  186. c->y = way;
  187. }
  188. updatesizehints(c);
  189. XSelectInput(dpy, w,
  190. StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
  191. XGetTransientForHint(dpy, w, &trans);
  192. grabbuttons(c, False);
  193. wc.border_width = c->border;
  194. XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  195. XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  196. configure(c); /* propagates border_width, if size doesn't change */
  197. updatetitle(c);
  198. for(t = clients; t && t->win != trans; t = t->next);
  199. settags(c, t);
  200. if(!c->isversatile)
  201. c->isversatile = (t != NULL) || c->isfixed;
  202. attach(c);
  203. attachstack(c);
  204. c->isbanned = True;
  205. XMoveWindow(dpy, w, c->x + 2 * sw, c->y);
  206. XMapWindow(dpy, w);
  207. setclientstate(c, NormalState);
  208. if(isvisible(c))
  209. focus(c);
  210. lt->arrange();
  211. }
  212. void
  213. resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
  214. float actual, dx, dy, max, min;
  215. XWindowChanges wc;
  216. if(w <= 0 || h <= 0)
  217. return;
  218. if(sizehints) {
  219. if(c->minw && w < c->minw)
  220. w = c->minw;
  221. if(c->minh && h < c->minh)
  222. h = c->minh;
  223. if(c->maxw && w > c->maxw)
  224. w = c->maxw;
  225. if(c->maxh && h > c->maxh)
  226. h = c->maxh;
  227. /* inspired by algorithm from fluxbox */
  228. if(c->minay > 0 && c->maxay && (h - c->baseh) > 0) {
  229. dx = (float)(w - c->basew);
  230. dy = (float)(h - c->baseh);
  231. min = (float)(c->minax) / (float)(c->minay);
  232. max = (float)(c->maxax) / (float)(c->maxay);
  233. actual = dx / dy;
  234. if(max > 0 && min > 0 && actual > 0) {
  235. if(actual < min) {
  236. dy = (dx * min + dy) / (min * min + 1);
  237. dx = dy * min;
  238. w = (int)dx + c->basew;
  239. h = (int)dy + c->baseh;
  240. }
  241. else if(actual > max) {
  242. dy = (dx * min + dy) / (max * max + 1);
  243. dx = dy * min;
  244. w = (int)dx + c->basew;
  245. h = (int)dy + c->baseh;
  246. }
  247. }
  248. }
  249. if(c->incw)
  250. w -= (w - c->basew) % c->incw;
  251. if(c->inch)
  252. h -= (h - c->baseh) % c->inch;
  253. }
  254. if(w == sw && h == sh)
  255. c->border = 0;
  256. else
  257. c->border = BORDERPX;
  258. /* offscreen appearance fixes */
  259. if(x > sw)
  260. x = sw - w - 2 * c->border;
  261. if(y > sh)
  262. y = sh - h - 2 * c->border;
  263. if(x + w + 2 * c->border < sx)
  264. x = sx;
  265. if(y + h + 2 * c->border < sy)
  266. y = sy;
  267. if(c->x != x || c->y != y || c->w != w || c->h != h) {
  268. c->x = wc.x = x;
  269. c->y = wc.y = y;
  270. c->w = wc.width = w;
  271. c->h = wc.height = h;
  272. wc.border_width = c->border;
  273. XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
  274. configure(c);
  275. XSync(dpy, False);
  276. }
  277. }
  278. void
  279. toggleversatile(Arg *arg) {
  280. if(!sel || lt->arrange == versatile)
  281. return;
  282. sel->isversatile = !sel->isversatile;
  283. lt->arrange();
  284. }
  285. void
  286. updatesizehints(Client *c) {
  287. long msize;
  288. XSizeHints size;
  289. if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
  290. size.flags = PSize;
  291. c->flags = size.flags;
  292. if(c->flags & PBaseSize) {
  293. c->basew = size.base_width;
  294. c->baseh = size.base_height;
  295. }
  296. else
  297. c->basew = c->baseh = 0;
  298. if(c->flags & PResizeInc) {
  299. c->incw = size.width_inc;
  300. c->inch = size.height_inc;
  301. }
  302. else
  303. c->incw = c->inch = 0;
  304. if(c->flags & PMaxSize) {
  305. c->maxw = size.max_width;
  306. c->maxh = size.max_height;
  307. }
  308. else
  309. c->maxw = c->maxh = 0;
  310. if(c->flags & PMinSize) {
  311. c->minw = size.min_width;
  312. c->minh = size.min_height;
  313. }
  314. else
  315. c->minw = c->minh = 0;
  316. if(c->flags & PAspect) {
  317. c->minax = size.min_aspect.x;
  318. c->minay = size.min_aspect.y;
  319. c->maxax = size.max_aspect.x;
  320. c->maxay = size.max_aspect.y;
  321. }
  322. else
  323. c->minax = c->minay = c->maxax = c->maxay = 0;
  324. c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
  325. && c->maxw == c->minw && c->maxh == c->minh);
  326. }
  327. void
  328. updatetitle(Client *c) {
  329. char **list = NULL;
  330. int n;
  331. XTextProperty name;
  332. name.nitems = 0;
  333. c->name[0] = 0;
  334. XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
  335. if(!name.nitems)
  336. XGetWMName(dpy, c->win, &name);
  337. if(!name.nitems)
  338. return;
  339. if(name.encoding == XA_STRING)
  340. strncpy(c->name, (char *)name.value, sizeof c->name);
  341. else {
  342. if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
  343. && n > 0 && *list)
  344. {
  345. strncpy(c->name, *list, sizeof c->name);
  346. XFreeStringList(list);
  347. }
  348. }
  349. XFree(name.value);
  350. }
  351. void
  352. unmanage(Client *c) {
  353. Client *nc;
  354. /* The server grab construct avoids race conditions. */
  355. XGrabServer(dpy);
  356. XSetErrorHandler(xerrordummy);
  357. detach(c);
  358. detachstack(c);
  359. if(sel == c) {
  360. for(nc = stack; nc && !isvisible(nc); nc = nc->snext);
  361. focus(nc);
  362. }
  363. XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  364. setclientstate(c, WithdrawnState);
  365. free(c->tags);
  366. free(c);
  367. XSync(dpy, False);
  368. XSetErrorHandler(xerror);
  369. XUngrabServer(dpy);
  370. lt->arrange();
  371. }
  372. void
  373. zoom(Arg *arg) {
  374. unsigned int n;
  375. Client *c;
  376. if(!sel)
  377. return;
  378. if(sel->isversatile || (lt->arrange == versatile)) {
  379. togglemax(sel);
  380. return;
  381. }
  382. for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
  383. n++;
  384. if((c = sel) == nexttiled(clients))
  385. if(!(c = nexttiled(c->next)))
  386. return;
  387. detach(c);
  388. attach(c);
  389. focus(c);
  390. lt->arrange();
  391. }