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.

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