diff options
Diffstat (limited to 'calmwm.c')
-rw-r--r-- | calmwm.c | 476 |
1 files changed, 189 insertions, 287 deletions
diff --git a/calmwm.c b/calmwm.c index ab0142e..3601d6c 100644 --- a/calmwm.c +++ b/calmwm.c @@ -2,344 +2,246 @@ * calmwm - the calm window manager * * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org> - * All rights reserved. * - * $Id$ + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD$ */ -#include "headers.h" +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/wait.h> + +#include <err.h> +#include <errno.h> +#include <getopt.h> +#include <limits.h> +#include <locale.h> +#include <poll.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + #include "calmwm.h" -Display *G_dpy; -XFontStruct *G_font; - -Cursor G_cursor_move; -Cursor G_cursor_resize; -Cursor G_cursor_select; -Cursor G_cursor_default; -Cursor G_cursor_question; - -struct screen_ctx_q G_screenq; -struct screen_ctx *G_curscreen; -u_int G_nscreens; - -struct client_ctx_q G_clientq; - -int G_doshape, G_shape_ev; -int G_starting; -struct conf G_conf; -struct fontdesc *DefaultFont; -char *DefaultFontName; - -/* From TWM */ -#define gray_width 2 -#define gray_height 2 -static char gray_bits[] = {0x02, 0x01}; - -/* List borrowed from 9wm/rio */ -char *tryfonts[] = { - "9x15bold", - "blit", - "*-lucidatypewriter-bold-*-14-*-75-*", - "*-lucidatypewriter-medium-*-12-*-75-*", - "fixed", - "*", - NULL, -}; - -static void _sigchld_cb(int); +Display *X_Dpy; +Time Last_Event_Time = CurrentTime; +Atom cwmh[CWMH_NITEMS]; +Atom ewmh[EWMH_NITEMS]; +struct screen_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq); +struct conf Conf; +volatile sig_atomic_t cwm_status; + +static void sighdlr(int); +static int x_errorhandler(Display *, XErrorEvent *); +static int x_init(const char *); +static void x_teardown(void); +static int x_wmerrorhandler(Display *, XErrorEvent *); int main(int argc, char **argv) { - int ch; - int conf_flags = 0; - - DefaultFontName = "sans-serif:pixelsize=14:bold"; - - while ((ch = getopt(argc, argv, "sf:")) != -1) { + const char *conf_file = NULL; + char *conf_path, *display_name = NULL; + char *fallback; + int ch, xfd; + struct pollfd pfd[1]; + struct passwd *pw; + + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + warnx("no locale support"); + mbtowc(NULL, NULL, MB_CUR_MAX); + + fallback = u_argv(argv); + Conf.wm_argv = u_argv(argv); + while ((ch = getopt(argc, argv, "c:d:")) != -1) { switch (ch) { - case 's': - conf_flags |= CONF_STICKY_GROUPS; + case 'c': + conf_file = optarg; break; - case 'f': - DefaultFontName = xstrdup(optarg); + case 'd': + display_name = optarg; break; default: - errx(1, "Unknown option '%c'", ch); + usage(); } } + argc -= optind; + argv += optind; + + if (signal(SIGCHLD, sighdlr) == SIG_ERR) + err(1, "signal"); + if (signal(SIGHUP, sighdlr) == SIG_ERR) + err(1, "signal"); + + Conf.homedir = getenv("HOME"); + if ((Conf.homedir == NULL) || (Conf.homedir[0] == '\0')) { + pw = getpwuid(getuid()); + if (pw != NULL && pw->pw_dir != NULL && *pw->pw_dir != '\0') + Conf.homedir = pw->pw_dir; + else + Conf.homedir = "/"; + } - /* Ignore a few signals. */ - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) - err(1, "signal"); - - if (signal(SIGCHLD, _sigchld_cb) == SIG_ERR) - err(1, "signal"); - - group_init(); - - G_starting = 1; - conf_setup(&G_conf); - G_conf.flags |= conf_flags; - client_setup(); - x_setup(); - G_starting = 0; - - xev_init(); - XEV_QUICK(NULL, NULL, MapRequest, xev_handle_maprequest, NULL); - XEV_QUICK(NULL, NULL, UnmapNotify, xev_handle_unmapnotify, NULL); - XEV_QUICK(NULL, NULL, ConfigureRequest, - xev_handle_configurerequest, NULL); - XEV_QUICK(NULL, NULL, PropertyNotify, xev_handle_propertynotify, NULL); - XEV_QUICK(NULL, NULL, EnterNotify, xev_handle_enternotify, NULL); - XEV_QUICK(NULL, NULL, LeaveNotify, xev_handle_leavenotify, NULL); - XEV_QUICK(NULL, NULL, ButtonPress, xev_handle_buttonpress, NULL); - XEV_QUICK(NULL, NULL, ButtonRelease, xev_handle_buttonrelease, NULL); - XEV_QUICK(NULL, NULL, KeyPress, xev_handle_keypress, NULL); - XEV_QUICK(NULL, NULL, KeyRelease, xev_handle_keyrelease, NULL); - XEV_QUICK(NULL, NULL, Expose, xev_handle_expose, NULL); - XEV_QUICK(NULL, NULL, DestroyNotify, xev_handle_destroynotify, NULL); - XEV_QUICK(NULL, NULL, ClientMessage, xev_handle_clientmessage, NULL); - - xev_loop(); - - return (0); -} + if (conf_file == NULL) + xasprintf(&conf_path, "%s/%s", Conf.homedir, CONFFILE); + else + conf_path = xstrdup(conf_file); -void -x_setup(void) -{ - int i; - struct screen_ctx *sc; - char *fontname; + if (access(conf_path, R_OK) != 0) { + if (conf_file != NULL) + warn("%s", conf_file); + free(conf_path); + conf_path = NULL; + } - TAILQ_INIT(&G_screenq); + conf_init(&Conf); - if ((G_dpy = XOpenDisplay("")) == NULL) - errx(1, "%s:%d XOpenDisplay()", __FILE__, __LINE__); + if (conf_path && (parse_config(conf_path, &Conf) == -1)) + warnx("config file %s has errors", conf_path); + free(conf_path); - XSetErrorHandler(x_errorhandler); + xfd = x_init(display_name); + cwm_status = CWM_RUNNING; - G_doshape = XShapeQueryExtension(G_dpy, &G_shape_ev, &i); + if (pledge("stdio rpath proc exec", NULL) == -1) + err(1, "pledge"); - i = 0; - while ((fontname = tryfonts[i++]) != NULL) { - if ((G_font = XLoadQueryFont(G_dpy, fontname)) != NULL) - break; + memset(&pfd, 0, sizeof(pfd)); + pfd[0].fd = xfd; + pfd[0].events = POLLIN; + while (cwm_status == CWM_RUNNING) { + xev_process(); + if (poll(pfd, 1, INFTIM) == -1) { + if (errno != EINTR) + warn("poll"); + } } + x_teardown(); + if (cwm_status == CWM_EXEC_WM) + u_exec(Conf.wm_argv); - if (fontname == NULL) - errx(1, "Couldn't load any fonts."); + warnx("'%s' failed to start, restarting fallback", Conf.wm_argv); + u_exec(fallback); - G_nscreens = ScreenCount(G_dpy); - for (i = 0; i < (int)G_nscreens; i++) { - XMALLOC(sc, struct screen_ctx); - x_setupscreen(sc, i); - TAILQ_INSERT_TAIL(&G_screenq, sc, entry); - } - - G_cursor_move = XCreateFontCursor(G_dpy, XC_fleur); - G_cursor_resize = XCreateFontCursor(G_dpy, XC_bottom_right_corner); - /* (used to be) XCreateFontCursor(G_dpy, XC_hand1); */ - G_cursor_select = XCreateFontCursor(G_dpy, XC_hand1); -/* G_cursor_select = cursor_bigarrow(G_curscreen); */ - G_cursor_default = XCreateFontCursor(G_dpy, XC_X_cursor); -/* G_cursor_default = cursor_bigarrow(G_curscreen); */ - G_cursor_question = XCreateFontCursor(G_dpy, XC_question_arrow); + return(0); } -int -x_setupscreen(struct screen_ctx *sc, u_int which) +static int +x_init(const char *dpyname) { - XColor tmp; - XGCValues gv, gv1/* , gv2 */; - Window *wins, w0, w1; - u_int nwins, i = 0; - XWindowAttributes winattr; - XSetWindowAttributes rootattr; - struct keybinding *kb; - - sc->display = x_screenname(which); - sc->which = which; - sc->rootwin = RootWindow(G_dpy, which); - XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which), - "black", &sc->fgcolor, &tmp); - XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which), - "#00cc00", &sc->bgcolor, &tmp); - XAllocNamedColor(G_dpy,DefaultColormap(G_dpy, which), - "blue", &sc->fccolor, &tmp); - XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which), - "red", &sc->redcolor, &tmp); - XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which), - "#00ccc8", &sc->cyancolor, &tmp); - XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which), - "white", &sc->whitecolor, &tmp); - XAllocNamedColor(G_dpy, DefaultColormap(G_dpy, which), - "black", &sc->blackcolor, &tmp); - - TAILQ_FOREACH(kb, &G_conf.keybindingq, entry) - xu_key_grab(sc->rootwin, kb->modmask, kb->keysym); - - /* Special -- for alt state. */ -/* xu_key_grab(sc->rootwin, 0, XK_Alt_L); */ -/* xu_key_grab(sc->rootwin, 0, XK_Alt_R); */ - - sc->blackpixl = BlackPixel(G_dpy, sc->which); - sc->whitepixl = WhitePixel(G_dpy, sc->which); - sc->bluepixl = sc->fccolor.pixel; - sc->redpixl = sc->redcolor.pixel; - sc->cyanpixl = sc->cyancolor.pixel; - - sc->gray = XCreatePixmapFromBitmapData(G_dpy, sc->rootwin, - gray_bits, gray_width, gray_height, - sc->blackpixl, sc->whitepixl, DefaultDepth(G_dpy, sc->which)); - - sc->blue = XCreatePixmapFromBitmapData(G_dpy, sc->rootwin, - gray_bits, gray_width, gray_height, - sc->bluepixl, sc->whitepixl, DefaultDepth(G_dpy, sc->which)); - - sc->red = XCreatePixmapFromBitmapData(G_dpy, sc->rootwin, - gray_bits, gray_width, gray_height, - sc->redpixl, sc->whitepixl, DefaultDepth(G_dpy, sc->which)); - - gv.foreground = sc->blackpixl^sc->whitepixl; - gv.background = sc->whitepixl; - gv.function = GXxor; - gv.line_width = 1; - gv.subwindow_mode = IncludeInferiors; - gv.font = G_font->fid; - - sc->gc = XCreateGC(G_dpy, sc->rootwin, - GCForeground|GCBackground|GCFunction| - GCLineWidth|GCSubwindowMode|GCFont, &gv); - -#ifdef notyet - gv2.foreground = sc->blackpixl^sc->cyanpixl; - gv2.background = sc->cyanpixl; - gv2.function = GXxor; - gv2.line_width = 1; - gv2.subwindow_mode = IncludeInferiors; - gv2.font = G_font->fid; -#endif - - sc->hlgc = XCreateGC(G_dpy, sc->rootwin, - GCForeground|GCBackground|GCFunction| - GCLineWidth|GCSubwindowMode|GCFont, &gv); - - gv1.function = GXinvert; - gv1.subwindow_mode = IncludeInferiors; - gv1.line_width = 1; - gv1.font = G_font->fid; - - sc->invgc = XCreateGC(G_dpy, sc->rootwin, - GCFunction|GCSubwindowMode|GCLineWidth|GCFont, &gv1); - - font_init(sc); - DefaultFont = font_getx(sc, DefaultFontName); - - /* - * XXX - this should *really* be in screen_init(). ordering - * problem. - */ - TAILQ_INIT(&sc->mruq); - - /* Initialize menu window. */ - grab_menuinit(sc); - search_init(sc); - - /* Deal with existing clients. */ - XQueryTree(G_dpy, sc->rootwin, &w0, &w1, &wins, &nwins); - - for (i = 0; i < nwins; i++) { - XGetWindowAttributes(G_dpy, wins[i], &winattr); - if (winattr.override_redirect || - winattr.map_state != IsViewable) { - char *name; - XFetchName(G_dpy, wins[i], &name); - continue; - } - client_new(wins[i], sc, winattr.map_state != IsUnmapped); - } - XFree(wins); + int i; - G_curscreen = sc; /* XXX */ - screen_init(); - screen_updatestackingorder(); + if ((X_Dpy = XOpenDisplay(dpyname)) == NULL) + errx(1, "unable to open display \"%s\"", XDisplayName(dpyname)); - rootattr.event_mask = ChildMask|PropertyChangeMask|EnterWindowMask| - LeaveWindowMask|ColormapChangeMask|ButtonMask; + XSetErrorHandler(x_wmerrorhandler); + XSelectInput(X_Dpy, DefaultRootWindow(X_Dpy), SubstructureRedirectMask); + XSync(X_Dpy, False); + XSetErrorHandler(x_errorhandler); - /* Set the root cursor to a nice obnoxious arrow :-) */ -/* rootattr.cursor = cursor_bigarrow(sc); */ + Conf.xrandr = XRRQueryExtension(X_Dpy, &Conf.xrandr_event_base, &i); - XChangeWindowAttributes(G_dpy, sc->rootwin, - /* CWCursor| */CWEventMask, &rootattr); + conf_atoms(); + conf_cursor(&Conf); - XSync(G_dpy, False); + for (i = 0; i < ScreenCount(X_Dpy); i++) + screen_init(i); - return (0); + return ConnectionNumber(X_Dpy); } -char * -x_screenname(int which) +static void +x_teardown(void) { - char *cp, *dstr, *sn; - size_t snlen; - - if (which > 9) - errx(1, "Can't handle more than 9 screens. If you need it, " - "tell <marius@monkey.org>. It's a trivial fix."); - - dstr = xstrdup(DisplayString(G_dpy)); - - if ((cp = rindex(dstr, ':')) == NULL) - return (NULL); - - if ((cp = index(cp, '.')) != NULL) - *cp = '\0'; + struct screen_ctx *sc; + unsigned int i; + + conf_clear(&Conf); + + TAILQ_FOREACH(sc, &Screenq, entry) { + for (i = 0; i < CWM_COLOR_NITEMS; i++) + XftColorFree(X_Dpy, DefaultVisual(X_Dpy, sc->which), + DefaultColormap(X_Dpy, sc->which), + &sc->xftcolor[i]); + XftFontClose(X_Dpy, sc->xftfont); + XftDrawDestroy(sc->menu.xftdraw); + XDestroyWindow(X_Dpy, sc->menu.win); + XUngrabKey(X_Dpy, AnyKey, AnyModifier, sc->rootwin); + } + XUngrabPointer(X_Dpy, CurrentTime); + XUngrabKeyboard(X_Dpy, CurrentTime); + for (i = 0; i < CF_NITEMS; i++) + XFreeCursor(X_Dpy, Conf.cursor[i]); + XSync(X_Dpy, False); + XSetInputFocus(X_Dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XCloseDisplay(X_Dpy); +} - snlen = strlen(dstr) + 3; /* string, dot, number, null */ - sn = (char *)xmalloc(snlen); - snprintf(sn, snlen, "%s.%d", dstr, which); - free(dstr); +static int +x_wmerrorhandler(Display *dpy, XErrorEvent *e) +{ + errx(1, "root window unavailable - perhaps another wm is running?"); - return (sn); + return(0); } -int +static int x_errorhandler(Display *dpy, XErrorEvent *e) { #ifdef DEBUG - { - char msg[80], number[80], req[80]; + char msg[80], number[80], req[80]; - XGetErrorText(G_dpy, e->error_code, msg, sizeof(msg)); - snprintf(number, sizeof(number), "%d", e->request_code); - XGetErrorDatabaseText(G_dpy, "XRequest", number, - "<unknown>", req, sizeof(req)); + XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg)); + (void)snprintf(number, sizeof(number), "%d", e->request_code); + XGetErrorDatabaseText(X_Dpy, "XRequest", number, + "<unknown>", req, sizeof(req)); - warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg); - } + warnx("%s(0x%x): %s", req, (unsigned int)e->resourceid, msg); #endif + return(0); +} - if (G_starting && - e->error_code == BadAccess && - e->request_code == X_GrabKey) - errx(1, "root window unavailable - perhaps another " - "wm is running?"); +static void +sighdlr(int sig) +{ + pid_t pid; + int save_errno = errno, status; + + switch (sig) { + case SIGCHLD: + /* Collect dead children. */ + while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0 || + (pid < 0 && errno == EINTR)) + ; + break; + case SIGHUP: + cwm_status = CWM_EXEC_WM; + break; + } - return (0); + errno = save_errno; } -static void -_sigchld_cb(int which) +__dead void +usage(void) { - pid_t pid; - int status; + extern char *__progname; -/* Collect dead children. */ - while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || - (pid < 0 && errno == EINTR)) - ; + (void)fprintf(stderr, "usage: %s [-c file] [-d display]\n", + __progname); + exit(1); } |