client.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. }