aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--Makefile7
-rw-r--r--config.def.h2
-rw-r--r--config.h69
-rw-r--r--config.mk38
-rw-r--r--tabbed.129
-rw-r--r--tabbed.c77
-rw-r--r--tabbed.desktop8
8 files changed, 188 insertions, 46 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b1b45c8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.o
+tabbed
+patches
+xembed
diff --git a/Makefile b/Makefile
index f8f5ba4..66ca89e 100644
--- a/Makefile
+++ b/Makefile
@@ -47,8 +47,8 @@ dist: clean
install: all
# installing executable files.
- mkdir -p "${DESTDIR}${PREFIX}/bin"
- cp -f ${BIN} "${DESTDIR}${PREFIX}/bin"
+ @mkdir -p "${DESTDIR}${PREFIX}/bin"
+ @cp -f ${BIN} "${DESTDIR}${PREFIX}/bin"
for f in ${BIN}; do chmod 755 "${DESTDIR}${PREFIX}/bin/$$f"; done
# installing doc files.
mkdir -p "${DESTDIR}${DOCPREFIX}"
@@ -56,6 +56,8 @@ install: all
# installing manual pages for general commands: section 1.
mkdir -p "${DESTDIR}${MANPREFIX}/man1"
for m in ${MAN1}; do sed "s/VERSION/${VERSION}/g" < $$m > "${DESTDIR}${MANPREFIX}/man1/$$m"; done
+ mkdir -p $(DESTDIR)$(PREFIX)/share/applications
+ cp -f tabbed.desktop ${DESTDIR}${PREFIX}/share/applications
uninstall:
# removing executable files.
@@ -65,5 +67,6 @@ uninstall:
# removing manual pages.
for m in ${MAN1}; do rm -f "${DESTDIR}${MANPREFIX}/man1/$$m"; done
-rmdir "${DESTDIR}${DOCPREFIX}"
+ rm -f ${DESTDIR}${PREFIX}/share/applications/tabbed.desktop
.PHONY: all clean dist install uninstall
diff --git a/config.def.h b/config.def.h
index 51bb13d..d901af5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -14,6 +14,7 @@ static const char titletrim[] = "...";
static const int tabwidth = 200;
static const Bool foreground = True;
static Bool urgentswitch = False;
+static Bool hideframe = True;
/*
* Where to place a new tab when it is opened. When npisrelative is True,
@@ -62,5 +63,6 @@ static const Key keys[] = {
{ MODKEY, XK_u, focusurgent, { 0 } },
{ MODKEY|ShiftMask, XK_u, toggle, { .v = (void*) &urgentswitch } },
+ { 0, XK_F10, toggleframe, { 0 } },
{ 0, XK_F11, fullscreen, { 0 } },
};
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..7f4d137
--- /dev/null
+++ b/config.h
@@ -0,0 +1,69 @@
+/* See LICENSE file for copyright and license details. */
+
+/* appearance */
+static const char font[] = "Liga Agave:size=12";
+static const char* normbgcolor = "#EBDBB2";
+static const char* normfgcolor = "#ABABAB";
+static const char* selbgcolor = "#EBDBB2";
+static const char* selfgcolor = "#849900";
+static const char* urgbgcolor = "#EBDBB2";
+static const char* urgfgcolor = "#cc0000";
+static const char before[] = "<";
+static const char after[] = ">";
+static const char titletrim[] = "...";
+static const int tabwidth = 200;
+static const Bool foreground = True;
+static Bool urgentswitch = False;
+static Bool hideframe = True;
+
+/*
+ * Where to place a new tab when it is opened. When npisrelative is True,
+ * then the current position is changed + newposition. If npisrelative
+ * is False, then newposition is an absolute position.
+ */
+static int newposition = 1;
+static Bool npisrelative = True;
+
+#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 -w $1`\" &&" \
+ "xprop -id $1 -f $0 8s -set $0 \"$prop\"", \
+ p, winid, NULL \
+ } \
+}
+
+#define CTRLMODKEY ControlMask
+#define ALTMODKEY Mod1Mask
+static Key keys[] = {
+ /* modifier key function argument */
+ { CTRLMODKEY|ShiftMask, XK_t, focusonce, { 0 } },
+ { CTRLMODKEY|ShiftMask, XK_t, spawn, { 0 } },
+
+ // { CTRLMODKEY|ShiftMask, XK_l, rotate, { .i = +1 } },
+ // { CTRLMODKEY|ShiftMask, XK_h, rotate, { .i = -1 } },
+ { CTRLMODKEY|ShiftMask, XK_j, movetab, { .i = -1 } },
+ { CTRLMODKEY|ShiftMask, XK_k, movetab, { .i = +1 } },
+ // { CTRLMODKEY, XK_Tab, rotate, { .i = 0 } },
+
+ // { CTRLMODKEY, XK_grave, spawn, SETPROP("_TABBED_SELECT_TAB") },
+ { ALTMODKEY|ShiftMask, XK_1, move, { .i = 0 } },
+ { ALTMODKEY|ShiftMask, XK_2, move, { .i = 1 } },
+ { ALTMODKEY|ShiftMask, XK_3, move, { .i = 2 } },
+ { ALTMODKEY|ShiftMask, XK_4, move, { .i = 3 } },
+ { ALTMODKEY|ShiftMask, XK_5, move, { .i = 4 } },
+ { ALTMODKEY|ShiftMask, XK_6, move, { .i = 5 } },
+ { ALTMODKEY|ShiftMask, XK_7, move, { .i = 6 } },
+ { ALTMODKEY|ShiftMask, XK_8, move, { .i = 7 } },
+ { ALTMODKEY|ShiftMask, XK_9, move, { .i = 8 } },
+ { ALTMODKEY|ShiftMask, XK_0, move, { .i = 9 } },
+
+ // { CTRLMODKEY, XK_q, killclient, { 0 } },
+
+ // { CTRLMODKEY, XK_u, focusurgent, { 0 } },
+ // { CTRLMODKEY|ShiftMask, XK_u, toggle, { .v = (void*) &urgentswitch } },
+
+ { 0, XK_F10, toggleframe, { 0 } },
+ { 0, XK_F11, fullscreen, { 0 } },
+};
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..a9e97b0
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,38 @@
+# tabbed version
+VERSION = 0.6
+
+# Customize below to fit your system
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/share/man
+
+# Patched Xft with support for coloured emojis
+# https://github.com/uditkarode/libxft-bgra
+XftINC = /usr/local/include
+XftLIB = /usr/local/lib
+X11INC = /usr/include
+X11LIB = /usr/lib
+
+# freetype
+FREETYPELIBS = -lfontconfig -lXft
+FREETYPEINC = /usr/include/freetype2
+# OpenBSD (uncomment)
+#FREETYPEINC = ${X11INC}/freetype2
+
+# includes and libs
+INCS = -I. -I$(XftINC) -I$(X11INC) -I${FREETYPEINC}
+LIBS = -lc -L$(XftLIB) -L${X11LIB} -lX11 ${FREETYPELIBS}
+
+# flags
+CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE
+CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
+LDFLAGS = -Wl,-rpath=$(XftLIB) -s ${LIBS}
+
+# Solaris
+#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
+#LDFLAGS = ${LIBS}
+
+# compiler and linker
+# CC = tcc
+CC = gcc
diff --git a/tabbed.1 b/tabbed.1
index 07bdbd7..f586c01 100644
--- a/tabbed.1
+++ b/tabbed.1
@@ -6,6 +6,7 @@ tabbed \- generic tabbed interface
.RB [ \-c ]
.RB [ \-d ]
.RB [ \-k ]
+.RB [ \-m ]
.RB [ \-s ]
.RB [ \-v ]
.RB [ \-g
@@ -61,6 +62,9 @@ for further details.
close foreground tabbed client (instead of tabbed and all clients) when
WM_DELETE_WINDOW is sent.
.TP
+.BI \-m
+Maximize the window.
+.TP
.BI \-n " name"
will set the WM_CLASS attribute to
.I name.
@@ -110,40 +114,25 @@ defines the urgent foreground color.
prints version information to stderr, then exits.
.SH USAGE
.TP
-.B Ctrl\-Shift\-Return
+.B Ctrl\-Shift\-T
open new tab
.TP
-.B Ctrl\-Shift\-h
-previous tab
-.TP
-.B Ctrl\-Shift\-l
-next tab
-.TP
.B Ctrl\-Shift\-j
move selected tab one to the left
.TP
.B Ctrl\-Shift\-k
move selected tab one to the right
.TP
-.B Ctrl\-Shift\-u
-toggle autofocus of urgent tabs
-.TP
-.B Ctrl\-Tab
-toggle between the selected and last selected tab
-.TP
.B Ctrl\-`
open dmenu to either create a new tab appending the entered string or select
an already existing tab.
.TP
-.B Ctrl\-q
-close tab
-.TP
-.B Ctrl\-u
-focus next urgent tab
-.TP
-.B Ctrl\-[0..9]
+.B Alt\-Shift\-[0..9]
jumps to nth tab
.TP
+.B F10
+Toggle window frame.
+.TP
.B F11
Toggle fullscreen mode.
.SH EXAMPLES
diff --git a/tabbed.c b/tabbed.c
index eafe28a..a63446c 100644
--- a/tabbed.c
+++ b/tabbed.c
@@ -49,7 +49,7 @@
enum { ColFG, ColBG, ColLast }; /* color */
enum { WMProtocols, WMDelete, WMName, WMState, WMFullscreen,
- XEmbed, WMSelectTab, WMLast }; /* default atoms */
+ XEmbed, WMSelectTab, WMMotifHints, WMLast }; /* default atoms */
typedef union {
int i;
@@ -103,7 +103,7 @@ static void expose(const XEvent *e);
static void focus(int c);
static void focusin(const XEvent *e);
static void focusonce(const Arg *arg);
-static void focusurgent(const Arg *arg);
+/* static void focusurgent(const Arg *arg); */
static void fullscreen(const Arg *arg);
static char *getatom(int a);
static int getclient(Window w);
@@ -128,7 +128,8 @@ static void setup(void);
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 toggle(const Arg *arg); */
+static void toggleframe(const Arg *arg);
static void unmanage(int c);
static void unmapnotify(const XEvent *e);
static void updatenumlockmask(void);
@@ -156,7 +157,7 @@ static int bh, obh, wx, wy, ww, wh;
static unsigned int numlockmask;
static Bool running = True, nextfocus, doinitspawn = True,
fillagain = False, closelastclient = False,
- killclientsfirst = False;
+ killclientsfirst = False, maximize = False;
static Display *dpy;
static DC dc;
static Atom wmatom[WMLast];
@@ -326,6 +327,7 @@ drawbar(void)
XftColor *col;
int c, cc, fc, width;
char *name = NULL;
+ char tabtitle[256];
if (nclients == 0) {
dc.x = 0;
@@ -367,10 +369,13 @@ drawbar(void)
} else {
col = clients[c]->urgent ? dc.urg : dc.norm;
}
- drawtext(clients[c]->name, col);
+ snprintf(tabtitle, sizeof(tabtitle), "%d: %s",
+ c + 1, clients[c]->name);
+ drawtext(tabtitle, col);
dc.x += dc.w;
clients[c]->tabx = dc.x;
}
+
XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, ww, bh, 0, 0);
XSync(dpy, False);
}
@@ -506,21 +511,22 @@ focusonce(const Arg *arg)
nextfocus = True;
}
-void
-focusurgent(const Arg *arg)
-{
- int c;
-
- if (sel < 0)
- return;
-
- for (c = (sel + 1) % nclients; c != sel; c = (c + 1) % nclients) {
- if (clients[c]->urgent) {
- focus(c);
- return;
- }
- }
-}
+/* void
+ * focusurgent(const Arg *arg)
+ * {
+ * int c;
+ *
+ * if (sel < 0)
+ * return;
+ *
+ * for (c = (sel + 1) % nclients; c != sel; c = (c + 1) % nclients) {
+ * if (clients[c]->urgent) {
+ * focus(c);
+ * return;
+ * }
+ * }
+ * }
+ */
void
fullscreen(const Arg *arg)
@@ -995,6 +1001,7 @@ setup(void)
wmatom[WMSelectTab] = XInternAtom(dpy, "_TABBED_SELECT_TAB", False);
wmatom[WMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
wmatom[XEmbed] = XInternAtom(dpy, "_XEMBED", False);
+ wmatom[WMMotifHints] = XInternAtom(dpy, "_MOTIF_WM_HINTS", False);
/* init appearance */
wx = 0;
@@ -1003,6 +1010,11 @@ setup(void)
wh = 600;
isfixed = 0;
+ if (maximize) {
+ ww = DisplayWidth(dpy, screen);
+ wh = DisplayHeight(dpy, screen);
+ }
+
if (geometry) {
tx = ty = tw = th = 0;
bitm = XParseGeometry(geometry, &tx, &ty, (unsigned *)&tw,
@@ -1060,7 +1072,7 @@ setup(void)
size_hint->width = ww;
size_hint->min_height = bh + 1;
} else {
- size_hint->flags = PMaxSize | PMinSize;
+ size_hint->flags = PPosition | PMaxSize | PMinSize;
size_hint->min_width = size_hint->max_width = ww;
size_hint->min_height = size_hint->max_height = wh;
}
@@ -1071,6 +1083,10 @@ setup(void)
XSetWMProtocols(dpy, win, &wmatom[WMDelete], 1);
+ long hints[5] = {hideframe ? 2 : 0, 0, 0, 0, 0};
+ XChangeProperty(dpy, win, wmatom[WMMotifHints], XA_ATOM,
+ 32, PropModeReplace, (unsigned char *)&hints, 5);
+
snprintf(winid, sizeof(winid), "%lu", win);
setenv("XEMBED", winid, 1);
@@ -1117,10 +1133,20 @@ textnw(const char *text, unsigned int len)
return ext.xOff;
}
+/* void
+ * toggle(const Arg *arg)
+ * {
+ * *(Bool*) arg->v = !*(Bool*) arg->v;
+ * }
+ */
+
void
-toggle(const Arg *arg)
+toggleframe(const Arg *arg)
{
- *(Bool*) arg->v = !*(Bool*) arg->v;
+ hideframe = !hideframe;
+ long hints[5] = {hideframe ? 2 : 0, 0, 0, 0, 0};
+ XChangeProperty(dpy, win, wmatom[WMMotifHints], XA_ATOM,
+ 32, PropModeReplace, (unsigned char *)&hints, 5);
}
void
@@ -1268,7 +1294,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 [-dfkmsv] [-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);
}
@@ -1297,6 +1323,9 @@ main(int argc, char *argv[])
case 'k':
killclientsfirst = True;
break;
+ case 'm':
+ maximize = True;
+ break;
case 'n':
wmname = EARGF(usage());
break;
diff --git a/tabbed.desktop b/tabbed.desktop
new file mode 100644
index 0000000..1038459
--- /dev/null
+++ b/tabbed.desktop
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=st
+Comment=Run st simple terminal inside a tabbed session
+Exec=tabbed -c -m -r 2 st -w '' -e /bin/bash --login
+Icon=utilities-terminal
+Terminal=false
+Type=Application
+Categories=System;TerminalEmulator;