[dev] [PATCH] select or open new tab with Ctrl-T

From: Markus Teich <markus.teich_AT_stusta.mhn.de>
Date: Thu, 28 Nov 2013 18:26:21 +0100

The default config will display all open tabs in dmenu. You can either select
one of them, or if you enter a string, that does not start with „0x“, tabbed
will open a new tab and run the command specified at tabbed-startup but append
the entered string to the command first.

With
tabbed -r 2 surf -e ''
you can hit Ctrl-T and either select an already opened tab or enter an URL,
which will be opened in a new tab with surf.
---
Hello,
I had the insight, that it would not be surfs responsibility to know about tabs,
so here is a tabbed only patch achieving the above mentioned features.
--Markus
 config.def.h |  9 +++++++++
 tabbed.c     | 51 ++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 53 insertions(+), 7 deletions(-)
diff --git a/config.def.h b/config.def.h
index ca4b8d6..3a92bd9 100644
--- a/config.def.h
+++ b/config.def.h
_AT_@ -19,11 +19,20 @@ static const Bool foreground    = True;
 static int  newposition   = 0;
 static Bool npisrelative  = False;
 
+#define SETPROP(p) { \
+	.v = (char *[]){ "/bin/sh", "-c", \
+		"prop=\"`xwininfo -children -id $1 | grep '^     0x' | sed -e's_AT_^ *\\(0x[0-9a-f]*\\) \"\\([^\"]*\\)\".*@\\1 \\2@' | xargs -0 printf %b | dmenu -l 10`\" &&" \
+		"xprop -id $1 -f $0 8s -set $0 \"$prop\"", \
+		p, winid, NULL \
+	} \
+}
+
 #define MODKEY ControlMask
 static Key keys[] = { \
 	/* modifier                     key        function        argument */
 	{ MODKEY|ShiftMask,             XK_Return, focusonce,      { 0 } },
 	{ MODKEY|ShiftMask,             XK_Return, spawn,          { 0 } },
+	{ MODKEY,                       XK_t,      spawn,          SETPROP("_TABBED_SELECT_TAB") },
 
 	{ MODKEY|ShiftMask,             XK_l,      rotate,         { .i = +1 } },
 	{ MODKEY|ShiftMask,             XK_h,      rotate,         { .i = -1 } },
diff --git a/tabbed.c b/tabbed.c
index 3a6e7f9..e870db4 100644
--- a/tabbed.c
+++ b/tabbed.c
_AT_@ -48,7 +48,7 @@
 
 enum { ColFG, ColBG, ColLast };                         /* color */
 enum { WMProtocols, WMDelete, WMName, WMState, WMFullscreen,
-	XEmbed, WMLast };                               /* default atoms */
+	XEmbed, WMSelectTab, WMLast };                      /* default atoms */
 
 typedef union {
 	int i;
_AT_@ -103,6 +103,7 @@ static void focus(int c);
 static void focusin(const XEvent *e);
 static void focusonce(const Arg *arg);
 static void fullscreen(const Arg *arg);
+static char* getatom(int a);
 static int getclient(Window w);
 static unsigned long getcolor(const char *colstr);
 static int getfirsttab(void);
_AT_@ -157,6 +158,7 @@ static Window root, win;
 static Client **clients = NULL;
 static int nclients = 0, sel = -1, lastsel = -1;
 static int (*xerrorxlib)(Display *, XErrorEvent *);
+static int cmd_append_pos = 0;
 static char winid[64];
 static char **cmd = NULL;
 static char *wmname = "tabbed";
_AT_@ -428,6 +430,7 @@ focus(int c) {
 
 	/* If c, sel and clients are -1, raise tabbed-win itself */
 	if(nclients == 0) {
+		cmd[cmd_append_pos] = NULL;
 		for(i = 0, n = strlen(buf); cmd[i] && n < sizeof(buf); i++)
 			n += snprintf(&buf[n], sizeof(buf) - n, " %s", cmd[i]);
 
_AT_@ -489,6 +492,26 @@ fullscreen(const Arg *arg) {
 	XSendEvent(dpy, root, False, SubstructureNotifyMask, &e);
 }
 
+char *
+getatom(int a) {
+	static char buf[BUFSIZ];
+	Atom adummy;
+	int idummy;
+	unsigned long ldummy;
+	unsigned char *p = NULL;
+
+	XGetWindowProperty(dpy, win, wmatom[a], 0L, BUFSIZ, False, XA_STRING,
+			&adummy, &idummy, &ldummy, &ldummy, &p);
+	if(p) {
+		strncpy(buf, (char *)p, LENGTH(buf)-1);
+	} else {
+		buf[0] = '\0';
+	}
+	XFree(p);
+
+	return buf;
+}
+
 int
 getclient(Window w) {
 	int i;
_AT_@ -775,8 +798,20 @@ void
 propertynotify(const XEvent *e) {
 	const XPropertyEvent *ev = &e->xproperty;
 	int c;
+	char* selection = NULL;
+	Arg arg;
 
-	if(ev->state != PropertyDelete && ev->atom == XA_WM_NAME
+	if(ev->state == PropertyNewValue && ev->atom == wmatom[WMSelectTab]) {
+		selection = getatom(WMSelectTab);
+		if(!strncmp(selection, "0x", 2)) {
+			arg.i = getclient(strtoul(selection, NULL, 0));
+			move(&arg);
+		} else {
+			cmd[cmd_append_pos] = selection;
+			arg.v = cmd;
+			spawn(&arg);
+		}
+	} else if(ev->state != PropertyDelete && ev->atom == XA_WM_NAME
 			&& (c = getclient(ev->window)) > -1) {
 		updatetitle(c);
 	}
_AT_@ -862,13 +897,14 @@ void
 setcmd(int argc, char *argv[], int replace) {
 	int i;
 
-	cmd = emallocz((argc+2) * sizeof(*cmd));
+	cmd = emallocz((argc+3) * sizeof(*cmd));
 	if (argc == 0)
 		return;
 	for(i = 0; i < argc; i++)
 		cmd[i] = argv[i];
 	cmd[(replace > 0)? replace : argc] = winid;
-	cmd[argc + !(replace > 0)] = NULL;
+	cmd_append_pos = argc + !replace;
+	cmd[cmd_append_pos] = cmd[cmd_append_pos+1] = NULL;
 }
 
 void
_AT_@ -892,8 +928,8 @@ setup(void) {
 	wmatom[XEmbed] = XInternAtom(dpy, "_XEMBED", False);
 	wmatom[WMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
 	wmatom[WMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
-	wmatom[WMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN",
-			False);
+	wmatom[WMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+	wmatom[WMSelectTab] = XInternAtom(dpy, "_TABBED_SELECT_TAB", False);
 
 	/* init appearance */
 	wx = 0;
_AT_@ -943,7 +979,7 @@ setup(void) {
 			dc.norm[ColFG], dc.norm[ColBG]);
 	XMapRaised(dpy, win);
 	XSelectInput(dpy, win, SubstructureNotifyMask|FocusChangeMask|
-			ButtonPressMask|ExposureMask|KeyPressMask|
+			ButtonPressMask|ExposureMask|KeyPressMask|PropertyChangeMask|
 			StructureNotifyMask|SubstructureRedirectMask);
 	xerrorxlib = XSetErrorHandler(xerror);
 
_AT_@ -993,6 +1029,7 @@ spawn(const Arg *arg) {
 			fprintf(stderr, "tabbed: execvp %s",
 					((char **)arg->v)[0]);
 		} else {
+			cmd[cmd_append_pos] = NULL;
 			execvp(cmd[0], cmd);
 			fprintf(stderr, "tabbed: execvp %s", cmd[0]);
 		}
-- 
1.8.2
Received on Thu Nov 28 2013 - 18:26:21 CET

This archive was generated by hypermail 2.3.0 : Thu Nov 28 2013 - 18:36:07 CET