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.

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