diff --git a/Makefile b/Makefile index 58a27f4..e0abfac 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,11 @@ PREFIX= /usr/local SRCS= calmwm.c screen.c xmalloc.c client.c menu.c \ search.c util.c xutil.c conf.c xevents.c group.c \ - kbfunc.c mousefunc.c font.c parse.y + kbfunc.c mousefunc.c parse.y OBJS= calmwm.o screen.o xmalloc.o client.o menu.o \ search.o util.o xutil.o conf.o xevents.o group.o \ - kbfunc.o mousefunc.o font.o strlcpy.o strlcat.o y.tab.o \ + kbfunc.o mousefunc.o strlcpy.o strlcat.o y.tab.o \ strtonum.o fgetln.o CPPFLAGS+= `pkg-config --cflags fontconfig x11 xft xinerama xrandr` diff --git a/calmwm.c b/calmwm.c index 237071b..1ee349e 100644 --- a/calmwm.c +++ b/calmwm.c @@ -144,7 +144,6 @@ dpy_init(const char *dpyname) static void x_setup(void) { - struct keybinding *kb; int i; Cursor_default = XCreateFontCursor(X_Dpy, XC_X_cursor); @@ -155,13 +154,6 @@ x_setup(void) for (i = 0; i < ScreenCount(X_Dpy); i++) screen_init(i); - - /* - * XXX key grabs weren't done before, since Screenq was empty, - * do them here for now (this needs changing). - */ - TAILQ_FOREACH(kb, &Conf.keybindingq, entry) - conf_grab(&Conf, kb); } static void @@ -181,7 +173,7 @@ x_wmerrorhandler(Display *dpy, XErrorEvent *e) static int x_errorhandler(Display *dpy, XErrorEvent *e) { -#if DEBUG +#ifdef DEBUG char msg[80], number[80], req[80]; XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg)); diff --git a/calmwm.h b/calmwm.h index c08f6a5..d5119b1 100644 --- a/calmwm.h +++ b/calmwm.h @@ -97,20 +97,16 @@ union arg { int i; }; -enum menucolor { - CWM_COLOR_MENU_FG, - CWM_COLOR_MENU_BG, - CWM_COLOR_MENU_FONT, - CWM_COLOR_MENU_FONT_SEL, - CWM_COLOR_MENU_MAX -}; - -enum bordercolor { +enum color { CWM_COLOR_BORDER_ACTIVE, CWM_COLOR_BORDER_INACTIVE, CWM_COLOR_BORDER_GROUP, CWM_COLOR_BORDER_UNGROUP, - CWM_COLOR_BORDER_MAX + CWM_COLOR_MENU_FG, + CWM_COLOR_MENU_BG, + CWM_COLOR_MENU_FONT, + CWM_COLOR_MENU_FONT_SEL, + CWM_COLOR_MAX }; struct geom { @@ -133,6 +129,11 @@ struct winname { }; TAILQ_HEAD(winname_q, winname); +enum wm_protocols { + _WM_DELETE_WINDOW = 0x0001, + _WM_TAKE_FOCUS = 0x0002, +}; + struct client_ctx { TAILQ_ENTRY(client_ctx) entry; TAILQ_ENTRY(client_ctx) group_entry; @@ -159,9 +160,7 @@ struct client_ctx { int x; /* x position */ int y; /* y position */ } ptr; -#define CLIENT_PROTO_DELETE 0x0001 -#define CLIENT_PROTO_TAKEFOCUS 0x0002 - int xproto; + enum wm_protocols xproto; #define CLIENT_HIDDEN 0x0001 #define CLIENT_IGNORE 0x0002 #define CLIENT_VMAXIMIZED 0x0004 @@ -222,13 +221,12 @@ struct screen_ctx { Colormap colormap; Window rootwin; Window menuwin; - unsigned long color[CWM_COLOR_BORDER_MAX]; int cycling; struct geom view; /* viewable area */ struct geom work; /* workable area, gap-applied */ struct gap gap; struct cycle_entry_q mruq; - XftColor xftcolor[CWM_COLOR_MENU_MAX]; + XftColor xftcolor[CWM_COLOR_MAX]; XftDraw *xftdraw; XftFont *xftfont; int xinerama_no; @@ -247,8 +245,8 @@ struct keybinding { TAILQ_ENTRY(keybinding) entry; void (*callback)(struct client_ctx *, union arg *); union arg argument; - int modmask; - int keysym; + u_int modmask; + KeySym keysym; int keycode; #define KBFLAG_NEEDCLIENT 0x0001 int flags; @@ -259,8 +257,8 @@ TAILQ_HEAD(keybinding_q, keybinding); struct mousebinding { TAILQ_ENTRY(mousebinding) entry; void (*callback)(struct client_ctx *, void *); - int modmask; - int button; + u_int modmask; + u_int button; #define MOUSEBIND_CTX_ROOT 0x0001 #define MOUSEBIND_CTX_WIN 0x0002 int context; @@ -302,8 +300,7 @@ struct conf { #define CONF_SNAPDIST 0 int snapdist; struct gap gap; - char *color[CWM_COLOR_BORDER_MAX]; - char *menucolor[CWM_COLOR_MENU_MAX]; + char *color[CWM_COLOR_MAX]; char termpath[MAXPATHLEN]; char lockpath[MAXPATHLEN]; char known_hosts[MAXPATHLEN]; @@ -343,7 +340,7 @@ void client_lower(struct client_ctx *); void client_map(struct client_ctx *); void client_maximize(struct client_ctx *); void client_move(struct client_ctx *); -struct client_ctx *client_new(Window, struct screen_ctx *, int); +struct client_ctx *client_init(Window, struct screen_ctx *, int); void client_ptrsave(struct client_ctx *); void client_ptrwarp(struct client_ctx *); void client_raise(struct client_ctx *); @@ -360,7 +357,6 @@ void client_warp(struct client_ctx *); void group_alltoggle(struct screen_ctx *); void group_autogroup(struct client_ctx *); -void group_client_delete(struct client_ctx *); void group_cycle(struct screen_ctx *, int); void group_hidetoggle(struct screen_ctx *, int); void group_init(struct screen_ctx *); @@ -442,7 +438,6 @@ struct menu *menu_filter(struct screen_ctx *, struct menu_q *, char *, char *, int, void (*)(struct menu_q *, struct menu_q *, char *), void (*)(struct menu *, int)); -void menu_init(struct screen_ctx *); void menuq_clear(struct menu_q *); int parse_config(const char *, struct conf *); @@ -452,24 +447,12 @@ void conf_bindname(struct conf *, char *, char *); void conf_clear(struct conf *); void conf_client(struct client_ctx *); void conf_cmd_add(struct conf *, char *, char *); -void conf_color(struct conf *, struct screen_ctx *); -void conf_font(struct conf *, struct screen_ctx *); -void conf_gap(struct conf *, struct screen_ctx *); -void conf_grab(struct conf *, struct keybinding *); -void conf_grab_mouse(struct client_ctx *); +void conf_grab_kbd(Window); +void conf_grab_mouse(Window); void conf_init(struct conf *); void conf_ignore(struct conf *, char *); -void conf_mousebind(struct conf *, char *, char *); -void conf_ungrab(struct conf *, struct keybinding *); - -int font_ascent(struct screen_ctx *); -int font_descent(struct screen_ctx *); -void font_draw(struct screen_ctx *, const char *, int, - Drawable, int, int, int); -u_int font_height(struct screen_ctx *); -void font_init(struct screen_ctx *, const char *, - const char **); -int font_width(struct screen_ctx *, const char *, int); +int conf_mousebind(struct conf *, char *, char *); +void conf_screen(struct screen_ctx *); void xev_loop(void); @@ -477,21 +460,21 @@ void xu_btn_grab(Window, int, u_int); void xu_btn_ungrab(Window, int, u_int); void xu_configure(struct client_ctx *); void xu_getatoms(void); -unsigned long xu_getcolor(struct screen_ctx *, char *); int xu_getprop(Window, Atom, Atom, long, u_char **); int xu_get_wm_state(Window, int *); int xu_getstrprop(Window, Atom, char **); -void xu_key_grab(Window, int, int); -void xu_key_ungrab(Window, int, int); +void xu_key_grab(Window, u_int, KeySym); void xu_ptr_getpos(Window, int *, int *); -int xu_ptr_grab(Window, int, Cursor); -int xu_ptr_regrab(int, Cursor); +int xu_ptr_grab(Window, u_int, Cursor); +int xu_ptr_regrab(u_int, Cursor); void xu_ptr_setpos(Window, int, int); void xu_ptr_ungrab(void); -void xu_sendmsg(Window, Atom, long); +void xu_sendmsg(Window, Atom, Atom); void xu_set_wm_state(Window win, int); -void xu_xorcolor(XRenderColor, XRenderColor, - XRenderColor *); +void xu_xft_draw(struct screen_ctx *, const char *, + int, int, int); +int xu_xft_width(XftFont *, const char *, int); +void xu_xorcolor(XftColor, XftColor, XftColor *); void xu_ewmh_net_supported(struct screen_ctx *); void xu_ewmh_net_supported_wm_check(struct screen_ctx *); @@ -508,6 +491,11 @@ void xu_ewmh_net_desktop_names(struct screen_ctx *, char *, int); void xu_ewmh_net_wm_desktop(struct client_ctx *); +Atom *xu_ewmh_get_net_wm_state(struct client_ctx *, int *); +void xu_ewmh_handle_net_wm_state_msg(struct client_ctx *, + int, Atom , Atom); +void xu_ewmh_set_net_wm_state(struct client_ctx *); +void xu_ewmh_restore_net_wm_state(struct client_ctx *); void u_exec(char *); void u_spawn(char *); @@ -542,6 +530,7 @@ enum { WM_PROTOCOLS, _MOTIF_WM_HINTS, UTF8_STRING, + WM_CHANGE_STATE, CWMH_NITEMS }; enum { @@ -559,8 +548,18 @@ enum { _NET_WORKAREA, _NET_WM_NAME, _NET_WM_DESKTOP, + _NET_CLOSE_WINDOW, + _NET_WM_STATE, +#define _NET_WM_STATES_NITEMS 2 + _NET_WM_STATE_MAXIMIZED_VERT, + _NET_WM_STATE_MAXIMIZED_HORZ, EWMH_NITEMS }; +enum { + _NET_WM_STATE_REMOVE, + _NET_WM_STATE_ADD, + _NET_WM_STATE_TOGGLE +}; struct atom_ctx { char *name; Atom atom; diff --git a/client.c b/client.c index c485b07..cfa253b 100644 --- a/client.c +++ b/client.c @@ -36,7 +36,7 @@ static struct client_ctx *client_mruprev(struct client_ctx *); static void client_mtf(struct client_ctx *); static void client_none(struct screen_ctx *); static void client_placecalc(struct client_ctx *); -static void client_update(struct client_ctx *); +static void client_wm_protocols(struct client_ctx *); static void client_getmwmhints(struct client_ctx *); static int client_inbound(struct client_ctx *, int, int); @@ -55,7 +55,7 @@ client_find(Window win) } struct client_ctx * -client_new(Window win, struct screen_ctx *sc, int mapped) +client_init(Window win, struct screen_ctx *sc, int mapped) { struct client_ctx *cc; XClassHint xch; @@ -132,7 +132,8 @@ client_new(Window win, struct screen_ctx *sc, int mapped) xu_ewmh_net_client_list(sc); - client_update(cc); + client_wm_protocols(cc); + xu_ewmh_restore_net_wm_state(cc); if (mapped) group_autogroup(cc); @@ -149,13 +150,10 @@ client_delete(struct client_ctx *cc) struct screen_ctx *sc = cc->sc; struct winname *wn; - group_client_delete(cc); - XGrabServer(X_Dpy); cc->state = WithdrawnState; xu_set_wm_state(cc->win, cc->state); XRemoveFromSaveSet(X_Dpy, cc->win); - XSync(X_Dpy, False); XUngrabServer(X_Dpy); @@ -164,6 +162,9 @@ client_delete(struct client_ctx *cc) xu_ewmh_net_client_list(sc); + if (cc->group != NULL) + TAILQ_REMOVE(&cc->group->clients, cc, group_entry); + if (cc == client_current()) client_none(sc); @@ -212,7 +213,7 @@ client_setactive(struct client_ctx *cc, int fg) XInstallColormap(X_Dpy, cc->colormap); XSetInputFocus(X_Dpy, cc->win, RevertToPointerRoot, CurrentTime); - conf_grab_mouse(cc); + conf_grab_mouse(cc->win); /* * If we're in the middle of alt-tabbing, don't change * the order please. @@ -301,6 +302,7 @@ client_maximize(struct client_ctx *cc) resize: client_resize(cc, 0); + xu_ewmh_set_net_wm_state(cc); } void @@ -341,6 +343,7 @@ client_vmaximize(struct client_ctx *cc) resize: client_resize(cc, 0); + xu_ewmh_set_net_wm_state(cc); } void @@ -381,6 +384,7 @@ client_hmaximize(struct client_ctx *cc) resize: client_resize(cc, 0); + xu_ewmh_set_net_wm_state(cc); } void @@ -389,6 +393,7 @@ client_resize(struct client_ctx *cc, int reset) if (reset) { cc->flags &= ~CLIENT_MAXIMIZED; cc->bwidth = Conf.bwidth; + xu_ewmh_set_net_wm_state(cc); } client_draw_border(cc); @@ -480,46 +485,43 @@ client_draw_border(struct client_ctx *cc) if (cc->active) switch (cc->flags & CLIENT_HIGHLIGHT) { case CLIENT_GROUP: - pixel = sc->color[CWM_COLOR_BORDER_GROUP]; + pixel = sc->xftcolor[CWM_COLOR_BORDER_GROUP].pixel; break; case CLIENT_UNGROUP: - pixel = sc->color[CWM_COLOR_BORDER_UNGROUP]; + pixel = sc->xftcolor[CWM_COLOR_BORDER_UNGROUP].pixel; break; default: - pixel = sc->color[CWM_COLOR_BORDER_ACTIVE]; + pixel = sc->xftcolor[CWM_COLOR_BORDER_ACTIVE].pixel; break; } else - pixel = sc->color[CWM_COLOR_BORDER_INACTIVE]; + pixel = sc->xftcolor[CWM_COLOR_BORDER_INACTIVE].pixel; XSetWindowBorderWidth(X_Dpy, cc->win, cc->bwidth); XSetWindowBorder(X_Dpy, cc->win, pixel); } static void -client_update(struct client_ctx *cc) +client_wm_protocols(struct client_ctx *cc) { Atom *p; - int i; - long n; + int i, j; - if ((n = xu_getprop(cc->win, cwmh[WM_PROTOCOLS].atom, - XA_ATOM, 20L, (u_char **)&p)) <= 0) - return; - - for (i = 0; i < n; i++) - if (p[i] == cwmh[WM_DELETE_WINDOW].atom) - cc->xproto |= CLIENT_PROTO_DELETE; - else if (p[i] == cwmh[WM_TAKE_FOCUS].atom) - cc->xproto |= CLIENT_PROTO_TAKEFOCUS; - - XFree(p); + if (XGetWMProtocols(X_Dpy, cc->win, &p, &j)) { + for (i = 0; i < j; i++) { + if (p[i] == cwmh[WM_DELETE_WINDOW].atom) + cc->xproto |= _WM_DELETE_WINDOW; + else if (p[i] == cwmh[WM_TAKE_FOCUS].atom) + cc->xproto |= _WM_TAKE_FOCUS; + } + XFree(p); + } } void client_send_delete(struct client_ctx *cc) { - if (cc->xproto & CLIENT_PROTO_DELETE) + if (cc->xproto & _WM_DELETE_WINDOW) xu_sendmsg(cc->win, cwmh[WM_PROTOCOLS].atom, cwmh[WM_DELETE_WINDOW].atom); else diff --git a/conf.c b/conf.c index 705c9e0..7c4f77d 100644 --- a/conf.c +++ b/conf.c @@ -84,39 +84,63 @@ conf_ignore(struct conf *c, char *val) TAILQ_INSERT_TAIL(&c->ignoreq, wm, entry); } -void -conf_gap(struct conf *c, struct screen_ctx *sc) -{ - sc->gap = c->gap; -} - -void -conf_font(struct conf *c, struct screen_ctx *sc) -{ - font_init(sc, c->font, (const char **)c->menucolor); -} - -static char *menu_color_binds[CWM_COLOR_MENU_MAX] = { +static char *color_binds[CWM_COLOR_MAX] = { + "#CCCCCC", /* CWM_COLOR_BORDER_ACTIVE */ + "#666666", /* CWM_COLOR_BORDER_INACTIVE */ + "blue", /* CWM_COLOR_BORDER_GROUP */ + "red", /* CWM_COLOR_BORDER_UNGROUP */ "black", /* CWM_COLOR_MENU_FG */ "white", /* CWM_COLOR_MENU_BG */ "black", /* CWM_COLOR_MENU_FONT */ "", /* CWM_COLOR_MENU_FONT_SEL */ }; -static char *color_binds[CWM_COLOR_BORDER_MAX] = { - "#CCCCCC", /* CWM_COLOR_BORDER_ACTIVE */ - "#666666", /* CWM_COLOR_BORDER_INACTIVE */ - "blue", /* CWM_COLOR_BORDER_GROUP */ - "red", /* CWM_COLOR_BORDER_UNGROUP */ -}; - void -conf_color(struct conf *c, struct screen_ctx *sc) +conf_screen(struct screen_ctx *sc) { - int i; + int i; + XftColor xc; - for (i = 0; i < CWM_COLOR_BORDER_MAX; i++) - sc->color[i] = xu_getcolor(sc, c->color[i]); + sc->gap = Conf.gap; + + sc->xftfont = XftFontOpenName(X_Dpy, sc->which, Conf.font); + if (sc->xftfont == NULL) + errx(1, "XftFontOpenName"); + + for (i = 0; i < CWM_COLOR_MAX; i++) { + if (*Conf.color[i] == '\0') + break; + if (XftColorAllocName(X_Dpy, sc->visual, sc->colormap, + Conf.color[i], &xc)) { + sc->xftcolor[i] = xc; + XftColorFree(X_Dpy, sc->visual, sc->colormap, &xc); + } else { + warnx("XftColorAllocName: '%s'", Conf.color[i]); + XftColorAllocName(X_Dpy, sc->visual, sc->colormap, + color_binds[i], &sc->xftcolor[i]); + } + } + if (i == CWM_COLOR_MAX) + return; + + xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_BG], + sc->xftcolor[CWM_COLOR_MENU_FG], &xc); + xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_FONT], xc, &xc); + if (!XftColorAllocValue(X_Dpy, sc->visual, sc->colormap, + &xc.color, &sc->xftcolor[CWM_COLOR_MENU_FONT_SEL])) + warnx("XftColorAllocValue: '%s'", Conf.color[i]); + + sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1, + Conf.bwidth, + sc->xftcolor[CWM_COLOR_MENU_FG].pixel, + sc->xftcolor[CWM_COLOR_MENU_BG].pixel); + + sc->xftdraw = XftDrawCreate(X_Dpy, sc->menuwin, + sc->visual, sc->colormap); + if (sc->xftdraw == NULL) + errx(1, "XftDrawCreate"); + + conf_grab_kbd(sc->rootwin); } static struct { @@ -195,7 +219,7 @@ m_binds[] = { void conf_init(struct conf *c) { - int i; + u_int i; bzero(c, sizeof(*c)); @@ -218,9 +242,6 @@ conf_init(struct conf *c) for (i = 0; i < nitems(color_binds); i++) c->color[i] = xstrdup(color_binds[i]); - for (i = 0; i < nitems(menu_color_binds); i++) - c->menucolor[i] = xstrdup(menu_color_binds[i]); - /* Default term/lock */ (void)strlcpy(c->termpath, "xterm", sizeof(c->termpath)); (void)strlcpy(c->lockpath, "xlock", sizeof(c->lockpath)); @@ -268,7 +289,7 @@ conf_clear(struct conf *c) free(mb); } - for (i = 0; i < CWM_COLOR_BORDER_MAX; i++) + for (i = 0; i < CWM_COLOR_MAX; i++) free(c->color[i]); free(c->font); @@ -413,37 +434,6 @@ static struct { {.i = CWM_TILE_VERT } }, }; -/* - * The following two functions are used when grabbing and ungrabbing keys for - * bindings - */ - -/* - * Grab key combination on all screens and add to the global queue - */ -void -conf_grab(struct conf *c, struct keybinding *kb) -{ - extern struct screen_ctx_q Screenq; - struct screen_ctx *sc; - - TAILQ_FOREACH(sc, &Screenq, entry) - xu_key_grab(sc->rootwin, kb->modmask, kb->keysym); -} - -/* - * Ungrab key combination from all screens and remove from global queue - */ -void -conf_ungrab(struct conf *c, struct keybinding *kb) -{ - extern struct screen_ctx_q Screenq; - struct screen_ctx *sc; - - TAILQ_FOREACH(sc, &Screenq, entry) - xu_key_ungrab(sc->rootwin, kb->modmask, kb->keysym); -} - static struct { char chr; int mask; @@ -459,7 +449,7 @@ conf_bindname(struct conf *c, char *name, char *binding) { struct keybinding *current_binding; char *substring, *tmp; - int i; + u_int i; current_binding = xcalloc(1, sizeof(*current_binding)); @@ -507,7 +497,6 @@ conf_bindname(struct conf *c, char *name, char *binding) current_binding->flags = name_to_kbfunc[i].flags; current_binding->argument = name_to_kbfunc[i].argument; current_binding->argtype |= ARG_INT; - conf_grab(c, current_binding); TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry); return; } @@ -516,7 +505,6 @@ conf_bindname(struct conf *c, char *name, char *binding) current_binding->flags = 0; current_binding->argument.c = xstrdup(binding); current_binding->argtype |= ARG_CHAR; - conf_grab(c, current_binding); TAILQ_INSERT_TAIL(&c->keybindingq, current_binding, entry); } @@ -532,7 +520,6 @@ conf_unbind(struct conf *c, struct keybinding *unbind) if ((key->keycode != 0 && key->keysym == NoSymbol && key->keycode == unbind->keycode) || key->keysym == unbind->keysym) { - conf_ungrab(c, key); TAILQ_REMOVE(&c->keybindingq, key, entry); if (key->argtype & ARG_CHAR) free(key->argument.c); @@ -558,13 +545,16 @@ static struct { { "menu_cmd", mousefunc_menu_cmd, MOUSEBIND_CTX_ROOT }, }; -void +static unsigned int mouse_btns[] = { Button1, Button2, Button3 }; + +int conf_mousebind(struct conf *c, char *name, char *binding) { struct mousebinding *current_binding; char *substring, *tmp; + u_int button; const char *errstr; - int i; + u_int i; current_binding = xcalloc(1, sizeof(*current_binding)); @@ -581,16 +571,27 @@ conf_mousebind(struct conf *c, char *name, char *binding) } else substring = name; - current_binding->button = strtonum(substring, 1, 3, &errstr); + button = strtonum(substring, 1, 3, &errstr); if (errstr) - warnx("number of buttons is %s: %s", errstr, substring); + warnx("button number is %s: %s", errstr, substring); + + for (i = 0; i < nitems(mouse_btns); i++) { + if (button == mouse_btns[i]) { + current_binding->button = button; + break; + } + } + if (!current_binding->button || errstr) { + free(current_binding); + return (0); + } /* We now have the correct binding, remove duplicates. */ conf_mouseunbind(c, current_binding); if (strcmp("unmap", binding) == 0) { free(current_binding); - return; + return (1); } for (i = 0; i < nitems(name_to_mousefunc); i++) { @@ -600,8 +601,10 @@ conf_mousebind(struct conf *c, char *name, char *binding) current_binding->context = name_to_mousefunc[i].context; current_binding->callback = name_to_mousefunc[i].handler; TAILQ_INSERT_TAIL(&c->mousebindingq, current_binding, entry); - return; + return (1); } + + return (0); } static void @@ -620,33 +623,26 @@ conf_mouseunbind(struct conf *c, struct mousebinding *unbind) } } -/* - * Grab the mouse buttons that we need for bindings for this client - */ void -conf_grab_mouse(struct client_ctx *cc) +conf_grab_mouse(Window win) { struct mousebinding *mb; - int button; TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) { if (mb->context != MOUSEBIND_CTX_WIN) continue; - - switch(mb->button) { - case 1: - button = Button1; - break; - case 2: - button = Button2; - break; - case 3: - button = Button3; - break; - default: - warnx("strange button in mousebinding\n"); - continue; - } - xu_btn_grab(cc->win, mb->modmask, button); + xu_btn_grab(win, mb->modmask, mb->button); } } + +void +conf_grab_kbd(Window win) +{ + struct keybinding *kb; + + XUngrabKey(X_Dpy, AnyKey, AnyModifier, win); + + TAILQ_FOREACH(kb, &Conf.keybindingq, entry) + xu_key_grab(win, kb->modmask, kb->keysym); +} + diff --git a/font.c b/font.c deleted file mode 100644 index 648450e..0000000 --- a/font.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * calmwm - the calm window manager - * - * Copyright (c) 2005 Marius Eriksen - * - * 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 -#include "queue.h" - -#include -#include -#include -#include -#include -#include - -#include "calmwm.h" - -int -font_ascent(struct screen_ctx *sc) -{ - return (sc->xftfont->ascent); -} - -int -font_descent(struct screen_ctx *sc) -{ - return (sc->xftfont->descent); -} - -u_int -font_height(struct screen_ctx *sc) -{ - return (sc->xftfont->height + 1); -} - -void -font_init(struct screen_ctx *sc, const char *name, const char **color) -{ - int i; - XRenderColor c; - - sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin, - sc->visual, sc->colormap); - if (sc->xftdraw == NULL) - errx(1, "XftDrawCreate"); - - sc->xftfont = XftFontOpenName(X_Dpy, sc->which, name); - if (sc->xftfont == NULL) - errx(1, "XftFontOpenName"); - - for (i = 0; i < CWM_COLOR_MENU_MAX; i++) { - if (*color[i] == '\0') - break; - if (!XftColorAllocName(X_Dpy, sc->visual, sc->colormap, - color[i], &sc->xftcolor[i])) - errx(1, "XftColorAllocName"); - } - if (i == CWM_COLOR_MENU_MAX) - return; - - xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_BG].color, - sc->xftcolor[CWM_COLOR_MENU_FG].color, &c); - xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_FONT].color, c, &c); - if (!XftColorAllocValue(X_Dpy, sc->visual, sc->colormap, - &c, &sc->xftcolor[CWM_COLOR_MENU_FONT_SEL])) - errx(1, "XftColorAllocValue"); -} - -int -font_width(struct screen_ctx *sc, const char *text, int len) -{ - XGlyphInfo extents; - - XftTextExtentsUtf8(X_Dpy, sc->xftfont, (const FcChar8*)text, - len, &extents); - - return (extents.xOff); -} - -void -font_draw(struct screen_ctx *sc, const char *text, int len, - Drawable d, int active, int x, int y) -{ - int color; - - color = active ? CWM_COLOR_MENU_FONT_SEL : CWM_COLOR_MENU_FONT; - XftDrawChange(sc->xftdraw, d); - XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor[color], sc->xftfont, x, y, - (const FcChar8*)text, len); -} diff --git a/group.c b/group.c index 48dfc68..30bc5d5 100644 --- a/group.c +++ b/group.c @@ -308,17 +308,6 @@ group_cycle(struct screen_ctx *sc, int flags) group_setactive(sc, showgroup->shortcut); } -/* called when a client is deleted */ -void -group_client_delete(struct client_ctx *cc) -{ - if (cc->group == NULL) - return; - - TAILQ_REMOVE(&cc->group->clients, cc, group_entry); - cc->group = NULL; /* he he */ -} - void group_menu(XButtonEvent *e) { diff --git a/kbfunc.c b/kbfunc.c index bec81a4..37b8af7 100644 --- a/kbfunc.c +++ b/kbfunc.c @@ -88,17 +88,16 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg) } switch (flags & TYPEMASK) { case CWM_MOVE: - cc->geom.y += my; - if (cc->geom.y + cc->geom.h < 0) - cc->geom.y = -cc->geom.h; - if (cc->geom.y > sc->view.h - 1) - cc->geom.y = sc->view.h - 1; - cc->geom.x += mx; if (cc->geom.x + cc->geom.w < 0) cc->geom.x = -cc->geom.w; if (cc->geom.x > sc->view.w - 1) cc->geom.x = sc->view.w - 1; + cc->geom.y += my; + if (cc->geom.y + cc->geom.h < 0) + cc->geom.y = -cc->geom.h; + if (cc->geom.y > sc->view.h - 1) + cc->geom.y = sc->view.h - 1; cc->geom.x += client_snapcalc(cc->geom.x, cc->geom.x + cc->geom.w + (cc->bwidth * 2), @@ -109,15 +108,15 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg) client_move(cc); xu_ptr_getpos(cc->win, &x, &y); - cc->ptr.y = y + my; cc->ptr.x = x + mx; + cc->ptr.y = y + my; client_ptrwarp(cc); break; case CWM_RESIZE: - if ((cc->geom.h += my) < 1) - cc->geom.h = 1; if ((cc->geom.w += mx) < 1) cc->geom.w = 1; + if ((cc->geom.h += my) < 1) + cc->geom.h = 1; client_resize(cc, 1); /* Make sure the pointer stays within the window. */ diff --git a/menu.c b/menu.c index b467ffb..d610945 100644 --- a/menu.c +++ b/menu.c @@ -42,7 +42,7 @@ enum ctltype { }; struct menu_ctx { - struct screen_ctx *sc; + struct screen_ctx *sc; char searchstr[MENU_MAXENTRY + 1]; char dispstr[MENU_MAXENTRY*2 + 1]; char promptstr[MENU_MAXENTRY + 1]; @@ -65,27 +65,16 @@ struct menu_ctx { static struct menu *menu_handle_key(XEvent *, struct menu_ctx *, struct menu_q *, struct menu_q *); static void menu_handle_move(XEvent *, struct menu_ctx *, - struct screen_ctx *, struct menu_q *); + struct menu_q *); static struct menu *menu_handle_release(XEvent *, struct menu_ctx *, - struct screen_ctx *, struct menu_q *); -static void menu_draw(struct screen_ctx *, struct menu_ctx *, - struct menu_q *, struct menu_q *); -static void menu_draw_entry(struct screen_ctx *, struct menu_ctx *, - struct menu_q *, int, int); -static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *, + struct menu_q *); +static void menu_draw(struct menu_ctx *, struct menu_q *, + struct menu_q *); +static void menu_draw_entry(struct menu_ctx *, struct menu_q *, int, int); +static int menu_calc_entry(struct menu_ctx *, int, int); static struct menu *menu_complete_path(struct menu_ctx *); -static int menu_keycode(XKeyEvent *, enum ctltype *, - char *); - -void -menu_init(struct screen_ctx *sc) -{ - sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1, - Conf.bwidth, - sc->xftcolor[CWM_COLOR_MENU_FG].pixel, - sc->xftcolor[CWM_COLOR_MENU_BG].pixel); -} +static int menu_keycode(XKeyEvent *, enum ctltype *, char *); struct menu * menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, @@ -112,18 +101,13 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, mc.sc = sc; mc.flags = flags; - if (prompt == NULL) { - evmask = MENUMASK; - mc.promptstr[0] = '\0'; - mc.list = 1; - } else { - evmask = MENUMASK | KEYMASK; /* only accept keys if prompt */ - (void)snprintf(mc.promptstr, sizeof(mc.promptstr), "%s%s", - prompt, PROMPT_SCHAR); - (void)snprintf(mc.dispstr, sizeof(mc.dispstr), "%s%s%s", - mc.promptstr, mc.searchstr, PROMPT_ECHAR); - mc.width = font_width(sc, mc.dispstr, strlen(mc.dispstr)); + if (prompt != NULL) { + evmask = MENUMASK | KEYMASK; /* accept keys as well */ + (void)strlcpy(mc.promptstr, prompt, sizeof(mc.promptstr)); mc.hasprompt = 1; + } else { + evmask = MENUMASK; + mc.list = 1; } if (initial != NULL) @@ -135,8 +119,6 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, mc.print = print; mc.entry = mc.prev = -1; - XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, mc.width, - font_height(sc)); XSelectInput(X_Dpy, sc->menuwin, evmask); XMapRaised(X_Dpy, sc->menuwin); @@ -164,13 +146,13 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, goto out; /* FALLTHROUGH */ case Expose: - menu_draw(sc, &mc, menuq, &resultq); + menu_draw(&mc, menuq, &resultq); break; case MotionNotify: - menu_handle_move(&e, &mc, sc, &resultq); + menu_handle_move(&e, &mc, &resultq); break; case ButtonRelease: - if ((mi = menu_handle_release(&e, &mc, sc, &resultq)) + if ((mi = menu_handle_release(&e, &mc, &resultq)) != NULL) goto out; break; @@ -192,6 +174,7 @@ out: xu_ptr_setpos(sc->rootwin, xsave, ysave); xu_ptr_ungrab(); + XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0, 1, 1); XUnmapWindow(X_Dpy, sc->menuwin); XUngrabKeyboard(X_Dpy, CurrentTime); @@ -203,7 +186,7 @@ menu_complete_path(struct menu_ctx *mc) { struct menu *mi, *mr; struct menu_q menuq; - char *path = NULL; + char *path = NULL; path = xcalloc(1, sizeof(mr->text)); mr = xcalloc(1, sizeof(*mr)); @@ -348,9 +331,9 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq, } static void -menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, - struct menu_q *resultq) +menu_draw(struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq) { + struct screen_ctx *sc = mc->sc; struct menu *mi; struct geom xine; int n, xsave, ysave; @@ -371,10 +354,11 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, mc->width = 0; mc->height = 0; if (mc->hasprompt) { - (void)snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%s", - mc->promptstr, mc->searchstr, PROMPT_ECHAR); - mc->width = font_width(sc, mc->dispstr, strlen(mc->dispstr)); - mc->height = font_height(sc); + (void)snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%s%s", + mc->promptstr, PROMPT_SCHAR, mc->searchstr, PROMPT_ECHAR); + mc->width = xu_xft_width(sc->xftfont, mc->dispstr, + strlen(mc->dispstr)); + mc->height = sc->xftfont->height + 1; mc->num = 1; } @@ -389,9 +373,9 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, text = mi->text; } - mc->width = MAX(mc->width, font_width(sc, text, + mc->width = MAX(mc->width, xu_xft_width(sc->xftfont, text, MIN(strlen(text), MENU_MAXENTRY))); - mc->height += font_height(sc); + mc->height += sc->xftfont->height + 1; mc->num++; } @@ -424,8 +408,8 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, mc->width, mc->height); if (mc->hasprompt) { - font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin, 0, - 0, font_ascent(sc)); + xu_xft_draw(sc, mc->dispstr, CWM_COLOR_MENU_FONT, + 0, sc->xftfont->ascent); n = 1; } else n = 0; @@ -433,29 +417,29 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, TAILQ_FOREACH(mi, resultq, resultentry) { char *text = mi->print[0] != '\0' ? mi->print : mi->text; - int y = n * font_height(sc) + font_ascent(sc) + 1; + int y = n * (sc->xftfont->height + 1) + sc->xftfont->ascent + 1; /* Stop drawing when menu doesn't fit inside the screen. */ if (mc->y + y > xine.h) break; - font_draw(sc, text, MIN(strlen(text), MENU_MAXENTRY), - sc->menuwin, 0, 0, y); + xu_xft_draw(sc, text, CWM_COLOR_MENU_FONT, 0, y); n++; } if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0')) { mc->entry = 1; - menu_draw_entry(sc, mc, resultq, mc->entry, 1); + menu_draw_entry(mc, resultq, mc->entry, 1); } } static void -menu_draw_entry(struct screen_ctx *sc, struct menu_ctx *mc, - struct menu_q *resultq, int entry, int active) +menu_draw_entry(struct menu_ctx *mc, struct menu_q *resultq, + int entry, int active) { - struct menu *mi; - char *text; - int color, i = 0; + struct screen_ctx *sc = mc->sc; + struct menu *mi; + char *text; + int color, i = 0; if (mc->hasprompt) i = 1; @@ -467,44 +451,43 @@ menu_draw_entry(struct screen_ctx *sc, struct menu_ctx *mc, return; color = active ? CWM_COLOR_MENU_FG : CWM_COLOR_MENU_BG; - text = mi->print[0] != '\0' ? mi->print : mi->text; + text = mi->print[0] != '\0' ? mi->print : mi->text; XftDrawRect(sc->xftdraw, &sc->xftcolor[color], 0, - font_height(sc) * entry, mc->width, - font_height(sc) + font_descent(sc)); - font_draw(sc, text, strlen(text), sc->menuwin, active, - 0, font_height(sc) * entry + font_ascent(sc) + 1); + (sc->xftfont->height + 1) * entry, mc->width, + (sc->xftfont->height + 1) + sc->xftfont->descent); + color = active ? CWM_COLOR_MENU_FONT_SEL : CWM_COLOR_MENU_FONT; + xu_xft_draw(sc, text, color, + 0, (sc->xftfont->height + 1) * entry + sc->xftfont->ascent + 1); } static void -menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc, - struct menu_q *resultq) +menu_handle_move(XEvent *e, struct menu_ctx *mc, struct menu_q *resultq) { mc->prev = mc->entry; - mc->entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y); + mc->entry = menu_calc_entry(mc, e->xbutton.x, e->xbutton.y); if (mc->prev == mc->entry) return; if (mc->prev != -1) - menu_draw_entry(sc, mc, resultq, mc->prev, 0); + menu_draw_entry(mc, resultq, mc->prev, 0); if (mc->entry != -1) { (void)xu_ptr_regrab(MENUGRABMASK, Cursor_normal); - menu_draw_entry(sc, mc, resultq, mc->entry, 1); + menu_draw_entry(mc, resultq, mc->entry, 1); } else (void)xu_ptr_regrab(MENUGRABMASK, Cursor_default); if (mc->hasprompt) - menu_draw_entry(sc, mc, resultq, 1, 1); + menu_draw_entry(mc, resultq, 1, 1); } static struct menu * -menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc, - struct menu_q *resultq) +menu_handle_release(XEvent *e, struct menu_ctx *mc, struct menu_q *resultq) { - struct menu *mi; - int entry, i = 0; + struct menu *mi; + int entry, i = 0; - entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y); + entry = menu_calc_entry(mc, e->xbutton.x, e->xbutton.y); if (mc->hasprompt) i = 1; @@ -521,15 +504,17 @@ menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc, } static int -menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y) +menu_calc_entry(struct menu_ctx *mc, int x, int y) { - int entry; + struct screen_ctx *sc = mc->sc; + int entry; - entry = y / font_height(sc); + entry = y / (sc->xftfont->height + 1); /* in bounds? */ if (x < 0 || x > mc->width || y < 0 || - y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num) + y > (sc->xftfont->height + 1) * mc->num || + entry < 0 || entry >= mc->num) entry = -1; if (mc->hasprompt && entry == 0) diff --git a/mousefunc.c b/mousefunc.c index dcf1073..9305633 100644 --- a/mousefunc.c +++ b/mousefunc.c @@ -31,14 +31,12 @@ #include "calmwm.h" -static int mousefunc_sweep_calc(struct client_ctx *, int, int, int, int); +static void mousefunc_sweep_calc(struct client_ctx *, int, int, int, int); static void mousefunc_sweep_draw(struct client_ctx *); -static int +static void mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my) { - int width = cc->geom.w, height = cc->geom.h; - cc->geom.w = abs(x - mx) - cc->bwidth; cc->geom.h = abs(y - my) - cc->bwidth; @@ -46,32 +44,27 @@ mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my) cc->geom.x = x <= mx ? x : x - cc->geom.w; cc->geom.y = y <= my ? y : y - cc->geom.h; - - return (width != cc->geom.w || height != cc->geom.h); } static void mousefunc_sweep_draw(struct client_ctx *cc) { struct screen_ctx *sc = cc->sc; - char asize[10]; /* fits "nnnnxnnnn\0" */ - int width, width_size, width_name; + char asize[14]; /* fits " nnnn x nnnn \0" */ - (void)snprintf(asize, sizeof(asize), "%dx%d", + (void)snprintf(asize, sizeof(asize), " %4d x %-4d ", (cc->geom.w - cc->hint.basew) / cc->hint.incw, (cc->geom.h - cc->hint.baseh) / cc->hint.inch); - width_size = font_width(sc, asize, strlen(asize)) + 4; - width_name = font_width(sc, cc->name, strlen(cc->name)) + 4; - width = MAX(width_size, width_name); XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0); - XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0, width, font_height(sc) * 2); + XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0, + xu_xft_width(sc->xftfont, asize, strlen(asize)), + sc->xftfont->height); XMapWindow(X_Dpy, sc->menuwin); XClearWindow(X_Dpy, sc->menuwin); - font_draw(sc, cc->name, strlen(cc->name), sc->menuwin, 0, - 2, font_ascent(sc) + 1); - font_draw(sc, asize, strlen(asize), sc->menuwin, 0, - width / 2 - width_size / 2, font_height(sc) + font_ascent(sc) + 1); + + xu_xft_draw(sc, asize, CWM_COLOR_MENU_FONT, + 0, sc->xftfont->ascent + 1); } void @@ -102,15 +95,14 @@ mousefunc_window_resize(struct client_ctx *cc, void *arg) client_draw_border(cc); break; case MotionNotify: - if (mousefunc_sweep_calc(cc, x, y, - ev.xmotion.x_root, ev.xmotion.y_root)) - /* Recompute window output */ - mousefunc_sweep_draw(cc); + mousefunc_sweep_calc(cc, x, y, + ev.xmotion.x_root, ev.xmotion.y_root); /* don't resize more than 60 times / second */ if ((ev.xmotion.time - ltime) > (1000 / 60)) { ltime = ev.xmotion.time; client_resize(cc, 1); + mousefunc_sweep_draw(cc); } break; case ButtonRelease: diff --git a/parse.y b/parse.y index 376bc2b..9e93749 100644 --- a/parse.y +++ b/parse.y @@ -44,18 +44,17 @@ static struct file { char *name; int lineno; int errors; -} *file; - -struct file *pushfile(const char *); -int popfile(void); -int yyparse(void); -int yylex(void); -int yyerror(const char *, ...); -int kw_cmp(const void *, const void *); -int lookup(char *); -int lgetc(int); -int lungetc(int); -int findeol(void); +} *file, *topfile; +struct file *pushfile(const char *); +int popfile(void); +int yyparse(void); +int yylex(void); +int yyerror(const char *, ...); +int kw_cmp(const void *, const void *); +int lookup(char *); +int lgetc(int); +int lungetc(int); +int findeol(void); static struct conf *conf; @@ -119,12 +118,24 @@ main : FONTNAME STRING { conf->flags |= CONF_STICKY_GROUPS; } | BORDERWIDTH NUMBER { + if ($2 < 0) { + yyerror("invalid borderwidth: %d", $2); + YYERROR; + } conf->bwidth = $2; } | MOVEAMOUNT NUMBER { + if ($2 < 0) { + yyerror("invalid movemount: %d", $2); + YYERROR; + } conf->mamount = $2; } | SNAPDIST NUMBER { + if ($2 < 0) { + yyerror("invalid snapdist: %d", $2); + YYERROR; + } conf->snapdist = $2; } | COMMAND STRING string { @@ -135,10 +146,9 @@ main : FONTNAME STRING { | AUTOGROUP NUMBER STRING { if ($2 < 0 || $2 > 9) { free($3); - yyerror("autogroup number out of range: %d", $2); + yyerror("invalid autogroup: %d", $2); YYERROR; } - conf_autogroup(conf, $2, $3); free($3); } @@ -152,13 +162,23 @@ main : FONTNAME STRING { free($3); } | GAP NUMBER NUMBER NUMBER NUMBER { + if ($2 < 0 || $3 < 0 || $4 < 0 || $5 < 0) { + yyerror("invalid gap: %d %d %d %d", + $2, $3, $4, $5); + YYERROR; + } conf->gap.top = $2; conf->gap.bottom = $3; conf->gap.left = $4; conf->gap.right = $5; } | MOUSEBIND STRING string { - conf_mousebind(conf, $2, $3); + if (!conf_mousebind(conf, $2, $3)) { + yyerror("invalid mousebind: %s %s", $2, $3); + free($2); + free($3); + YYERROR; + } free($2); free($3); } @@ -184,20 +204,20 @@ colors : ACTIVEBORDER STRING { conf->color[CWM_COLOR_BORDER_UNGROUP] = $2; } | MENUBG STRING { - free(conf->menucolor[CWM_COLOR_MENU_BG]); - conf->menucolor[CWM_COLOR_MENU_BG] = $2; + free(conf->color[CWM_COLOR_MENU_BG]); + conf->color[CWM_COLOR_MENU_BG] = $2; } | MENUFG STRING { - free(conf->menucolor[CWM_COLOR_MENU_FG]); - conf->menucolor[CWM_COLOR_MENU_FG] = $2; + free(conf->color[CWM_COLOR_MENU_FG]); + conf->color[CWM_COLOR_MENU_FG] = $2; } | FONTCOLOR STRING { - free(conf->menucolor[CWM_COLOR_MENU_FONT]); - conf->menucolor[CWM_COLOR_MENU_FONT] = $2; + free(conf->color[CWM_COLOR_MENU_FONT]); + conf->color[CWM_COLOR_MENU_FONT] = $2; } | FONTSELCOLOR STRING { - free(conf->menucolor[CWM_COLOR_MENU_FONT_SEL]); - conf->menucolor[CWM_COLOR_MENU_FONT_SEL] = $2; + free(conf->color[CWM_COLOR_MENU_FONT_SEL]); + conf->color[CWM_COLOR_MENU_FONT_SEL] = $2; } ; %% @@ -210,7 +230,7 @@ struct keywords { int yyerror(const char *fmt, ...) { - va_list ap; + va_list ap; file->errors++; va_start(ap, fmt); @@ -294,8 +314,9 @@ lgetc(int quotec) if (quotec) { if ((c = getc(file->stream)) == EOF) { - yyerror("reached end of file while parsing quoted string"); - if (popfile() == EOF) + yyerror("reached end of file while parsing " + "quoted string"); + if (file == topfile || popfile() == EOF) return (EOF); return (quotec); } @@ -313,7 +334,7 @@ lgetc(int quotec) } while (c == EOF) { - if (popfile() == EOF) + if (file == topfile || popfile() == EOF) return (EOF); c = getc(file->stream); } @@ -342,11 +363,13 @@ findeol(void) int c; parsebuf = NULL; - pushback_index = 0; /* skip to either EOF or the first real EOL */ while (1) { - c = lgetc(0); + if (pushback_index) + c = pushback_buffer[--pushback_index]; + else + c = lgetc(0); if (c == '\n') { file->lineno++; break; @@ -447,9 +470,10 @@ nodigits: #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && x != '<' && x != '>' && \ - x != '!' && x != '=' && x != '#' && x != ',')) + x != '!' && x != '=' && x != '/' && x != '#' && \ + x != ',')) - if (isalnum(c) || c == ':' || c == '_' || c == '*' || c == '/') { + if (isalnum(c) || c == ':' || c == '_' || c == '*') { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { @@ -481,6 +505,7 @@ pushfile(const char *name) nfile->name = xstrdup(name); if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { + warn("%s", nfile->name); free(nfile->name); free(nfile); return (NULL); @@ -495,16 +520,15 @@ popfile(void) { struct file *prev; - if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { + if ((prev = TAILQ_PREV(file, files, entry)) != NULL) prev->errors += file->errors; - TAILQ_REMOVE(&files, file, entry); - fclose(file->stream); - free(file->name); - free(file); - file = prev; - return (0); - } - return (EOF); + + TAILQ_REMOVE(&files, file, entry); + fclose(file->stream); + free(file->name); + free(file); + file = prev; + return (file ? 0 : EOF); } int @@ -518,12 +542,12 @@ parse_config(const char *filename, struct conf *xconf) free(conf); return (-1); } + topfile = file; conf_init(conf); yyparse(); errors = file->errors; - file->errors = 0; popfile(); if (errors) { @@ -575,12 +599,9 @@ parse_config(const char *filename, struct conf *xconf) (void)strlcpy(xconf->lockpath, conf->lockpath, sizeof(xconf->lockpath)); - for (i = 0; i < CWM_COLOR_BORDER_MAX; i++) + for (i = 0; i < CWM_COLOR_MAX; i++) xconf->color[i] = conf->color[i]; - for (i = 0; i < CWM_COLOR_MENU_MAX; i++) - xconf->menucolor[i] = conf->menucolor[i]; - xconf->font = conf->font; } diff --git a/screen.c b/screen.c index e856336..14e7608 100644 --- a/screen.c +++ b/screen.c @@ -49,16 +49,13 @@ screen_init(int which) xu_ewmh_net_supported(sc); xu_ewmh_net_supported_wm_check(sc); - conf_gap(&Conf, sc); - conf_color(&Conf, sc); - conf_font(&Conf, sc); + conf_screen(sc); screen_update_geometry(sc); TAILQ_INIT(&sc->mruq); group_init(sc); - menu_init(sc); rootattr.cursor = Cursor_normal; rootattr.event_mask = SubstructureRedirectMask|SubstructureNotifyMask| @@ -76,7 +73,7 @@ screen_init(int which) if (winattr.override_redirect || winattr.map_state != IsViewable) continue; - (void)client_new(wins[i], sc, winattr.map_state != IsUnmapped); + (void)client_init(wins[i], sc, winattr.map_state != IsUnmapped); } XFree(wins); diff --git a/xevents.c b/xevents.c index da7542b..9c42737 100644 --- a/xevents.c +++ b/xevents.c @@ -86,7 +86,7 @@ xev_handle_maprequest(XEvent *ee) if ((cc = client_find(e->window)) == NULL) { XGetWindowAttributes(X_Dpy, e->window, &xattr); - cc = client_new(e->window, screen_fromroot(xattr.root), 1); + cc = client_init(e->window, screen_fromroot(xattr.root), 1); } if ((cc->flags & CLIENT_IGNORE) == 0) @@ -203,13 +203,12 @@ xev_handle_propertynotify(XEvent *ee) break; } } else { - TAILQ_FOREACH(sc, &Screenq, entry) - if (sc->rootwin == e->window) - goto test; - return; -test: - if (e->atom == ewmh[_NET_DESKTOP_NAMES].atom) - group_update_names(sc); + TAILQ_FOREACH(sc, &Screenq, entry) { + if (sc->rootwin == e->window) { + if (e->atom == ewmh[_NET_DESKTOP_NAMES].atom) + group_update_names(sc); + } + } } } @@ -277,7 +276,7 @@ xev_handle_keypress(XEvent *ee) struct client_ctx *cc = NULL, fakecc; struct keybinding *kb; KeySym keysym, skeysym; - int modshift; + u_int modshift; keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0); skeysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 1); @@ -322,7 +321,8 @@ xev_handle_keyrelease(XEvent *ee) XKeyEvent *e = &ee->xkey; struct screen_ctx *sc; struct client_ctx *cc; - int i, keysym; + KeySym keysym; + u_int i; sc = screen_fromroot(e->root); cc = client_current(); @@ -340,17 +340,29 @@ static void xev_handle_clientmessage(XEvent *ee) { XClientMessageEvent *e = &ee->xclient; - Atom xa_wm_change_state; - struct client_ctx *cc; - - xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False); + struct client_ctx *cc, *old_cc; if ((cc = client_find(e->window)) == NULL) return; - if (e->message_type == xa_wm_change_state && e->format == 32 && - e->data.l[0] == IconicState) + if (e->message_type == cwmh[WM_CHANGE_STATE].atom && + e->format == 32 && e->data.l[0] == IconicState) client_hide(cc); + + if (e->message_type == ewmh[_NET_CLOSE_WINDOW].atom) + client_send_delete(cc); + + if (e->message_type == ewmh[_NET_ACTIVE_WINDOW].atom && + e->format == 32) { + old_cc = client_current(); + if (old_cc) + client_ptrsave(old_cc); + client_ptrwarp(cc); + } + if (e->message_type == ewmh[_NET_WM_STATE].atom && + e->format == 32) + xu_ewmh_handle_net_wm_state_msg(cc, + e->data.l[0], e->data.l[1], e->data.l[2]); } static void @@ -377,15 +389,13 @@ static void xev_handle_mappingnotify(XEvent *ee) { XMappingEvent *e = &ee->xmapping; - struct keybinding *kb; - - TAILQ_FOREACH(kb, &Conf.keybindingq, entry) - conf_ungrab(&Conf, kb); + struct screen_ctx *sc; XRefreshKeyboardMapping(e); - - TAILQ_FOREACH(kb, &Conf.keybindingq, entry) - conf_grab(&Conf, kb); + if (e->request == MappingKeyboard) { + TAILQ_FOREACH(sc, &Screenq, entry) + conf_grab_kbd(sc->rootwin); + } } static void diff --git a/xutil.c b/xutil.c index f8bd200..df5fc4f 100644 --- a/xutil.c +++ b/xutil.c @@ -33,7 +33,7 @@ static unsigned int ign_mods[] = { 0, LockMask, Mod2Mask, Mod2Mask | LockMask }; int -xu_ptr_grab(Window win, int mask, Cursor curs) +xu_ptr_grab(Window win, u_int mask, Cursor curs) { return (XGrabPointer(X_Dpy, win, False, mask, GrabModeAsync, GrabModeAsync, @@ -41,7 +41,7 @@ xu_ptr_grab(Window win, int mask, Cursor curs) } int -xu_ptr_regrab(int mask, Cursor curs) +xu_ptr_regrab(u_int mask, Cursor curs) { return (XChangeActivePointerGrab(X_Dpy, mask, curs, CurrentTime) == GrabSuccess ? 0 : -1); @@ -56,7 +56,8 @@ xu_ptr_ungrab(void) void xu_btn_grab(Window win, int mask, u_int btn) { - int i; + u_int i; + for (i = 0; i < nitems(ign_mods); i++) XGrabButton(X_Dpy, btn, (mask | ign_mods[i]), win, False, BUTTONMASK, GrabModeAsync, @@ -66,7 +67,8 @@ xu_btn_grab(Window win, int mask, u_int btn) void xu_btn_ungrab(Window win, int mask, u_int btn) { - int i; + u_int i; + for (i = 0; i < nitems(ign_mods); i++) XUngrabButton(X_Dpy, btn, (mask | ign_mods[i]), win); } @@ -88,10 +90,10 @@ xu_ptr_setpos(Window win, int x, int y) } void -xu_key_grab(Window win, int mask, int keysym) +xu_key_grab(Window win, u_int mask, KeySym keysym) { KeyCode code; - int i; + u_int i; code = XKeysymToKeycode(X_Dpy, keysym); if ((XkbKeycodeToKeysym(X_Dpy, code, 0, 0) != keysym) && @@ -103,21 +105,6 @@ xu_key_grab(Window win, int mask, int keysym) True, GrabModeAsync, GrabModeAsync); } -void -xu_key_ungrab(Window win, int mask, int keysym) -{ - KeyCode code; - int i; - - code = XKeysymToKeycode(X_Dpy, keysym); - if ((XkbKeycodeToKeysym(X_Dpy, code, 0, 0) != keysym) && - (XkbKeycodeToKeysym(X_Dpy, code, 0, 1) == keysym)) - mask |= ShiftMask; - - for (i = 0; i < nitems(ign_mods); i++) - XUngrabKey(X_Dpy, code, (mask | ign_mods[i]), win); -} - void xu_configure(struct client_ctx *cc) { @@ -138,19 +125,19 @@ xu_configure(struct client_ctx *cc) } void -xu_sendmsg(Window win, Atom atm, long val) +xu_sendmsg(Window win, Atom type, Atom atm) { - XEvent e; + XClientMessageEvent e; - (void)memset(&e, 0, sizeof(e)); - e.xclient.type = ClientMessage; - e.xclient.window = win; - e.xclient.message_type = atm; - e.xclient.format = 32; - e.xclient.data.l[0] = val; - e.xclient.data.l[1] = CurrentTime; + bzero(&e, sizeof(e)); + e.type = ClientMessage; + e.window = win; + e.message_type = type; + e.format = 32; + e.data.l[0] = atm; + e.data.l[1] = CurrentTime; - XSendEvent(X_Dpy, win, False, 0, &e); + XSendEvent(X_Dpy, win, False, 0L, (XEvent *)&e); } int @@ -237,6 +224,7 @@ struct atom_ctx cwmh[CWMH_NITEMS] = { {"WM_PROTOCOLS", None}, {"_MOTIF_WM_HINTS", None}, {"UTF8_STRING", None}, + {"WM_CHANGE_STATE", None}, }; struct atom_ctx ewmh[EWMH_NITEMS] = { {"_NET_SUPPORTED", None}, @@ -253,12 +241,16 @@ struct atom_ctx ewmh[EWMH_NITEMS] = { {"_NET_WORKAREA", None}, {"_NET_WM_NAME", None}, {"_NET_WM_DESKTOP", None}, + {"_NET_CLOSE_WINDOW", None}, + {"_NET_WM_STATE", None}, + {"_NET_WM_STATE_MAXIMIZED_VERT",None}, + {"_NET_WM_STATE_MAXIMIZED_HORZ",None}, }; void xu_getatoms(void) { - int i; + u_int i; for (i = 0; i < nitems(cwmh); i++) cwmh[i].atom = XInternAtom(X_Dpy, cwmh[i].name, False); @@ -271,7 +263,7 @@ void xu_ewmh_net_supported(struct screen_ctx *sc) { Atom atom[EWMH_NITEMS]; - int i; + u_int i; for (i = 0; i < nitems(ewmh); i++) atom[i] = ewmh[i].atom; @@ -416,24 +408,125 @@ xu_ewmh_net_wm_desktop(struct client_ctx *cc) XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&no, 1); } -unsigned long -xu_getcolor(struct screen_ctx *sc, char *name) +Atom * +xu_ewmh_get_net_wm_state(struct client_ctx *cc, int *n) { - XColor color, tmp; + Atom *state, *p = NULL; - if (!XAllocNamedColor(X_Dpy, sc->colormap, name, &color, &tmp)) { - warnx("XAllocNamedColor error: '%s'", name); - return (0); - } + if ((*n = xu_getprop(cc->win, ewmh[_NET_WM_STATE].atom, XA_ATOM, 64L, + (u_char **)&p)) <= 0) + return (NULL); - return (color.pixel); + state = xmalloc(*n * sizeof(Atom)); + memcpy(state, p, *n * sizeof(Atom)); + XFree((char *)p); + + return (state); } void -xu_xorcolor(XRenderColor a, XRenderColor b, XRenderColor *r) +xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action, + Atom first, Atom second) { - r->red = a.red ^ b.red; - r->green = a.green ^ b.green; - r->blue = a.blue ^ b.blue; - r->alpha = 0xffff; + int i; + static struct handlers { + int atom; + int property; + void (*toggle)(struct client_ctx *); + } handlers[] = { + { _NET_WM_STATE_MAXIMIZED_VERT, + CLIENT_VMAXIMIZED, + client_vmaximize }, + { _NET_WM_STATE_MAXIMIZED_HORZ, + CLIENT_HMAXIMIZED, + client_hmaximize }, + }; + + for (i = 0; i < nitems(handlers); i++) { + if (first != ewmh[handlers[i].atom].atom && + second != ewmh[handlers[i].atom].atom) + continue; + switch (action) { + case _NET_WM_STATE_ADD: + if ((cc->flags & handlers[i].property) == 0) + handlers[i].toggle(cc); + break; + case _NET_WM_STATE_REMOVE: + if (cc->flags & handlers[i].property) + handlers[i].toggle(cc); + break; + case _NET_WM_STATE_TOGGLE: + handlers[i].toggle(cc); + } + } +} + +void +xu_ewmh_restore_net_wm_state(struct client_ctx *cc) +{ + Atom *atoms; + int i, n; + + atoms = xu_ewmh_get_net_wm_state(cc, &n); + for (i = 0; i < n; i++) { + if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_HORZ].atom) + client_hmaximize(cc); + if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_VERT].atom) + client_vmaximize(cc); + } + free(atoms); +} + +void +xu_ewmh_set_net_wm_state(struct client_ctx *cc) +{ + Atom *atoms, *oatoms; + int n, i, j; + + oatoms = xu_ewmh_get_net_wm_state(cc, &n); + atoms = xmalloc((n + _NET_WM_STATES_NITEMS) * sizeof(Atom)); + for (i = j = 0; i < n; i++) { + if (oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_HORZ].atom && + oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_VERT].atom) + atoms[j++] = oatoms[i]; + } + free(oatoms); + if (cc->flags & CLIENT_HMAXIMIZED) + atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_HORZ].atom; + if (cc->flags & CLIENT_VMAXIMIZED) + atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_VERT].atom; + if (j > 0) + XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE].atom, + XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, j); + else + XDeleteProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE].atom); + free(atoms); +} + +void +xu_xorcolor(XftColor a, XftColor b, XftColor *r) +{ + r->pixel = a.pixel ^ b.pixel; + r->color.red = a.color.red ^ b.color.red; + r->color.green = a.color.green ^ b.color.green; + r->color.blue = a.color.blue ^ b.color.blue; + r->color.alpha = 0xffff; +} + +int +xu_xft_width(XftFont *xftfont, const char *text, int len) +{ + XGlyphInfo extents; + + XftTextExtentsUtf8(X_Dpy, xftfont, (const FcChar8*)text, + len, &extents); + + return (extents.xOff); +} + +void +xu_xft_draw(struct screen_ctx *sc, const char *text, int color, int x, int y) +{ + XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor[color], sc->xftfont, + x, y, (const FcChar8*)text, strlen(text)); }