diff --git a/calmwm.h b/calmwm.h index bbea152..732733b 100644 --- a/calmwm.h +++ b/calmwm.h @@ -64,12 +64,12 @@ size_t strlcpy(char *, const char *, size_t); #define CONFFILE ".cwmrc" #define WMNAME "CWM" -#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) -#define MOUSEMASK (BUTTONMASK|PointerMotionMask) -#define MENUMASK (MOUSEMASK|ButtonMotionMask|ExposureMask) -#define MENUGRABMASK (MOUSEMASK|ButtonMotionMask|StructureNotifyMask) -#define KEYMASK (KeyPressMask|ExposureMask) -#define IGNOREMODMASK (LockMask|Mod2Mask) +#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask) +#define MOUSEMASK (BUTTONMASK | PointerMotionMask) +#define MENUMASK (MOUSEMASK | ButtonMotionMask | ExposureMask) +#define MENUGRABMASK (MOUSEMASK | ButtonMotionMask | StructureNotifyMask) +#define KEYMASK (KeyPressMask | ExposureMask) +#define IGNOREMODMASK (LockMask | Mod2Mask | 0x2000) /* kb movement */ #define CWM_MOVE 0x0001 @@ -168,6 +168,7 @@ struct client_ctx { TAILQ_ENTRY(client_ctx) entry; TAILQ_ENTRY(client_ctx) group_entry; struct screen_ctx *sc; + struct group_ctx *gc; Window win; Colormap colormap; unsigned int bwidth; /* border width */ @@ -219,7 +220,6 @@ struct client_ctx { char *name; char *label; char *matchname; - struct group_ctx *group; XClassHint ch; XWMHints *wmh; }; @@ -373,6 +373,7 @@ enum { _NET_SUPPORTING_WM_CHECK, _NET_ACTIVE_WINDOW, _NET_CLIENT_LIST, + _NET_CLIENT_LIST_STACKING, _NET_NUMBER_OF_DESKTOPS, _NET_CURRENT_DESKTOP, _NET_DESKTOP_VIEWPORT, @@ -385,13 +386,14 @@ enum { _NET_WM_DESKTOP, _NET_CLOSE_WINDOW, _NET_WM_STATE, -#define _NET_WM_STATES_NITEMS 6 +#define _NET_WM_STATES_NITEMS 7 _NET_WM_STATE_STICKY, _NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_HIDDEN, _NET_WM_STATE_FULLSCREEN, _NET_WM_STATE_DEMANDS_ATTENTION, + _CWM_WM_STATE_FREEZE, EWMH_NITEMS }; enum { @@ -445,7 +447,8 @@ void client_warp(struct client_ctx *); void client_wm_hints(struct client_ctx *); void group_alltoggle(struct screen_ctx *); -void group_autogroup(struct client_ctx *); +void group_assign(struct group_ctx *, struct client_ctx *); +int group_autogroup(struct client_ctx *); void group_cycle(struct screen_ctx *, int); void group_hide(struct group_ctx *); void group_hidetoggle(struct screen_ctx *, int); @@ -454,6 +457,7 @@ int group_holds_only_sticky(struct group_ctx *); void group_init(struct screen_ctx *, int); void group_movetogroup(struct client_ctx *, int); void group_only(struct screen_ctx *, int); +int group_restore(struct client_ctx *); void group_show(struct group_ctx *); void group_toggle_membership_enter(struct client_ctx *); void group_toggle_membership_leave(struct client_ctx *); @@ -582,6 +586,7 @@ void xu_ewmh_net_supported_wm_check(struct screen_ctx *); void xu_ewmh_net_desktop_geometry(struct screen_ctx *); void xu_ewmh_net_workarea(struct screen_ctx *); void xu_ewmh_net_client_list(struct screen_ctx *); +void xu_ewmh_net_client_list_stacking(struct screen_ctx *); void xu_ewmh_net_active_window(struct screen_ctx *, Window); void xu_ewmh_net_wm_desktop_viewport(struct screen_ctx *); void xu_ewmh_net_wm_number_of_desktops(struct screen_ctx *); diff --git a/client.c b/client.c index 06763e1..ba85452 100644 --- a/client.c +++ b/client.c @@ -112,6 +112,7 @@ client_init(Window win, struct screen_ctx *sc) TAILQ_INSERT_TAIL(&sc->clientq, cc, entry); xu_ewmh_net_client_list(sc); + xu_ewmh_net_client_list_stacking(sc); xu_ewmh_restore_net_wm_state(cc); if (client_get_wm_state(cc) == IconicState) @@ -119,9 +120,17 @@ client_init(Window win, struct screen_ctx *sc) else client_unhide(cc); - if (mapped) - group_autogroup(cc); - + if (mapped) { + if (group_restore(cc)) + goto out; + if (group_autogroup(cc)) + goto out; + if (Conf.flags & CONF_STICKY_GROUPS) + group_assign(sc->group_active, cc); + else + group_assign(NULL, cc); + } +out: XSync(X_Dpy, False); XUngrabServer(X_Dpy); @@ -152,9 +161,10 @@ client_delete(struct client_ctx *cc) TAILQ_REMOVE(&sc->clientq, cc, entry); xu_ewmh_net_client_list(sc); + xu_ewmh_net_client_list_stacking(sc); - if (cc->group != NULL) - TAILQ_REMOVE(&cc->group->clientq, cc, group_entry); + if (cc->gc != NULL) + TAILQ_REMOVE(&cc->gc->clientq, cc, group_entry); if (cc == client_current()) client_none(sc); @@ -194,7 +204,7 @@ client_setactive(struct client_ctx *cc) if (cc->flags & CLIENT_WM_TAKE_FOCUS) client_msg(cc, cwmh[WM_TAKE_FOCUS], Last_Event_Time); - if ((oldcc = client_current())) { + if ((oldcc = client_current()) != NULL) { oldcc->flags &= ~CLIENT_ACTIVE; client_draw_border(oldcc); } @@ -233,10 +243,15 @@ client_current(void) void client_toggle_freeze(struct client_ctx *cc) { + if (cc->flags & CLIENT_FULLSCREEN) + return; + if (cc->flags & CLIENT_FREEZE) cc->flags &= ~CLIENT_FREEZE; else cc->flags |= CLIENT_FREEZE; + + xu_ewmh_set_net_wm_state(cc); } void @@ -299,7 +314,7 @@ client_toggle_maximize(struct client_ctx *cc) struct screen_ctx *sc = cc->sc; struct geom area; - if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY)) + if (cc->flags & CLIENT_FREEZE) return; if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_MAXIMIZED) { @@ -344,7 +359,7 @@ client_toggle_vmaximize(struct client_ctx *cc) struct screen_ctx *sc = cc->sc; struct geom area; - if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY)) + if (cc->flags & CLIENT_FREEZE) return; if (cc->flags & CLIENT_VMAXIMIZED) { @@ -376,7 +391,7 @@ client_toggle_hmaximize(struct client_ctx *cc) struct screen_ctx *sc = cc->sc; struct geom area; - if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY)) + if (cc->flags & CLIENT_FREEZE) return; if (cc->flags & CLIENT_HMAXIMIZED) { @@ -491,9 +506,6 @@ client_ptrsave(struct client_ctx *cc) void client_hide(struct client_ctx *cc) { - if (cc->flags & CLIENT_STICKY) - return; - XUnmapWindow(X_Dpy, cc->win); cc->flags &= ~CLIENT_ACTIVE; @@ -507,9 +519,6 @@ client_hide(struct client_ctx *cc) void client_unhide(struct client_ctx *cc) { - if (cc->flags & CLIENT_STICKY) - return; - XMapRaised(X_Dpy, cc->win); cc->flags &= ~CLIENT_HIDDEN; @@ -647,29 +656,33 @@ match: void client_cycle(struct screen_ctx *sc, int flags) { - struct client_ctx *oldcc, *newcc; + struct client_ctx *newcc, *oldcc; int again = 1; + /* For X apps that ignore events. */ + XGrabKeyboard(X_Dpy, sc->rootwin, True, + GrabModeAsync, GrabModeAsync, CurrentTime); + if (TAILQ_EMPTY(&sc->clientq)) return; oldcc = client_current(); if (oldcc == NULL) - oldcc = ((flags & CWM_RCYCLE) ? + oldcc = (flags & CWM_RCYCLE) ? TAILQ_LAST(&sc->clientq, client_ctx_q) : - TAILQ_FIRST(&sc->clientq)); + TAILQ_FIRST(&sc->clientq); newcc = oldcc; while (again) { again = 0; - newcc = ((flags & CWM_RCYCLE) ? client_prev(newcc) : - client_next(newcc)); + newcc = (flags & CWM_RCYCLE) ? client_prev(newcc) : + client_next(newcc); /* Only cycle visible and non-ignored windows. */ - if ((newcc->flags & (CLIENT_HIDDEN|CLIENT_IGNORE)) + if ((newcc->flags & (CLIENT_HIDDEN | CLIENT_IGNORE)) || ((flags & CWM_INGROUP) && - (newcc->group != oldcc->group))) + (newcc->gc != oldcc->gc))) again = 1; /* Is oldcc the only non-hidden window? */ @@ -694,9 +707,10 @@ client_cycle_leave(struct screen_ctx *sc) sc->cycling = 0; - if ((cc = client_current())) { + if ((cc = client_current()) != NULL) { client_mtf(cc); - group_toggle_membership_leave(cc); + cc->flags &= ~CLIENT_HIGHLIGHT; + client_draw_border(cc); XUngrabKeyboard(X_Dpy, CurrentTime); } } @@ -705,20 +719,20 @@ static struct client_ctx * client_next(struct client_ctx *cc) { struct screen_ctx *sc = cc->sc; - struct client_ctx *ccc; + struct client_ctx *newcc; - return(((ccc = TAILQ_NEXT(cc, entry)) != NULL) ? - ccc : TAILQ_FIRST(&sc->clientq)); + return(((newcc = TAILQ_NEXT(cc, entry)) != NULL) ? + newcc : TAILQ_FIRST(&sc->clientq)); } static struct client_ctx * client_prev(struct client_ctx *cc) { struct screen_ctx *sc = cc->sc; - struct client_ctx *ccc; + struct client_ctx *newcc; - return(((ccc = TAILQ_PREV(cc, client_ctx_q, entry)) != NULL) ? - ccc : TAILQ_LAST(&sc->clientq, client_ctx_q)); + return(((newcc = TAILQ_PREV(cc, client_ctx_q, entry)) != NULL) ? + newcc : TAILQ_LAST(&sc->clientq, client_ctx_q)); } static void @@ -727,7 +741,7 @@ client_placecalc(struct client_ctx *cc) struct screen_ctx *sc = cc->sc; int xslack, yslack; - if (cc->hint.flags & (USPosition|PPosition)) { + if (cc->hint.flags & (USPosition | PPosition)) { /* * Ignore XINERAMA screens, just make sure it's somewhere * in the virtual desktop. else it stops people putting xterms @@ -901,8 +915,8 @@ client_transient(struct client_ctx *cc) Window trans; if (XGetTransientForHint(X_Dpy, cc->win, &trans)) { - if ((tc = client_find(trans)) && tc->group) { - group_movetogroup(cc, tc->group->num); + if ((tc = client_find(trans)) != NULL && tc->gc) { + group_movetogroup(cc, tc->gc->num); if (tc->flags & CLIENT_IGNORE) cc->flags |= CLIENT_IGNORE; } @@ -947,7 +961,7 @@ void client_htile(struct client_ctx *cc) { struct client_ctx *ci; - struct group_ctx *gc = cc->group; + struct group_ctx *gc = cc->gc; struct screen_ctx *sc = cc->sc; struct geom area; int i, n, mh, x, h, w; @@ -1006,7 +1020,7 @@ void client_vtile(struct client_ctx *cc) { struct client_ctx *ci; - struct group_ctx *gc = cc->group; + struct group_ctx *gc = cc->gc; struct screen_ctx *sc = cc->sc; struct geom area; int i, n, mw, y, h, w; diff --git a/conf.c b/conf.c index 66cd6fa..9f724ab 100644 --- a/conf.c +++ b/conf.c @@ -40,7 +40,7 @@ static void conf_unbind_mouse(struct conf *, struct binding *); int conf_cmd_add(struct conf *c, const char *name, const char *path) { - struct cmd *cmd, *prev; + struct cmd *cmd; cmd = xmalloc(sizeof(*cmd)); @@ -55,13 +55,6 @@ conf_cmd_add(struct conf *c, const char *name, const char *path) TAILQ_INSERT_TAIL(&c->cmdq, cmd, entry); - /* keep queue sorted by name */ - while ((prev = TAILQ_PREV(cmd, cmd_q, entry)) && - (strcmp(prev->name, cmd->name) > 0)) { - TAILQ_REMOVE(&c->cmdq, cmd, entry); - TAILQ_INSERT_BEFORE(prev, cmd, entry); - } - return(1); } @@ -224,18 +217,18 @@ static const struct { { "M-j", "movedown" }, { "M-k", "moveup" }, { "M-l", "moveright" }, - { "M-H", "bigmoveleft" }, - { "M-J", "bigmovedown" }, - { "M-K", "bigmoveup" }, - { "M-L", "bigmoveright" }, + { "MS-h", "bigmoveleft" }, + { "MS-j", "bigmovedown" }, + { "MS-k", "bigmoveup" }, + { "MS-l", "bigmoveright" }, { "CM-h", "resizeleft" }, { "CM-j", "resizedown" }, { "CM-k", "resizeup" }, { "CM-l", "resizeright" }, - { "CM-H", "bigresizeleft" }, - { "CM-J", "bigresizedown" }, - { "CM-K", "bigresizeup" }, - { "CM-L", "bigresizeright" }, + { "CMS-h", "bigresizeleft" }, + { "CMS-j", "bigresizedown" }, + { "CMS-k", "bigresizeup" }, + { "CMS-l", "bigresizeright" }, { "C-Left", "ptrmoveleft" }, { "C-Down", "ptrmovedown" }, { "C-Up", "ptrmoveup" }, @@ -397,9 +390,9 @@ static const struct { { "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLE} }, { "rcyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_RCYCLE} }, { "cycleingroup", kbfunc_client_cycle, CWM_WIN, - {.i = CWM_CYCLE|CWM_INGROUP} }, + {.i = (CWM_CYCLE | CWM_INGROUP)} }, { "rcycleingroup", kbfunc_client_cycle, CWM_WIN, - {.i = CWM_RCYCLE|CWM_INGROUP} }, + {.i = (CWM_RCYCLE | CWM_INGROUP)} }, { "grouptoggle", kbfunc_client_grouptoggle, CWM_WIN, {.i = 0}}, { "sticky", kbfunc_client_toggle_sticky, CWM_WIN, {0} }, { "fullscreen", kbfunc_client_toggle_fullscreen, CWM_WIN, {0} }, @@ -415,53 +408,53 @@ static const struct { { "terminal", kbfunc_term, 0, {0} }, { "lock", kbfunc_lock, 0, {0} }, { "moveup", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_UP|CWM_MOVE)} }, + {.i = (CWM_UP | CWM_MOVE)} }, { "movedown", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_DOWN|CWM_MOVE)} }, + {.i = (CWM_DOWN | CWM_MOVE)} }, { "moveright", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_RIGHT|CWM_MOVE)} }, + {.i = (CWM_RIGHT | CWM_MOVE)} }, { "moveleft", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_LEFT|CWM_MOVE)} }, + {.i = (CWM_LEFT | CWM_MOVE)} }, { "bigmoveup", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_UP|CWM_MOVE|CWM_BIGMOVE)} }, + {.i = (CWM_UP | CWM_MOVE | CWM_BIGMOVE)} }, { "bigmovedown", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_DOWN|CWM_MOVE|CWM_BIGMOVE)} }, + {.i = (CWM_DOWN | CWM_MOVE | CWM_BIGMOVE)} }, { "bigmoveright", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_RIGHT|CWM_MOVE|CWM_BIGMOVE)} }, + {.i = (CWM_RIGHT | CWM_MOVE | CWM_BIGMOVE)} }, { "bigmoveleft", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_LEFT|CWM_MOVE|CWM_BIGMOVE)} }, + {.i = (CWM_LEFT | CWM_MOVE | CWM_BIGMOVE)} }, { "resizeup", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_UP|CWM_RESIZE)} }, + {.i = (CWM_UP | CWM_RESIZE)} }, { "resizedown", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_DOWN|CWM_RESIZE)} }, + {.i = (CWM_DOWN | CWM_RESIZE)} }, { "resizeright", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_RIGHT|CWM_RESIZE)} }, + {.i = (CWM_RIGHT | CWM_RESIZE)} }, { "resizeleft", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_LEFT|CWM_RESIZE)} }, + {.i = (CWM_LEFT | CWM_RESIZE)} }, { "bigresizeup", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_UP|CWM_RESIZE|CWM_BIGMOVE)} }, + {.i = (CWM_UP | CWM_RESIZE | CWM_BIGMOVE)} }, { "bigresizedown", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_DOWN|CWM_RESIZE|CWM_BIGMOVE)} }, + {.i = (CWM_DOWN | CWM_RESIZE | CWM_BIGMOVE)} }, { "bigresizeright", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_RIGHT|CWM_RESIZE|CWM_BIGMOVE)} }, + {.i = (CWM_RIGHT | CWM_RESIZE | CWM_BIGMOVE)} }, { "bigresizeleft", kbfunc_client_moveresize, CWM_WIN, - {.i = (CWM_LEFT|CWM_RESIZE|CWM_BIGMOVE)} }, + {.i = (CWM_LEFT | CWM_RESIZE | CWM_BIGMOVE)} }, { "ptrmoveup", kbfunc_client_moveresize, 0, - {.i = (CWM_UP|CWM_PTRMOVE)} }, + {.i = (CWM_UP | CWM_PTRMOVE)} }, { "ptrmovedown", kbfunc_client_moveresize, 0, - {.i = (CWM_DOWN|CWM_PTRMOVE)} }, + {.i = (CWM_DOWN | CWM_PTRMOVE)} }, { "ptrmoveleft", kbfunc_client_moveresize, 0, - {.i = (CWM_LEFT|CWM_PTRMOVE)} }, + {.i = (CWM_LEFT | CWM_PTRMOVE)} }, { "ptrmoveright", kbfunc_client_moveresize, 0, - {.i = (CWM_RIGHT|CWM_PTRMOVE)} }, + {.i = (CWM_RIGHT | CWM_PTRMOVE)} }, { "bigptrmoveup", kbfunc_client_moveresize, 0, - {.i = (CWM_UP|CWM_PTRMOVE|CWM_BIGMOVE)} }, + {.i = (CWM_UP | CWM_PTRMOVE | CWM_BIGMOVE)} }, { "bigptrmovedown", kbfunc_client_moveresize, 0, - {.i = (CWM_DOWN|CWM_PTRMOVE|CWM_BIGMOVE)} }, + {.i = (CWM_DOWN | CWM_PTRMOVE | CWM_BIGMOVE)} }, { "bigptrmoveleft", kbfunc_client_moveresize, 0, - {.i = (CWM_LEFT|CWM_PTRMOVE|CWM_BIGMOVE)} }, + {.i = (CWM_LEFT | CWM_PTRMOVE | CWM_BIGMOVE)} }, { "bigptrmoveright", kbfunc_client_moveresize, 0, - {.i = (CWM_RIGHT|CWM_PTRMOVE|CWM_BIGMOVE)} }, + {.i = (CWM_RIGHT | CWM_PTRMOVE | CWM_BIGMOVE)} }, { "htile", kbfunc_tile, CWM_WIN, {.i = CWM_TILE_HORIZ} }, { "vtile", kbfunc_tile, CWM_WIN, {.i = CWM_TILE_VERT} }, { "window_lower", kbfunc_client_lower, CWM_WIN, {0} }, @@ -675,6 +668,7 @@ static char *ewmhints[] = { "_NET_SUPPORTING_WM_CHECK", "_NET_ACTIVE_WINDOW", "_NET_CLIENT_LIST", + "_NET_CLIENT_LIST_STACKING", "_NET_NUMBER_OF_DESKTOPS", "_NET_CURRENT_DESKTOP", "_NET_DESKTOP_VIEWPORT", @@ -693,6 +687,7 @@ static char *ewmhints[] = { "_NET_WM_STATE_HIDDEN", "_NET_WM_STATE_FULLSCREEN", "_NET_WM_STATE_DEMANDS_ATTENTION", + "_CWM_WM_STATE_FREEZE", }; void diff --git a/cwm.1 b/cwm.1 index e4776ca..447b646 100644 --- a/cwm.1 +++ b/cwm.1 @@ -117,9 +117,9 @@ Toggle maximization of current window. Toggle vertical maximization of current window. .It Ic CMS-= Toggle horizontal maximization of current window. -.It Ic C-[Up|Down|Left|Right] +.It Ic C-[Up | Down | Left | Right] Move pointer by a small amount. -.It Ic CS-[Up|Down|Left|Right] +.It Ic CS-[Up | Down | Left | Right] Move pointer by a large amount; see .Xr cwmrc 5 . .It Ic M-[hjkl] diff --git a/group.c b/group.c index 9fe6115..10130f4 100644 --- a/group.c +++ b/group.c @@ -32,7 +32,8 @@ #include "calmwm.h" -static void group_assign(struct group_ctx *, struct client_ctx *); +static struct group_ctx *group_next(struct group_ctx *); +static struct group_ctx *group_prev(struct group_ctx *); static void group_restack(struct group_ctx *); static void group_setactive(struct group_ctx *); @@ -41,15 +42,18 @@ const char *num_to_name[] = { "seven", "eight", "nine" }; -static void +void group_assign(struct group_ctx *gc, struct client_ctx *cc) { - if (cc->group != NULL) - TAILQ_REMOVE(&cc->group->clientq, cc, group_entry); + if (cc->gc != NULL) + TAILQ_REMOVE(&cc->gc->clientq, cc, group_entry); - cc->group = gc; + if ((gc != NULL) && (gc->num == 0)) + gc = NULL; - if (cc->group != NULL) + cc->gc = gc; + + if (cc->gc != NULL) TAILQ_INSERT_TAIL(&gc->clientq, cc, group_entry); xu_ewmh_net_wm_desktop(cc); @@ -62,8 +66,10 @@ group_hide(struct group_ctx *gc) screen_updatestackingorder(gc->sc); - TAILQ_FOREACH(cc, &gc->clientq, group_entry) - client_hide(cc); + TAILQ_FOREACH(cc, &gc->clientq, group_entry) { + if (!(cc->flags & CLIENT_STICKY)) + client_hide(cc); + } } void @@ -71,8 +77,10 @@ group_show(struct group_ctx *gc) { struct client_ctx *cc; - TAILQ_FOREACH(cc, &gc->clientq, group_entry) - client_unhide(cc); + TAILQ_FOREACH(cc, &gc->clientq, group_entry) { + if (!(cc->flags & CLIENT_STICKY)) + client_unhide(cc); + } group_restack(gc); group_setactive(gc); @@ -154,7 +162,7 @@ group_movetogroup(struct client_ctx *cc, int idx) break; } - if (cc->group == gc) + if (cc->gc == gc) return; if (group_holds_only_hidden(gc)) client_hide(cc); @@ -167,7 +175,7 @@ group_toggle_membership_enter(struct client_ctx *cc) struct screen_ctx *sc = cc->sc; struct group_ctx *gc = sc->group_active; - if (gc == cc->group) { + if (gc == cc->gc) { group_assign(NULL, cc); cc->flags |= CLIENT_UNGROUP; } else { @@ -255,36 +263,31 @@ group_only(struct screen_ctx *sc, int idx) } } -/* - * Cycle through active groups. If none exist, then just stay put. - */ void group_cycle(struct screen_ctx *sc, int flags) { - struct group_ctx *gc, *showgroup = NULL; + struct group_ctx *newgc, *oldgc, *showgroup = NULL; - if (((gc = sc->group_active)) == NULL) - errx(1, "group_cycle: no active group"); + oldgc = sc->group_active; + newgc = oldgc; for (;;) { - gc = (flags & CWM_RCYCLE) ? TAILQ_PREV(gc, group_ctx_q, - entry) : TAILQ_NEXT(gc, entry); - if (gc == NULL) - gc = (flags & CWM_RCYCLE) ? TAILQ_LAST(&sc->groupq, - group_ctx_q) : TAILQ_FIRST(&sc->groupq); - if (gc == sc->group_active) + newgc = (flags & CWM_RCYCLE) ? group_prev(newgc) : + group_next(newgc); + + if (newgc == oldgc) break; - if (!group_holds_only_sticky(gc) && showgroup == NULL) - showgroup = gc; - else if (!group_holds_only_hidden(gc)) - group_hide(gc); + if (!group_holds_only_sticky(newgc) && showgroup == NULL) + showgroup = newgc; + else if (!group_holds_only_hidden(newgc)) + group_hide(newgc); } if (showgroup == NULL) return; - group_hide(sc->group_active); + group_hide(oldgc); if (group_holds_only_hidden(showgroup)) group_show(showgroup); @@ -292,6 +295,26 @@ group_cycle(struct screen_ctx *sc, int flags) group_setactive(showgroup); } +static struct group_ctx * +group_next(struct group_ctx *gc) +{ + struct screen_ctx *sc = gc->sc; + struct group_ctx *newgc; + + return(((newgc = TAILQ_NEXT(gc, entry)) != NULL) ? + newgc : TAILQ_FIRST(&sc->groupq)); +} + +static struct group_ctx * +group_prev(struct group_ctx *gc) +{ + struct screen_ctx *sc = gc->sc; + struct group_ctx *newgc; + + return(((newgc = TAILQ_PREV(gc, group_ctx_q, entry)) != NULL) ? + newgc : TAILQ_LAST(&sc->groupq, group_ctx_q)); +} + void group_alltoggle(struct screen_ctx *sc) { @@ -306,51 +329,58 @@ group_alltoggle(struct screen_ctx *sc) sc->hideall = !sc->hideall; } -void +int +group_restore(struct client_ctx *cc) +{ + struct screen_ctx *sc = cc->sc; + struct group_ctx *gc; + int num; + long *grpnum; + + if (xu_getprop(cc->win, ewmh[_NET_WM_DESKTOP], XA_CARDINAL, 1L, + (unsigned char **)&grpnum) <= 0) + return(0); + + num = (*grpnum == -1) ? 0 : *grpnum; + num = MIN(num, (CALMWM_NGROUPS - 1)); + XFree(grpnum); + + TAILQ_FOREACH(gc, &sc->groupq, entry) { + if (gc->num == num) { + group_assign(gc, cc); + return(1); + } + } + return(0); +} + +int group_autogroup(struct client_ctx *cc) { struct screen_ctx *sc = cc->sc; struct autogroupwin *aw; struct group_ctx *gc; - int num = -2, both_match = 0; - long *grpnum; + int num = -1, both_match = 0; if (cc->ch.res_class == NULL || cc->ch.res_name == NULL) - return; + return(0); - if (xu_getprop(cc->win, ewmh[_NET_WM_DESKTOP], - XA_CARDINAL, 1, (unsigned char **)&grpnum) > 0) { - num = *grpnum; - if (num > CALMWM_NGROUPS || num < -1) - num = CALMWM_NGROUPS - 1; - XFree(grpnum); - } else { - TAILQ_FOREACH(aw, &Conf.autogroupq, entry) { - if (strcmp(aw->class, cc->ch.res_class) == 0) { - if ((aw->name != NULL) && - (strcmp(aw->name, cc->ch.res_name) == 0)) { - num = aw->num; - both_match = 1; - } else if (aw->name == NULL && !both_match) - num = aw->num; - } + TAILQ_FOREACH(aw, &Conf.autogroupq, entry) { + if (strcmp(aw->class, cc->ch.res_class) == 0) { + if ((aw->name != NULL) && + (strcmp(aw->name, cc->ch.res_name) == 0)) { + num = aw->num; + both_match = 1; + } else if (aw->name == NULL && !both_match) + num = aw->num; } } - if ((num == -1) || (num == 0)) { - group_assign(NULL, cc); - return; - } - TAILQ_FOREACH(gc, &sc->groupq, entry) { if (gc->num == num) { group_assign(gc, cc); - return; + return(1); } } - - if (Conf.flags & CONF_STICKY_GROUPS) - group_assign(sc->group_active, cc); - else - group_assign(NULL, cc); + return(0); } diff --git a/kbfunc.c b/kbfunc.c index b100c18..1bd6861 100644 --- a/kbfunc.c +++ b/kbfunc.c @@ -61,7 +61,7 @@ kbfunc_client_moveresize(struct client_ctx *cc, union arg *arg) int x, y, flags, amt; unsigned int mx, my; - if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY)) + if (cc->flags & CLIENT_FREEZE) return; mx = my = 0; @@ -177,8 +177,13 @@ kbfunc_menu_cmd(struct client_ctx *cc, union arg *arg) struct menu_q menuq; TAILQ_INIT(&menuq); - TAILQ_FOREACH(cmd, &Conf.cmdq, entry) + TAILQ_FOREACH(cmd, &Conf.cmdq, entry) { + if ((strcmp(cmd->name, "lock") == 0) || + (strcmp(cmd->name, "term") == 0)) + continue; + /* search_match_text() needs mi->text */ menuq_add(&menuq, cmd, "%s", cmd->name); + } if ((mi = menu_filter(sc, &menuq, "application", NULL, 0, search_match_text, search_print_cmd)) != NULL) @@ -215,13 +220,7 @@ kbfunc_menu_group(struct client_ctx *cc, union arg *arg) void kbfunc_client_cycle(struct client_ctx *cc, union arg *arg) { - struct screen_ctx *sc = cc->sc; - - /* XXX for X apps that ignore events */ - XGrabKeyboard(X_Dpy, sc->rootwin, True, - GrabModeAsync, GrabModeAsync, CurrentTime); - - client_cycle(sc, arg->i); + client_cycle(cc->sc, arg->i); } void @@ -466,7 +465,7 @@ void kbfunc_client_grouptoggle(struct client_ctx *cc, union arg *arg) { if (arg->i == 0) { - /* XXX for stupid X apps like xpdf and gvim */ + /* For X apps that steal events. */ XGrabKeyboard(X_Dpy, cc->win, True, GrabModeAsync, GrabModeAsync, CurrentTime); } diff --git a/mousefunc.c b/mousefunc.c index b177cdf..e38de9a 100644 --- a/mousefunc.c +++ b/mousefunc.c @@ -72,7 +72,7 @@ mousefunc_client_resize(struct client_ctx *cc, union arg *arg) struct screen_ctx *sc = cc->sc; int x = cc->geom.x, y = cc->geom.y; - if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY)) + if (cc->flags & CLIENT_FREEZE) return; client_raise(cc); @@ -128,7 +128,7 @@ mousefunc_client_move(struct client_ctx *cc, union arg *arg) client_raise(cc); - if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY)) + if (cc->flags & CLIENT_FREEZE) return; if (xu_ptr_grab(cc->win, MOUSEMASK, Conf.cursor[CF_MOVE]) < 0) @@ -233,8 +233,12 @@ mousefunc_menu_cmd(struct client_ctx *cc, union arg *arg) struct menu_q menuq; TAILQ_INIT(&menuq); - TAILQ_FOREACH(cmd, &Conf.cmdq, entry) + TAILQ_FOREACH(cmd, &Conf.cmdq, entry) { + if ((strcmp(cmd->name, "lock") == 0) || + (strcmp(cmd->name, "term") == 0)) + continue; menuq_add(&menuq, cmd, NULL); + } if ((mi = menu_filter(sc, &menuq, NULL, NULL, CWM_MENU_LIST, NULL, search_print_cmd)) != NULL) diff --git a/screen.c b/screen.c index a8c4575..c51082b 100644 --- a/screen.c +++ b/screen.c @@ -67,12 +67,12 @@ screen_init(int which) xu_ewmh_net_virtual_roots(sc); rootattr.cursor = Conf.cursor[CF_NORMAL]; - rootattr.event_mask = SubstructureRedirectMask|SubstructureNotifyMask| - PropertyChangeMask|EnterWindowMask|LeaveWindowMask| - ColormapChangeMask|BUTTONMASK; + rootattr.event_mask = SubstructureRedirectMask | + SubstructureNotifyMask | PropertyChangeMask | EnterWindowMask | + LeaveWindowMask | ColormapChangeMask | BUTTONMASK; XChangeWindowAttributes(X_Dpy, sc->rootwin, - CWEventMask|CWCursor, &rootattr); + (CWEventMask | CWCursor), &rootattr); /* Deal with existing clients. */ if (XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) { diff --git a/search.c b/search.c index c7cb9b6..60da260 100644 --- a/search.c +++ b/search.c @@ -127,14 +127,8 @@ void search_print_cmd(struct menu *mi, int i) { struct cmd *cmd = (struct cmd *)mi->ctx; - int special = 0; - if ((strcmp(cmd->name, "lock") == 0) || - (strcmp(cmd->name, "term") == 0)) - special = 1; - - (void)snprintf(mi->print, sizeof(mi->print), - (special) ? "[%s]" : "%s", cmd->name); + (void)snprintf(mi->print, sizeof(mi->print), "%s", cmd->name); } void @@ -162,7 +156,7 @@ search_print_client(struct menu *mi, int list) cc->matchname = cc->name; (void)snprintf(mi->print, sizeof(mi->print), "(%d) %c[%s] %s", - (cc->group) ? cc->group->num : 0, flag, + (cc->gc) ? cc->gc->num : 0, flag, (cc->label) ? cc->label : "", cc->matchname); } diff --git a/xevents.c b/xevents.c index 7be381a..8cea6a5 100644 --- a/xevents.c +++ b/xevents.c @@ -77,7 +77,7 @@ xev_handle_maprequest(XEvent *ee) XMapRequestEvent *e = &ee->xmaprequest; struct client_ctx *cc = NULL, *old_cc; - if ((old_cc = client_current())) + if ((old_cc = client_current()) != NULL) client_ptrsave(old_cc); if ((cc = client_find(e->window)) == NULL) @@ -252,7 +252,7 @@ xev_handle_buttonrelease(XEvent *ee) { struct client_ctx *cc; - if ((cc = client_current())) + if ((cc = client_current()) != NULL) group_toggle_membership_leave(cc); } @@ -339,7 +339,7 @@ xev_handle_clientmessage(XEvent *ee) } } else if (e->message_type == ewmh[_NET_ACTIVE_WINDOW]) { if ((cc = client_find(e->window)) != NULL) { - if ((old_cc = client_current())) + if ((old_cc = client_current()) != NULL) client_ptrsave(old_cc); client_ptrwarp(cc); } diff --git a/xutil.c b/xutil.c index 5294edc..c4db9f6 100644 --- a/xutil.c +++ b/xutil.c @@ -228,6 +228,27 @@ xu_ewmh_net_client_list(struct screen_ctx *sc) free(winlist); } +void +xu_ewmh_net_client_list_stacking(struct screen_ctx *sc) +{ + struct client_ctx *cc; + Window *winlist; + int i = 0, j; + + TAILQ_FOREACH(cc, &sc->clientq, entry) + i++; + if (i == 0) + return; + + j = i; + winlist = xreallocarray(NULL, i, sizeof(*winlist)); + TAILQ_FOREACH(cc, &sc->clientq, entry) + winlist[--j] = cc->win; + XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST_STACKING], + XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i); + free(winlist); +} + void xu_ewmh_net_active_window(struct screen_ctx *sc, Window w) { @@ -341,8 +362,8 @@ xu_ewmh_net_wm_desktop(struct client_ctx *cc) { long num = 0xffffffff; - if (cc->group) - num = cc->group->num; + if (cc->gc) + num = cc->gc->num; XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_DESKTOP], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&num, 1); @@ -392,6 +413,9 @@ xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action, { _NET_WM_STATE_DEMANDS_ATTENTION, CLIENT_URGENCY, client_urgency }, + { _CWM_WM_STATE_FREEZE, + CLIENT_FREEZE, + client_toggle_freeze }, }; for (i = 0; i < nitems(handlers); i++) { @@ -423,16 +447,18 @@ xu_ewmh_restore_net_wm_state(struct client_ctx *cc) for (i = 0; i < n; i++) { if (atoms[i] == ewmh[_NET_WM_STATE_STICKY]) client_toggle_sticky(cc); - if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_HORZ]) - client_toggle_hmaximize(cc); if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_VERT]) client_toggle_vmaximize(cc); + if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_HORZ]) + client_toggle_hmaximize(cc); if (atoms[i] == ewmh[_NET_WM_STATE_HIDDEN]) client_toggle_hidden(cc); if (atoms[i] == ewmh[_NET_WM_STATE_FULLSCREEN]) client_toggle_fullscreen(cc); if (atoms[i] == ewmh[_NET_WM_STATE_DEMANDS_ATTENTION]) client_urgency(cc); + if (atoms[i] == ewmh[_CWM_WM_STATE_FREEZE]) + client_toggle_freeze(cc); } free(atoms); } @@ -447,11 +473,12 @@ xu_ewmh_set_net_wm_state(struct client_ctx *cc) atoms = xreallocarray(NULL, (n + _NET_WM_STATES_NITEMS), sizeof(Atom)); for (i = j = 0; i < n; i++) { if (oatoms[i] != ewmh[_NET_WM_STATE_STICKY] && - oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_HORZ] && oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_VERT] && + oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_HORZ] && oatoms[i] != ewmh[_NET_WM_STATE_HIDDEN] && oatoms[i] != ewmh[_NET_WM_STATE_FULLSCREEN] && - oatoms[i] != ewmh[_NET_WM_STATE_DEMANDS_ATTENTION]) + oatoms[i] != ewmh[_NET_WM_STATE_DEMANDS_ATTENTION] && + oatoms[i] != ewmh[_CWM_WM_STATE_FREEZE]) atoms[j++] = oatoms[i]; } free(oatoms); @@ -462,13 +489,15 @@ xu_ewmh_set_net_wm_state(struct client_ctx *cc) if (cc->flags & CLIENT_FULLSCREEN) atoms[j++] = ewmh[_NET_WM_STATE_FULLSCREEN]; else { - if (cc->flags & CLIENT_HMAXIMIZED) - atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_HORZ]; if (cc->flags & CLIENT_VMAXIMIZED) atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_VERT]; + if (cc->flags & CLIENT_HMAXIMIZED) + atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_HORZ]; } if (cc->flags & CLIENT_URGENCY) atoms[j++] = ewmh[_NET_WM_STATE_DEMANDS_ATTENTION]; + if (cc->flags & CLIENT_FREEZE) + atoms[j++] = ewmh[_CWM_WM_STATE_FREEZE]; if (j > 0) XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE], XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, j);