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.

423 lines
7.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
  1. /*
  2. * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
  3. * See LICENSE file for license details.
  4. */
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <X11/Xatom.h>
  9. #include <X11/Xutil.h>
  10. #include "dwm.h"
  11. void
  12. ban(Client *c)
  13. {
  14. XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
  15. XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
  16. }
  17. static void
  18. resizetitle(Client *c)
  19. {
  20. int i;
  21. c->tw = 0;
  22. for(i = 0; i < TLast; i++)
  23. if(c->tags[i])
  24. c->tw += textw(c->tags[i]);
  25. c->tw += textw(c->name);
  26. if(c->tw > c->w)
  27. c->tw = c->w + 2;
  28. c->tx = c->x + c->w - c->tw + 2;
  29. c->ty = c->y;
  30. XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
  31. }
  32. void
  33. settitle(Client *c)
  34. {
  35. XTextProperty name;
  36. int n;
  37. char **list = NULL;
  38. name.nitems = 0;
  39. c->name[0] = 0;
  40. XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
  41. if(!name.nitems)
  42. XGetWMName(dpy, c->win, &name);
  43. if(!name.nitems)
  44. return;
  45. if(name.encoding == XA_STRING)
  46. strncpy(c->name, (char *)name.value, sizeof(c->name));
  47. else {
  48. if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
  49. && n > 0 && *list)
  50. {
  51. strncpy(c->name, *list, sizeof(c->name));
  52. XFreeStringList(list);
  53. }
  54. }
  55. XFree(name.value);
  56. resizetitle(c);
  57. }
  58. void
  59. setsize(Client *c)
  60. {
  61. XSizeHints size;
  62. long msize;
  63. if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
  64. size.flags = PSize;
  65. c->flags = size.flags;
  66. if(c->flags & PBaseSize) {
  67. c->basew = size.base_width;
  68. c->baseh = size.base_height;
  69. }
  70. else
  71. c->basew = c->baseh = 0;
  72. if(c->flags & PResizeInc) {
  73. c->incw = size.width_inc;
  74. c->inch = size.height_inc;
  75. }
  76. else
  77. c->incw = c->inch = 0;
  78. if(c->flags & PMaxSize) {
  79. c->maxw = size.max_width;
  80. c->maxh = size.max_height;
  81. }
  82. else
  83. c->maxw = c->maxh = 0;
  84. if(c->flags & PMinSize) {
  85. c->minw = size.min_width;
  86. c->minh = size.min_height;
  87. }
  88. else
  89. c->minw = c->minh = 0;
  90. if(c->flags & PWinGravity)
  91. c->grav = size.win_gravity;
  92. else
  93. c->grav = NorthWestGravity;
  94. }
  95. void
  96. higher(Client *c)
  97. {
  98. XRaiseWindow(dpy, c->win);
  99. XRaiseWindow(dpy, c->title);
  100. }
  101. void
  102. lower(Client *c)
  103. {
  104. XLowerWindow(dpy, c->title);
  105. XLowerWindow(dpy, c->win);
  106. }
  107. void
  108. focus(Client *c)
  109. {
  110. Client *old = sel;
  111. XEvent ev;
  112. XFlush(dpy);
  113. sel = c;
  114. if(old && old != c)
  115. drawtitle(old);
  116. drawtitle(c);
  117. XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
  118. XFlush(dpy);
  119. while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  120. }
  121. void
  122. manage(Window w, XWindowAttributes *wa)
  123. {
  124. Client *c, **l;
  125. XSetWindowAttributes twa;
  126. Window trans;
  127. c = emallocz(sizeof(Client));
  128. c->win = w;
  129. c->tx = c->x = wa->x;
  130. c->ty = c->y = wa->y;
  131. if(c->y < bh)
  132. c->ty = c->y += bh;
  133. c->tw = c->w = wa->width;
  134. c->h = wa->height;
  135. c->th = bh;
  136. c->border = 1;
  137. c->proto = getproto(c->win);
  138. setsize(c);
  139. XSelectInput(dpy, c->win,
  140. StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
  141. XGetTransientForHint(dpy, c->win, &trans);
  142. twa.override_redirect = 1;
  143. twa.background_pixmap = ParentRelative;
  144. twa.event_mask = ExposureMask;
  145. c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
  146. 0, DefaultDepth(dpy, screen), CopyFromParent,
  147. DefaultVisual(dpy, screen),
  148. CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
  149. settitle(c);
  150. settags(c);
  151. for(l = &clients; *l; l = &(*l)->next);
  152. c->next = *l; /* *l == nil */
  153. *l = c;
  154. XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
  155. GrabModeAsync, GrabModeSync, None, None);
  156. XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
  157. GrabModeAsync, GrabModeSync, None, None);
  158. XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
  159. GrabModeAsync, GrabModeSync, None, None);
  160. if(!c->dofloat)
  161. c->dofloat = trans
  162. || ((c->maxw == c->minw) && (c->maxh == c->minh));
  163. arrange(NULL);
  164. /* mapping the window now prevents flicker */
  165. if(c->tags[tsel]) {
  166. XMapRaised(dpy, c->win);
  167. XMapRaised(dpy, c->title);
  168. focus(c);
  169. }
  170. else {
  171. ban(c);
  172. XMapRaised(dpy, c->win);
  173. XMapRaised(dpy, c->title);
  174. }
  175. }
  176. void
  177. gravitate(Client *c, Bool invert)
  178. {
  179. int dx = 0, dy = 0;
  180. switch(c->grav) {
  181. case StaticGravity:
  182. case NorthWestGravity:
  183. case NorthGravity:
  184. case NorthEastGravity:
  185. dy = c->border;
  186. break;
  187. case EastGravity:
  188. case CenterGravity:
  189. case WestGravity:
  190. dy = -(c->h / 2) + c->border;
  191. break;
  192. case SouthEastGravity:
  193. case SouthGravity:
  194. case SouthWestGravity:
  195. dy = -c->h;
  196. break;
  197. default:
  198. break;
  199. }
  200. switch (c->grav) {
  201. case StaticGravity:
  202. case NorthWestGravity:
  203. case WestGravity:
  204. case SouthWestGravity:
  205. dx = c->border;
  206. break;
  207. case NorthGravity:
  208. case CenterGravity:
  209. case SouthGravity:
  210. dx = -(c->w / 2) + c->border;
  211. break;
  212. case NorthEastGravity:
  213. case EastGravity:
  214. case SouthEastGravity:
  215. dx = -(c->w + c->border);
  216. break;
  217. default:
  218. break;
  219. }
  220. if(invert) {
  221. dx = -dx;
  222. dy = -dy;
  223. }
  224. c->x += dx;
  225. c->y += dy;
  226. }
  227. void
  228. resize(Client *c, Bool inc)
  229. {
  230. XConfigureEvent e;
  231. if(inc) {
  232. if(c->incw)
  233. c->w -= (c->w - c->basew) % c->incw;
  234. if(c->inch)
  235. c->h -= (c->h - c->baseh) % c->inch;
  236. }
  237. if(c->x > sw) /* might happen on restart */
  238. c->x = sw - c->w;
  239. if(c->y > sh)
  240. c->ty = c->y = sh - c->h;
  241. if(c->minw && c->w < c->minw)
  242. c->w = c->minw;
  243. if(c->minh && c->h < c->minh)
  244. c->h = c->minh;
  245. if(c->maxw && c->w > c->maxw)
  246. c->w = c->maxw;
  247. if(c->maxh && c->h > c->maxh)
  248. c->h = c->maxh;
  249. resizetitle(c);
  250. XSetWindowBorderWidth(dpy, c->win, 1);
  251. XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
  252. e.type = ConfigureNotify;
  253. e.event = c->win;
  254. e.window = c->win;
  255. e.x = c->x;
  256. e.y = c->y;
  257. e.width = c->w;
  258. e.height = c->h;
  259. e.border_width = c->border;
  260. e.above = None;
  261. e.override_redirect = False;
  262. XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
  263. XFlush(dpy);
  264. }
  265. static int
  266. xerrordummy(Display *dsply, XErrorEvent *ee)
  267. {
  268. return 0;
  269. }
  270. void
  271. unmanage(Client *c)
  272. {
  273. Client **l;
  274. XGrabServer(dpy);
  275. XSetErrorHandler(xerrordummy);
  276. XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  277. XDestroyWindow(dpy, c->title);
  278. for(l = &clients; *l && *l != c; l = &(*l)->next);
  279. *l = c->next;
  280. for(l = &clients; *l; l = &(*l)->next)
  281. if((*l)->revert == c)
  282. (*l)->revert = NULL;
  283. if(sel == c)
  284. sel = sel->revert ? sel->revert : clients;
  285. free(c);
  286. XFlush(dpy);
  287. XSetErrorHandler(xerror);
  288. XUngrabServer(dpy);
  289. arrange(NULL);
  290. if(sel)
  291. focus(sel);
  292. }
  293. Client *
  294. getctitle(Window w)
  295. {
  296. Client *c;
  297. for(c = clients; c; c = c->next)
  298. if(c->title == w)
  299. return c;
  300. return NULL;
  301. }
  302. Client *
  303. getclient(Window w)
  304. {
  305. Client *c;
  306. for(c = clients; c; c = c->next)
  307. if(c->win == w)
  308. return c;
  309. return NULL;
  310. }
  311. void
  312. zoom(Arg *arg)
  313. {
  314. Client **l, *c;
  315. if(!sel)
  316. return;
  317. if(sel == getnext(clients) && sel->next) {
  318. if((c = getnext(sel->next)))
  319. sel = c;
  320. }
  321. for(l = &clients; *l && *l != sel; l = &(*l)->next);
  322. *l = sel->next;
  323. sel->next = clients; /* pop */
  324. clients = sel;
  325. arrange(NULL);
  326. focus(sel);
  327. }
  328. void
  329. maximize(Arg *arg)
  330. {
  331. if(!sel)
  332. return;
  333. sel->x = sx;
  334. sel->y = sy + bh;
  335. sel->w = sw - 2 * sel->border;
  336. sel->h = sh - 2 * sel->border - bh;
  337. higher(sel);
  338. resize(sel, False);
  339. }
  340. void
  341. focusprev(Arg *arg)
  342. {
  343. Client *c;
  344. if(!sel)
  345. return;
  346. if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
  347. higher(c);
  348. focus(c);
  349. }
  350. }
  351. void
  352. focusnext(Arg *arg)
  353. {
  354. Client *c;
  355. if(!sel)
  356. return;
  357. if(!(c = getnext(sel->next)))
  358. c = getnext(clients);
  359. if(c) {
  360. higher(c);
  361. c->revert = sel;
  362. focus(c);
  363. }
  364. }
  365. void
  366. killclient(Arg *arg)
  367. {
  368. if(!sel)
  369. return;
  370. if(sel->proto & WM_PROTOCOL_DELWIN)
  371. sendevent(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
  372. else
  373. XKillClient(dpy, sel->win);
  374. }