aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Langer <nikitalanger@icloud.com>2026-04-13 18:25:32 +0200
committerNikita Langer <nikitalanger@icloud.com>2026-04-13 18:25:32 +0200
commitc9f28bb73890de5faa3ebcae7ca9df0fa62fc7d2 (patch)
tree406fb23438a2678f20492fb0a80ce09ead545747
parente65146d2918e0072fc09b3dfb06785e170787164 (diff)
downloadtabbed-master.tar.gz
tabbed-master.tar.bz2
tabbed-master.tar.xz
tabbed-master.zip
-rw-r--r--Makefile7
-rw-r--r--config.def.h13
-rw-r--r--patches/tabbed-alpha-0.9.diff124
-rw-r--r--patches/tabbed-drag-20230128-41e2b8f.diff83
-rw-r--r--tabbed.c102
5 files changed, 312 insertions, 17 deletions
diff --git a/Makefile b/Makefile
index d7a2c35..9038198 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ DOCPREFIX = ${PREFIX}/share/doc/${NAME}
# use system flags.
TABBED_CFLAGS = -I/usr/X11R6/include -I/usr/include/freetype2 ${CFLAGS}
-TABBED_LDFLAGS = -L/usr/X11R6/lib -lX11 -lfontconfig -lXft ${LDFLAGS}
+TABBED_LDFLAGS = -L/usr/X11R6/lib -lX11 -lfontconfig -lXft -lXrender ${LDFLAGS}
TABBED_CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700L
# OpenBSD (uncomment)
@@ -37,7 +37,10 @@ config.h:
${CC} -o $@ $< ${TABBED_LDFLAGS}
clean:
- rm -f ${BIN} ${OBJ} "${NAME}-${VERSION}.tar.gz"
+ rm -f ${BIN} ${OBJ} "${NAME}-${VERSION}.tar.gz" config.h
+
+patch:
+ rm -f *.rej *.orig
dist: clean
mkdir -p "${NAME}-${VERSION}"
diff --git a/config.def.h b/config.def.h
index 51bb13d..4707e5b 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,7 +1,7 @@
/* See LICENSE file for copyright and license details. */
/* appearance */
-static const char font[] = "monospace:size=9";
+static const char font[] = "JetBrains Mono Nerd Font Propo:size=10";
static const char* normbgcolor = "#222222";
static const char* normfgcolor = "#cccccc";
static const char* selbgcolor = "#555555";
@@ -27,17 +27,19 @@ static Bool npisrelative = False;
.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`\" &&" \
+ "xargs -0 printf %b | dmenu -vi -l 10 -w $1`\" &&" \
"xprop -id $1 -f $0 8s -set $0 \"$prop\"", \
p, winid, NULL \
} \
}
-#define MODKEY ControlMask
+// #define MODKEY ControlMask
+#define MODKEY Mod1Mask
static const Key keys[] = {
/* modifier key function argument */
{ MODKEY|ShiftMask, XK_Return, focusonce, { 0 } },
- { MODKEY|ShiftMask, XK_Return, spawn, { 0 } },
+ // { MODKEY|ShiftMask, XK_Return, spawn, { 0 } },
+ { MODKEY, XK_Return, spawn, { 0 } },
{ MODKEY|ShiftMask, XK_l, rotate, { .i = +1 } },
{ MODKEY|ShiftMask, XK_h, rotate, { .i = -1 } },
@@ -45,7 +47,8 @@ static const Key keys[] = {
{ MODKEY|ShiftMask, XK_k, movetab, { .i = +1 } },
{ MODKEY, XK_Tab, rotate, { .i = 0 } },
- { MODKEY, XK_grave, spawn, SETPROP("_TABBED_SELECT_TAB") },
+ // { MODKEY, XK_grave, spawn, SETPROP("_TABBED_SELECT_TAB") },
+ { MODKEY, XK_g, spawn, SETPROP("_TABBED_SELECT_TAB") },
{ MODKEY, XK_1, move, { .i = 0 } },
{ MODKEY, XK_2, move, { .i = 1 } },
{ MODKEY, XK_3, move, { .i = 2 } },
diff --git a/patches/tabbed-alpha-0.9.diff b/patches/tabbed-alpha-0.9.diff
new file mode 100644
index 0000000..13e703b
--- /dev/null
+++ b/patches/tabbed-alpha-0.9.diff
@@ -0,0 +1,124 @@
+diff --git a/Makefile b/Makefile
+index d7a2c35..16ceff0 100644
+--- a/Makefile
++++ b/Makefile
+@@ -10,7 +10,7 @@ DOCPREFIX = ${PREFIX}/share/doc/${NAME}
+
+ # use system flags.
+ TABBED_CFLAGS = -I/usr/X11R6/include -I/usr/include/freetype2 ${CFLAGS}
+-TABBED_LDFLAGS = -L/usr/X11R6/lib -lX11 -lfontconfig -lXft ${LDFLAGS}
++TABBED_LDFLAGS = -L/usr/X11R6/lib -lX11 -lfontconfig -lXft -lXrender ${LDFLAGS}
+ TABBED_CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=700L
+
+ # OpenBSD (uncomment)
+diff --git a/tabbed.c b/tabbed.c
+index aa45716..d1911a3 100644
+--- a/tabbed.c
++++ b/tabbed.c
+@@ -170,6 +170,9 @@ static char **cmd;
+ static char *wmname = "tabbed";
+ static const char *geometry;
+
++static Colormap cmap;
++static Visual *visual = NULL;
++
+ char *argv0;
+
+ /* configuration, allows nested code to access above variables */
+@@ -254,8 +257,8 @@ configurenotify(const XEvent *e)
+ ww = ev->width;
+ wh = ev->height;
+ XFreePixmap(dpy, dc.drawable);
+- dc.drawable = XCreatePixmap(dpy, root, ww, wh,
+- DefaultDepth(dpy, screen));
++ dc.drawable = XCreatePixmap(dpy, win, ww, wh,
++ 32);
+
+ if (!obh && (wh <= bh)) {
+ obh = bh;
+@@ -407,7 +410,7 @@ drawtext(const char *text, XftColor col[ColLast])
+ ;
+ }
+
+- d = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen));
++ d = XftDrawCreate(dpy, dc.drawable, visual, cmap);
+ XftDrawStringUtf8(d, &col[ColFG], dc.font.xfont, x, y, (XftChar8 *) buf, len);
+ XftDrawDestroy(d);
+ }
+@@ -587,7 +590,7 @@ getcolor(const char *colstr)
+ {
+ XftColor color;
+
+- if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), colstr, &color))
++ if (!XftColorAllocName(dpy, visual, cmap, colstr, &color))
+ die("%s: cannot allocate color '%s'\n", argv0, colstr);
+
+ return color;
+@@ -1049,18 +1052,60 @@ setup(void)
+ wy = dh + wy - wh - 1;
+ }
+
++ XVisualInfo *vis;
++ XRenderPictFormat *fmt;
++ int nvi;
++ int i;
++
++ XVisualInfo tpl = {
++ .screen = screen,
++ .depth = 32,
++ .class = TrueColor
++ };
++
++ vis = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &tpl, &nvi);
++ for(i = 0; i < nvi; i ++) {
++ fmt = XRenderFindVisualFormat(dpy, vis[i].visual);
++ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
++ visual = vis[i].visual;
++ break;
++ }
++ }
++
++ XFree(vis);
++
++ if (! visual) {
++ fprintf(stderr, "Couldn't find ARGB visual.\n");
++ exit(1);
++ }
++
++ cmap = XCreateColormap( dpy, root, visual, None);
+ dc.norm[ColBG] = getcolor(normbgcolor);
+ dc.norm[ColFG] = getcolor(normfgcolor);
+ dc.sel[ColBG] = getcolor(selbgcolor);
+ dc.sel[ColFG] = getcolor(selfgcolor);
+ dc.urg[ColBG] = getcolor(urgbgcolor);
+ dc.urg[ColFG] = getcolor(urgfgcolor);
+- dc.drawable = XCreatePixmap(dpy, root, ww, wh,
+- DefaultDepth(dpy, screen));
+- dc.gc = XCreateGC(dpy, root, 0, 0);
+
+- win = XCreateSimpleWindow(dpy, root, wx, wy, ww, wh, 0,
+- dc.norm[ColFG].pixel, dc.norm[ColBG].pixel);
++ XSetWindowAttributes attrs;
++ attrs.background_pixel = dc.norm[ColBG].pixel;
++ attrs.border_pixel = dc.norm[ColFG].pixel;
++ attrs.bit_gravity = NorthWestGravity;
++ attrs.event_mask = FocusChangeMask | KeyPressMask
++ | ExposureMask | VisibilityChangeMask | StructureNotifyMask
++ | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
++ attrs.background_pixmap = None ;
++ attrs.colormap = cmap;
++
++ win = XCreateWindow(dpy, root, wx, wy,
++ ww, wh, 0, 32, InputOutput,
++ visual, CWBackPixmap | CWBorderPixel | CWBitGravity
++ | CWEventMask | CWColormap, &attrs);
++
++ dc.drawable = XCreatePixmap(dpy, win, ww, wh,
++ 32);
++ dc.gc = XCreateGC(dpy, dc.drawable, 0, 0);
++
+ XMapRaised(dpy, win);
+ XSelectInput(dpy, win, SubstructureNotifyMask | FocusChangeMask |
+ ButtonPressMask | ExposureMask | KeyPressMask |
+--
+2.51.0
diff --git a/patches/tabbed-drag-20230128-41e2b8f.diff b/patches/tabbed-drag-20230128-41e2b8f.diff
new file mode 100644
index 0000000..30af15c
--- /dev/null
+++ b/patches/tabbed-drag-20230128-41e2b8f.diff
@@ -0,0 +1,83 @@
+From caf61ed5c47b32938bea4a0577f4f6953ddd1578 Mon Sep 17 00:00:00 2001
+From: Casey Fitzpatrick <kcghost@gmail.com>
+Date: Fri, 27 Jan 2023 19:46:05 -0500
+Subject: [PATCH] Support draggable tabs
+
+---
+ tabbed.c | 39 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 38 insertions(+), 1 deletion(-)
+
+diff --git a/tabbed.c b/tabbed.c
+index eafe28a..2e3b61a 100644
+--- a/tabbed.c
++++ b/tabbed.c
+@@ -88,6 +88,7 @@ typedef struct {
+
+ /* function declarations */
+ static void buttonpress(const XEvent *e);
++static void motionnotify(const XEvent *e);
+ static void cleanup(void);
+ static void clientmessage(const XEvent *e);
+ static void configurenotify(const XEvent *e);
+@@ -151,6 +152,7 @@ static void (*handler[LASTEvent]) (const XEvent *) = {
+ [KeyPress] = keypress,
+ [MapRequest] = maprequest,
+ [PropertyNotify] = propertynotify,
++ [MotionNotify] = motionnotify,
+ };
+ static int bh, obh, wx, wy, ww, wh;
+ static unsigned int numlockmask;
+@@ -209,6 +211,41 @@ buttonpress(const XEvent *e)
+ }
+ }
+
++void
++motionnotify(const XEvent *e)
++{
++ const XMotionEvent *ev = &e->xmotion;
++ int i, fc;
++ Arg arg;
++
++ if (ev->y < 0 || ev->y > bh)
++ return;
++
++ if (! (ev->state & Button1Mask)) {
++ return;
++ }
++
++ if (((fc = getfirsttab()) > 0 && ev->x < TEXTW(before)) || ev->x < 0)
++ return;
++
++ if (sel < 0)
++ return;
++
++ for (i = fc; i < nclients; i++) {
++ if (clients[i]->tabx > ev->x) {
++ if (i == sel+1) {
++ arg.i = 1;
++ movetab(&arg);
++ }
++ if (i == sel-1) {
++ arg.i = -1;
++ movetab(&arg);
++ }
++ break;
++ }
++ }
++}
++
+ void
+ cleanup(void)
+ {
+@@ -1046,7 +1083,7 @@ setup(void)
+ XSelectInput(dpy, win, SubstructureNotifyMask | FocusChangeMask |
+ ButtonPressMask | ExposureMask | KeyPressMask |
+ PropertyChangeMask | StructureNotifyMask |
+- SubstructureRedirectMask);
++ SubstructureRedirectMask | ButtonMotionMask);
+ xerrorxlib = XSetErrorHandler(xerror);
+
+ class_hint.res_name = wmname;
+--
+2.25.1
+
diff --git a/tabbed.c b/tabbed.c
index 2fb5aa7..19307b1 100644
--- a/tabbed.c
+++ b/tabbed.c
@@ -89,6 +89,7 @@ typedef struct {
/* function declarations */
static void buttonpress(const XEvent *e);
+static void motionnotify(const XEvent *e);
static void cleanup(void);
static void clientmessage(const XEvent *e);
static void configurenotify(const XEvent *e);
@@ -151,6 +152,7 @@ static void (*handler[LASTEvent]) (const XEvent *) = {
[KeyPress] = keypress,
[MapRequest] = maprequest,
[PropertyNotify] = propertynotify,
+ [MotionNotify] = motionnotify,
};
static int bh, obh, wx, wy, ww, wh;
static unsigned int numlockmask;
@@ -170,6 +172,9 @@ static char **cmd;
static char *wmname = "tabbed";
static const char *geometry;
+static Colormap cmap;
+static Visual *visual = NULL;
+
char *argv0;
/* configuration, allows nested code to access above variables */
@@ -210,6 +215,41 @@ buttonpress(const XEvent *e)
}
void
+motionnotify(const XEvent *e)
+{
+ const XMotionEvent *ev = &e->xmotion;
+ int i, fc;
+ Arg arg;
+
+ if (ev->y < 0 || ev->y > bh)
+ return;
+
+ if (! (ev->state & Button1Mask)) {
+ return;
+ }
+
+ if (((fc = getfirsttab()) > 0 && ev->x < TEXTW(before)) || ev->x < 0)
+ return;
+
+ if (sel < 0)
+ return;
+
+ for (i = fc; i < nclients; i++) {
+ if (clients[i]->tabx > ev->x) {
+ if (i == sel+1) {
+ arg.i = 1;
+ movetab(&arg);
+ }
+ if (i == sel-1) {
+ arg.i = -1;
+ movetab(&arg);
+ }
+ break;
+ }
+ }
+}
+
+void
cleanup(void)
{
int i;
@@ -254,8 +294,8 @@ configurenotify(const XEvent *e)
ww = ev->width;
wh = ev->height;
XFreePixmap(dpy, dc.drawable);
- dc.drawable = XCreatePixmap(dpy, root, ww, wh,
- DefaultDepth(dpy, screen));
+ dc.drawable = XCreatePixmap(dpy, win, ww, wh,
+ 32);
if (!obh && (wh <= bh)) {
obh = bh;
@@ -407,7 +447,7 @@ drawtext(const char *text, XftColor col[ColLast])
;
}
- d = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen));
+ d = XftDrawCreate(dpy, dc.drawable, visual, cmap);
XftDrawStringUtf8(d, &col[ColFG], dc.font.xfont, x, y, (XftChar8 *) buf, len);
XftDrawDestroy(d);
}
@@ -587,7 +627,7 @@ getcolor(const char *colstr)
{
XftColor color;
- if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), colstr, &color))
+ if (!XftColorAllocName(dpy, visual, cmap, colstr, &color))
die("%s: cannot allocate color '%s'\n", argv0, colstr);
return color;
@@ -1049,23 +1089,65 @@ setup(void)
wy = dh + wy - wh - 1;
}
+ XVisualInfo *vis;
+ XRenderPictFormat *fmt;
+ int nvi;
+ int i;
+
+ XVisualInfo tpl = {
+ .screen = screen,
+ .depth = 32,
+ .class = TrueColor
+ };
+
+ vis = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &tpl, &nvi);
+ for(i = 0; i < nvi; i ++) {
+ fmt = XRenderFindVisualFormat(dpy, vis[i].visual);
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
+ visual = vis[i].visual;
+ break;
+ }
+ }
+
+ XFree(vis);
+
+ if (! visual) {
+ fprintf(stderr, "Couldn't find ARGB visual.\n");
+ exit(1);
+ }
+
+ cmap = XCreateColormap( dpy, root, visual, None);
dc.norm[ColBG] = getcolor(normbgcolor);
dc.norm[ColFG] = getcolor(normfgcolor);
dc.sel[ColBG] = getcolor(selbgcolor);
dc.sel[ColFG] = getcolor(selfgcolor);
dc.urg[ColBG] = getcolor(urgbgcolor);
dc.urg[ColFG] = getcolor(urgfgcolor);
- dc.drawable = XCreatePixmap(dpy, root, ww, wh,
- DefaultDepth(dpy, screen));
- dc.gc = XCreateGC(dpy, root, 0, 0);
- win = XCreateSimpleWindow(dpy, root, wx, wy, ww, wh, 0,
- dc.norm[ColFG].pixel, dc.norm[ColBG].pixel);
+ XSetWindowAttributes attrs;
+ attrs.background_pixel = dc.norm[ColBG].pixel;
+ attrs.border_pixel = dc.norm[ColFG].pixel;
+ attrs.bit_gravity = NorthWestGravity;
+ attrs.event_mask = FocusChangeMask | KeyPressMask
+ | ExposureMask | VisibilityChangeMask | StructureNotifyMask
+ | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
+ attrs.background_pixmap = None ;
+ attrs.colormap = cmap;
+
+ win = XCreateWindow(dpy, root, wx, wy,
+ ww, wh, 0, 32, InputOutput,
+ visual, CWBackPixmap | CWBorderPixel | CWBitGravity
+ | CWEventMask | CWColormap, &attrs);
+
+ dc.drawable = XCreatePixmap(dpy, win, ww, wh,
+ 32);
+ dc.gc = XCreateGC(dpy, dc.drawable, 0, 0);
+
XMapRaised(dpy, win);
XSelectInput(dpy, win, SubstructureNotifyMask | FocusChangeMask |
ButtonPressMask | ExposureMask | KeyPressMask |
PropertyChangeMask | StructureNotifyMask |
- SubstructureRedirectMask);
+ SubstructureRedirectMask | ButtonMotionMask);
xerrorxlib = XSetErrorHandler(xerror);
class_hint.res_name = wmname;