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.

326 lines
6.0 KiB

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 <math.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <X11/Xatom.h>
  9. #include "util.h"
  10. #include "wm.h"
  11. void
  12. arrange(void *aux)
  13. {
  14. Client *c;
  15. int n, cols, rows, gw, gh, i, j;
  16. float rt, fd;
  17. if(!clients)
  18. return;
  19. for(n = 0, c = clients; c; c = c->next, n++);
  20. rt = sqrt(n);
  21. if(modff(rt, &fd) < 0.5)
  22. rows = floor(rt);
  23. else
  24. rows = ceil(rt);
  25. if(rows * rows < n)
  26. cols = rows + 1;
  27. else
  28. cols = rows;
  29. gw = (sw - 1) / cols;
  30. gh = (sh - bh - 1) / rows;
  31. for(i = j = 0, c = clients; c; c = c->next) {
  32. c->x = i * gw;
  33. c->y = j * gh + bh;
  34. c->w = gw;
  35. c->h = gh;
  36. resize(c);
  37. if(++i == cols) {
  38. j++;
  39. i = 0;
  40. }
  41. }
  42. }
  43. void
  44. sel(void *aux)
  45. {
  46. const char *arg = aux;
  47. Client *c = NULL;
  48. if(!arg || !stack)
  49. return;
  50. if(!strncmp(arg, "next", 5))
  51. c = stack->snext ? stack->snext : stack;
  52. else if(!strncmp(arg, "prev", 5))
  53. for(c = stack; c && c->snext; c = c->snext);
  54. if(!c)
  55. c = stack;
  56. raise(c);
  57. focus(c);
  58. }
  59. void
  60. kill(void *aux)
  61. {
  62. Client *c = stack;
  63. if(!c)
  64. return;
  65. if(c->proto & WM_PROTOCOL_DELWIN)
  66. send_message(c->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
  67. else
  68. XKillClient(dpy, c->win);
  69. }
  70. static void
  71. resize_title(Client *c)
  72. {
  73. c->tw = textw(&brush.font, c->name) + bh;
  74. if(c->tw > c->w)
  75. c->tw = c->w + 2;
  76. c->tx = c->x + c->w - c->tw + 2;
  77. c->ty = c->y;
  78. XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
  79. }
  80. void
  81. update_name(Client *c)
  82. {
  83. XTextProperty name;
  84. int n;
  85. char **list = NULL;
  86. name.nitems = 0;
  87. c->name[0] = 0;
  88. XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
  89. if(!name.nitems)
  90. XGetWMName(dpy, c->win, &name);
  91. if(!name.nitems)
  92. return;
  93. if(name.encoding == XA_STRING)
  94. strncpy(c->name, (char *)name.value, sizeof(c->name));
  95. else {
  96. if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
  97. && n > 0 && *list)
  98. {
  99. strncpy(c->name, *list, sizeof(c->name));
  100. XFreeStringList(list);
  101. }
  102. }
  103. XFree(name.value);
  104. resize_title(c);
  105. }
  106. void
  107. update_size(Client *c)
  108. {
  109. XSizeHints size;
  110. long msize;
  111. if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
  112. size.flags = PSize;
  113. c->flags = size.flags;
  114. if(c->flags & PBaseSize) {
  115. c->basew = size.base_width;
  116. c->baseh = size.base_height;
  117. }
  118. else
  119. c->basew = c->baseh = 0;
  120. if(c->flags & PResizeInc) {
  121. c->incw = size.width_inc;
  122. c->inch = size.height_inc;
  123. }
  124. else
  125. c->incw = c->inch = 0;
  126. if(c->flags & PMaxSize) {
  127. c->maxw = size.max_width;
  128. c->maxh = size.max_height;
  129. }
  130. else
  131. c->maxw = c->maxh = 0;
  132. if(c->flags & PMinSize) {
  133. c->minw = size.min_width;
  134. c->minh = size.min_height;
  135. }
  136. else
  137. c->minw = c->minh = 0;
  138. }
  139. void
  140. raise(Client *c)
  141. {
  142. XRaiseWindow(dpy, c->win);
  143. XRaiseWindow(dpy, c->title);
  144. }
  145. void
  146. lower(Client *c)
  147. {
  148. XLowerWindow(dpy, c->title);
  149. XLowerWindow(dpy, c->win);
  150. }
  151. void
  152. focus(Client *c)
  153. {
  154. Client **l, *old;
  155. old = stack;
  156. for(l = &stack; *l && *l != c; l = &(*l)->snext);
  157. eassert(*l == c);
  158. *l = c->snext;
  159. c->snext = stack;
  160. stack = c;
  161. if(old && old != c) {
  162. XMapWindow(dpy, old->title);
  163. draw_client(old);
  164. }
  165. XUnmapWindow(dpy, c->title);
  166. draw_client(c);
  167. XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
  168. XFlush(dpy);
  169. }
  170. void
  171. manage(Window w, XWindowAttributes *wa)
  172. {
  173. Client *c, **l;
  174. XSetWindowAttributes twa;
  175. c = emallocz(sizeof(Client));
  176. c->win = w;
  177. c->tx = c->x = wa->x;
  178. c->ty = c->y = wa->y;
  179. if(c->y < bh)
  180. c->ty = c->y += bh;
  181. c->tw = c->w = wa->width;
  182. c->h = wa->height;
  183. c->th = bh;
  184. update_size(c);
  185. XSetWindowBorderWidth(dpy, c->win, 1);
  186. XSetWindowBorder(dpy, c->win, brush.border);
  187. XSelectInput(dpy, c->win,
  188. StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
  189. XGetTransientForHint(dpy, c->win, &c->trans);
  190. twa.override_redirect = 1;
  191. twa.background_pixmap = ParentRelative;
  192. twa.event_mask = ExposureMask;
  193. c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
  194. 0, DefaultDepth(dpy, screen), CopyFromParent,
  195. DefaultVisual(dpy, screen),
  196. CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
  197. update_name(c);
  198. for(l=&clients; *l; l=&(*l)->next);
  199. c->next = *l; /* *l == nil */
  200. *l = c;
  201. c->snext = stack;
  202. stack = c;
  203. XMapRaised(dpy, c->win);
  204. XMapRaised(dpy, c->title);
  205. XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
  206. GrabModeAsync, GrabModeSync, None, None);
  207. XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
  208. GrabModeAsync, GrabModeSync, None, None);
  209. XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
  210. GrabModeAsync, GrabModeSync, None, None);
  211. resize(c);
  212. focus(c);
  213. }
  214. void
  215. resize(Client *c)
  216. {
  217. XConfigureEvent e;
  218. resize_title(c);
  219. XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
  220. e.type = ConfigureNotify;
  221. e.event = c->win;
  222. e.window = c->win;
  223. e.x = c->x;
  224. e.y = c->y;
  225. e.width = c->w;
  226. e.height = c->h;
  227. e.border_width = 0;
  228. e.above = None;
  229. e.override_redirect = False;
  230. XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
  231. XFlush(dpy);
  232. }
  233. static int
  234. dummy_error_handler(Display *dpy, XErrorEvent *error)
  235. {
  236. return 0;
  237. }
  238. void
  239. unmanage(Client *c)
  240. {
  241. Client **l;
  242. XGrabServer(dpy);
  243. XSetErrorHandler(dummy_error_handler);
  244. XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  245. XDestroyWindow(dpy, c->title);
  246. for(l=&clients; *l && *l != c; l=&(*l)->next);
  247. eassert(*l == c);
  248. *l = c->next;
  249. for(l=&stack; *l && *l != c; l=&(*l)->snext);
  250. eassert(*l == c);
  251. *l = c->snext;
  252. free(c);
  253. XFlush(dpy);
  254. XSetErrorHandler(error_handler);
  255. XUngrabServer(dpy);
  256. if(stack)
  257. focus(stack);
  258. }
  259. Client *
  260. gettitle(Window w)
  261. {
  262. Client *c;
  263. for(c = clients; c; c = c->next)
  264. if(c->title == w)
  265. return c;
  266. return NULL;
  267. }
  268. Client *
  269. getclient(Window w)
  270. {
  271. Client *c;
  272. for(c = clients; c; c = c->next)
  273. if(c->win == w)
  274. return c;
  275. return NULL;
  276. }
  277. void
  278. draw_client(Client *c)
  279. {
  280. if(c == stack) {
  281. draw_bar();
  282. return;
  283. }
  284. brush.x = brush.y = 0;
  285. brush.w = c->tw;
  286. brush.h = c->th;
  287. draw(dpy, &brush, True, c->name);
  288. XCopyArea(dpy, brush.drawable, c->title, brush.gc,
  289. 0, 0, c->tw, c->th, 0, 0);
  290. XFlush(dpy);
  291. }