Configuration file for DWM on MacBook Air
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.

386 lines
8.8 KiB

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