select or open new tab with Ctrl-T - tabbed - tab interface for application sup… | |
git clone git://git.suckless.org/tabbed | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit a1aa453e99f198186d39b90b1229cc1bcb8dc466 | |
parent b46a3a278856bb33dc299d11d0be1b01d04df39c | |
Author: Markus Teich <[email protected]> | |
Date: Thu, 28 Nov 2013 18:26:21 +0100 | |
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 <[email protected]> | |
Diffstat: | |
M config.def.h | 9 +++++++++ | |
M tabbed.c | 51 ++++++++++++++++++++++++++---… | |
2 files changed, 53 insertions(+), 7 deletions(-) | |
--- | |
diff --git a/config.def.h b/config.def.h | |
@@ -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'… | |
+ "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("_T… | |
{ MODKEY|ShiftMask, XK_l, rotate, { .i = +1 }… | |
{ MODKEY|ShiftMask, XK_h, rotate, { .i = -1 }… | |
diff --git a/tabbed.c b/tabbed.c | |
@@ -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", Fa… | |
+ 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|PropertyChan… | |
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]); | |
} |