diff options
| -rw-r--r-- | .gitignore | 4 | ||||
| -rw-r--r-- | Makefile | 7 | ||||
| -rw-r--r-- | config.def.h | 2 | ||||
| -rw-r--r-- | config.h | 69 | ||||
| -rw-r--r-- | config.mk | 38 | ||||
| -rw-r--r-- | tabbed.1 | 29 | ||||
| -rw-r--r-- | tabbed.c | 77 | ||||
| -rw-r--r-- | tabbed.desktop | 8 |
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 @@ -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 @@ -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 @@ -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; |
