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.

400 lines
7.1 KiB

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