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.

394 lines
7.4 KiB

19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 years ago
19 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. 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. }