[hackers] [dvtm] pertag patch addition

2015-10-05 Thread Ross Mohn
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

2015-10-02 Thread Ross Mohn
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

2015-07-17 Thread Ross Mohn
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

2015-07-15 Thread Ross Mohn
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

2015-07-14 Thread Ross Mohn
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

2015-07-14 Thread Ross Mohn
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

2015-07-14 Thread Ross Mohn
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

2015-06-05 Thread Ross Mohn
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;