Configuration of dwm for Mac Computers
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.

577 lines
9.9 KiB

18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
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 <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 void (*arrange)(Arg *) = tiling;
  12. static Rule rule[] = {
  13. { "Firefox-bin", "Gecko", { [Twww] = "www" } },
  14. };
  15. static Client *
  16. next(Client *c)
  17. {
  18. for(; c && !c->tags[tsel]; c = c->next);
  19. return c;
  20. }
  21. void
  22. zoom(Arg *arg)
  23. {
  24. Client **l, *old;
  25. if(!(old = sel))
  26. return;
  27. for(l = &clients; *l && *l != sel; l = &(*l)->next);
  28. *l = sel->next;
  29. old->next = clients; /* pop */
  30. clients = old;
  31. sel = old;
  32. arrange(NULL);
  33. focus(sel);
  34. }
  35. void
  36. max(Arg *arg)
  37. {
  38. if(!sel)
  39. return;
  40. sel->x = sx;
  41. sel->y = sy;
  42. sel->w = sw - 2 * sel->border;
  43. sel->h = sh - 2 * sel->border;
  44. craise(sel);
  45. resize(sel);
  46. discard_events(EnterWindowMask);
  47. }
  48. void
  49. view(Arg *arg)
  50. {
  51. tsel = arg->i;
  52. arrange(NULL);
  53. }
  54. void
  55. tag(Arg *arg)
  56. {
  57. int i, n;
  58. if(!sel)
  59. return;
  60. if(arg->i == tsel) {
  61. for(n = i = 0; i < TLast; i++)
  62. if(sel->tags[i])
  63. n++;
  64. if(n < 2)
  65. return;
  66. }
  67. if(sel->tags[arg->i])
  68. sel->tags[arg->i] = NULL; /* toggle tag */
  69. else
  70. sel->tags[arg->i] = tags[arg->i];
  71. arrange(NULL);
  72. }
  73. static void
  74. ban_client(Client *c)
  75. {
  76. XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
  77. XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
  78. }
  79. void
  80. floating(Arg *arg)
  81. {
  82. Client *c;
  83. arrange = floating;
  84. for(c = clients; c; c = c->next) {
  85. if(c->tags[tsel])
  86. resize(c);
  87. else
  88. ban_client(c);
  89. }
  90. if(sel && !sel->tags[tsel]) {
  91. if((sel = next(clients))) {
  92. craise(sel);
  93. focus(sel);
  94. }
  95. }
  96. discard_events(EnterWindowMask);
  97. }
  98. void
  99. tiling(Arg *arg)
  100. {
  101. Client *c;
  102. int n, i, w, h;
  103. w = sw - mw;
  104. arrange = tiling;
  105. for(n = 0, c = clients; c; c = c->next)
  106. if(c->tags[tsel])
  107. n++;
  108. h = (n > 2) ? sh / (n - 2) : sh;
  109. for(i = 0, c = clients; c; c = c->next) {
  110. if(c->tags[tsel]) {
  111. if(n == 1) {
  112. c->x = sx;
  113. c->y = sy;
  114. c->w = sw;
  115. c->h = sh;
  116. }
  117. else if(i == 1) {
  118. c->x = sx;
  119. c->y = sy;
  120. c->w = mw;
  121. c->h = sh;
  122. }
  123. else {
  124. c->x = sx + mw;
  125. c->y = sy + (i - 2) * h;
  126. c->w = w;
  127. c->h = h;
  128. }
  129. resize(c);
  130. i++;
  131. }
  132. else
  133. ban_client(c);
  134. }
  135. if(sel && !sel->tags[tsel]) {
  136. if((sel = next(clients))) {
  137. craise(sel);
  138. focus(sel);
  139. }
  140. }
  141. discard_events(EnterWindowMask);
  142. }
  143. void
  144. prevc(Arg *arg)
  145. {
  146. Client *c;
  147. if(!sel)
  148. return;
  149. if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
  150. craise(c);
  151. focus(c);
  152. }
  153. }
  154. void
  155. nextc(Arg *arg)
  156. {
  157. Client *c;
  158. if(!sel)
  159. return;
  160. if(!(c = next(sel->next)))
  161. c = next(clients);
  162. if(c) {
  163. craise(c);
  164. c->revert = sel;
  165. focus(c);
  166. }
  167. }
  168. void
  169. ckill(Arg *arg)
  170. {
  171. if(!sel)
  172. return;
  173. if(sel->proto & WM_PROTOCOL_DELWIN)
  174. send_message(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
  175. else
  176. XKillClient(dpy, sel->win);
  177. }
  178. static void
  179. resize_title(Client *c)
  180. {
  181. int i;
  182. c->tw = 0;
  183. for(i = 0; i < TLast; i++)
  184. if(c->tags[i])
  185. c->tw += textw(c->tags[i]) + dc.font.height;
  186. c->tw += textw(c->name) + dc.font.height;
  187. if(c->tw > c->w)
  188. c->tw = c->w + 2;
  189. c->tx = c->x + c->w - c->tw + 2;
  190. c->ty = c->y;
  191. XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
  192. }
  193. void
  194. update_name(Client *c)
  195. {
  196. XTextProperty name;
  197. int n;
  198. char **list = NULL;
  199. name.nitems = 0;
  200. c->name[0] = 0;
  201. XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
  202. if(!name.nitems)
  203. XGetWMName(dpy, c->win, &name);
  204. if(!name.nitems)
  205. return;
  206. if(name.encoding == XA_STRING)
  207. strncpy(c->name, (char *)name.value, sizeof(c->name));
  208. else {
  209. if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
  210. && n > 0 && *list)
  211. {
  212. strncpy(c->name, *list, sizeof(c->name));
  213. XFreeStringList(list);
  214. }
  215. }
  216. XFree(name.value);
  217. resize_title(c);
  218. }
  219. void
  220. update_size(Client *c)
  221. {
  222. XSizeHints size;
  223. long msize;
  224. if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
  225. size.flags = PSize;
  226. c->flags = size.flags;
  227. if(c->flags & PBaseSize) {
  228. c->basew = size.base_width;
  229. c->baseh = size.base_height;
  230. }
  231. else
  232. c->basew = c->baseh = 0;
  233. if(c->flags & PResizeInc) {
  234. c->incw = size.width_inc;
  235. c->inch = size.height_inc;
  236. }
  237. else
  238. c->incw = c->inch = 0;
  239. if(c->flags & PMaxSize) {
  240. c->maxw = size.max_width;
  241. c->maxh = size.max_height;
  242. }
  243. else
  244. c->maxw = c->maxh = 0;
  245. if(c->flags & PMinSize) {
  246. c->minw = size.min_width;
  247. c->minh = size.min_height;
  248. }
  249. else
  250. c->minw = c->minh = 0;
  251. if(c->flags & PWinGravity)
  252. c->grav = size.win_gravity;
  253. else
  254. c->grav = NorthWestGravity;
  255. }
  256. void
  257. craise(Client *c)
  258. {
  259. XRaiseWindow(dpy, c->win);
  260. XRaiseWindow(dpy, c->title);
  261. }
  262. void
  263. lower(Client *c)
  264. {
  265. XLowerWindow(dpy, c->title);
  266. XLowerWindow(dpy, c->win);
  267. }
  268. void
  269. focus(Client *c)
  270. {
  271. if(sel && sel != c) {
  272. XSetWindowBorder(dpy, sel->win, dc.bg);
  273. XMapWindow(dpy, sel->title);
  274. draw_client(sel);
  275. }
  276. sel = c;
  277. XUnmapWindow(dpy, c->title);
  278. XSetWindowBorder(dpy, c->win, dc.fg);
  279. draw_client(c);
  280. XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
  281. XFlush(dpy);
  282. discard_events(EnterWindowMask);
  283. }
  284. static void
  285. init_tags(Client *c)
  286. {
  287. XClassHint ch;
  288. static unsigned int len = rule ? sizeof(rule) / sizeof(rule[0]) : 0;
  289. unsigned int i, j;
  290. Bool matched = False;
  291. if(!len) {
  292. c->tags[tsel] = tags[tsel];
  293. return;
  294. }
  295. if(XGetClassHint(dpy, c->win, &ch)) {
  296. if(ch.res_class && ch.res_name) {
  297. fprintf(stderr, "%s:%s\n", ch.res_class, ch.res_name);
  298. for(i = 0; i < len; i++)
  299. if(!strncmp(rule[i].class, ch.res_class, sizeof(rule[i].class))
  300. && !strncmp(rule[i].instance, ch.res_name, sizeof(rule[i].instance)))
  301. {
  302. fprintf(stderr, "->>>%s:%s\n", ch.res_class, ch.res_name);
  303. for(j = 0; j < TLast; j++)
  304. c->tags[j] = rule[i].tags[j];
  305. matched = True;
  306. break;
  307. }
  308. }
  309. if(ch.res_class)
  310. XFree(ch.res_class);
  311. if(ch.res_name)
  312. XFree(ch.res_name);
  313. }
  314. if(!matched)
  315. c->tags[tsel] = tags[tsel];
  316. }
  317. void
  318. manage(Window w, XWindowAttributes *wa)
  319. {
  320. Client *c, **l;
  321. XSetWindowAttributes twa;
  322. c = emallocz(sizeof(Client));
  323. c->win = w;
  324. c->tx = c->x = wa->x;
  325. c->ty = c->y = wa->y;
  326. c->tw = c->w = wa->width;
  327. c->h = wa->height;
  328. c->th = th;
  329. c->border = 1;
  330. c->proto = win_proto(c->win);
  331. update_size(c);
  332. XSelectInput(dpy, c->win,
  333. StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
  334. XGetTransientForHint(dpy, c->win, &c->trans);
  335. twa.override_redirect = 1;
  336. twa.background_pixmap = ParentRelative;
  337. twa.event_mask = ExposureMask;
  338. c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
  339. 0, DefaultDepth(dpy, screen), CopyFromParent,
  340. DefaultVisual(dpy, screen),
  341. CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
  342. update_name(c);
  343. init_tags(c);
  344. for(l = &clients; *l; l = &(*l)->next);
  345. c->next = *l; /* *l == nil */
  346. *l = c;
  347. XSetWindowBorderWidth(dpy, c->win, 1);
  348. XMapRaised(dpy, c->win);
  349. XMapRaised(dpy, c->title);
  350. XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
  351. GrabModeAsync, GrabModeSync, None, None);
  352. XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
  353. GrabModeAsync, GrabModeSync, None, None);
  354. XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
  355. GrabModeAsync, GrabModeSync, None, None);
  356. arrange(NULL);
  357. if(c->tags[tsel])
  358. focus(c);
  359. else
  360. ban_client(c);
  361. }
  362. void
  363. gravitate(Client *c, Bool invert)
  364. {
  365. int dx = 0, dy = 0;
  366. switch(c->grav) {
  367. case StaticGravity:
  368. case NorthWestGravity:
  369. case NorthGravity:
  370. case NorthEastGravity:
  371. dy = c->border;
  372. break;
  373. case EastGravity:
  374. case CenterGravity:
  375. case WestGravity:
  376. dy = -(c->h / 2) + c->border;
  377. break;
  378. case SouthEastGravity:
  379. case SouthGravity:
  380. case SouthWestGravity:
  381. dy = -c->h;
  382. break;
  383. default:
  384. break;
  385. }
  386. switch (c->grav) {
  387. case StaticGravity:
  388. case NorthWestGravity:
  389. case WestGravity:
  390. case SouthWestGravity:
  391. dx = c->border;
  392. break;
  393. case NorthGravity:
  394. case CenterGravity:
  395. case SouthGravity:
  396. dx = -(c->w / 2) + c->border;
  397. break;
  398. case NorthEastGravity:
  399. case EastGravity:
  400. case SouthEastGravity:
  401. dx = -(c->w + c->border);
  402. break;
  403. default:
  404. break;
  405. }
  406. if(invert) {
  407. dx = -dx;
  408. dy = -dy;
  409. }
  410. c->x += dx;
  411. c->y += dy;
  412. }
  413. void
  414. resize(Client *c)
  415. {
  416. XConfigureEvent e;
  417. if(c->incw)
  418. c->w -= (c->w - c->basew) % c->incw;
  419. if(c->inch)
  420. c->h -= (c->h - c->baseh) % c->inch;
  421. if(c->minw && c->w < c->minw)
  422. c->w = c->minw;
  423. if(c->minh && c->h < c->minh)
  424. c->h = c->minh;
  425. if(c->maxw && c->w > c->maxw)
  426. c->w = c->maxw;
  427. if(c->maxh && c->h > c->maxh)
  428. c->h = c->maxh;
  429. resize_title(c);
  430. XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
  431. e.type = ConfigureNotify;
  432. e.event = c->win;
  433. e.window = c->win;
  434. e.x = c->x;
  435. e.y = c->y;
  436. e.width = c->w;
  437. e.height = c->h;
  438. e.border_width = c->border;
  439. e.above = None;
  440. e.override_redirect = False;
  441. XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
  442. XFlush(dpy);
  443. }
  444. static int
  445. dummy_error_handler(Display *dsply, XErrorEvent *err)
  446. {
  447. return 0;
  448. }
  449. void
  450. unmanage(Client *c)
  451. {
  452. Client **l;
  453. XGrabServer(dpy);
  454. XSetErrorHandler(dummy_error_handler);
  455. XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  456. XDestroyWindow(dpy, c->title);
  457. for(l = &clients; *l && *l != c; l = &(*l)->next);
  458. *l = c->next;
  459. for(l = &clients; *l; l = &(*l)->next)
  460. if((*l)->revert == c)
  461. (*l)->revert = NULL;
  462. if(sel == c)
  463. sel = sel->revert ? sel->revert : clients;
  464. free(c);
  465. XFlush(dpy);
  466. XSetErrorHandler(error_handler);
  467. XUngrabServer(dpy);
  468. arrange(NULL);
  469. if(sel)
  470. focus(sel);
  471. }
  472. Client *
  473. gettitle(Window w)
  474. {
  475. Client *c;
  476. for(c = clients; c; c = c->next)
  477. if(c->title == w)
  478. return c;
  479. return NULL;
  480. }
  481. Client *
  482. getclient(Window w)
  483. {
  484. Client *c;
  485. for(c = clients; c; c = c->next)
  486. if(c->win == w)
  487. return c;
  488. return NULL;
  489. }
  490. void
  491. draw_client(Client *c)
  492. {
  493. int i;
  494. if(c == sel)
  495. return;
  496. dc.x = dc.y = 0;
  497. dc.h = c->th;
  498. dc.w = 0;
  499. for(i = 0; i < TLast; i++) {
  500. if(c->tags[i]) {
  501. dc.x += dc.w;
  502. dc.w = textw(c->tags[i]) + dc.font.height;
  503. draw(True, c->tags[i]);
  504. }
  505. }
  506. dc.x += dc.w;
  507. dc.w = textw(c->name) + dc.font.height;
  508. draw(True, c->name);
  509. XCopyArea(dpy, dc.drawable, c->title, dc.gc,
  510. 0, 0, c->tw, c->th, 0, 0);
  511. XFlush(dpy);
  512. }