~kris/suckless

tabbed

a1aa453e99f198186d39b90b1229cc1bcb8dc466 — Markus Teich 12 years ago b46a3a2
select or open new tab with Ctrl-T

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.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
2 files changed, 53 insertions(+), 7 deletions(-)

M config.def.h
M tabbed.c
M config.def.h => config.def.h +9 -0
@@ 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@^ *\\(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 } },

M tabbed.c => tabbed.c +44 -7
@@ 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;


@@ 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);


@@ 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";


@@ 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]);



@@ 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;


@@ 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);
	}


@@ 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


@@ 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;


@@ 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);



@@ 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]);
		}