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.

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