diff --git a/calmwm.c b/calmwm.c index 08d0b53..58cb768 100644 --- a/calmwm.c +++ b/calmwm.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -48,21 +49,22 @@ struct client_ctx_q Clientq = TAILQ_HEAD_INITIALIZER(Clientq); int HasRandr, Randr_ev; struct conf Conf; +char *homedir; static void sigchld_cb(int); static void dpy_init(const char *); static int x_errorhandler(Display *, XErrorEvent *); static int x_wmerrorhandler(Display *, XErrorEvent *); static void x_setup(void); -static void x_setupscreen(struct screen_ctx *, u_int); static void x_teardown(void); int main(int argc, char **argv) { const char *conf_file = NULL; - char *display_name = NULL; + char *conf_path, *display_name = NULL; int ch; + struct passwd *pw; if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) warnx("no locale support"); @@ -87,15 +89,36 @@ main(int argc, char **argv) if (signal(SIGCHLD, sigchld_cb) == SIG_ERR) err(1, "signal"); + if ((homedir = getenv("HOME")) == NULL || *homedir == '\0') { + pw = getpwuid(getuid()); + if (pw != NULL && pw->pw_dir != NULL && *pw->pw_dir != '\0') + homedir = pw->pw_dir; + else + homedir = "/"; + } + + if (conf_file == NULL) + xasprintf(&conf_path, "%s/%s", homedir, CONFFILE); + else + conf_path = xstrdup(conf_file); + + if (access(conf_path, R_OK) != 0) { + if (conf_file != NULL) + warn("%s", conf_file); + free(conf_path); + conf_path = NULL; + } + dpy_init(display_name); - bzero(&Conf, sizeof(Conf)); - conf_setup(&Conf, conf_file); + conf_init(&Conf); + if (conf_path && (parse_config(conf_path, &Conf) == -1)) + warnx("config file %s has errors, not loading", conf_path); + free(conf_path); + xu_getatoms(); x_setup(); - xev_loop(); - x_teardown(); return (0); @@ -135,7 +158,7 @@ x_setup(void) for (i = 0; i < ScreenCount(X_Dpy); i++) { sc = xcalloc(1, sizeof(*sc)); - x_setupscreen(sc, i); + screen_init(sc, i); TAILQ_INSERT_TAIL(&Screenq, sc, entry); } @@ -150,69 +173,9 @@ x_setup(void) static void x_teardown(void) { - struct screen_ctx *sc; - - TAILQ_FOREACH(sc, &Screenq, entry) - XFreeGC(X_Dpy, sc->gc); - XCloseDisplay(X_Dpy); } -static void -x_setupscreen(struct screen_ctx *sc, u_int which) -{ - Window *wins, w0, w1; - XWindowAttributes winattr; - XSetWindowAttributes rootattr; - u_int nwins, i; - - sc->which = which; - sc->rootwin = RootWindow(X_Dpy, sc->which); - - xu_ewmh_net_supported(sc); - xu_ewmh_net_supported_wm_check(sc); - - conf_gap(&Conf, sc); - - screen_update_geometry(sc); - - conf_color(&Conf, sc); - - group_init(sc); - conf_font(&Conf, sc); - - TAILQ_INIT(&sc->mruq); - - /* Initialize menu window. */ - menu_init(sc); - - rootattr.cursor = Cursor_normal; - rootattr.event_mask = CHILDMASK|PropertyChangeMask|EnterWindowMask| - LeaveWindowMask|ColormapChangeMask|BUTTONMASK; - - XChangeWindowAttributes(X_Dpy, sc->rootwin, - CWEventMask|CWCursor, &rootattr); - - /* Deal with existing clients. */ - XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins); - - for (i = 0; i < nwins; i++) { - XGetWindowAttributes(X_Dpy, wins[i], &winattr); - if (winattr.override_redirect || - winattr.map_state != IsViewable) - continue; - (void)client_new(wins[i], sc, winattr.map_state != IsUnmapped); - } - XFree(wins); - - screen_updatestackingorder(sc); - - if (HasRandr) - XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask); - - XSync(X_Dpy, False); -} - static int x_wmerrorhandler(Display *dpy, XErrorEvent *e) { diff --git a/calmwm.h b/calmwm.h index 7bbe0f9..cf63a64 100644 --- a/calmwm.h +++ b/calmwm.h @@ -56,15 +56,12 @@ size_t strlcat(char *, const char *, size_t); #define CONFFILE ".cwmrc" #define WMNAME "CWM" -#define CHILDMASK (SubstructureRedirectMask|SubstructureNotifyMask) #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) +#define MENUMASK (MOUSEMASK|ButtonMotionMask|ExposureMask) +#define MENUGRABMASK (MOUSEMASK|ButtonMotionMask|StructureNotifyMask) #define KEYMASK (KeyPressMask|ExposureMask) -#define MENUMASK (BUTTONMASK|ButtonMotionMask|ExposureMask| \ - PointerMotionMask) -#define MENUGRABMASK (BUTTONMASK|ButtonMotionMask|StructureNotifyMask|\ - PointerMotionMask) -#define SEARCHMASK (KeyPressMask|ExposureMask) +#define IGNOREMODMASK (LockMask|Mod2Mask) /* kb movement */ #define CWM_MOVE 0x0001 @@ -96,14 +93,19 @@ 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 cwmcolor { CWM_COLOR_BORDER_ACTIVE, CWM_COLOR_BORDER_INACTIVE, CWM_COLOR_BORDER_GROUP, CWM_COLOR_BORDER_UNGROUP, - CWM_COLOR_FG_MENU, - CWM_COLOR_BG_MENU, - CWM_COLOR_FONT, CWM_COLOR_MAX }; @@ -139,7 +141,7 @@ struct client_ctx { struct screen_ctx *sc; Window win; XSizeHints *size; - Colormap cmap; + Colormap colormap; u_int bwidth; /* border width */ struct geom geom, savegeom; struct { @@ -166,16 +168,16 @@ struct client_ctx { #define CLIENT_VMAXIMIZED 0x0004 #define CLIENT_HMAXIMIZED 0x0008 #define CLIENT_FREEZE 0x0010 +#define CLIENT_GROUP 0x0020 +#define CLIENT_UNGROUP 0x0040 +#define CLIENT_HIGHLIGHT (CLIENT_GROUP | CLIENT_UNGROUP) #define CLIENT_MAXFLAGS (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED) #define CLIENT_MAXIMIZED (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED) int flags; int state; int active; int stackingorder; -#define CLIENT_HIGHLIGHT_GROUP 0x0001 -#define CLIENT_HIGHLIGHT_UNGROUP 0x0002 - int highlight; struct winname_q nameq; #define CLIENT_MAXNAMEQLEN 5 int nameqlen; @@ -217,18 +219,19 @@ TAILQ_HEAD(autogroupwin_q, autogroupwin); struct screen_ctx { TAILQ_ENTRY(screen_ctx) entry; u_int which; + Visual *visual; + Colormap colormap; Window rootwin; Window menuwin; struct color color[CWM_COLOR_MAX]; - GC gc; int cycling; struct geom view; /* viewable area */ struct geom work; /* workable area, gap-applied */ struct gap gap; struct cycle_entry_q mruq; - XftColor xftcolor; + XftColor xftcolor[CWM_COLOR_MENU_MAX]; XftDraw *xftdraw; - XftFont *font; + XftFont *xftfont; int xinerama_no; XineramaScreenInfo *xinerama; #define CALMWM_NGROUPS 9 @@ -266,7 +269,6 @@ TAILQ_HEAD(mousebinding_q, mousebinding); struct cmd { TAILQ_ENTRY(cmd) entry; - int flags; char image[MAXPATHLEN]; #define CMD_MAXLABELLEN 256 char label[CMD_MAXLABELLEN]; @@ -301,8 +303,10 @@ struct conf { int snapdist; struct gap gap; struct color color[CWM_COLOR_MAX]; + char *menucolor[CWM_COLOR_MENU_MAX]; char termpath[MAXPATHLEN]; char lockpath[MAXPATHLEN]; + char known_hosts[MAXPATHLEN]; #define CONF_FONT "sans-serif:pixelsize=14:bold" char *font; }; @@ -324,7 +328,8 @@ __dead void usage(void); void client_applysizehints(struct client_ctx *); struct client_ctx *client_current(void); void client_cycle(struct screen_ctx *, int); -void client_cycle_leave(struct screen_ctx *, struct client_ctx *); +void client_cycle_leave(struct screen_ctx *, + struct client_ctx *); void client_delete(struct client_ctx *); void client_draw_border(struct client_ctx *); struct client_ctx *client_find(Window); @@ -337,7 +342,6 @@ void client_lower(struct client_ctx *); void client_map(struct client_ctx *); void client_maximize(struct client_ctx *); void client_move(struct client_ctx *); -void client_mtf(struct client_ctx *); struct client_ctx *client_new(Window, struct screen_ctx *, int); void client_ptrsave(struct client_ctx *); void client_ptrwarp(struct client_ctx *); @@ -371,8 +375,8 @@ void search_match_client(struct menu_q *, struct menu_q *, char *); void search_match_exec(struct menu_q *, struct menu_q *, char *); -void search_match_exec_path(struct menu_q *, struct menu_q *, - char *); +void search_match_exec_path(struct menu_q *, + struct menu_q *, char *); void search_match_path_any(struct menu_q *, struct menu_q *, char *); void search_match_text(struct menu_q *, struct menu_q *, @@ -381,6 +385,7 @@ void search_print_client(struct menu *, int); XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int); struct screen_ctx *screen_fromroot(Window); +void screen_init(struct screen_ctx *, u_int); void screen_update_geometry(struct screen_ctx *); void screen_updatestackingorder(struct screen_ctx *); @@ -436,13 +441,14 @@ struct menu *menu_filter(struct screen_ctx *, struct menu_q *, 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 *); 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 *, int); +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 *); @@ -450,16 +456,15 @@ void conf_grab(struct conf *, struct keybinding *); void conf_grab_mouse(struct client_ctx *); void conf_init(struct conf *); void conf_mousebind(struct conf *, char *, char *); -void conf_setup(struct conf *, const 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); + Drawable, int, int, int); u_int font_height(struct screen_ctx *); void font_init(struct screen_ctx *, const char *, - const char *); + const char **); int font_width(struct screen_ctx *, const char *, int); void xev_loop(void); @@ -481,6 +486,8 @@ void xu_ptr_setpos(Window, int, int); void xu_ptr_ungrab(void); void xu_sendmsg(Window, Atom, long); void xu_setstate(struct client_ctx *, int); +void xu_xorcolor(XRenderColor, XRenderColor, + XRenderColor *); void xu_ewmh_net_supported(struct screen_ctx *); void xu_ewmh_net_supported_wm_check(struct screen_ctx *); @@ -493,11 +500,11 @@ void xu_ewmh_net_wm_number_of_desktops(struct screen_ctx *); void xu_ewmh_net_showing_desktop(struct screen_ctx *); void xu_ewmh_net_virtual_roots(struct screen_ctx *); void xu_ewmh_net_current_desktop(struct screen_ctx *, long); -void xu_ewmh_net_desktop_names(struct screen_ctx *, char *, int); +void xu_ewmh_net_desktop_names(struct screen_ctx *, char *, + int); void xu_ewmh_net_wm_desktop(struct client_ctx *); - void u_exec(char *); void u_spawn(char *); @@ -520,8 +527,9 @@ extern Cursor Cursor_resize; extern struct screen_ctx_q Screenq; extern struct client_ctx_q Clientq; extern struct conf Conf; +extern char *homedir; -extern int HasXinerama, HasRandr, Randr_ev; +extern int HasRandr, Randr_ev; enum { WM_STATE, diff --git a/client.c b/client.c index 455f5ef..2394d2d 100644 --- a/client.c +++ b/client.c @@ -33,6 +33,7 @@ static struct client_ctx *client_mrunext(struct client_ctx *); 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 *); @@ -91,7 +92,7 @@ client_new(Window win, struct screen_ctx *sc, int mapped) cc->geom.y = wattr.y; cc->geom.w = wattr.width; cc->geom.h = wattr.height; - cc->cmap = wattr.colormap; + cc->colormap = wattr.colormap; if (wattr.map_state != IsViewable) { client_placecalc(cc); @@ -158,7 +159,7 @@ client_delete(struct client_ctx *cc) xu_ewmh_net_client_list(sc); - if (_curcc == cc) + if (cc == client_current()) client_none(sc); XFree(cc->size); @@ -180,7 +181,7 @@ client_leave(struct client_ctx *cc) struct screen_ctx *sc; if (cc == NULL) - cc = _curcc; + cc = client_current(); if (cc == NULL) return; @@ -194,14 +195,14 @@ client_setactive(struct client_ctx *cc, int fg) struct screen_ctx *sc; if (cc == NULL) - cc = _curcc; + cc = client_current(); if (cc == NULL) return; sc = cc->sc; if (fg) { - XInstallColormap(X_Dpy, cc->cmap); + XInstallColormap(X_Dpy, cc->colormap); XSetInputFocus(X_Dpy, cc->win, RevertToPointerRoot, CurrentTime); conf_grab_mouse(cc); @@ -214,7 +215,7 @@ client_setactive(struct client_ctx *cc, int fg) } else client_leave(cc); - if (fg && _curcc != cc) { + if (fg && cc != client_current()) { client_setactive(NULL, 0); _curcc = cc; xu_ewmh_net_active_window(sc, cc->win); @@ -480,7 +481,7 @@ client_hide(struct client_ctx *cc) cc->flags |= CLIENT_HIDDEN; xu_setstate(cc, IconicState); - if (cc == _curcc) + if (cc == client_current()) client_none(cc->sc); } @@ -489,7 +490,6 @@ client_unhide(struct client_ctx *cc) { XMapRaised(X_Dpy, cc->win); - cc->highlight = 0; cc->flags &= ~CLIENT_HIDDEN; xu_setstate(cc, NormalState); client_draw_border(cc); @@ -502,11 +502,11 @@ client_draw_border(struct client_ctx *cc) unsigned long pixel; if (cc->active) - switch (cc->highlight) { - case CLIENT_HIGHLIGHT_GROUP: + switch (cc->flags & CLIENT_HIGHLIGHT) { + case CLIENT_GROUP: pixel = sc->color[CWM_COLOR_BORDER_GROUP].pixel; break; - case CLIENT_HIGHLIGHT_UNGROUP: + case CLIENT_UNGROUP: pixel = sc->color[CWM_COLOR_BORDER_UNGROUP].pixel; break; default: @@ -731,19 +731,17 @@ client_placecalc(struct client_ctx *cc) } } -void +static void client_mtf(struct client_ctx *cc) { struct screen_ctx *sc; if (cc == NULL) - cc = _curcc; + cc = client_current(); if (cc == NULL) return; sc = cc->sc; - - /* Move to front. */ TAILQ_REMOVE(&sc->mruq, cc, mru_entry); TAILQ_INSERT_HEAD(&sc->mruq, cc, mru_entry); } diff --git a/conf.c b/conf.c index 4f50039..88c5fd9 100644 --- a/conf.c +++ b/conf.c @@ -36,7 +36,7 @@ static void conf_unbind(struct conf *, struct keybinding *); /* Add an command menu entry to the end of the menu */ void -conf_cmd_add(struct conf *c, char *image, char *label, int flags) +conf_cmd_add(struct conf *c, char *image, char *label) { /* "term" and "lock" have special meanings. */ @@ -46,7 +46,6 @@ conf_cmd_add(struct conf *c, char *image, char *label, int flags) (void)strlcpy(c->lockpath, image, sizeof(c->lockpath)); else { struct cmd *cmd = xmalloc(sizeof(*cmd)); - cmd->flags = flags; (void)strlcpy(cmd->image, image, sizeof(cmd->image)); (void)strlcpy(cmd->label, label, sizeof(cmd->label)); TAILQ_INSERT_TAIL(&c->cmdq, cmd, entry); @@ -62,17 +61,21 @@ conf_gap(struct conf *c, struct screen_ctx *sc) void conf_font(struct conf *c, struct screen_ctx *sc) { - font_init(sc, c->font, c->color[CWM_COLOR_FONT].name); + font_init(sc, c->font, (const char **)c->menucolor); } -static struct color color_binds[] = { +static char *menu_color_binds[CWM_COLOR_MENU_MAX] = { + "black", /* CWM_COLOR_MENU_FG */ + "white", /* CWM_COLOR_MENU_BG */ + "black", /* CWM_COLOR_MENU_FONT */ + "", /* CWM_COLOR_MENU_FONT_SEL */ +}; + +static struct color color_binds[CWM_COLOR_MAX] = { { "#CCCCCC", 0 }, /* CWM_COLOR_BORDER_ACTIVE */ { "#666666", 0 }, /* CWM_COLOR_BORDER_INACTIVE */ { "blue", 0 }, /* CWM_COLOR_BORDER_GROUP */ { "red", 0 }, /* CWM_COLOR_BORDER_UNGROUP */ - { "black", 0 }, /* CWM_COLOR_FG_MENU */ - { "white", 0 }, /* CWM_COLOR_BG_MENU */ - { "black", 0 }, /* CWM_COLOR_FONT */ }; void @@ -162,7 +165,8 @@ conf_init(struct conf *c) { int i; - c->flags = 0; + bzero(c, sizeof(*c)); + c->bwidth = CONF_BWIDTH; c->mamount = CONF_MAMOUNT; c->snapdist = CONF_SNAPDIST; @@ -182,10 +186,16 @@ conf_init(struct conf *c) for (i = 0; i < nitems(color_binds); i++) c->color[i].name = xstrdup(color_binds[i].name); + 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)); + (void)snprintf(c->known_hosts, sizeof(c->known_hosts), "%s/%s", + homedir, ".ssh/known_hosts"); + c->font = xstrdup(CONF_FONT); } @@ -232,38 +242,6 @@ conf_clear(struct conf *c) free(c->font); } -void -conf_setup(struct conf *c, const char *conf_file) -{ - char conf_path[MAXPATHLEN]; - char *home; - struct stat sb; - int parse = 0; - - conf_init(c); - - if (conf_file == NULL) { - if ((home = getenv("HOME")) == NULL) - errx(1, "No HOME directory."); - - (void)snprintf(conf_path, sizeof(conf_path), "%s/%s", - home, CONFFILE); - - if (stat(conf_path, &sb) == 0 && (sb.st_mode & S_IFREG)) - parse = 1; - } else { - if (stat(conf_file, &sb) == -1 || !(sb.st_mode & S_IFREG)) - errx(1, "%s: %s", conf_file, strerror(errno)); - else { - (void)strlcpy(conf_path, conf_file, sizeof(conf_path)); - parse = 1; - } - } - - if (parse && (parse_config(conf_path, c) == -1)) - warnx("config file %s has errors, not loading", conf_path); -} - void conf_client(struct client_ctx *cc) { diff --git a/cwmrc.5 b/cwmrc.5 index 39ab221..c8ea841 100644 --- a/cwmrc.5 +++ b/cwmrc.5 @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: November 7 2012 $ +.Dd $Mdocdate: November 29 2012 $ .Dt CWMRC 5 .Os .Sh NAME @@ -50,6 +50,7 @@ or if their name and class properties match and .Ar windowclass , respectively. +The more specific last match wins. .Ar group is a number between 0 and 9. If @@ -111,6 +112,9 @@ Set the color of the active border. .It Ic color font Ar color Set menu font color. .Pp +.It Ic color selfont Ar color +Set font color for selected menu item. +.Pp .It Ic color groupborder Ar color Set the color of the border while grouping a window. .Pp diff --git a/font.c b/font.c index 4267e91..648450e 100644 --- a/font.c +++ b/font.c @@ -33,36 +33,52 @@ int font_ascent(struct screen_ctx *sc) { - return (sc->font->ascent); + return (sc->xftfont->ascent); } int font_descent(struct screen_ctx *sc) { - return (sc->font->descent); + return (sc->xftfont->descent); } u_int font_height(struct screen_ctx *sc) { - return (sc->font->height + 1); + return (sc->xftfont->height + 1); } void -font_init(struct screen_ctx *sc, const char *name, const char *color) +font_init(struct screen_ctx *sc, const char *name, const char **color) { + int i; + XRenderColor c; + sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin, - DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which)); + sc->visual, sc->colormap); if (sc->xftdraw == NULL) errx(1, "XftDrawCreate"); - if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which), - DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor)) - errx(1, "XftColorAllocName"); - - sc->font = XftFontOpenName(X_Dpy, sc->which, name); - if (sc->font == NULL) + 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 @@ -70,7 +86,7 @@ font_width(struct screen_ctx *sc, const char *text, int len) { XGlyphInfo extents; - XftTextExtentsUtf8(X_Dpy, sc->font, (const FcChar8*)text, + XftTextExtentsUtf8(X_Dpy, sc->xftfont, (const FcChar8*)text, len, &extents); return (extents.xOff); @@ -78,9 +94,12 @@ font_width(struct screen_ctx *sc, const char *text, int len) void font_draw(struct screen_ctx *sc, const char *text, int len, - Drawable d, int x, int y) + 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, sc->font, x, y, + XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor[color], sc->xftfont, x, y, (const FcChar8*)text, len); } diff --git a/group.c b/group.c index 834fac4..ab72eef 100644 --- a/group.c +++ b/group.c @@ -218,16 +218,14 @@ void group_sticky_toggle_enter(struct client_ctx *cc) { struct screen_ctx *sc = cc->sc; - struct group_ctx *gc; - - gc = sc->group_active; + struct group_ctx *gc = sc->group_active; if (gc == cc->group) { group_remove(cc); - cc->highlight = CLIENT_HIGHLIGHT_UNGROUP; + cc->flags |= CLIENT_UNGROUP; } else { group_add(gc, cc); - cc->highlight = CLIENT_HIGHLIGHT_GROUP; + cc->flags |= CLIENT_GROUP; } client_draw_border(cc); @@ -236,7 +234,7 @@ group_sticky_toggle_enter(struct client_ctx *cc) void group_sticky_toggle_exit(struct client_ctx *cc) { - cc->highlight = 0; + cc->flags &= ~CLIENT_HIGHLIGHT; client_draw_border(cc); } @@ -385,10 +383,7 @@ group_menu(XButtonEvent *e) (gc->hidden) ? group_show(sc, gc) : group_hide(sc, gc); cleanup: - while ((mi = TAILQ_FIRST(&menuq)) != NULL) { - TAILQ_REMOVE(&menuq, mi, entry); - free(mi); - } + menuq_clear(&menuq); } void @@ -412,7 +407,7 @@ group_autogroup(struct client_ctx *cc) struct screen_ctx *sc = cc->sc; struct autogroupwin *aw; struct group_ctx *gc; - int no = -1; + int no = -1, both_match = 0; long *grpno; if (cc->app_class == NULL || cc->app_name == NULL) @@ -429,11 +424,13 @@ group_autogroup(struct client_ctx *cc) XFree(grpno); } else { TAILQ_FOREACH(aw, &Conf.autogroupq, entry) { - if (strcmp(aw->class, cc->app_class) == 0 && - (aw->name == NULL || - strcmp(aw->name, cc->app_name) == 0)) { - no = aw->num; - break; + if (strcmp(aw->class, cc->app_class) == 0) { + if ((aw->name != NULL) && + (strcmp(aw->name, cc->app_name) == 0)) { + no = aw->num; + both_match = 1; + } else if (aw->name == NULL && !both_match) + no = aw->num; } } } diff --git a/kbfunc.c b/kbfunc.c index c110a9f..d574878 100644 --- a/kbfunc.c +++ b/kbfunc.c @@ -33,7 +33,6 @@ #include "calmwm.h" -#define KNOWN_HOSTS ".ssh/known_hosts" #define HASH_MARKER "|1|" extern char **cwm_argv; @@ -168,10 +167,7 @@ kbfunc_client_search(struct client_ctx *cc, union arg *arg) client_ptrwarp(cc); } - while ((mi = TAILQ_FIRST(&menuq)) != NULL) { - TAILQ_REMOVE(&menuq, mi, entry); - free(mi); - } + menuq_clear(&menuq); } void @@ -195,10 +191,7 @@ kbfunc_menu_search(struct client_ctx *cc, union arg *arg) search_match_text, NULL)) != NULL) u_spawn(((struct cmd *)mi->ctx)->image); - while ((mi = TAILQ_FIRST(&menuq)) != NULL) { - TAILQ_REMOVE(&menuq, mi, entry); - free(mi); - } + menuq_clear(&menuq); } void @@ -320,10 +313,7 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg) out: if (mi != NULL && mi->dummy) free(mi); - while ((mi = TAILQ_FIRST(&menuq)) != NULL) { - TAILQ_REMOVE(&menuq, mi, entry); - free(mi); - } + menuq_clear(&menuq); } void @@ -333,21 +323,16 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg) struct menu *mi; struct menu_q menuq; FILE *fp; - char *buf, *lbuf, *p, *home; - char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN]; + char *buf, *lbuf, *p; + char hostbuf[MAXHOSTNAMELEN]; char cmd[256]; int l; size_t len; - if ((home = getenv("HOME")) == NULL) - return; - - l = snprintf(filename, sizeof(filename), "%s/%s", home, KNOWN_HOSTS); - if (l == -1 || l >= sizeof(filename)) - return; - - if ((fp = fopen(filename, "r")) == NULL) + if ((fp = fopen(Conf.known_hosts, "r")) == NULL) { + warn("kbfunc_ssh: %s", Conf.known_hosts); return; + } TAILQ_INIT(&menuq); lbuf = NULL; @@ -390,10 +375,7 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg) out: if (mi != NULL && mi->dummy) free(mi); - while ((mi = TAILQ_FIRST(&menuq)) != NULL) { - TAILQ_REMOVE(&menuq, mi, entry); - free(mi); - } + menuq_clear(&menuq); } void diff --git a/menu.c b/menu.c index dcf801d..87c04d6 100644 --- a/menu.c +++ b/menu.c @@ -65,11 +65,13 @@ 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 screen_ctx *, 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 *, int, int); static int menu_keycode(XKeyEvent *, enum ctltype *, @@ -78,20 +80,10 @@ static int menu_keycode(XKeyEvent *, enum ctltype *, void menu_init(struct screen_ctx *sc) { - XGCValues gv; - sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1, Conf.bwidth, - sc->color[CWM_COLOR_FG_MENU].pixel, - sc->color[CWM_COLOR_BG_MENU].pixel); - - gv.foreground = - sc->color[CWM_COLOR_FG_MENU].pixel^sc->color[CWM_COLOR_BG_MENU].pixel; - gv.background = sc->color[CWM_COLOR_BG_MENU].pixel; - gv.function = GXxor; - - sc->gc = XCreateGC(X_Dpy, sc->menuwin, - GCForeground|GCBackground|GCFunction, &gv); + sc->xftcolor[CWM_COLOR_MENU_FG].pixel, + sc->xftcolor[CWM_COLOR_MENU_BG].pixel); } struct menu * @@ -174,7 +166,7 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt, menu_draw(sc, &mc, menuq, &resultq); break; case MotionNotify: - menu_handle_move(&e, &mc, sc); + menu_handle_move(&e, &mc, sc, &resultq); break; case ButtonRelease: if ((mi = menu_handle_release(&e, &mc, sc, &resultq)) @@ -223,10 +215,7 @@ menu_complete_path(struct menu_ctx *mc) strlcpy(path, mi->text, sizeof(mi->text)); } - while ((mi = TAILQ_FIRST(&menuq)) != NULL) { - TAILQ_REMOVE(&menuq, mi, entry); - free(mi); - } + menuq_clear(&menuq); if (path[0] != '\0') snprintf(mr->text, sizeof(mr->text), "%s \"%s\"", @@ -442,8 +431,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, font_ascent(sc) + 1); + font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin, 0, + 0, font_ascent(sc)); n = 1; } else n = 0; @@ -458,34 +447,61 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, break; font_draw(sc, text, MIN(strlen(text), MENU_MAXENTRY), - sc->menuwin, 0, y); + sc->menuwin, 0, 0, y); n++; } - - if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0')) - XFillRectangle(X_Dpy, sc->menuwin, sc->gc, - 0, font_height(sc), mc->width, font_height(sc)); - - if (mc->noresult) - XFillRectangle(X_Dpy, sc->menuwin, sc->gc, - 0, 0, mc->width, font_height(sc)); + if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0')) { + mc->entry = 1; + menu_draw_entry(sc, mc, resultq, mc->entry, 1); + } } static void -menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc) +menu_draw_entry(struct screen_ctx *sc, struct menu_ctx *mc, + struct menu_q *resultq, int entry, int active) +{ + struct menu *mi; + char *text; + int color, i = 0; + + if (mc->hasprompt) + i = 1; + + TAILQ_FOREACH(mi, resultq, resultentry) + if (entry == i++) + break; + if (mi == NULL) + return; + + color = active ? CWM_COLOR_MENU_FG : CWM_COLOR_MENU_BG; + 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); +} + +static void +menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc, + struct menu_q *resultq) { mc->prev = mc->entry; mc->entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y); + if (mc->prev == mc->entry) + return; + if (mc->prev != -1) - XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0, - font_height(sc) * mc->prev, mc->width, font_height(sc)); + menu_draw_entry(sc, mc, resultq, mc->prev, 0); if (mc->entry != -1) { (void)xu_ptr_regrab(MENUGRABMASK, Cursor_normal); - XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0, - font_height(sc) * mc->entry, mc->width, font_height(sc)); + menu_draw_entry(sc, mc, resultq, mc->entry, 1); } else (void)xu_ptr_regrab(MENUGRABMASK, Cursor_default); + + if (mc->hasprompt) + menu_draw_entry(sc, mc, resultq, 1, 1); } static struct menu * @@ -519,7 +535,7 @@ menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y) entry = y / font_height(sc); /* in bounds? */ - if (x <= 0 || x > mc->width || y <= 0 || + if (x < 0 || x > mc->width || y < 0 || y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num) entry = -1; @@ -613,3 +629,14 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr) return (0); } + +void +menuq_clear(struct menu_q *mq) +{ + struct menu *mi; + + while ((mi = TAILQ_FIRST(mq)) != NULL) { + TAILQ_REMOVE(mq, mi, entry); + free(mi); + } +} diff --git a/mousefunc.c b/mousefunc.c index 37dd7a1..7c07a36 100644 --- a/mousefunc.c +++ b/mousefunc.c @@ -68,9 +68,9 @@ mousefunc_sweep_draw(struct client_ctx *cc) XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0, width, font_height(sc) * 2); XMapWindow(X_Dpy, sc->menuwin); XClearWindow(X_Dpy, sc->menuwin); - font_draw(sc, cc->name, strlen(cc->name), 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, + font_draw(sc, asize, strlen(asize), sc->menuwin, 0, width / 2 - width_size / 2, font_height(sc) + font_ascent(sc) + 1); } @@ -250,12 +250,8 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg) if (old_cc != NULL) client_ptrsave(old_cc); client_ptrwarp(cc); - } else { - while ((mi = TAILQ_FIRST(&menuq)) != NULL) { - TAILQ_REMOVE(&menuq, mi, entry); - free(mi); - } - } + } else + menuq_clear(&menuq); } void @@ -280,8 +276,5 @@ mousefunc_menu_cmd(struct client_ctx *cc, void *arg) if (mi != NULL) u_spawn(((struct cmd *)mi->ctx)->image); else - while ((mi = TAILQ_FIRST(&menuq)) != NULL) { - TAILQ_REMOVE(&menuq, mi, entry); - free(mi); - } + menuq_clear(&menuq); } diff --git a/parse.y b/parse.y index 006d1b8..aae8f3c 100644 --- a/parse.y +++ b/parse.y @@ -75,7 +75,8 @@ typedef struct { %token COLOR SNAPDIST %token ACTIVEBORDER INACTIVEBORDER %token GROUPBORDER UNGROUPBORDER -%token MENUBG MENUFG FONTCOLOR +%token MENUBG MENUFG +%token FONTCOLOR FONTSELCOLOR %token ERROR %token STRING %token NUMBER @@ -127,7 +128,7 @@ main : FONTNAME STRING { conf->snapdist = $2; } | COMMAND STRING string { - conf_cmd_add(conf, $3, $2, 0); + conf_cmd_add(conf, $3, $2); free($2); free($3); } @@ -188,16 +189,20 @@ colors : ACTIVEBORDER STRING { conf->color[CWM_COLOR_BORDER_UNGROUP].name = $2; } | MENUBG STRING { - free(conf->color[CWM_COLOR_BG_MENU].name); - conf->color[CWM_COLOR_BG_MENU].name = $2; + free(conf->menucolor[CWM_COLOR_MENU_BG]); + conf->menucolor[CWM_COLOR_MENU_BG] = $2; } | MENUFG STRING { - free(conf->color[CWM_COLOR_FG_MENU].name); - conf->color[CWM_COLOR_FG_MENU].name = $2; + free(conf->menucolor[CWM_COLOR_MENU_FG]); + conf->menucolor[CWM_COLOR_MENU_FG] = $2; } | FONTCOLOR STRING { - free(conf->color[CWM_COLOR_FONT].name); - conf->color[CWM_COLOR_FONT].name = $2; + free(conf->menucolor[CWM_COLOR_MENU_FONT]); + conf->menucolor[CWM_COLOR_MENU_FONT] = $2; + } + | FONTSELCOLOR STRING { + free(conf->menucolor[CWM_COLOR_MENU_FONT_SEL]); + conf->menucolor[CWM_COLOR_MENU_FONT_SEL] = $2; } ; %% @@ -249,6 +254,7 @@ lookup(char *s) { "mousebind", MOUSEBIND}, { "moveamount", MOVEAMOUNT}, { "no", NO}, + { "selfont", FONTSELCOLOR}, { "snapdist", SNAPDIST}, { "sticky", STICKY}, { "ungroupborder", UNGROUPBORDER}, @@ -577,6 +583,9 @@ parse_config(const char *filename, struct conf *xconf) for (i = 0; i < CWM_COLOR_MAX; i++) xconf->color[i].name = conf->color[i].name; + 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 c723378..92ff9a4 100644 --- a/screen.c +++ b/screen.c @@ -32,6 +32,63 @@ static void screen_init_xinerama(struct screen_ctx *); +void +screen_init(struct screen_ctx *sc, u_int which) +{ + Window *wins, w0, w1; + XWindowAttributes winattr; + XSetWindowAttributes rootattr; + u_int nwins, i; + + sc->which = which; + sc->visual = DefaultVisual(X_Dpy, sc->which); + sc->colormap = DefaultColormap(X_Dpy, sc->which); + sc->rootwin = RootWindow(X_Dpy, sc->which); + + xu_ewmh_net_supported(sc); + xu_ewmh_net_supported_wm_check(sc); + + conf_gap(&Conf, sc); + + screen_update_geometry(sc); + + conf_color(&Conf, sc); + + group_init(sc); + conf_font(&Conf, sc); + + TAILQ_INIT(&sc->mruq); + + menu_init(sc); + + rootattr.cursor = Cursor_normal; + rootattr.event_mask = SubstructureRedirectMask|SubstructureNotifyMask| + PropertyChangeMask|EnterWindowMask|LeaveWindowMask| + ColormapChangeMask|BUTTONMASK; + + XChangeWindowAttributes(X_Dpy, sc->rootwin, + CWEventMask|CWCursor, &rootattr); + + /* Deal with existing clients. */ + XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins); + + for (i = 0; i < nwins; i++) { + XGetWindowAttributes(X_Dpy, wins[i], &winattr); + if (winattr.override_redirect || + winattr.map_state != IsViewable) + continue; + (void)client_new(wins[i], sc, winattr.map_state != IsUnmapped); + } + XFree(wins); + + screen_updatestackingorder(sc); + + if (HasRandr) + XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask); + + XSync(X_Dpy, False); +} + struct screen_ctx * screen_fromroot(Window rootwin) { diff --git a/xevents.c b/xevents.c index acfb2bc..abfaf0e 100644 --- a/xevents.c +++ b/xevents.c @@ -241,8 +241,7 @@ xev_handle_buttonpress(XEvent *ee) sc = screen_fromroot(e->root); cc = client_find(e->window); - /* Ignore caps lock and numlock */ - e->state &= ~(Mod2Mask | LockMask); + e->state &= ~IGNOREMODMASK; TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) { if (e->button == mb->button && e->state == mb->modmask) @@ -283,8 +282,7 @@ xev_handle_keypress(XEvent *ee) keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0); skeysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 1); - /* we don't care about caps lock and numlock here */ - e->state &= ~(LockMask | Mod2Mask); + e->state &= ~IGNOREMODMASK; TAILQ_FOREACH(kb, &Conf.keybindingq, entry) { if (keysym != kb->keysym && skeysym == kb->keysym) diff --git a/xutil.c b/xutil.c index fa3fc7f..d141766 100644 --- a/xutil.c +++ b/xutil.c @@ -422,11 +422,19 @@ xu_getcolor(struct screen_ctx *sc, char *name) { XColor color, tmp; - if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which), - name, &color, &tmp)) { + if (!XAllocNamedColor(X_Dpy, sc->colormap, name, &color, &tmp)) { warnx("XAllocNamedColor error: '%s'", name); return (0); } return (color.pixel); } + +void +xu_xorcolor(XRenderColor a, XRenderColor b, XRenderColor *r) +{ + r->red = a.red ^ b.red; + r->green = a.green ^ b.green; + r->blue = a.blue ^ b.blue; + r->alpha = 0xffff; +}