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.

413 lines
9.7 KiB

18 years ago
18 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
18 years ago
18 years ago
18 years ago
17 years ago
18 years ago
18 years ago
18 years ago
  1. /* © 2006-2007 Anselm R. Garbe <garbeam at gmail dot com>
  2. * © 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
  3. * See LICENSE file for license details. */
  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 int
  74. xerrordummy(Display *dsply, XErrorEvent *ee) {
  75. return 0;
  76. }
  77. /* extern */
  78. void
  79. attach(Client *c) {
  80. if(clients)
  81. clients->prev = c;
  82. c->next = clients;
  83. clients = c;
  84. }
  85. void
  86. configure(Client *c) {
  87. XConfigureEvent ce;
  88. ce.type = ConfigureNotify;
  89. ce.display = dpy;
  90. ce.event = c->win;
  91. ce.window = c->win;
  92. ce.x = c->x;
  93. ce.y = c->y;
  94. ce.width = c->w;
  95. ce.height = c->h;
  96. ce.border_width = c->border;
  97. ce.above = None;
  98. ce.override_redirect = False;
  99. XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
  100. }
  101. void
  102. detach(Client *c) {
  103. if(c->prev)
  104. c->prev->next = c->next;
  105. if(c->next)
  106. c->next->prev = c->prev;
  107. if(c == clients)
  108. clients = c->next;
  109. c->next = c->prev = NULL;
  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. focustopvisible(void) {
  137. Client *c;
  138. for(c = stack; c && !isvisible(c); c = c->snext);
  139. focus(c);
  140. }
  141. void
  142. killclient(const char *arg) {
  143. XEvent ev;
  144. if(!sel)
  145. return;
  146. if(isprotodel(sel)) {
  147. ev.type = ClientMessage;
  148. ev.xclient.window = sel->win;
  149. ev.xclient.message_type = wmatom[WMProtocols];
  150. ev.xclient.format = 32;
  151. ev.xclient.data.l[0] = wmatom[WMDelete];
  152. ev.xclient.data.l[1] = CurrentTime;
  153. XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
  154. }
  155. else
  156. XKillClient(dpy, sel->win);
  157. }
  158. void
  159. manage(Window w, XWindowAttributes *wa) {
  160. Client *c, *t = NULL;
  161. Window trans;
  162. Status rettrans;
  163. XWindowChanges wc;
  164. c = emallocz(sizeof(Client));
  165. c->tags = emallocz(ntags * sizeof(Bool));
  166. c->win = w;
  167. c->x = wa->x;
  168. c->y = wa->y;
  169. c->w = wa->width;
  170. c->h = wa->height;
  171. c->oldborder = wa->border_width;
  172. if(c->w == sw && c->h == sh) {
  173. c->x = sx;
  174. c->y = sy;
  175. c->border = wa->border_width;
  176. }
  177. else {
  178. if(c->x + c->w + 2 * c->border > wax + waw)
  179. c->x = wax + waw - c->w - 2 * c->border;
  180. if(c->y + c->h + 2 * c->border > way + wah)
  181. c->y = way + wah - c->h - 2 * c->border;
  182. if(c->x < wax)
  183. c->x = wax;
  184. if(c->y < way)
  185. c->y = way;
  186. c->border = BORDERPX;
  187. }
  188. wc.border_width = c->border;
  189. XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  190. XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  191. configure(c); /* propagates border_width, if size doesn't change */
  192. updatesizehints(c);
  193. XSelectInput(dpy, w,
  194. StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
  195. grabbuttons(c, False);
  196. updatetitle(c);
  197. if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
  198. for(t = clients; t && t->win != trans; t = t->next);
  199. settags(c, t);
  200. if(!c->isfloating)
  201. c->isfloating = (rettrans == Success) || 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 dx, dy, max, min, ratio;
  215. XWindowChanges wc;
  216. if(w <= 0 || h <= 0)
  217. return;
  218. if(sizehints) {
  219. if(c->minay > 0 && c->maxay > 0 && (h - c->baseh) > 0) {
  220. dx = (float)(w - c->basew);
  221. dy = (float)(h - c->baseh);
  222. min = (float)(c->minax) / (float)(c->minay);
  223. max = (float)(c->maxax) / (float)(c->maxay);
  224. ratio = dx / dy;
  225. if(max > 0 && min > 0 && ratio > 0) {
  226. if(ratio < min) {
  227. dy = (dx * min + dy) / (min * min + 1);
  228. dx = dy * min;
  229. w = (int)dx + c->basew;
  230. h = (int)dy + c->baseh;
  231. }
  232. else if(ratio > max) {
  233. dy = (dx * min + dy) / (max * max + 1);
  234. dx = dy * min;
  235. w = (int)dx + c->basew;
  236. h = (int)dy + c->baseh;
  237. }
  238. }
  239. }
  240. if(c->minw && w < c->minw)
  241. w = c->minw;
  242. if(c->minh && h < c->minh)
  243. h = c->minh;
  244. if(c->maxw && w > c->maxw)
  245. w = c->maxw;
  246. if(c->maxh && h > c->maxh)
  247. h = c->maxh;
  248. if(c->incw)
  249. w -= (w - c->basew) % c->incw;
  250. if(c->inch)
  251. h -= (h - c->baseh) % c->inch;
  252. }
  253. if(w <= 0 || h <= 0)
  254. return;
  255. /* offscreen appearance fixes */
  256. if(x > sw)
  257. x = sw - w - 2 * c->border;
  258. if(y > sh)
  259. y = sh - h - 2 * c->border;
  260. if(x + w + 2 * c->border < sx)
  261. x = sx;
  262. if(y + h + 2 * c->border < sy)
  263. y = sy;
  264. if(c->x != x || c->y != y || c->w != w || c->h != h) {
  265. c->x = wc.x = x;
  266. c->y = wc.y = y;
  267. c->w = wc.width = w;
  268. c->h = wc.height = h;
  269. wc.border_width = c->border;
  270. XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
  271. configure(c);
  272. XSync(dpy, False);
  273. }
  274. }
  275. void
  276. togglefloating(const char *arg) {
  277. if(!sel || lt->arrange == floating)
  278. return;
  279. sel->isfloating = !sel->isfloating;
  280. if(sel->isfloating && sel->isfixed)
  281. resize(sel, sel->x, sel->y, sel->minw, sel->minh, True);
  282. lt->arrange();
  283. }
  284. void
  285. updatesizehints(Client *c) {
  286. long msize;
  287. XSizeHints size;
  288. if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
  289. size.flags = PSize;
  290. c->flags = size.flags;
  291. if(c->flags & PBaseSize) {
  292. c->basew = size.base_width;
  293. c->baseh = size.base_height;
  294. }
  295. else if(c->flags & PMinSize) {
  296. c->basew = size.min_width;
  297. c->baseh = size.min_height;
  298. }
  299. else
  300. c->basew = c->baseh = 0;
  301. if(c->flags & PResizeInc) {
  302. c->incw = size.width_inc;
  303. c->inch = size.height_inc;
  304. }
  305. else
  306. c->incw = c->inch = 0;
  307. if(c->flags & PMaxSize) {
  308. c->maxw = size.max_width;
  309. c->maxh = size.max_height;
  310. }
  311. else
  312. c->maxw = c->maxh = 0;
  313. if(c->flags & PMinSize) {
  314. c->minw = size.min_width;
  315. c->minh = size.min_height;
  316. }
  317. else if(c->flags & PBaseSize) {
  318. c->minw = size.base_width;
  319. c->minh = size.base_height;
  320. }
  321. else
  322. c->minw = c->minh = 0;
  323. if(c->flags & PAspect) {
  324. c->minax = size.min_aspect.x;
  325. c->maxax = size.max_aspect.x;
  326. c->minay = size.min_aspect.y;
  327. c->maxay = size.max_aspect.y;
  328. }
  329. else
  330. c->minax = c->maxax = c->minay = c->maxay = 0;
  331. c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
  332. && c->maxw == c->minw && c->maxh == c->minh);
  333. }
  334. void
  335. updatetitle(Client *c) {
  336. char **list = NULL;
  337. int n;
  338. XTextProperty name;
  339. name.nitems = 0;
  340. c->name[0] = 0;
  341. XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
  342. if(!name.nitems)
  343. XGetWMName(dpy, c->win, &name);
  344. if(!name.nitems)
  345. return;
  346. if(name.encoding == XA_STRING)
  347. strncpy(c->name, (char *)name.value, sizeof c->name - 1);
  348. else {
  349. if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
  350. && n > 0 && *list)
  351. {
  352. strncpy(c->name, *list, sizeof c->name - 1);
  353. XFreeStringList(list);
  354. }
  355. }
  356. c->name[sizeof c->name - 1] = '\0';
  357. XFree(name.value);
  358. }
  359. void
  360. unmanage(Client *c) {
  361. XWindowChanges wc;
  362. wc.border_width = c->oldborder;
  363. /* The server grab construct avoids race conditions. */
  364. XGrabServer(dpy);
  365. XSetErrorHandler(xerrordummy);
  366. XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
  367. detach(c);
  368. detachstack(c);
  369. if(sel == c)
  370. focustopvisible();
  371. XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  372. setclientstate(c, WithdrawnState);
  373. free(c->tags);
  374. free(c);
  375. XSync(dpy, False);
  376. XSetErrorHandler(xerror);
  377. XUngrabServer(dpy);
  378. lt->arrange();
  379. }