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.

344 lines
8.3 KiB

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