dvtm

dynamic virtual terminal manager - with my changes
git clone https://pi.duncano.de/git/dvtm.git
Log | Files | Refs | README | LICENSE

commit 1e8fc97f763d80bd90a7bc1df6bf33f0e3f95b01
parent f83552a135396a1c42ccd1dd19c2abfcb8f7b70d
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Wed,  8 Oct 2014 12:58:40 +0200

Implement tagging

Diffstat:
bstack.c | 9+++++++--
config.def.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++------
dvtm.1 | 31+++++++++++++++++++++++++------
dvtm.c | 328+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
fibonacci.c | 9+++++++--
fullscreen.c | 2+-
grid.c | 9+++++++--
tile.c | 9+++++++--
tstack.c | 9+++++++--
vstack.c | 9+++++++--
10 files changed, 381 insertions(+), 89 deletions(-)

diff --git a/bstack.c b/bstack.c @@ -3,14 +3,18 @@ static void bstack(void) unsigned int i, n, nx, ny, nw, nh, mh, tw; Client *c; - for (n = 0, c = clients; c && !c->minimized; c = c->next, n++); + for (n = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) + if (!c->minimized) + n++; mh = n <= 1 ? wah : screen.mfact * wah; tw = n <= 1 ? 0 : waw / (n - 1); nx = wax; ny = way; - for (i = 0, c = clients; c && !c->minimized; c = c->next, i++) { + for (i = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) { + if (c->minimized) + continue; if (i == 0) { /* master */ nh = mh; nw = waw; @@ -32,5 +36,6 @@ static void bstack(void) if (i > 0) nx += nw; + i++; } } diff --git a/config.def.h b/config.def.h @@ -29,7 +29,9 @@ static Color colors[] = { /* curses attributes for the status bar */ #define BAR_ATTR (COLOR(BLUE) | A_NORMAL) /* status bar (command line option -s) position */ -#define BAR_POS BAR_TOP /* BAR_BOTTOM, BAR_OFF */ +#define BAR_POS BAR_TOP /* BAR_BOTTOM, BAR_OFF */ +/* whether status bar should be hidden if only one client exists */ +#define BAR_AUTOHIDE true /* determines whether the statusbar text should be right or left aligned */ #define BAR_ALIGN ALIGN_RIGHT /* separator between window title and window number */ @@ -42,6 +44,16 @@ static Color colors[] = { #define MFACT 0.5 /* scroll back buffer size in lines */ #define SCROLL_HISTORY 500 +/* printf format string for the tag in the status bar */ +#define TAG_SYMBOL "[%s]" +/* curses attributes for the currently selected tags */ +#define TAG_SEL (COLOR(BLUE) | A_BOLD) +/* curses attributes for not selected tags which contain no windows */ +#define TAG_NORMAL (COLOR(DEFAULT) | A_NORMAL) +/* curses attributes for not selected tags which contain windows */ +#define TAG_OCCUPIED (COLOR(BLUE) | A_NORMAL) + +const char tags[][8] = { "1", "2", "3", "4", "5" }; #include "tile.c" #include "grid.c" @@ -56,7 +68,7 @@ static Layout layouts[] = { { "[ ]", fullscreen }, }; -#define MOD CTRL('g') +#define MOD CTRL('g') /* you can at most specifiy MAX_ARGS (3) number of arguments */ static KeyBinding bindings[] = { @@ -67,7 +79,7 @@ static KeyBinding bindings[] = { { { MOD, 'u', }, { focusnextnm, { NULL } } }, { { MOD, 'i', }, { focusprevnm, { NULL } } }, { { MOD, 'k', }, { focusprev, { NULL } } }, - { { MOD, 't', }, { setlayout, { "[]=" } } }, + { { MOD, 'd', }, { setlayout, { "[]=" } } }, { { MOD, 'g', }, { setlayout, { "+++" } } }, { { MOD, 'b', }, { setlayout, { "TTT" } } }, { { MOD, 'm', }, { setlayout, { "[ ]" } } }, @@ -90,18 +102,49 @@ static KeyBinding bindings[] = { { { MOD, '\t', }, { focuslast, { NULL } } }, { { MOD, 'q', }, { quit, { NULL } } }, { { MOD, 'a', }, { togglerunall, { NULL } } }, + { { MOD, CTRL('L'), }, { redraw, { NULL } } }, { { MOD, 'r', }, { redraw, { NULL } } }, { { MOD, 'B', }, { togglebell, { NULL } } }, - { { MOD, 'v', }, { copymode, { NULL } } }, + { { MOD, 'e', }, { copymode, { NULL } } }, { { MOD, '/', }, { copymode, { "/" } } }, - { { MOD, '?', }, { copymode, { "?" } } }, { { MOD, 'p', }, { paste, { NULL } } }, { { MOD, KEY_PPAGE, }, { scrollback, { "-1" } } }, { { MOD, KEY_NPAGE, }, { scrollback, { "1" } } }, - { { MOD, KEY_F(1), }, { create, { "man dvtm", "dvtm help" } } }, + { { MOD, '?', }, { create, { "man dvtm", "dvtm help" } } }, + { { MOD, MOD, }, { send, { (const char []){MOD, 0} } } }, + { { KEY_SPREVIOUS, }, { scrollback, { "-1" } } }, + { { KEY_SNEXT, }, { scrollback, { "1" } } }, { { MOD, MOD, }, { send, { (const char []){MOD, 0} } } }, { { KEY_SPREVIOUS, }, { scrollback, { "-1" } } }, { { KEY_SNEXT, }, { scrollback, { "1" } } }, + { { MOD, '0', }, { view, { NULL } } }, + { { MOD, KEY_F(1), }, { view, { tags[0] } } }, + { { MOD, KEY_F(2), }, { view, { tags[1] } } }, + { { MOD, KEY_F(3), }, { view, { tags[2] } } }, + { { MOD, KEY_F(4), }, { view, { tags[3] } } }, + { { MOD, KEY_F(5), }, { view, { tags[4] } } }, + { { MOD, 'v', '1' }, { view, { tags[0] } } }, + { { MOD, 'v', '2' }, { view, { tags[1] } } }, + { { MOD, 'v', '3' }, { view, { tags[2] } } }, + { { MOD, 'v', '4' }, { view, { tags[3] } } }, + { { MOD, 'v', '5' }, { view, { tags[4] } } }, + { { MOD, 'v', '\t', }, { viewprevtag, { NULL } } }, + { { MOD, 't', '0' }, { tag, { NULL } } }, + { { MOD, 't', '1' }, { tag, { tags[0] } } }, + { { MOD, 't', '2' }, { tag, { tags[1] } } }, + { { MOD, 't', '3' }, { tag, { tags[2] } } }, + { { MOD, 't', '4' }, { tag, { tags[3] } } }, + { { MOD, 't', '5' }, { tag, { tags[4] } } }, + { { MOD, 'V', '1' }, { toggleview, { tags[0] } } }, + { { MOD, 'V', '2' }, { toggleview, { tags[1] } } }, + { { MOD, 'V', '3' }, { toggleview, { tags[2] } } }, + { { MOD, 'V', '4' }, { toggleview, { tags[3] } } }, + { { MOD, 'V', '5' }, { toggleview, { tags[4] } } }, + { { MOD, 'T', '1' }, { toggletag, { tags[0] } } }, + { { MOD, 'T', '2' }, { toggletag, { tags[1] } } }, + { { MOD, 'T', '3' }, { toggletag, { tags[2] } } }, + { { MOD, 'T', '4' }, { toggletag, { tags[3] } } }, + { { MOD, 'T', '5' }, { toggletag, { tags[4] } } }, }; static const ColorRule colorrules[] = { diff --git a/dvtm.1 b/dvtm.1 @@ -132,7 +132,7 @@ Toggle between defined layouts (affects all windows). .B Mod\-Enter Zooms/cycles current window to/from master area. .TP -.B Mod\-t +.B Mod\-d Change to vertical stack tiling layout. .TP .B Mod\-b @@ -145,6 +145,8 @@ Change to grid layout. Show/hide the status bar. .TP .B Mod\-r +.TQ +.B Mod\-^L Redraw whole screen. .TP .B Mod\-a @@ -157,24 +159,41 @@ Toggle bell (off by default). .B Mod\-M Toggle dvtm mouse grabbing. .TP -.B Mod\-v +.B Mod\-e Enter copy mode (see section below for further information). .TP .B Mod\-/ Enter copy mode and start searching forward (assumes a vi-like editor). .TP -.B Mod\-? -Enter copy mode and start searching backwards (assumes a vi-like editor). -.TP .B Mod\-p Paste last copied text from copy mode at current cursor position. .TP -.B Mod\-F1 +.B Mod\-? Show this manual page. .TP .B Mod\-Mod Send the Mod key. .TP +.B Mod-F[1..n] +.TQ +.B Mod-v-[1..n] +View all windows with nth tag. +.TP +.B Mod-0 +View all windows with any tag. +.TP +.B Mod-v-Tab +Toggles to the previously selected tags. +.TP +.B Mod-V-[1..n] +Add/remove all windows with nth tag to/from the view. +.TP +.B Mod-t-[1..n] +Apply nth tag to focused window. +.TP +.B Mod-T-[1..n] +Add/remove nth tag to/from focused window. +.TP .B Mod\-q Quit dvtm. .SS Mouse commands diff --git a/dvtm.c b/dvtm.c @@ -78,6 +78,8 @@ struct Client { volatile sig_atomic_t died; Client *next; Client *prev; + Client *snext; + bool tags[1]; }; typedef struct { @@ -135,6 +137,7 @@ enum { ALIGN_LEFT, ALIGN_RIGHT }; typedef struct { int fd; int pos; + bool autohide; unsigned short int h; unsigned short int y; char text[512]; @@ -187,11 +190,16 @@ static void send(const char *args[]); static void setlayout(const char *args[]); static void setmfact(const char *args[]); static void startup(const char *args[]); +static void tag(const char *args[]); static void togglebar(const char *args[]); static void togglebell(const char *key[]); static void toggleminimize(const char *args[]); static void togglemouse(const char *args[]); static void togglerunall(const char *args[]); +static void toggletag(const char *args[]); +static void toggleview(const char *args[]); +static void viewprevtag(const char *args[]); +static void view(const char *args[]); static void zoom(const char *args[]); /* commands for use by mouse bindings */ @@ -201,6 +209,8 @@ static void mouse_minimize(const char *args[]); static void mouse_zoom(const char *args[]); /* functions and variables available to layouts via config.h */ +static Client* nextvisible(Client *c); +static void focus(Client *c); static void resize(Client *c, int x, int y, int w, int h); extern Screen screen; static unsigned int waw, wah, wax, way; @@ -212,12 +222,15 @@ static char *title; /* global variables */ static const char *dvtm_name = "dvtm"; Screen screen = { .mfact = MFACT, .history = SCROLL_HISTORY }; +static Client *stack = NULL; static Client *sel = NULL; static Client *lastsel = NULL; static Client *msel = NULL; +static bool seltags[countof(tags)] = {[0] = true}; +static bool prevtags[countof(tags)]; static bool mouse_events_enabled = ENABLE_MOUSE; static Layout *layout = layouts; -static StatusBar bar = { .fd = -1, .pos = BAR_POS, .h = 1 }; +static StatusBar bar = { .fd = -1, .pos = BAR_POS, .autohide = BAR_AUTOHIDE, .h = 1 }; static CmdFifo cmdfifo = { .fd = -1 }; static const char *shell; static Register copyreg; @@ -247,23 +260,96 @@ isarrange(void (*func)()) { } static bool +isvisible(Client *c) { + for (unsigned int i = 0; i < countof(tags); i++) + if (c->tags[i] && seltags[i]) + return true; + return false; +} + +static bool is_content_visible(Client *c) { if (!c) return false; if (isarrange(fullscreen)) return sel == c; - return !c->minimized; + return isvisible(c) && !c->minimized; +} + +static Client* +nextvisible(Client *c) { + for (; c && !isvisible(c); c = c->next); + return c; +} + +static Client* +nextbytag(Client *c, int tag) { + for (; c && !c->tags[tag]; c = c->next); + return c; +} + +bool +isoccupied(unsigned int t) { + for (Client *c = clients; c; c = c->next) + if (c->tags[t]) + return true; + return false; +} + +static void +reorder(int tag) { + Client *c; + uint8_t order = 0; + if (tag < 0) + for (c = nextvisible(clients); c; c = nextvisible(c->next)) + c->order = ++order; + else + for (c = nextbytag(clients, tag); c; c = nextbytag(c->next, tag)) + c->order = ++order; +} + +static void +updatebarpos(void) { + bar.y = 0; + wax = 0; + way = 0; + wah = screen.h; + waw = screen.w; + if (bar.pos == BAR_TOP) { + wah -= bar.h; + way += bar.h; + } else if (bar.pos == BAR_BOTTOM) { + wah -= bar.h; + bar.y = wah; + } } static void drawbar(void) { - wchar_t wbuf[sizeof bar.text]; - int x, y, w, maxwidth = screen.w - 2; + int sx, sy, x = 0; if (bar.pos == BAR_OFF) return; - getyx(stdscr, y, x); + getyx(stdscr, sy, sx); + attrset(BAR_ATTR); + move(bar.y, 0); + for (unsigned int i = 0; i < countof(tags); i++){ + if (seltags[i]) + attrset(TAG_SEL); + else if (isoccupied(i)) + attrset(TAG_OCCUPIED); + else + attrset(TAG_NORMAL); + printw(TAG_SYMBOL, tags[i]); + /* -2 because we assume %s is contained in TAG_SYMBOL */ + x += sstrlen(TAG_SYMBOL) - 2 + strlen(tags[i]); + } + attrset(TAG_NORMAL); + addch('['); attrset(BAR_ATTR); - mvaddch(bar.y, 0, '['); + + wchar_t wbuf[sizeof bar.text]; + int w, maxwidth = screen.w - x - 2; + if (mbstowcs(wbuf, bar.text, sizeof bar.text) == (size_t)-1) return; if ((w = wcswidth(wbuf, maxwidth)) == -1) @@ -277,15 +363,16 @@ drawbar(void) { for (; w < maxwidth; w++) addch(' '); } + attrset(TAG_NORMAL); mvaddch(bar.y, screen.w - 1, ']'); attrset(NORMAL_ATTR); - move(y, x); + move(sy, sx); wnoutrefresh(stdscr); } static int show_border(void) { - return (bar.fd != -1 && bar.pos != BAR_OFF) || (clients && clients->next); + return (bar.pos != BAR_OFF) || (clients && clients->next); } static void @@ -333,8 +420,17 @@ draw(Client *c) { static void draw_all(void) { + if (!nextvisible(clients)) { + sel = NULL; + curs_set(0); + erase(); + drawbar(); + doupdate(); + return; + } + if (!isarrange(fullscreen)) { - for (Client *c = clients; c; c = c->next) { + for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { if (c == sel) continue; draw(c); @@ -351,18 +447,26 @@ draw_all(void) { static void arrange(void) { int m = 0; - for (Client *c = clients; c; c = c->next) + for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) if (c->minimized) m++; erase(); - drawbar(); attrset(NORMAL_ATTR); + if (bar.fd == -1 && bar.autohide) { + int n = 0; + for (Client *c = nextvisible(clients); c; c = nextvisible(c->next), n++); + if ((!clients || !clients->next) && n == 1) + bar.pos = BAR_OFF; + else + bar.pos = BAR_POS; + updatebarpos(); + } if (m && !isarrange(fullscreen)) wah--; layout->arrange(); if (m && !isarrange(fullscreen)) { int nw = waw / m, nx = wax; - for (Client *c = clients; c; c = c->next) { + for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { if (c->minimized) { resize(c, nx, way+wah, nw, 1); nx += nw; @@ -370,7 +474,10 @@ arrange(void) { } wah++; } + reorder(-1); + focus(NULL); wnoutrefresh(stdscr); + drawbar(); draw_all(); } @@ -381,7 +488,7 @@ attach(Client *c) { c->next = clients; c->prev = NULL; clients = c; - for (int o = 1; c; c = c->next, o++) + for (int o = 1; c; c = nextvisible(c->next), o++) c->order = o; } @@ -398,19 +505,25 @@ attachafter(Client *c, Client *a) { /* attach c after a */ c->next = a->next; c->prev = a; a->next = c; - for (int o = a->order; c; c = c->next) + for (int o = a->order; c; c = nextvisible(c->next)) c->order = ++o; } } static void +attachstack(Client *c) { + c->snext = stack; + stack = c; +} + +static void detach(Client *c) { Client *d; if (c->prev) c->prev->next = c->next; if (c->next) { c->next->prev = c->prev; - for (d = c->next; d; d = d->next) + for (d = nextvisible(c->next); d; d = nextvisible(d->next)) --d->order; } if (c == clients) @@ -428,24 +541,38 @@ settitle(Client *c) { } static void +detachstack(Client *c) { + Client **tc; + for (tc=&stack; *tc && *tc != c; tc=&(*tc)->snext); + *tc = c->snext; +} + +static void focus(Client *c) { Client *tmp = sel; + if (!c) + for (c = stack; c && !isvisible(c); c = c->snext); if (sel == c) return; lastsel = sel; sel = c; - settitle(c); if (tmp && !isarrange(fullscreen)) { draw_border(tmp); wnoutrefresh(tmp->window); } - if (isarrange(fullscreen)) { - draw(c); - } else { - draw_border(c); - wnoutrefresh(c->window); + + if (c) { + detachstack(c); + attachstack(c); + settitle(c); + if (isarrange(fullscreen)) { + draw(c); + } else { + draw_border(c); + wnoutrefresh(c->window); + } } - curs_set(!c->minimized && vt_cursor_visible(c->term)); + curs_set(c && !c->minimized && vt_cursor_visible(c->term)); } static void @@ -525,7 +652,7 @@ get_client_by_coord(unsigned int x, unsigned int y) { return NULL; if (isarrange(fullscreen)) return sel; - for (Client *c = clients; c; c = c->next) { + for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { if (x >= c->x && x < c->x + c->w && y >= c->y && y < c->y + c->h) { debug("mouse event, x: %d y: %d client: %d\n", x, y, c->order); return c; @@ -578,24 +705,6 @@ sigterm_handler(int sig) { } static void -updatebarpos(void) { - bar.y = 0; - wax = 0; - way = 0; - wah = screen.h; - waw = screen.w; - if (bar.fd == -1) - return; - if (bar.pos == BAR_TOP) { - wah -= bar.h; - way += bar.h; - } else if (bar.pos == BAR_BOTTOM) { - wah -= bar.h; - bar.y = wah; - } -} - -static void resize_screen(void) { struct winsize ws; @@ -631,6 +740,88 @@ keybinding(KeyCombo keys) { return NULL; } +static unsigned int +idxoftag(const char *tag) { + unsigned int i; + for (i = 0; (i < countof(tags)) && (tags[i] != tag); i++); + return (i < countof(tags)) ? i : 0; +} + +static void +tagschanged() { + bool nm = false; + for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { + if (!c->minimized) { + nm = true; + break; + } + } + if (!nm && nextvisible(clients)) { + focus(NULL); + toggleminimize(NULL); + } else { + arrange(); + } +} + +static void +tag(const char *args[]) { + unsigned int i; + + if (!sel) + return; + for (i = 0; i < countof(tags); i++) + sel->tags[i] = (NULL == args[0]); + i = idxoftag(args[0]); + sel->tags[i] = true; + reorder(i); + tagschanged(); +} + +static void +toggletag(const char *args[]) { + unsigned int i, j; + + if (!sel) + return; + i = idxoftag(args[0]); + sel->tags[i] = !sel->tags[i]; + for (j = 0; j < countof(tags) && !sel->tags[j]; j++); + if (j == countof(tags)) + sel->tags[i] = true; /* at least one tag must be enabled */ + tagschanged(); +} + +static void +toggleview(const char *args[]) { + unsigned int i, j; + + i = idxoftag(args[0]); + seltags[i] = !seltags[i]; + for (j = 0; j < countof(tags) && !seltags[j]; j++); + if (j == countof(tags)) + seltags[i] = true; /* at least one tag must be viewed */ + tagschanged(); +} + +static void +view(const char *args[]) { + memcpy(prevtags, seltags, sizeof seltags); + for (unsigned int i = 0; i < countof(tags); i++) + seltags[i] = (NULL == args[0]); + seltags[idxoftag(args[0])] = true; + tagschanged(); +} + +static void +viewprevtag(const char *args[]) { + static bool tmp[countof(tags)]; + memcpy(tmp, seltags, sizeof seltags); + memcpy(seltags, prevtags, sizeof seltags); + memcpy(prevtags, tmp, sizeof seltags); + tagschanged(); +} + static void keypress(int code) { unsigned int len = 1; @@ -644,7 +835,7 @@ keypress(int code) { nodelay(stdscr, FALSE); } - for (Client *c = runinall ? clients : sel; c; c = c->next) { + for (Client *c = runinall ? nextvisible(clients) : sel; c; c = nextvisible(c->next)) { if (is_content_visible(c)) { if (code == '\e') vt_write(c->term, buf, len); @@ -730,12 +921,14 @@ setup(void) { static void destroy(Client *c) { + Client *t; if (sel == c) focusnextnm(NULL); detach(c); + detachstack(c); if (sel == c) { - if (clients) { - focus(clients); + if ((t = nextvisible(clients))) { + focus(t); toggleminimize(NULL); } else { sel = NULL; @@ -785,9 +978,10 @@ static char *getcwd_by_pid(Client *c) { /* commands for use by keybindings */ static void create(const char *args[]) { - Client *c = calloc(1, sizeof(Client)); + Client *c = calloc(1, sizeof(Client) + sizeof(seltags)); if (!c) return; + memcpy(c->tags, seltags, sizeof seltags); const char *cmd = (args && args[0]) ? args[0] : shell; const char *pargs[] = { "/bin/sh", "-c", cmd, NULL }; c->id = ++cmdfifo.id; @@ -804,8 +998,7 @@ create(const char *args[]) { return; } - c->has_title_line = show_border(); - c->term = c->app = vt_create(screen.h - c->has_title_line, screen.w, screen.history); + c->term = c->app = vt_create(screen.h, screen.w, screen.history); if (!c->term) { delwin(c->window); free(c); @@ -910,7 +1103,7 @@ copymode(const char *args[]) { static void focusn(const char *args[]) { - for (Client *c = clients; c; c = c->next) { + for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) { if (c->order == atoi(args[0])) { focus(c); if (c->minimized) @@ -922,11 +1115,12 @@ focusn(const char *args[]) { static void focusnext(const char *args[]) { + Client *c; if (!sel) return; - Client *c = sel->next; + for (c = sel->next; c && !isvisible(c); c = c->next); if (!c) - c = clients; + for (c = clients; c && !isvisible(c); c = c->next); if (c) focus(c); } @@ -937,20 +1131,23 @@ focusnextnm(const char *args[]) { return; Client *c = sel; do { - c = c->next; + c = nextvisible(c->next); if (!c) - c = clients; + c = nextvisible(clients); } while (c->minimized && c != sel); focus(c); } static void focusprev(const char *args[]) { + Client *c; if (!sel) return; - Client *c = sel->prev; - if (!c) + for (c = sel->prev; c && !isvisible(c); c = c->prev); + if (!c) { for (c = clients; c && c->next; c = c->next); + for (; c && !isvisible(c); c = c->prev); + } if (c) focus(c); } @@ -961,9 +1158,11 @@ focusprevnm(const char *args[]) { return; Client *c = sel; do { - c = c->prev; - if (!c) + for (c = c->prev; c && !isvisible(c); c = c->prev); + if (!c) { for (c = clients; c && c->next; c = c->next); + for (; c && !isvisible(c); c = c->prev); + } } while (c->minimized && c != sel); focus(c); } @@ -1078,6 +1277,7 @@ togglebar(const char *args[]) { bar.pos = (BAR_POS == BAR_OFF) ? BAR_TOP : BAR_POS; else bar.pos = BAR_OFF; + bar.autohide = false; updatebarpos(); redraw(NULL); } @@ -1089,13 +1289,13 @@ togglebell(const char *args[]) { static void toggleminimize(const char *args[]) { - Client *c, *m; + Client *c, *m, *t; unsigned int n; if (!sel) return; /* the last window can't be minimized */ if (!sel->minimized) { - for (n = 0, c = clients; c; c = c->next) + for (n = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) if (!c->minimized) n++; if (n == 1) @@ -1104,20 +1304,20 @@ toggleminimize(const char *args[]) { sel->minimized = !sel->minimized; m = sel; /* check whether the master client was minimized */ - if (sel == clients && sel->minimized) { - c = sel->next; + if (sel == nextvisible(clients) && sel->minimized) { + c = nextvisible(sel->next); detach(c); attach(c); focus(c); detach(m); - for (; c && c->next && !c->next->minimized; c = c->next); + for (; c && (t = nextvisible(c->next)) && !t->minimized; c = t); attachafter(m, c); } else if (m->minimized) { /* non master window got minimized move it above all other * minimized ones */ focusnextnm(NULL); detach(m); - for (c = clients; c && c->next && !c->next->minimized; c = c->next); + for (c = nextvisible(clients); c && (t = nextvisible(c->next)) && !t->minimized; c = t); attachafter(m, c); } else { /* window is no longer minimized, move it to the master area */ vt_dirty(m->term); @@ -1147,8 +1347,8 @@ zoom(const char *args[]) { return; if (args && args[0]) focusn(args); - if ((c = sel) == clients) - if (!(c = c->next)) + if ((c = sel) == nextvisible(clients)) + if (!(c = nextvisible(c->next))) return; detach(c); attach(c); diff --git a/fibonacci.c b/fibonacci.c @@ -3,7 +3,9 @@ static void fibonacci(int s) unsigned int nx, ny, nw, nnw, nh, nnh, i, n, mod; Client *c; - for (n = 0, c = clients; c && !c->minimized; c = c->next, n++); + for (n = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) + if (!c->minimized) + n++; /* initial position and dimensions */ nx = wax; @@ -19,7 +21,9 @@ static void fibonacci(int s) /* set the mod factor, 2 for dwindle, 4 for spiral */ mod = s ? 4 : 2; - for (i = 0, c = clients; c && !c->minimized; c = c->next, i++) { + for (i = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) { + if (c->minimized) + continue; /* dwindle: even case, spiral: case 0 */ if (i % mod == 0) { if (i) { @@ -75,6 +79,7 @@ static void fibonacci(int s) } resize(c, nx, ny, nw, nh); + i++; } } diff --git a/fullscreen.c b/fullscreen.c @@ -1,5 +1,5 @@ static void fullscreen(void) { - for (Client *c = clients; c; c = c->next) + for (Client *c = nextvisible(clients); c; c = nextvisible(c->next)) resize(c, wax, way, waw, wah); } diff --git a/grid.c b/grid.c @@ -3,7 +3,9 @@ static void grid(void) unsigned int i, n, nx, ny, nw, nh, aw, ah, cols, rows; Client *c; - for (n = 0, c = clients; c && !c->minimized; c = c->next, n++); + for (n = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) + if (!c->minimized) + n++; /* grid dimensions */ for (cols = 0; cols <= n / 2; cols++) if (cols * cols >= n) @@ -12,7 +14,9 @@ static void grid(void) /* window geoms (cell height/width) */ nh = wah / (rows ? rows : 1); nw = waw / (cols ? cols : 1); - for (i = 0, c = clients; c && !c->minimized; c = c->next, i++) { + for (i = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) { + if (c->minimized) + continue; /* if there are less clients in the last row than normal adjust the * split rate to fill the empty space */ if (rows > 1 && i == (rows * cols) - cols && (n - i) <= (n % cols)) @@ -41,5 +45,6 @@ static void grid(void) nx++, aw--; } resize(c, nx, ny, nw + aw, nh + ah); + i++; } } diff --git a/tile.c b/tile.c @@ -3,14 +3,18 @@ static void tile(void) unsigned int i, n, nx, ny, nw, nh, mw, th; Client *c; - for (n = 0, c = clients; c && !c->minimized; c = c->next, n++); + for (n = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) + if (!c->minimized) + n++; mw = n <= 1 ? waw : screen.mfact * waw; th = n <= 1 ? 0 : wah / (n - 1); nx = wax; ny = way; - for (i = 0, c = clients; c && !c->minimized; c = c->next, i++) { + for (i = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) { + if (c->minimized) + continue; if (i == 0) { /* master */ nw = mw; nh = wah; @@ -30,5 +34,6 @@ static void tile(void) resize(c, nx, ny, nw, nh); if (i > 0) ny += nh; + i++; } } diff --git a/tstack.c b/tstack.c @@ -3,14 +3,18 @@ void tstack(void) unsigned int i, n, nx, ny, nw, nh, mh, tw; Client *c; - for (n = 0, c = clients; c && !c->minimized; c = c->next, n++); + for (n = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) + if (!c->minimized) + n++; mh = n <= 1 ? wah : screen.mfact * wah; tw = n <= 1 ? 0 : waw / (n - 1); nx = wax; nw = waw; - for (i = 0, c = clients; c && !c->minimized; c = c->next, i++) { + for (i = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) { + if (c->minimized) + continue; if (i == 0) { /* master */ ny = way + wah - mh; nh = mh; @@ -32,5 +36,6 @@ void tstack(void) if (i > 0) nx += nw; + i++; } } diff --git a/vstack.c b/vstack.c @@ -4,18 +4,23 @@ static void vstack(void) unsigned int i, n, ny, nh, mh, th; Client *c; - for (n = 0, c = clients; c && !c->minimized; c = c->next, n++); + for (n = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) + if (!c->minimized) + n++; mh = n <= 1 ? wah : screen.mfact * wah; th = n <= 1 ? 0 : (wah - mh) / (n - 1); ny = way; - for (i = 0, c = clients; c && !c->minimized; c = c->next, i++) { + for (i = 0, c = nextvisible(clients); c; c = nextvisible(c->next)) { + if (c->minimized) + continue; if (i == 0) /* master */ nh = mh; else /* tile window */ nh = (i < n - 1) ? th : (way + wah) - ny; resize(c, wax, ny, waw, nh); ny += nh; + i++; } }