client.c 7.4 KB

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