123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644 |
- /*
- * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
- * For license, see COPYING.
- */
- #include <string.h>
- #include <getopt.h>
- #include <signal.h>
- #include <sys/wait.h>
- #include <X11/keysym.h>
- #include <X11/cursorfont.h>
- #ifdef HAVE_IMLIB2
- #include <Imlib2.h>
- #endif /* HAVE_IMLIB2 */
- #include "wmfs.h"
- #include "event.h"
- #include "ewmh.h"
- #include "screen.h"
- #include "infobar.h"
- #include "util.h"
- #include "config.h"
- #include "client.h"
- #include "layout.h"
- #include "systray.h"
- int
- wmfs_error_handler(Display *d, XErrorEvent *event)
- {
- char mess[256];
- /* Check if there is another WM running */
- if(event->error_code == BadAccess
- && W->root == event->resourceid)
- errl(EXIT_FAILURE, "Another Window Manager is already running.");
- /* Ignore focus change error for unmapped client
- * 42 = X_SetInputFocus
- * 28 = X_GrabButton
- */
- if(client_gb_win(event->resourceid))
- if(event->error_code == BadWindow
- || event->request_code == 42
- || event->request_code == 28)
- return 0;
- if(XGetErrorText(d, event->error_code, mess, 128))
- warnxl("%s(%d) opcodes %d/%d\n resource #%lx\n",
- mess,
- event->error_code,
- event->request_code,
- event->minor_code,
- event->resourceid);
- return 1;
- }
- int
- wmfs_error_handler_dummy(Display *d, XErrorEvent *event)
- {
- (void)d;
- (void)event;
- return 0;
- }
- void
- wmfs_numlockmask(void)
- {
- int i, j;
- XModifierKeymap *mm = XGetModifierMapping(W->dpy);
- for(i = 0; i < 8; i++)
- for(j = 0; j < mm->max_keypermod; ++j)
- if(mm->modifiermap[i * mm->max_keypermod + j]
- == XKeysymToKeycode(W->dpy, XK_Num_Lock))
- W->numlockmask = (1 << i);
- XFreeModifiermap(mm);
- }
- void
- wmfs_init_font(char *font, struct theme *t)
- {
- XFontStruct **xfs = NULL;
- char **misschar, **names, *defstring;
- int d;
- if(!(t->font.fontset = XCreateFontSet(W->dpy, font, &misschar, &d, &defstring)))
- {
- warnxl("Can't load font '%s'", font);
- t->font.fontset = XCreateFontSet(W->dpy, "fixed", &misschar, &d, &defstring);
- }
- XExtentsOfFontSet(t->font.fontset);
- XFontsOfFontSet(t->font.fontset, &xfs, &names);
- t->font.as = xfs[0]->max_bounds.ascent;
- t->font.de = xfs[0]->max_bounds.descent;
- t->font.width = xfs[0]->max_bounds.width;
- t->font.height = t->font.as + t->font.de;
- if(misschar)
- XFreeStringList(misschar);
- }
- static void
- wmfs_xinit(void)
- {
- XGCValues xgc =
- {
- .function = GXinvert,
- .subwindow_mode = IncludeInferiors,
- .line_width = 1
- };
- XSetWindowAttributes at =
- {
- .event_mask = (KeyMask | ButtonMask | MouseMask
- | PropertyChangeMask | SubstructureRedirectMask
- | SubstructureNotifyMask | StructureNotifyMask),
- .cursor = XCreateFontCursor(W->dpy, XC_left_ptr)
- };
- /*
- * X Error handler
- */
- XSetErrorHandler(wmfs_error_handler);
- /*
- * X var
- */
- W->xscreen = DefaultScreen(W->dpy);
- W->xdepth = DefaultDepth(W->dpy, W->xscreen);
- W->gc = DefaultGC(W->dpy, W->xscreen);
- W->xmaxw = DisplayWidth(W->dpy, W->xscreen);
- W->xmaxh = DisplayHeight(W->dpy, W->xscreen);
- /*
- * Keys
- */
- wmfs_numlockmask();
- /*
- * Root window/cursor
- */
- W->root = RootWindow(W->dpy, W->xscreen);
- XChangeWindowAttributes(W->dpy, W->root, CWEventMask | CWCursor, &at);
- W->rgc = XCreateGC(W->dpy, W->root, GCFunction | GCSubwindowMode | GCLineWidth, &xgc);
- /*
- * Locale (font encode)
- */
- setlocale(LC_CTYPE, "");
- /*
- * Barwin linked list
- */
- SLIST_INIT(&W->h.barwin);
- SLIST_INIT(&W->h.vbarwin);
- /*
- * Optional dep init
- */
- #ifdef HAVE_IMLIB2
- imlib_context_set_display(W->dpy);
- imlib_context_set_visual(DefaultVisual(W->dpy, W->xscreen));
- imlib_context_set_colormap(DefaultColormap(W->dpy, W->xscreen));
- #endif /* HAVE_IMLIB2 */
- W->flags |= WMFS_RUNNING;
- }
- void
- wmfs_grab_keys(void)
- {
- KeyCode c;
- struct keybind *k;
- wmfs_numlockmask();
- XUngrabKey(W->dpy, AnyKey, AnyModifier, W->root);
- SLIST_FOREACH(k, &W->h.keybind, next)
- if((c = XKeysymToKeycode(W->dpy, k->keysym)))
- {
- XGrabKey(W->dpy, c, k->mod, W->root, True, GrabModeAsync, GrabModeAsync);
- XGrabKey(W->dpy, c, k->mod | LockMask, W->root, True, GrabModeAsync, GrabModeAsync);
- XGrabKey(W->dpy, c, k->mod | W->numlockmask, W->root, True, GrabModeAsync, GrabModeAsync);
- XGrabKey(W->dpy, c, k->mod | LockMask | W->numlockmask, W->root, True, GrabModeAsync, GrabModeAsync);
- }
- }
- /** Scan xprops of previous session to set it back
- * Check if there are windows on X (previous sessions windows)
- */
- static void
- wmfs_scan(void)
- {
- struct geo g;
- struct client *c, *cc, *fc;
- struct screen *s;
- int i, n, rf, nscreen = 0;
- int tag = -1, screen = -1, flags = -1;
- unsigned long ir, il;
- long *ret = NULL, *tret = NULL;
- bool getg = false;
- XWindowAttributes wa;
- Window usl, usl2, *w = NULL, tm, focus;
- Atom rt;
- SLIST_INIT(&W->h.client);
- W->flags |= WMFS_SCAN;
- /* Get previous selected tag to apply it at the end */
- if(XGetWindowProperty(W->dpy, W->root, W->net_atom[wmfs_current_tag], 0, 32,
- False, XA_CARDINAL, &rt, &rf, &ir, &il,
- (unsigned char**)&tret)
- == Success && tret)
- {
- nscreen = (int)ir;
- }
- /* Previous focused client before reload */
- if(XGetWindowProperty(W->dpy, W->root, W->net_atom[wmfs_focus], 0, 32,
- False, XA_WINDOW, &rt, &rf, &ir, &il,
- (unsigned char**)&ret)
- == Success && ret)
- {
- focus = *ret;
- XFree(ret);
- }
- if(XQueryTree(W->dpy, W->root, &usl, &usl2, &w, (unsigned int*)&n))
- for(i = n - 1; i != -1; --i)
- {
- XGetWindowAttributes(W->dpy, w[i], &wa);
- if(!wa.override_redirect && wa.map_state == IsViewable)
- {
- if(ewmh_get_xembed_state(w[i]))
- {
- systray_add(w[i]);
- continue;
- }
- if(ewmh_manage_window_type_desktop(w[i]))
- continue;
- if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_TAG"), 0, 32,
- False, XA_CARDINAL, &rt, &rf, &ir, &il,
- (unsigned char**)&ret)
- == Success && ret)
- {
- tag = *ret;
- XFree(ret);
- }
- if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_SCREEN"), 0, 32,
- False, XA_CARDINAL, &rt, &rf, &ir, &il,
- (unsigned char**)&ret)
- == Success && ret)
- {
- screen = *ret;
- XFree(ret);
- }
- if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_FLAGS"), 0, 32,
- False, XA_CARDINAL, &rt, &rf, &ir, &il,
- (unsigned char**)&ret)
- == Success && ret)
- {
- flags = *ret;
- flags &= ~(CLIENT_TABBED | CLIENT_REMOVEALL);
- XFree(ret);
- }
- if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_GEO"), 0, 32,
- False, XA_CARDINAL, &rt, &rf, &ir, &il,
- (unsigned char**)&ret)
- == Success && ret)
- {
- g.x = ret[0];
- g.y = ret[1];
- g.w = ret[2];
- g.h = ret[3];
- getg = true;
- XFree(ret);
- }
- if(XGetWindowProperty(W->dpy, w[i], ATOM("_WMFS_TABMASTER"), 0, 32,
- False, XA_WINDOW, &rt, &rf, &ir, &il,
- (unsigned char**)&ret)
- == Success && ret)
- {
- tm = *ret;
- XFree(ret);
- }
- c = client_new(w[i], &wa, true);
- if(tm != c->win)
- c->tmp = tm;
- tm = 0;
- if(flags != -1)
- c->flags |= flags;
- if(tag != -1 && screen != -1)
- {
- c->screen = screen_gb_id(screen);
- if(getg)
- c->flags |= CLIENT_IGNORE_LAYOUT;
- tag_client(tag_gb_id(c->screen, tag), c);
- if(getg && tag <= TAILQ_LAST(&c->screen->tags, tsub)->id - 1)
- client_moveresize(c, &g);
- /* In a removed tag */
- else
- {
- c->geo = g;
- layout_client(c);
- }
- client_get_name(c);
- }
- }
- }
- if(!nscreen)
- {
- SLIST_FOREACH(s, &W->h.screen, next)
- if(!TAILQ_EMPTY(&s->tags))
- tag_screen(s, TAILQ_FIRST(&s->tags));
- }
- else
- {
- /* Set back selected tag */
- for(i = 0; i < nscreen; ++i)
- {
- s = screen_gb_id(i);
- tag_screen(s, tag_gb_id(s, tret[i]));
- }
- }
- /* Re-adjust tabbed clients */
- SLIST_FOREACH(c, &W->h.client, next)
- if((cc = client_gb_win(c->tmp)) && cc != c)
- _client_tab(c, cc);
- if((fc = client_gb_win(focus)) && fc != W->client)
- client_focus(fc);
- SLIST_FOREACH(c, &W->h.client, next)
- if(c->flags & CLIENT_TILED)
- layout_fix_hole(c);
- W->flags &= ~WMFS_SCAN;
- if(tret)
- XFree(tret);
- XFree(w);
- XSync(W->dpy, false);
- }
- static inline void
- wmfs_sigchld(void)
- {
- if(W->flags & WMFS_SIGCHLD)
- {
- while(waitpid(-1, NULL, WNOHANG) > 0);
- W->flags ^= WMFS_SIGCHLD;
- }
- }
- static void
- wmfs_loop(void)
- {
- XEvent ev;
- while((W->flags & WMFS_RUNNING) && !XNextEvent(W->dpy, &ev))
- {
- /* Manage SIGCHLD event here, X is not safe with it */
- wmfs_sigchld();
- EVENT_HANDLE(&ev);
- }
- }
- static inline void
- wmfs_init(void)
- {
- log_init();
- wmfs_xinit();
- ewmh_init();
- screen_init();
- event_init();
- config_init();
- }
- void
- wmfs_quit(void)
- {
- struct keybind *k;
- struct rule *r;
- struct theme *t;
- struct client *c;
- struct mousebind *m;
- struct launcher *l;
- ewmh_update_wmfs_props();
- XFreeGC(W->dpy, W->rgc);
- while(!SLIST_EMPTY(&W->h.client))
- {
- c = SLIST_FIRST(&W->h.client);
- client_update_props(c, CPROP_LOC | CPROP_FLAG | CPROP_GEO);
- c->flags |= (CLIENT_IGNORE_LAYOUT | CLIENT_REMOVEALL);
- XMapWindow(W->dpy, c->win);
- client_remove(c);
- }
- /* Will free:
- *
- * Screens -> tags
- * -> Infobars -> Elements
- */
- screen_free();
- /* Conf stuffs */
- while(!SLIST_EMPTY(&W->h.theme))
- {
- t = SLIST_FIRST(&W->h.theme);
- SLIST_REMOVE_HEAD(&W->h.theme, next);
- XFreeFontSet(W->dpy, t->font.fontset);
- status_free_ctx(&t->tags_n_sl);
- status_free_ctx(&t->tags_s_sl);
- status_free_ctx(&t->tags_o_sl);
- status_free_ctx(&t->tags_u_sl);
- status_free_ctx(&t->client_n_sl);
- status_free_ctx(&t->client_s_sl);
- free(t);
- }
- while(!SLIST_EMPTY(&W->h.keybind))
- {
- k = SLIST_FIRST(&W->h.keybind);
- SLIST_REMOVE_HEAD(&W->h.keybind, next);
- free((void*)k->cmd);
- free(k);
- }
- while(!SLIST_EMPTY(&W->h.mousebind))
- {
- m = SLIST_FIRST(&W->h.mousebind);
- SLIST_REMOVE_HEAD(&W->h.mousebind, globnext);
- free((void*)m->cmd);
- free(m);
- }
- while(!SLIST_EMPTY(&W->h.launcher))
- {
- l = SLIST_FIRST(&W->h.launcher);
- SLIST_REMOVE_HEAD(&W->h.launcher, next);
- free((void*)l->name);
- free((void*)l->prompt);
- free((void*)l->command);
- free(l);
- }
- while(!SLIST_EMPTY(&W->h.rule))
- {
- r = SLIST_FIRST(&W->h.rule);
- SLIST_REMOVE_HEAD(&W->h.rule, next);
- free(r->class);
- free(r->instance);
- free(r->role);
- free(r->name);
- free(r);
- }
- /* close log */
- if(W->log)
- fclose(W->log), W->log = NULL;
- W->flags &= ~WMFS_RUNNING;
- }
- /** Reload WMFS binary
- */
- void
- uicb_reload(Uicb cmd)
- {
- (void)cmd;
- W->flags &= ~WMFS_RUNNING;
- W->flags |= WMFS_RELOAD;
- }
- void
- uicb_quit(Uicb cmd)
- {
- (void)cmd;
- W->flags &= ~WMFS_RUNNING;
- }
- static void
- exec_uicb_function(Display *dpy, Window root, char *func, char *cmd)
- {
- Atom utf8s = XInternAtom(dpy, "UTF8_STRING", false);
- XClientMessageEvent e = {
- .type = ClientMessage,
- .message_type = XInternAtom(dpy, "_WMFS_FUNCTION", false),
- .window = root,
- .format = 32,
- .data.l[4] = true
- };
- XChangeProperty(dpy,root, XInternAtom(dpy, "_WMFS_FUNCTION", false), utf8s,
- 8, PropModeReplace, (unsigned char*)func, strlen(func));
- if(!cmd)
- cmd = "";
- XChangeProperty(dpy, root, XInternAtom(dpy, "_WMFS_CMD", false), utf8s,
- 8, PropModeReplace, (unsigned char*)cmd, strlen(cmd));
- XSendEvent(dpy, root, false, StructureNotifyMask, (XEvent*)&e);
- XSync(dpy, False);
- }
- static void
- signal_handle(int sig)
- {
- switch (sig)
- {
- case SIGQUIT:
- case SIGTERM:
- W->flags &= ~WMFS_RUNNING;
- break;
- case SIGCHLD:
- W->flags |= WMFS_SIGCHLD;
- break;
- }
- }
- int
- main(int argc, char **argv)
- {
- int i;
- bool r;
- Display *dpy;
- char path[MAX_PATH_LEN] = { 0 };
- struct sigaction sa;
- (void)argc;
- sprintf(path, "%s/"CONFIG_DEFAULT_PATH, getenv("HOME"));
- /* Opt */
- while((i = getopt(argc, argv, "hvC:c:")) != -1)
- {
- switch(i)
- {
- default:
- case 'h':
- printf("usage: %s [-hv] [-c <func> <cmd] [-C <file>]\n"
- " -h Show this page\n"
- " -v Show WMFS version\n"
- " -c <func> <cmd> Execute a specified UICB function\n"
- " -C <file> Launch WMFS with a specified configuration file\n", argv[0]);
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- printf("wmfs("WMFS_VERSION") 2 beta\n");
- exit(EXIT_SUCCESS);
- break;
- case 'c':
- if(!(dpy = XOpenDisplay(NULL)))
- {
- fprintf(stderr, "%s: Can't open X server\n", argv[0]);
- exit(EXIT_FAILURE);
- }
- exec_uicb_function(dpy, DefaultRootWindow(dpy), optarg, argv[optind]);
- XCloseDisplay(dpy);
- exit(EXIT_SUCCESS);
- break;
- case 'C':
- strncpy(path, optarg, MAX_PATH_LEN);
- break;
- }
- }
- W = (struct wmfs*)xcalloc(1, sizeof(struct wmfs));
- /* Default path ~/.config/wmfs/wmfsrc */
- W->confpath = path;
- /* Get X display */
- if(!(W->dpy = XOpenDisplay(NULL)))
- {
- fprintf(stderr, "%s: Can't open X server\n", argv[0]);
- exit(EXIT_FAILURE);
- }
- /* Set signal handler */
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = signal_handle;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGQUIT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGCHLD, &sa, NULL);
- /* Core */
- wmfs_init();
- wmfs_scan();
- wmfs_loop();
- wmfs_quit();
- r = (W->flags & WMFS_RELOAD);
- free(W);
- if(r)
- execvp(argv[0], argv);
- XCloseDisplay(W->dpy);
- return 1;
- }
|