wmfs.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*
  2. * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
  3. * For license, see COPYING.
  4. */
  5. #include <getopt.h>
  6. #include <X11/keysym.h>
  7. #include <X11/cursorfont.h>
  8. #include "wmfs.h"
  9. #include "event.h"
  10. #include "ewmh.h"
  11. #include "screen.h"
  12. #include "infobar.h"
  13. #include "util.h"
  14. #include "config.h"
  15. #include "client.h"
  16. #include "fifo.h"
  17. int
  18. wmfs_error_handler(Display *d, XErrorEvent *event)
  19. {
  20. char mess[256];
  21. /* Check if there is another WM running */
  22. if(event->error_code == BadAccess
  23. && W->root == event->resourceid)
  24. errx(EXIT_FAILURE, "Another Window Manager is already running.");
  25. /* Ignore focus change error for unmapped client
  26. * 42 = X_SetInputFocus
  27. * 28 = X_GrabButton
  28. */
  29. if(client_gb_win(event->resourceid))
  30. if(event->error_code == BadWindow
  31. || event->request_code == 42
  32. || event->request_code == 28)
  33. return 0;
  34. if(XGetErrorText(d, event->error_code, mess, 128))
  35. warnx("%s(%d) opcodes %d/%d\n resource #%lx\n",
  36. mess,
  37. event->error_code,
  38. event->request_code,
  39. event->minor_code,
  40. event->resourceid);
  41. return 1;
  42. }
  43. int
  44. wmfs_error_handler_dummy(Display *d, XErrorEvent *event)
  45. {
  46. (void)d;
  47. (void)event;
  48. return 0;
  49. }
  50. void
  51. wmfs_numlockmask(void)
  52. {
  53. int i, j;
  54. XModifierKeymap *mm = XGetModifierMapping(W->dpy);
  55. for(i = 0; i < 8; i++)
  56. for(j = 0; j < mm->max_keypermod; ++j)
  57. if(mm->modifiermap[i * mm->max_keypermod + j]
  58. == XKeysymToKeycode(W->dpy, XK_Num_Lock))
  59. W->numlockmask = (1 << i);
  60. XFreeModifiermap(mm);
  61. }
  62. void
  63. wmfs_init_font(char *font, struct theme *t)
  64. {
  65. XFontStruct **xfs = NULL;
  66. char **misschar, **names, *defstring;
  67. int d;
  68. if(!(t->font.fontset = XCreateFontSet(W->dpy, font, &misschar, &d, &defstring)))
  69. {
  70. warnx("Can't load font '%s'", font);
  71. t->font.fontset = XCreateFontSet(W->dpy, "fixed", &misschar, &d, &defstring);
  72. }
  73. XExtentsOfFontSet(t->font.fontset);
  74. XFontsOfFontSet(t->font.fontset, &xfs, &names);
  75. t->font.as = xfs[0]->max_bounds.ascent;
  76. t->font.de = xfs[0]->max_bounds.descent;
  77. t->font.width = xfs[0]->max_bounds.width;
  78. t->font.height = t->font.as + t->font.de;
  79. if(misschar)
  80. XFreeStringList(misschar);
  81. }
  82. static void
  83. wmfs_xinit(void)
  84. {
  85. XGCValues xgc =
  86. {
  87. .function = GXinvert,
  88. .subwindow_mode = IncludeInferiors,
  89. .line_width = 1
  90. };
  91. XSetWindowAttributes at =
  92. {
  93. .event_mask = (KeyMask | ButtonMask | MouseMask
  94. | PropertyChangeMask | SubstructureRedirectMask
  95. | SubstructureNotifyMask | StructureNotifyMask),
  96. .cursor = XCreateFontCursor(W->dpy, XC_left_ptr)
  97. };
  98. /*
  99. * X Error handler
  100. */
  101. XSetErrorHandler(wmfs_error_handler);
  102. /*
  103. * X var
  104. */
  105. W->xscreen = DefaultScreen(W->dpy);
  106. W->xdepth = DefaultDepth(W->dpy, W->xscreen);
  107. W->gc = DefaultGC(W->dpy, W->xscreen);
  108. /*
  109. * Keys
  110. */
  111. wmfs_numlockmask();
  112. /*
  113. * Root window/cursor
  114. */
  115. W->root = RootWindow(W->dpy, W->xscreen);
  116. XChangeWindowAttributes(W->dpy, W->root, CWEventMask | CWCursor, &at);
  117. W->rgc = XCreateGC(W->dpy, W->root, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
  118. /*
  119. * Locale (font encode)
  120. */
  121. setlocale(LC_CTYPE, "");
  122. /*
  123. * Barwin linked list
  124. */
  125. SLIST_INIT(&W->h.barwin);
  126. W->running = true;
  127. }
  128. void
  129. wmfs_grab_keys(void)
  130. {
  131. KeyCode c;
  132. struct keybind *k;
  133. wmfs_numlockmask();
  134. XUngrabKey(W->dpy, AnyKey, AnyModifier, W->root);
  135. SLIST_FOREACH(k, &W->h.keybind, next)
  136. if((c = XKeysymToKeycode(W->dpy, k->keysym)))
  137. {
  138. XGrabKey(W->dpy, c, k->mod, W->root, True, GrabModeAsync, GrabModeAsync);
  139. XGrabKey(W->dpy, c, k->mod | LockMask, W->root, True, GrabModeAsync, GrabModeAsync);
  140. XGrabKey(W->dpy, c, k->mod | W->numlockmask, W->root, True, GrabModeAsync, GrabModeAsync);
  141. XGrabKey(W->dpy, c, k->mod | LockMask | W->numlockmask, W->root, True, GrabModeAsync, GrabModeAsync);
  142. }
  143. }
  144. /** Scan if there are windows on X
  145. * for manage it
  146. */
  147. static void
  148. wmfs_scan(void)
  149. {
  150. int i, n;
  151. XWindowAttributes wa;
  152. Window usl, usl2, *w = NULL;
  153. SLIST_INIT(&W->h.client);
  154. /*
  155. Atom rt;
  156. int s, rf, tag = -1, screen = -1, flags = -1, i;
  157. ulong ir, il;
  158. uchar *ret;
  159. */
  160. if(XQueryTree(W->dpy, W->root, &usl, &usl2, &w, (unsigned int*)&n))
  161. for(i = n - 1; i != -1; --i)
  162. {
  163. XGetWindowAttributes(W->dpy, w[i], &wa);
  164. if(!wa.override_redirect && wa.map_state == IsViewable)
  165. {/*
  166. if(XGetWindowProperty(dpy, w[i], ATOM("_WMFS_TAG"), 0, 32,
  167. False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret) == Success && ret)
  168. {
  169. tag = *ret;
  170. XFree(ret);
  171. }
  172. if(XGetWindowProperty(dpy, w[i], ATOM("_WMFS_SCREEN"), 0, 32,
  173. False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret) == Success && ret)
  174. {
  175. screen = *ret;
  176. XFree(ret);
  177. }
  178. if(XGetWindowProperty(dpy, w[i], ATOM("_WMFS_FLAGS"), 0, 32,
  179. False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret) == Success && ret)
  180. {
  181. flags = *ret;
  182. XFree(ret);
  183. }
  184. */
  185. /*c = */ client_new(w[i], &wa);
  186. /*
  187. if(tag != -1)
  188. c->tag = tag;
  189. if(screen != -1)
  190. c->screen = screen;
  191. if(flags != -1)
  192. c->flags = flags;
  193. */
  194. }
  195. }
  196. XFree(w);
  197. }
  198. static void
  199. wmfs_loop(void)
  200. {
  201. XEvent ev;
  202. int fd = ConnectionNumber(W->dpy);
  203. fd_set iset;
  204. while(W->running)
  205. {
  206. int maxfd = fd + 1;
  207. FD_ZERO(&iset);
  208. FD_SET(fd, &iset);
  209. if(W->fifo.fd > 0)
  210. {
  211. maxfd += W->fifo.fd;
  212. FD_SET(W->fifo.fd, &iset);
  213. }
  214. if(select(maxfd, &iset, NULL, NULL, NULL) > 0)
  215. {
  216. if(FD_ISSET(fd, &iset))
  217. {
  218. while(W->running && XPending(W->dpy))
  219. {
  220. XNextEvent(W->dpy, &ev);
  221. EVENT_HANDLE(&ev);
  222. }
  223. }
  224. else if(W->fifo.fd > 0 && FD_ISSET(W->fifo.fd, &iset))
  225. {
  226. if(fifo_read() == 0)
  227. {
  228. close(W->fifo.fd);
  229. if(!(W->fifo.fd = open(W->fifo.path, O_RDONLY | O_NDELAY, 0)))
  230. warnx("Can't reopen FIFO: %s\n", strerror(errno));
  231. }
  232. }
  233. }
  234. }
  235. }
  236. static inline void
  237. wmfs_init(void)
  238. {
  239. wmfs_xinit();
  240. ewmh_init();
  241. screen_init();
  242. event_init();
  243. config_init();
  244. fifo_init();
  245. }
  246. void
  247. wmfs_quit(void)
  248. {
  249. struct keybind *k;
  250. struct theme *t;
  251. struct client *c;
  252. /* Will free:
  253. *
  254. * Screens -> tags
  255. * -> Infobars -> Elements
  256. */
  257. screen_free();
  258. XFreeGC(W->dpy, W->rgc);
  259. while(!SLIST_EMPTY(&W->h.client))
  260. {
  261. c = SLIST_FIRST(&W->h.client);
  262. client_remove(c);
  263. }
  264. /* Conf stuffs */
  265. while(!SLIST_EMPTY(&W->h.theme))
  266. {
  267. t = SLIST_FIRST(&W->h.theme);
  268. SLIST_REMOVE_HEAD(&W->h.theme, next);
  269. XFreeFontSet(W->dpy, t->font.fontset);
  270. free(t);
  271. }
  272. while(!SLIST_EMPTY(&W->h.keybind))
  273. {
  274. k = SLIST_FIRST(&W->h.keybind);
  275. SLIST_REMOVE_HEAD(&W->h.keybind, next);
  276. free((void*)k->cmd);
  277. free(k);
  278. }
  279. /* FIFO stuffs */
  280. if(W->fifo.fd > 0)
  281. {
  282. close(W->fifo.fd);
  283. unlink(W->fifo.path);
  284. }
  285. W->running = false;
  286. XCloseDisplay(W->dpy);
  287. }
  288. /** Reload WMFS binary
  289. */
  290. void
  291. uicb_reload(Uicb cmd)
  292. {
  293. (void)cmd;
  294. W->running = false;
  295. W->reload = true;
  296. }
  297. void
  298. uicb_quit(Uicb cmd)
  299. {
  300. (void)cmd;
  301. W->running = false;
  302. }
  303. int
  304. main(int argc, char **argv)
  305. {
  306. bool r;
  307. W = (struct wmfs*)xcalloc(1, sizeof(struct wmfs));
  308. /* Get X display */
  309. if(!(W->dpy = XOpenDisplay(NULL)))
  310. {
  311. fprintf(stderr, "%s: Can't open X server\n", argv[0]);
  312. exit(EXIT_FAILURE);
  313. }
  314. /* Opt */
  315. /*
  316. int i;
  317. while((i = getopt(argc, argv, "hviC:")) != -1)
  318. {
  319. switch(i)
  320. {
  321. case 'h':
  322. break;
  323. case 'v':
  324. break;
  325. case 'C':
  326. break;
  327. }
  328. }
  329. */
  330. /* Core */
  331. wmfs_init();
  332. wmfs_scan();
  333. wmfs_loop();
  334. wmfs_quit();
  335. r = W->reload;
  336. free(W);
  337. if(r)
  338. execvp(argv[0], argv);
  339. return 1;
  340. }