commit 23623e4ffa5aacb896fa4ac7164ad57918a528ba
parent 1c5078bc89c1ccf1b732c0f35f0689de6b24926f
Author: Christoph Lohmann <20h@r-36.net>
Date: Sun, 16 Apr 2017 23:47:30 +0200
Add toggle for bar appearance and position.
Diffstat:
config.def.h | | | 67 | ++++++++++++++++++++++++++++++++++++------------------------------- |
tabbed.1 | | | 22 | ++++++++++++++++++++++ |
tabbed.c | | | 227 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
3 files changed, 200 insertions(+), 116 deletions(-)
diff --git a/config.def.h b/config.def.h
@@ -14,6 +14,8 @@ static const char titletrim[] = "...";
static const int tabwidth = 200;
static const Bool foreground = True;
static Bool urgentswitch = False;
+Bool showbar = True; /* False means no bar */
+Bool bottombar = True; /* False means top bar */
/*
* Where to place a new tab when it is opened. When npisrelative is True,
@@ -24,43 +26,46 @@ 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 \
- } \
+ .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") },
+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, XK_b, togglebar, { 0 } },
+ { MODKEY, XK_m, toggletop, { 0 } },
- { MODKEY|ShiftMask, XK_l, rotate, { .i = +1 } },
- { MODKEY|ShiftMask, XK_h, rotate, { .i = -1 } },
- { MODKEY|ShiftMask, XK_j, movetab, { .i = -1 } },
- { MODKEY|ShiftMask, XK_k, movetab, { .i = +1 } },
- { MODKEY, XK_Tab, rotate, { .i = 0 } },
+ { MODKEY|ShiftMask, XK_l, rotate, { .i = +1 } },
+ { MODKEY|ShiftMask, XK_h, rotate, { .i = -1 } },
+ { MODKEY|ShiftMask, XK_j, movetab, { .i = -1 } },
+ { MODKEY|ShiftMask, XK_k, movetab, { .i = +1 } },
+ { MODKEY, XK_Tab, rotate, { .i = 0 } },
- { MODKEY, XK_1, move, { .i = 0 } },
- { MODKEY, XK_2, move, { .i = 1 } },
- { MODKEY, XK_3, move, { .i = 2 } },
- { MODKEY, XK_4, move, { .i = 3 } },
- { MODKEY, XK_5, move, { .i = 4 } },
- { MODKEY, XK_6, move, { .i = 5 } },
- { MODKEY, XK_7, move, { .i = 6 } },
- { MODKEY, XK_8, move, { .i = 7 } },
- { MODKEY, XK_9, move, { .i = 8 } },
- { MODKEY, XK_0, move, { .i = 9 } },
+ { MODKEY, XK_1, move, { .i = 0 } },
+ { MODKEY, XK_2, move, { .i = 1 } },
+ { MODKEY, XK_3, move, { .i = 2 } },
+ { MODKEY, XK_4, move, { .i = 3 } },
+ { MODKEY, XK_5, move, { .i = 4 } },
+ { MODKEY, XK_6, move, { .i = 5 } },
+ { MODKEY, XK_7, move, { .i = 6 } },
+ { MODKEY, XK_8, move, { .i = 7 } },
+ { MODKEY, XK_9, move, { .i = 8 } },
+ { MODKEY, XK_0, move, { .i = 9 } },
- { MODKEY, XK_q, killclient, { 0 } },
+ { MODKEY, XK_q, killclient, { 0 } },
- { MODKEY, XK_u, focusurgent, { 0 } },
- { MODKEY|ShiftMask, XK_u, toggle, { .v = (void*) &urgentswitch } },
+ { MODKEY, XK_u, focusurgent, { .v = NULL } },
+ { MODKEY|ShiftMask, XK_u, toggle, { .v = (void *)&urgentswitch } },
- { 0, XK_F11, fullscreen, { 0 } },
+ { 0, XK_F11, fullscreen, { 0 } },
};
+
diff --git a/tabbed.1 b/tabbed.1
@@ -3,9 +3,13 @@
tabbed \- generic tabbed interface
.SH SYNOPSIS
.B tabbed
+.RB [ \-B ]
+.RB [ \-b ]
.RB [ \-c ]
.RB [ \-d ]
.RB [ \-k ]
+.RB [ \-M ]
+.RB [ \-m ]
.RB [ \-s ]
.RB [ \-v ]
.RB [ \-g
@@ -38,6 +42,12 @@ disabled by providing the -s parameter. If no command is provided
tabbed will just print its xid and run no command.
.SH OPTIONS
.TP
+.B \-B
+show the status bar.
+.TP
+.B \-b
+do not show the status bar.
+.TP
.B \-c
close tabbed when the last tab is closed. Mutually exclusive with -f.
.TP
@@ -61,6 +71,12 @@ for further details.
close foreground tabbed client (instead of tabbed and all clients) when
WM_DELETE_WINDOW is sent.
.TP
+.B \-M
+show the status bar at the bottom.
+.TP
+.B \-b
+show the status bar at the top.
+.TP
.BI \-n " name"
will set the WM_CLASS attribute to
.I name.
@@ -131,6 +147,12 @@ toggle autofocus of urgent tabs
.B Ctrl\-Tab
toggle between the selected and last selected tab
.TP
+.B Ctrl\-b
+toggle the status bar
+.TP
+.B Ctrl\-m
+toggle the bar position between top and bottom
+.TP
.B Ctrl\-t
open dmenu to either create a new tab appending the entered string or select
an already existing tab.
diff --git a/tabbed.c b/tabbed.c
@@ -82,6 +82,7 @@ typedef struct {
char name[256];
Window win;
int tabx;
+ int remapped;
Bool urgent;
Bool closed;
} Client;
@@ -99,6 +100,7 @@ static void drawbar(void);
static void drawtext(const char *text, XftColor col[ColLast]);
static void *ecalloc(size_t n, size_t size);
static void *erealloc(void *o, size_t size);
+static void embedwindow(Window w);
static void expose(const XEvent *e);
static void focus(int c);
static void focusin(const XEvent *e);
@@ -119,6 +121,7 @@ static void maprequest(const XEvent *e);
static void move(const Arg *arg);
static void movetab(const Arg *arg);
static void propertynotify(const XEvent *e);
+static void reembedclients(void);
static void resize(int c, int w, int h);
static void rotate(const Arg *arg);
static void run(void);
@@ -129,6 +132,8 @@ static void sigchld(int unused);
static void spawn(const Arg *arg);
static int textnw(const char *text, unsigned int len);
static void toggle(const Arg *arg);
+static void togglebar(const Arg *arg);
+static void toggletop(const Arg *arg);
static void unmanage(int c);
static void unmapnotify(const XEvent *e);
static void updatenumlockmask(void);
@@ -182,7 +187,7 @@ buttonpress(const XEvent *e)
int i, fc;
Arg arg;
- if (ev->y < 0 || ev->y > bh)
+ if (showbar == False || ev->y < 0 || ev->y > bh)
return;
if (((fc = getfirsttab()) > 0 && ev->x < TEXTW(before)) || ev->x < 0)
@@ -253,11 +258,12 @@ configurenotify(const XEvent *e)
if (ev->window == win && (ev->width != ww || ev->height != wh)) {
ww = ev->width;
wh = ev->height;
+
XFreePixmap(dpy, dc.drawable);
dc.drawable = XCreatePixmap(dpy, root, ww, wh,
- DefaultDepth(dpy, screen));
+ DefaultDepth(dpy, screen));
if (sel > -1)
- resize(sel, ww, wh - bh);
+ resize(sel, ww, wh - (showbar? bh : 0));
XSync(dpy, False);
}
}
@@ -271,9 +277,9 @@ configurerequest(const XEvent *e)
if ((c = getclient(ev->window)) > -1) {
wc.x = 0;
- wc.y = bh;
+ wc.y = showbar? (bottombar? bh : 0) : 0;
wc.width = ww;
- wc.height = wh - bh;
+ wc.height = wh - (showbar? bh : 0);
wc.border_width = 0;
wc.sibling = ev->above;
wc.stack_mode = ev->detail;
@@ -318,12 +324,16 @@ drawbar(void)
int c, cc, fc, width;
char *name = NULL;
+ if (showbar == False)
+ return;
+
if (nclients == 0) {
dc.x = 0;
dc.w = ww;
XFetchName(dpy, win, &name);
- drawtext(name ? name : "", dc.norm);
- XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, bh, 0, 0);
+ drawtext(name? name : "", dc.norm);
+ XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, bh, 0,
+ bottombar? wh - bh - 1 : 0);
XSync(dpy, False);
return;
@@ -362,7 +372,7 @@ drawbar(void)
dc.x += dc.w;
clients[c]->tabx = dc.x;
}
- XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, bh, 0, 0);
+ XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, bh, 0, bottombar? wh - bh - 1 : 0);
XSync(dpy, False);
}
@@ -424,6 +434,51 @@ erealloc(void *o, size_t size)
}
void
+embedwindow(Window w)
+{
+ int i, j;
+ unsigned int modifiers[] = { 0, LockMask, numlockmask,
+ numlockmask | LockMask };
+ KeyCode code;
+ XEvent e;
+
+ updatenumlockmask();
+
+ XWithdrawWindow(dpy, w, 0);
+ XReparentWindow(dpy, w, win, 0, (showbar? (bottombar? 0 : bh) : 0));
+ XSelectInput(dpy, w, PropertyChangeMask |
+ StructureNotifyMask | EnterWindowMask);
+ XSync(dpy, False);
+
+ for (i = 0; i < LENGTH(keys); i++) {
+ if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) {
+ for (j = 0; j < LENGTH(modifiers); j++) {
+ XGrabKey(dpy, code, keys[i].mod |
+ modifiers[j], w, True,
+ GrabModeAsync, GrabModeAsync);
+ }
+ }
+ }
+
+ XLowerWindow(dpy, w);
+ XMapWindow(dpy, w);
+
+ e.xclient.window = w;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = wmatom[XEmbed];
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = CurrentTime;
+ e.xclient.data.l[1] = XEMBED_EMBEDDED_NOTIFY;
+ e.xclient.data.l[2] = 0;
+ e.xclient.data.l[3] = win;
+ e.xclient.data.l[4] = 0;
+ XSendEvent(dpy, root, False, NoEventMask, &e);
+
+ XSync(dpy, False);
+}
+
+
+void
expose(const XEvent *e)
{
const XExposeEvent *ev = &e->xexpose;
@@ -454,7 +509,7 @@ focus(int c)
if (c < 0 || c >= nclients)
return;
- resize(c, ww, wh - bh);
+ resize(c, ww, wh - (showbar? bh : 0));
XRaiseWindow(dpy, clients[c]->win);
XSetInputFocus(dpy, clients[c]->win, RevertToParent, CurrentTime);
sendxembed(c, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0);
@@ -686,81 +741,44 @@ killclient(const Arg *arg)
void
manage(Window w)
{
- updatenumlockmask();
- {
- int i, j, nextpos;
- unsigned int modifiers[] = { 0, LockMask, numlockmask,
- numlockmask | LockMask };
- KeyCode code;
- Client *c;
- XEvent e;
-
- XWithdrawWindow(dpy, w, 0);
- XReparentWindow(dpy, w, win, 0, bh);
- XSelectInput(dpy, w, PropertyChangeMask |
- StructureNotifyMask | EnterWindowMask);
- XSync(dpy, False);
+ Client *c;
+ int nextpos;
- for (i = 0; i < LENGTH(keys); i++) {
- if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) {
- for (j = 0; j < LENGTH(modifiers); j++) {
- XGrabKey(dpy, code, keys[i].mod |
- modifiers[j], w, True,
- GrabModeAsync, GrabModeAsync);
- }
- }
- }
-
- c = ecalloc(1, sizeof *c);
- c->win = w;
-
- nclients++;
- clients = erealloc(clients, sizeof(Client *) * nclients);
+ embedwindow(w);
- if(npisrelative) {
- nextpos = sel + newposition;
- } else {
- if (newposition < 0)
- nextpos = nclients - newposition;
- else
- nextpos = newposition;
- }
- if (nextpos >= nclients)
- nextpos = nclients - 1;
- if (nextpos < 0)
- nextpos = 0;
-
- if (nclients > 1 && nextpos < nclients - 1)
- memmove(&clients[nextpos + 1], &clients[nextpos],
- sizeof(Client *) * (nclients - nextpos - 1));
-
- clients[nextpos] = c;
- updatetitle(nextpos);
-
- XLowerWindow(dpy, w);
- XMapWindow(dpy, w);
-
- e.xclient.window = w;
- e.xclient.type = ClientMessage;
- e.xclient.message_type = wmatom[XEmbed];
- e.xclient.format = 32;
- e.xclient.data.l[0] = CurrentTime;
- e.xclient.data.l[1] = XEMBED_EMBEDDED_NOTIFY;
- e.xclient.data.l[2] = 0;
- e.xclient.data.l[3] = win;
- e.xclient.data.l[4] = 0;
- XSendEvent(dpy, root, False, NoEventMask, &e);
+ c = ecalloc(1, sizeof *c);
+ c->win = w;
- XSync(dpy, False);
+ nclients++;
+ clients = erealloc(clients, sizeof(Client *) * nclients);
- /* Adjust sel before focus does set it to lastsel. */
- if (sel >= nextpos)
- sel++;
- focus(nextfocus ? nextpos :
- sel < 0 ? 0 :
- sel);
- nextfocus = foreground;
+ if(npisrelative) {
+ nextpos = sel + newposition;
+ } else {
+ if (newposition < 0)
+ nextpos = nclients - newposition;
+ else
+ nextpos = newposition;
}
+ if (nextpos >= nclients)
+ nextpos = nclients - 1;
+ if (nextpos < 0)
+ nextpos = 0;
+
+ if (nclients > 1 && nextpos < nclients - 1)
+ memmove(&clients[nextpos + 1], &clients[nextpos],
+ sizeof(Client *) * (nclients - nextpos - 1));
+
+ clients[nextpos] = c;
+ updatetitle(nextpos);
+
+ /* Adjust sel before focus does set it to lastsel. */
+ if (sel >= nextpos)
+ sel++;
+ focus(nextfocus ? nextpos :
+ sel < 0 ? 0 :
+ sel);
+ nextfocus = foreground;
}
void
@@ -860,20 +878,30 @@ propertynotify(const XEvent *e)
}
void
+reembedclients(void)
+{
+ for (int c = 0; c < nclients; c++) {
+ embedwindow(clients[c]->win);
+ clients[c]->remapped = 2;
+ }
+ focus(sel);
+}
+
+void
resize(int c, int w, int h)
{
XConfigureEvent ce;
XWindowChanges wc;
ce.x = 0;
- ce.y = bh;
+ ce.y = (showbar? bh : 0);
ce.width = wc.width = w;
ce.height = wc.height = h;
ce.type = ConfigureNotify;
ce.display = dpy;
ce.event = clients[c]->win;
ce.window = clients[c]->win;
- ce.above = None;
+ ce.above = -1;
ce.override_redirect = False;
ce.border_width = 0;
@@ -1104,7 +1132,21 @@ textnw(const char *text, unsigned int len)
void
toggle(const Arg *arg)
{
- *(Bool*) arg->v = !*(Bool*) arg->v;
+ *(Bool*) arg->v = !*(Bool*) arg->v;
+}
+
+void
+togglebar(const Arg *arg)
+{
+ showbar = !showbar;
+ reembedclients();
+}
+
+void
+toggletop(const Arg *arg)
+{
+ bottombar = !bottombar;
+ reembedclients();
}
void
@@ -1172,8 +1214,11 @@ unmapnotify(const XEvent *e)
const XUnmapEvent *ev = &e->xunmap;
int c;
- if ((c = getclient(ev->window)) > -1)
- unmanage(c);
+ if ((c = getclient(ev->window)) > -1) {
+ if (clients[c]->remapped == 0)
+ unmanage(c);
+ clients[c]->remapped--;
+ }
}
void
@@ -1252,7 +1297,7 @@ xsettitle(Window w, const char *str)
void
usage(void)
{
- die("usage: %s [-dfksv] [-g geometry] [-n name] [-p [s+/-]pos]\n"
+ die("usage: %s [-BbdfkMmsv] [-g geometry] [-n name] [-p [s+/-]pos]\n"
" [-r narg] [-o color] [-O color] [-t color] [-T color]\n"
" [-u color] [-U color] command...\n", argv0);
}
@@ -1265,6 +1310,12 @@ main(int argc, char *argv[])
char *pstr;
ARGBEGIN {
+ case 'B':
+ showbar = True;
+ break;
+ case 'b':
+ showbar = False;
+ break;
case 'c':
closelastclient = True;
fillagain = False;
@@ -1281,6 +1332,12 @@ main(int argc, char *argv[])
case 'k':
killclientsfirst = True;
break;
+ case 'M':
+ bottombar = True;
+ break;
+ case 'm':
+ bottombar = False;
+ break;
case 'n':
wmname = EARGF(usage());
break;