diff --git a/config.h b/config.h index ecfc670..0982748 100644 --- a/config.h +++ b/config.h @@ -92,18 +92,9 @@ binding keys[] = { // Launcher { .mod = Mod4Mask, .key = XK_x, .act = ACTION_COMMAND, .data = "dmenu_run" }, - // Raise tag groups - { .mod = Mod4Mask, .key = XK_1, .act = ACTION_RAISE_TAG, .num = TAG1 }, - { .mod = Mod4Mask, .key = XK_2, .act = ACTION_RAISE_TAG, .num = TAG2 }, - { .mod = Mod4Mask, .key = XK_3, .act = ACTION_RAISE_TAG, .num = TAG3 }, - - // Tag/untag the current window - { .mod = ShiftMask|Mod4Mask, .key = XK_1, .act = ACTION_TAG, .num = TAG1 }, - { .mod = ShiftMask|Mod4Mask, .key = XK_2, .act = ACTION_TAG, .num = TAG2 }, - { .mod = ShiftMask|Mod4Mask, .key = XK_3, .act = ACTION_TAG, .num = TAG3 }, - { .mod = ShiftMask|ControlMask|Mod4Mask, .key = XK_1, .act = ACTION_UNTAG, .num = TAG1 }, - { .mod = ShiftMask|ControlMask|Mod4Mask, .key = XK_2, .act = ACTION_UNTAG, .num = TAG2 }, - { .mod = ShiftMask|ControlMask|Mod4Mask, .key = XK_3, .act = ACTION_UNTAG, .num = TAG3 }, + // Snapshot state + { .mod = Mod4Mask, .key = XK_s, .act = ACTION_SNAPSHOT }, + { .mod = Mod4Mask, .key = XK_r, .act = ACTION_ROLLBACK }, // Find or start apps by WM_CLASS (lower case match). { .mod = AnyModifier, .key = XK_F1, .act = ACTION_FIND_OR_START, .data = "urxvt" }, diff --git a/proto.h b/proto.h index 1791aab..8111beb 100644 --- a/proto.h +++ b/proto.h @@ -28,7 +28,6 @@ void client_set_focus(client *c); void client_activate(client *c); void window_listen(Window win); void client_update_border(client *c); -void client_flush_tags(client *c); void action_move(void *data, int num, client *cli); void action_focus(void *data, int num, client *cli); void action_close(void *data, int num, client *cli); @@ -38,11 +37,10 @@ void action_command(void *data, int num, client *cli); void action_find_or_start(void *data, int num, client *cli); void action_move_monitor(void *data, int num, client *cli); void action_focus_monitor(void *data, int num, client *cli); -void action_raise_tag(void *data, int tag, client *cli); void action_fullscreen(void *data, int num, client *cli); void action_above(void *data, int num, client *cli); -void action_tag(void *data, int num, client *cli); -void action_untag(void *data, int num, client *cli); +void action_snapshot(void *data, int num, client *cli); +void action_rollback(void *data, int num, client *cli); void create_notify(XEvent *e); void configure_request(XEvent *ev); void configure_notify(XEvent *e); diff --git a/xoat.1 b/xoat.1 index dee8eda..5ca635d 100644 --- a/xoat.1 +++ b/xoat.1 @@ -102,48 +102,15 @@ Launch urxvt .RS .RE .TP -.B Mod4-1 -Raise windows in tag 1. +.B Mod4-s +Snapshot current window positions and stacking order. .RS .RE .TP -.B Shift-Mod4-1 -Place current window in tag 1. -.RS -.RE -.TP -.B Shift-Control-Mod4-1 -Remove current window from tag 1. -.RS -.RE -.TP -.B Mod4-2 -Raise windows in tag 2. -.RS -.RE -.TP -.B Shift-Mod4-2 -Place current window in tag 2. -.RS -.RE -.TP -.B Shift-Control-Mod4-2 -Remove current window from tag 2. -.RS -.RE -.TP -.B Mod4-3 -Raise windows in tag 3. -.RS -.RE -.TP -.B Shift-Mod4-3 -Place current window in tag 3. -.RS -.RE -.TP -.B Shift-Control-Mod4-3 -Remove current window from tag 3. +.B Mod4-r +Rollback to snapshot. +Windows closed since the snapshot will not be reopened. +Newer windows not in the snapshot will be lowered. .RS .RE .SH OPTIONS diff --git a/xoat.c b/xoat.c index 7ca1252..95e189a 100644 --- a/xoat.c +++ b/xoat.c @@ -169,10 +169,6 @@ client* window_build_client(Window win) window_get_atom_prop(c->window, atoms[_NET_WM_STATE], c->states, MAX_NET_WM_STATES); c->urgent = client_has_state(c, atoms[_NET_WM_STATE_DEMANDS_ATTENTION]); - unsigned long tags = 0; - if (window_get_cardinal_prop(c->window, atoms[XOAT_TAGS], &tags, 1)) - c->tags = tags; - XWMHints *hints = XGetWMHints(display, c->window); if (hints) { @@ -481,15 +477,6 @@ void client_update_border(client *c) XSetWindowBorderWidth(display, c->window, client_has_state(c, atoms[_NET_WM_STATE_FULLSCREEN]) ? 0: BORDER); } -void client_flush_tags(client *c) -{ - unsigned long tags = c->tags; - window_set_cardinal_prop(c->window, atoms[XOAT_TAGS], &tags, 1); - - unsigned long desktop = tags & TAG3 ? 2: (tags & TAG2 ? 1: (tags & TAG1 ? 0: 0xffffffff)); - window_set_cardinal_prop(c->window, atoms[_NET_WM_DESKTOP], &desktop, 1); -} - // ------- key actions ------- void action_move(void *data, int num, client *cli) @@ -551,25 +538,6 @@ void action_focus_monitor(void *data, int num, client *cli) for (i = SPOT1; i <= SPOT3 && !spot_focus_top_window(i, mon, None); i++); } -void action_raise_tag(void *data, int tag, client *cli) -{ - int i; client *c = NULL, *t = NULL; - stack all; query_visible_windows(&all); - - for (i = all.depth-1; i > -1; i--) - { - if ((c = all.clients[i]) && c->manage && c->visible && c->tags & tag) - { - if (c->monitor == current_mon && c->spot == current_spot) t = c; - client_raise_family(c); - } - } - if (t) client_set_focus(t); - - unsigned long desktop = tag & TAG2 ? 1: (tag & TAG3 ? 2: 0); - window_set_cardinal_prop(root, atoms[_NET_CURRENT_DESKTOP], &desktop, 1); -} - void action_fullscreen(void *data, int num, client *cli) { if (!cli) return; @@ -597,18 +565,44 @@ void action_above(void *data, int num, client *cli) client_raise_family(cli); } -void action_tag(void *data, int num, client *cli) +void action_snapshot(void *data, int num, client *cli) { - if (!cli) return; - cli->tags |= (unsigned int)num; - client_flush_tags(cli); + int i; client *c; stack wins; + stack_free(&snapshot); + query_visible_windows(&wins); + for (i = 0; i < wins.depth; i++) + { + if ((c = wins.clients[i]) && c->manage) + { + snapshot.clients[snapshot.depth] = window_build_client(c->window); + snapshot.windows[snapshot.depth++] = c->window; + } + } } -void action_untag(void *data, int num, client *cli) +void action_rollback(void *data, int num, client *cli) { - if (!cli) return; - cli->tags &= ~((unsigned int)num); - client_flush_tags(cli); + int i; client *c = NULL, *s, *a = NULL; + for (i = snapshot.depth-1; i > -1; i--) + { + if ((s = snapshot.clients[i]) && (c = window_build_client(s->window)) && c->visible && c->manage) + { + c->monitor = s->monitor; + client_place_spot(c, s->spot, 1); + client_raise_family(c); + if (s->spot == current_spot && s->monitor == current_mon) + { + client_free(a); + a = c; c = NULL; + } + } + client_free(c); + } + if (a) + { + client_set_focus(a); + client_free(a); + } } // key actions @@ -625,9 +619,8 @@ action actions[ACTIONS] = { [ACTION_FOCUS_MONITOR] = action_focus_monitor, [ACTION_FULLSCREEN_TOGGLE] = action_fullscreen, [ACTION_ABOVE_TOGGLE] = action_above, - [ACTION_TAG] = action_tag, - [ACTION_UNTAG] = action_untag, - [ACTION_RAISE_TAG] = action_raise_tag, + [ACTION_SNAPSHOT] = action_snapshot, + [ACTION_ROLLBACK] = action_rollback, }; // ------- event handlers -------- @@ -690,7 +683,6 @@ void map_request(XEvent *e) client_place_spot(c, spot, 0); client_update_border(c); - client_flush_tags(c); } if (c) XMapWindow(display, c->window); client_free(c); @@ -936,6 +928,7 @@ int main(int argc, char *argv[]) XGrabButton(display, Button3, AnyModifier, root, True, ButtonPressMask, GrabModeSync, GrabModeSync, None, None); // setup existing managable windows + memset(&snapshot, 0, sizeof(stack)); query_visible_windows(&wins); for (i = 0; i < wins.depth; i++) { @@ -943,7 +936,6 @@ int main(int argc, char *argv[]) window_listen(c->window); client_update_border(c); - client_flush_tags(c); client_place_spot(c, c->spot, 0); // only activate first one diff --git a/xoat.h b/xoat.h index edc23df..c935782 100644 --- a/xoat.h +++ b/xoat.h @@ -70,10 +70,6 @@ enum { SPOT1_RIGHT }; -#define TAG1 1<<0 -#define TAG2 1<<1 -#define TAG3 1<<2 - typedef struct { short x, y, w, h; } box; @@ -96,7 +92,6 @@ typedef struct { Window transient_for; Atom type, states[MAX_NET_WM_STATES+1]; short monitor, spot, visible, manage, input, urgent; - unsigned short tags; char *class; } client; @@ -110,7 +105,7 @@ typedef struct { short current_spot = 0, current_mon = 0; Window current = None; -stack inplay; +stack inplay, snapshot; static int (*xerror)(Display *, XErrorEvent *); @@ -127,7 +122,6 @@ wm_strut struts; #define GENERAL_ATOMS(X) \ X(XOAT_SPOT),\ - X(XOAT_TAGS),\ X(XOAT_EXIT),\ X(XOAT_RESTART),\ X(_MOTIF_WM_HINTS),\ @@ -179,9 +173,8 @@ enum { ACTION_FOCUS_MONITOR, ACTION_FULLSCREEN_TOGGLE, ACTION_ABOVE_TOGGLE, - ACTION_TAG, - ACTION_UNTAG, - ACTION_RAISE_TAG, + ACTION_SNAPSHOT, + ACTION_ROLLBACK, ACTIONS }; diff --git a/xoat.md b/xoat.md index e6afb2b..c631177 100644 --- a/xoat.md +++ b/xoat.md @@ -71,32 +71,11 @@ Shift-Mod4-x F1 : Launch urxvt -Mod4-1 -: Raise windows in tag 1. +Mod4-s +: Snapshot current window positions and stacking order. -Shift-Mod4-1 -: Place current window in tag 1. - -Shift-Control-Mod4-1 -: Remove current window from tag 1. - -Mod4-2 -: Raise windows in tag 2. - -Shift-Mod4-2 -: Place current window in tag 2. - -Shift-Control-Mod4-2 -: Remove current window from tag 2. - -Mod4-3 -: Raise windows in tag 3. - -Shift-Mod4-3 -: Place current window in tag 3. - -Shift-Control-Mod4-3 -: Remove current window from tag 3. +Mod4-r +: Rollback to snapshot. Windows closed since the snapshot will not be reopened. Newer windows not in the snapshot will be lowered. # OPTIONS