[hackers] [dvtm] pertag patch addition
I've updated my pertag patch for dvtm so that it now includes the runinall setting, as well. The patch is also available here: http://waxandwane.org/dvtm.html Enjoy! -Ross An implementation for dvtm of the dwm pertag patch. With this patch, the below settings are chosen and remembered individually for each tag. This is in contrast to the default functionality where changes to these settings are applied across all tags. Each tag starts out with the default settings from your config.h file. * Layout * Number of clients in the master window * Percentage of the screen used by the master window * Status bar position and visibility * Status of the RunInAll feature tagging paradigm workflow - When toggling to view multiple tags, whichever tag is viewed first determines the settings for all the pertag features. From there you toggle additional tags on and off, and the pertag feature settings remain unchanged. If you then switch and choose to view a different individual tag, that new tag's settings become active for all the pertag features. From there, you again toggle additional tags on and off. Now you're able to toggle between the two tag-views you've set up by using the viewprevtag action (MOD+v+TAB) and the pertag feature settings remain as they were. In this way, you are not forced to reset all the pertag features every time you toggle with the viewprevtag action. workspace paradigm workflow - Though dvtm was designed for the tagging paradigm (above), it also works very well in a workspace paradigm. With this, you primarily use the view and tag actions rather than the toggleview and toggletag actions. All pertag feature settings that are set while viewing an individual tag are remembered for that tag. diff --git a/dvtm.c b/dvtm.c index e337061..2085e84 100644 --- a/dvtm.c +++ b/dvtm.c @@ -223,9 +223,20 @@ static char *title; #include "config.h" +typedef struct { + unsigned int curtag, prevtag; + int nmaster[LENGTH(tags) + 1]; + float mfact[LENGTH(tags) + 1]; + Layout *layout[LENGTH(tags) + 1]; + int barpos[LENGTH(tags) + 1]; + int barlastpos[LENGTH(tags) + 1]; + bool runinall[LENGTH(tags) + 1]; +} Pertag; + /* global variables */ static const char *dvtm_name = "dvtm"; Screen screen = { .mfact = MFACT, .nmaster = NMASTER, .history = SCROLL_HISTORY }; +static Pertag pertag; static Client *stack = NULL; static Client *sel = NULL; static Client *lastsel = NULL; @@ -302,15 +313,15 @@ updatebarpos(void) { static void hidebar(void) { if (bar.pos != BAR_OFF) { - bar.lastpos = bar.pos; - bar.pos = BAR_OFF; + bar.lastpos = pertag.barlastpos[pertag.curtag] = bar.pos; + bar.pos = pertag.barpos[pertag.curtag] = BAR_OFF; } } static void showbar(void) { if (bar.pos == BAR_OFF) - bar.pos = bar.lastpos; + bar.pos = pertag.barpos[pertag.curtag] = bar.lastpos; } static void @@ -389,7 +400,7 @@ draw_border(Client *c) { if (!show_border()) return; - if (sel == c || (runinall && !c->minimized)) + if (sel == c || (pertag.runinall[pertag.curtag] && !c->minimized)) attrs = SELECTED_ATTR; if (sel != c && c->urgent) attrs = URGENT_ATTR; @@ -808,9 +819,33 @@ toggletag(const char *args[]) { } static void +setpertag(void) { + screen.nmaster = pertag.nmaster[pertag.curtag]; + screen.mfact = pertag.mfact[pertag.curtag]; + layout = pertag.layout[pertag.curtag]; + if (bar.pos != pertag.barpos[pertag.curtag]) { + bar.pos = pertag.barpos[pertag.curtag]; + updatebarpos(); + } + bar.lastpos = pertag.barlastpos[pertag.curtag]; + runinall = pertag.runinall[pertag.curtag]; +} + +static void toggleview(const char *args[]) { + int i; + unsigned int newtagset = tagset[seltags] ^ (bitoftag(args[0]) & TAGMASK); if (newtagset) { + if(newtagset == TAGMASK) { + pertag.prevtag = pertag.curtag; + pertag.curtag = 0; + } else if(!(newtagset & 1 << (pertag.curtag - 1))) { + pertag.prevtag = pertag.curtag; + for (i=0; !(newtagset &1 << i); i++) ; + pertag.curtag = i + 1; + } + setpertag(); tagset[seltags] = newtagset; tagschanged(); } @@ -818,9 +853,19 @@ toggleview(const char *args[]) { static void view(const char *args[]) { + int i; + unsigned int newtagset = bitoftag(args[0]) & TAGMASK; if (tagset[seltags] != newtagset && newtagset) { seltags ^= 1; /* toggle sel tagset */ + pertag.prevtag = pertag.curtag; + if(args[0] == NULL) + pertag.curtag = 0; + else { + for (i = 0; (i < LENGTH(tags)) && (tags[i] != args[0]); i++) ; + pertag.curtag = i + 1; + } + setpertag(); tagset[seltags] = newtagset; tagschanged(); } @@ -828,7 +873,13 @@ view(const char *args[]) { static void viewprevtag(const char *args[]) { + unsigned int tmptag; + seltags ^= 1; + tmptag = pertag.prevtag; + pertag.prevtag = pertag.curtag; + pertag.curtag = tmptag; + setpertag(); tagschanged(); } @@ -845,7 +896,7 @@ keypress(int code) { nodelay(stdscr, FALSE); } - for (Client *c = runinall ? nextvisible(clients) : sel; c; c =
[hackers] [dvtm] Command keys in status bar patch
The attached patch is to display command keypresses in the status bar while a multiple keypress command is being entered. Almost all commands in dvtm begin with MOD, so require multiple keypresses. Command keys are displayed as they are pressed, and appear between the layout symbol and the status text. The keys are cleared from the status bar after the final key of a command is pressed, or if the key combination is not bound to a command. For example, if your MOD is set to ^G and you are toggling the view of tag 4, it first displays '^g' after you press MOD, then '^gV' after you press 'V', and then is cleared after you complete the command by pressing '4'. Please review. Thanks -Ross diff --git a/dvtm.c b/dvtm.c index e337061..42809ad 100644 --- a/dvtm.c +++ b/dvtm.c @@ -220,6 +220,7 @@ extern Screen screen; static unsigned int waw, wah, wax, way; static Client *clients = NULL; static char *title; +static KeyCombo keys; #include "config.h" @@ -345,6 +346,15 @@ drawbar(void) { attrset(TAG_NORMAL); addstr(layout->symbol); + if(keys) { + unsigned int keycount = 0; + while (keycount < MAX_KEYS && keys[keycount]) + if (keys[keycount] < ' ') +printw("^%c", 'a' - 1 + keys[keycount++]); + else +printw("%c", keys[keycount++]); + } + getyx(stdscr, y, x); (void)y; int maxwidth = screen.w - x - 2; @@ -1710,7 +1720,6 @@ parse_args(int argc, char *argv[]) { int main(int argc, char *argv[]) { - KeyCombo keys; unsigned int key_index = 0; memset(keys, 0, sizeof(keys)); sigset_t emptyset, blockset; @@ -1797,6 +1806,9 @@ main(int argc, char *argv[]) { memset(keys, 0, sizeof(keys)); keypress(code); } +drawbar(); +if (is_content_visible(sel)) + wnoutrefresh(sel->window); } if (r == 1) /* no data available on pty's */ continue;
[hackers] [dvtm] Status bar aesthetic patch
Hi, I like to to use my own characters at the beginning and end of the status bar message. Previously I've edited dvtm.c directly, but it's better to have this configurable in config.h so that eveeryone can choose their own. Thanks -Ross diff --git a/config.def.h b/config.def.h index e25d83c..32a2a1e 100644 --- a/config.def.h +++ b/config.def.h @@ -30,6 +30,9 @@ static Color colors[] = { #define URGENT_ATTR NORMAL_ATTR /* curses attributes for the status bar */ #define BAR_ATTR(COLOR(BLUE) | A_NORMAL) +/* characters for beginning and end of status bar message */ +#define BAR_BEGIN '[' +#define BAR_END ']' /* status bar (command line option -s) position */ #define BAR_POS BAR_TOP /* BAR_BOTTOM, BAR_OFF */ /* whether status bar should be hidden if only one client exists */ diff --git a/dvtm.c b/dvtm.c index dbacb39..7170f3b 100644 --- a/dvtm.c +++ b/dvtm.c @@ -348,7 +348,7 @@ drawbar(void) { (void)y; int maxwidth = screen.w - x - 2; - addch('['); + addch(BAR_BEGIN); attrset(BAR_ATTR); wchar_t wbuf[sizeof bar.text]; @@ -370,7 +370,7 @@ drawbar(void) { } attrset(TAG_NORMAL); - mvaddch(bar.y, screen.w - 1, ']'); + mvaddch(bar.y, screen.w - 1, BAR_END); attrset(NORMAL_ATTR); move(sy, sx); wnoutrefresh(stdscr);
[hackers] [dvtm] create in $CWD not working
Hi, The create() function can take a third argument in order to use the directory of the current client, sel, when it creates a new client. This command is mapped to MOD+C by default. To implement this, the function uses the /proc/ tree to find the current directory of process sel-pid. The problem, at least for me, is that sel-pid is the generic sh that spawns the actual user shell, so when I cd in my shell, the cwd of the calling sh process doesn't change. $ pstree -p 2199 dvtm(2199)─┬─sh(2239)───bash(2240)───mutt(11096) ├─sh(2324)───bash(2325) ├─sh(12015)───bash(12016)───vim(17544) └─sh(12116)───bash(12117)───pstree(21626) For example, sel-pid is 2324, and I'm interacting with shell pid 2325. The cwd of process 2324 is ~/, but I've changed the cwd of process 2325 to ~/local/repos/dvtm/. When I press MOD+C in my shell, dvtm creates a new client with cwd of ~/, same as sel-pid 2324, not where I expect it to in ~/local/repos/dvtm/. Do others also have this issue? I'm not very familiar with /proc/; is there something in there that could be used to identify the user shell instead? But that might not work for everyone. Thanks -Ross
[hackers] [dvtm] Default command mapping changes
Hi, In an effort to bring more attention to the dvtm project, I'm working on some additional documentation. In the process, I've done a full review of all the default command keys and would like to propose the below changes to the defaults. These are probably appropiate for dwm as well, but since I no longer use that application, I'll leave that to someone else to propose. First, the killclient and quit commands are very desctructive and too easy to press by accident with sometimes disasterous results. Because of this, I propose that the key presses be doubled to the following, to be sure that they are intentional. killclient MOD+x+x quitMOD+q+q Next, I'd like to have the incnmaster and setmfact defaults changed. This also allows the easy mapping of two additional commands: one for putting all windows into the master window (incnmaster(99)), and the other for resetting nmaster back to 1 (incnmaster(1)). Using '' and '' for setmfact is also consistent with resizing the width of windows in Vim. incnmaster(+1)l incnmaster(99)L incnmaster(+1)h incnmaster(0) H setmfact(+0.05) setmfact(-0.05) The last group might be the most contentious, but I think they make more sense than the current mappings. Currently, setlayout(fullscreen) is mapped to 'm' for monocle, and I propose to change it to 'o' for only (as it is in Vim). Also, setlayout(tile) is currently mapped to 'f' for default and I propose to change it to '=', which is reasonably consistent with Vim's mapping. This also matches the tile character in the default tiling icon '[]='. If these are objectionable, I could also live with 'f' for fullscreen and 'm' for master+tile. setlayout(fullscreen) o setlayout(tile) = Please let me know what you think. I hope that these changes can make it into the master branch so that I can include them in my documentation. Thanks! -Ross
Re: [hackers] [dvtm] Default command mapping changes
On Tue, Jul 14, 2015 at 02:15:10PM -0400, Ross Mohn wrote: incnmaster(+1)l incnmaster(99)L incnmaster(+1)h incnmaster(0) H Gah! I meant this: incnmaster(-1)l incnmaster(0) L incnmaster(+1)h incnmaster(99)H
Re: [hackers] [dvtm] Default command mapping changes
On Tue, Jul 14, 2015 at 02:36:09PM -0400, Ross Mohn wrote: On Tue, Jul 14, 2015 at 02:15:10PM -0400, Ross Mohn wrote: incnmaster(+1)l incnmaster(99)L incnmaster(+1)h incnmaster(0) H Gah! I meant this: incnmaster(-1)l incnmaster(0) L incnmaster(+1)h incnmaster(99)H This is not my day. Here's my final answer: incnmaster(-1)l incnmaster(1) L incnmaster(+1)h incnmaster(99)H
[hackers] [dvtm] Mouse clicks on tags patch
Hi again, The attached patch allows you to assign functions to mouse clicks on the tag indicators in the status bar. The default actions are: * left click to toggle viewing that tag * left double click to view only that tag * middle click to view all tags * right click to toggle assignment of the current client to that tag I want to expand the functionality to include the ability to assign functions to mouse clicks on other parts of the status bar, such as clicking on the layout indicator to cycle through the layouts, and clicking on the text area to create a new client. But, this will be much cleaner and require much less code if we switch the mouse handling to be more like that of the current dwm code. So, I've attached this patch as is, with its functionality for pressing just on the tag indicators in the status bar, but I'm stopping there and will work on rewriting the mouse handling in general within dvtm. Feedback appreciated! -Ross diff --git a/config.def.h b/config.def.h index b0a68d4..fe8dedd 100644 --- a/config.def.h +++ b/config.def.h @@ -192,6 +192,13 @@ static Button buttons[] = { { BUTTON2_CLICKED,{ mouse_zoom, { NULL } } }, { BUTTON3_CLICKED,{ mouse_minimize, { NULL } } }, }; + +static Button tag_buttons[] = { + { BUTTON1_CLICKED,{ mouse_toggleview, { NULL } } }, + { BUTTON1_DOUBLE_CLICKED, { mouse_view, { NULL } } }, + { BUTTON2_CLICKED,{ view, { NULL } } }, + { BUTTON3_CLICKED,{ mouse_toggletag, { NULL } } }, +}; #endif /* CONFIG_MOUSE */ static Cmd commands[] = { diff --git a/dvtm.c b/dvtm.c index 464a223..c01f006 100644 --- a/dvtm.c +++ b/dvtm.c @@ -210,6 +210,9 @@ static void mouse_focus(const char *args[]); static void mouse_fullscreen(const char *args[]); static void mouse_minimize(const char *args[]); static void mouse_zoom(const char *args[]); +static void mouse_toggleview(const char *args[]); +static void mouse_view(const char *args[]); +static void mouse_toggletag(const char *args[]); /* functions and variables available to layouts via config.h */ static Client* nextvisible(Client *c); @@ -231,6 +234,7 @@ static Client *lastsel = NULL; static Client *msel = NULL; static unsigned int seltags; static unsigned int tagset[2] = { 1, 1 }; +static int tsel = -1; static bool mouse_events_enabled = ENABLE_MOUSE; static Layout *layout = layouts; static StatusBar bar = { .fd = -1, .lastpos = BAR_POS, .pos = BAR_POS, .autohide = BAR_AUTOHIDE, .h = 1 }; @@ -683,6 +687,32 @@ get_client_by_coord(unsigned int x, unsigned int y) { return NULL; } +static int +get_tag_by_coord(unsigned int x, unsigned int y) { + unsigned int i; + unsigned int pos = 0; + int tagfield, labellen; + + if ((bar.pos == BAR_OFF) || + (bar.pos == BAR_TOP y = bar.h) || + (bar.pos == BAR_BOTTOM y screen.h - bar.h)) + return -1; + + /* Assumes TAG_SYMBOL includes '%s', a 2 character format specification */ + tagfield = strlen(TAG_SYMBOL) - 2; + + for (i = 0; i LENGTH(tags); i++){ + labellen = tagfield + strlen(tags[i]); + if (x = pos x pos + labellen) { + debug(mouse event, x: %d y: %d tag: %d\n, x, y, i); + return i; + } + pos += labellen; + } + + return -1; +} + static void sigchld_handler(int sig) { int errsv = errno; @@ -1418,6 +1448,24 @@ mouse_zoom(const char *args[]) { zoom(NULL); } +static void +mouse_toggleview(const char *args[]) { + args[0] = tags[tsel]; + toggleview(args); +} + +static void +mouse_view(const char *args[]) { + args[0] = tags[tsel]; + view(args); +} + +static void +mouse_toggletag(const char *args[]) { + args[0] = tags[tsel]; + toggletag(args); +} + static Cmd * get_cmd_by_name(const char *name) { for (unsigned int i = 0; i LENGTH(commands); i++) { @@ -1531,8 +1579,19 @@ handle_mouse(void) { return; msel = get_client_by_coord(event.x, event.y); - if (!msel) + if (!msel) { + tsel = get_tag_by_coord(event.x, event.y); + if (tsel == -1) + return; + debug(mouse x:%d y:%d tag:%d mask:%d\n, event.x, event.y, tsel, event.bstate); + for (i = 0; i LENGTH(tag_buttons); i++) { + if (event.bstate tag_buttons[i].mask) +tag_buttons[i].action.cmd(tag_buttons[i].action.args); + } + + tsel = -1; return; + } debug(mouse x:%d y:%d cx:%d cy:%d mask:%d\n, event.x, event.y, event.x - msel-x, event.y - msel-y, event.bstate); @@ -1776,6 +1835,7 @@ main(int argc, char *argv[]) { keys[key_index++] = code; KeyBinding *binding = NULL; if (code == KEY_MOUSE) { + key_index = 0; handle_mouse(); } else if ((binding = keybinding(keys))) { unsigned int key_length = 0;