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.

338 lines
6.1 KiB

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