commit: 4592bfb4ac1ba80c5b4fe749d561653aad68a3c8
parent: 0833df691cdaa0fcbb6253644447464864e0d908
author: Chris Noxz <chris@noxz.tech>
date: Sun, 13 Oct 2024 11:04:56 +0200
ungrab and drag tabs
2 files changed, 97 insertions(+), 35 deletions(-)
diff --git a/config.def.h b/config.def.h
@@ -2,6 +2,8 @@
/* appearance */
static char* font = "monospace:size=9";
+static char* pidbgcolor = "#222222";
+static char* pidfgcolor = "#cccccc";
static char* normbgcolor = "#222222";
static char* normfgcolor = "#cccccc";
static char* selbgcolor = "#555555";
@@ -11,7 +13,7 @@ static char* urgfgcolor = "#cc0000";
static char* before = "<";
static char* after = ">";
static char* titletrim = "...";
-static int tabwidth = 200;
+static int tabwidth = 100;
static int focusnew = 1;
static int urgentswitch = 0;
@@ -23,21 +25,13 @@ static int urgentswitch = 0;
static int newposition = -1;
static int npisrelative = 0;
-#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 \
- } \
-}
-
/*
* Xresources preferences to load at startup
*/
ResourcePref resources[] = {
{ "font", STRING, &font},
+ { "pidBackground", STRING, &pidbgcolor},
+ { "pidForeground", STRING, &pidfgcolor},
{ "normalBackground", STRING, &normbgcolor},
{ "normalForeground", STRING, &normfgcolor},
{ "selectedBackground", STRING, &selbgcolor},
@@ -66,7 +60,6 @@ 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_1, move, { .i = 0 } },
{ MODKEY, XK_2, move, { .i = 1 } },
{ MODKEY, XK_3, move, { .i = 2 } },
@@ -82,6 +75,7 @@ static const Key keys[] = {
{ MODKEY, XK_u, focusurgent, { 0 } },
{ MODKEY|ShiftMask, XK_u, toggle, { .v = (void*) &urgentswitch } },
+ { MODKEY, XK_b, togglebar, { 0 } },
{ 0, XK_F11, fullscreen, { 0 } },
};
diff --git a/tabbed.c b/tabbed.c
@@ -68,6 +68,8 @@ typedef struct {
typedef struct {
int x, y, w, h;
+ Bool visible;
+ XftColor pid[ColLast];
XftColor norm[ColLast];
XftColor sel[ColLast];
XftColor urg[ColLast];
@@ -135,6 +137,7 @@ static void keypress(const XEvent *e);
static void killclient(const Arg *arg);
static void manage(Window win);
static void maprequest(const XEvent *e);
+static void motionnotify(const XEvent *e);
static void move(const Arg *arg);
static void movetab(const Arg *arg);
static void propertynotify(const XEvent *e);
@@ -148,6 +151,7 @@ static void setup(void);
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 unmanage(int c);
static void unmapnotify(const XEvent *e);
static void updatenumlockmask(void);
@@ -163,15 +167,16 @@ static void (*handler[LASTEvent]) (const XEvent *) = {
[ConfigureNotify] = configurenotify,
[ConfigureRequest] = configurerequest,
[CreateNotify] = createnotify,
- [UnmapNotify] = unmapnotify,
[DestroyNotify] = destroynotify,
[Expose] = expose,
[FocusIn] = focusin,
[KeyPress] = keypress,
[MapRequest] = maprequest,
+ [MotionNotify] = motionnotify,
[PropertyNotify] = propertynotify,
+ [UnmapNotify] = unmapnotify,
};
-static int bh, obh, wx, wy, ww, wh;
+static int bh, obh, vbh, wx, wy, ww, wh;
static unsigned int numlockmask;
static Bool running = True, nextfocus, doinitspawn = True,
fillagain = False, closelastclient = False,
@@ -185,6 +190,7 @@ static int nclients, sel = -1, lastsel = -1;
static int (*xerrorxlib)(Display *, XErrorEvent *);
static int cmd_append_pos;
static char winid[64];
+static char winpid[64];
static char **cmd;
static char *wmname = "tabbed";
static pid_t nextpid;
@@ -228,11 +234,11 @@ pid_t getchildpid(pid_t pid) {
return -1;
f = fopen(path, "r");
- if(f == NULL)
+ if (f == NULL)
return -1;
// guess first child
- if(fscanf(f, "%d ", &pid) != 1)
+ if (fscanf(f, "%d ", &pid) != 1)
return -1;
return pid;
@@ -248,7 +254,7 @@ buttonpress(const XEvent *e)
if (ev->y < 0 || ev->y > bh)
return;
- if (((fc = getfirsttab()) > 0 && ev->x < TEXTW(before)) || ev->x < 0)
+ if (ev->x < TEXTW(winpid) || ((fc = getfirsttab()) > 0 && ev->x < (TEXTW(before))) || ev->x < 0)
return;
for (i = fc; i < nclients; i++) {
@@ -408,6 +414,15 @@ drawbar(void)
char *name = NULL;
char tabtitle[256];
+ if ((dc.visible ? vbh : 0) != bh) {
+ bh = dc.visible ? vbh : 0;
+ for (c = 0; c < nclients; c++)
+ XMoveResizeWindow(dpy, clients[c]->win, 0, bh, ww, wh - bh);
+ }
+
+ if (bh == 0)
+ return;
+
if (nclients == 0) {
dc.x = 0;
dc.w = ww;
@@ -422,7 +437,7 @@ drawbar(void)
width = ww;
cc = ww / tabwidth;
if (nclients > cc)
- cc = (ww - TEXTW(before) - TEXTW(after)) / tabwidth;
+ cc = (ww - TEXTW(winpid) - TEXTW(before) - TEXTW(after)) / tabwidth;
if ((fc = getfirsttab()) + cc < nclients) {
dc.w = TEXTW(after);
@@ -432,6 +447,11 @@ drawbar(void)
}
dc.x = 0;
+ dc.w = TEXTW(winpid);
+ drawtext(winpid, dc.pid);
+ dc.x += dc.w;
+ width -= dc.w;
+
if (fc > 0) {
dc.w = TEXTW(before);
drawtext(before, dc.sel);
@@ -483,11 +503,8 @@ drawtext(const char *text, XftColor col[ColLast])
return;
memcpy(buf, text, len);
- if (len < olen) {
- for (i = len, j = strlen(titletrim); j && i;
- buf[--i] = titletrim[--j])
- ;
- }
+ if (len < olen)
+ for (i = len, j = strlen(titletrim); j && i; buf[--i] = titletrim[--j]);
d = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen));
XftDrawStringUtf8(d, &col[ColFG], dc.font.xfont, x, y, (XftChar8 *) buf, len);
@@ -673,7 +690,7 @@ getfirsttab(void)
cc = ww / tabwidth;
if (nclients > cc)
- cc = (ww - TEXTW(before) - TEXTW(after)) / tabwidth;
+ cc = (ww - TEXTW(winpid) - TEXTW(before) - TEXTW(after)) / tabwidth;
ret = sel - cc / 2 + (cc + 1) % 2;
return ret < 0 ? 0 :
@@ -867,11 +884,33 @@ maprequest(const XEvent *e)
manage(ev->window);
}
+void
+motionnotify(const XEvent *e)
+{
+ int i, fc;
+ const XMotionEvent *ev = &e->xmotion;
+ Arg arg;
+
+ if (sel < 0 || !(ev->state & Button1Mask) || ev->x < 0 ||
+ ((fc = getfirsttab()) > 0 && ev->x < TEXTW(before)))
+ return;
+
+ for (i = fc; i < nclients; i++) {
+ if (clients[i]->tabx > ev->x) {
+ if (i == sel + (arg.i = 1) || i == sel + (arg.i = -1))
+ movetab(&arg);
+ break;
+ }
+ }
+}
+
void
move(const Arg *arg)
{
- if (arg->i >= 0 && arg->i < nclients)
- focus(arg->i);
+ int i;
+
+ if ((i = arg->i < nclients ? arg->i : nclients - 1) >= 0)
+ focus(i);
}
void
@@ -1094,6 +1133,7 @@ setup(void)
XClassHint class_hint;
XSizeHints *size_hint;
struct sigaction sa;
+ pid_t pid = getpid();
/* do not transform children into zombies when they terminate */
sigemptyset(&sa.sa_mask);
@@ -1108,7 +1148,8 @@ setup(void)
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
initfont(font);
- bh = dc.h = dc.font.height + 2;
+ vbh = dc.h = dc.font.height + 4;
+ dc.visible = 1;
/* init atoms */
wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
@@ -1154,6 +1195,8 @@ setup(void)
wy = dh + wy - wh - 1;
}
+ dc.pid[ColBG] = getcolor(pidbgcolor);
+ dc.pid[ColFG] = getcolor(pidfgcolor);
dc.norm[ColBG] = getcolor(normbgcolor);
dc.norm[ColFG] = getcolor(normfgcolor);
dc.sel[ColBG] = getcolor(selbgcolor);
@@ -1170,7 +1213,7 @@ setup(void)
XSelectInput(dpy, win, SubstructureNotifyMask | FocusChangeMask |
ButtonPressMask | ExposureMask | KeyPressMask |
PropertyChangeMask | StructureNotifyMask |
- SubstructureRedirectMask);
+ SubstructureRedirectMask | ButtonMotionMask);
xerrorxlib = XSetErrorHandler(xerror);
class_hint.res_name = wmname;
@@ -1178,13 +1221,14 @@ setup(void)
XSetClassHint(dpy, win, &class_hint);
size_hint = XAllocSizeHints();
- if (!isfixed) {
- size_hint->flags = PSize | PMinSize;
- size_hint->height = wh;
- size_hint->width = ww;
- size_hint->min_height = bh + 1;
- } else {
- size_hint->flags = PMaxSize | PMinSize;
+ size_hint->flags = PSize | PResizeInc | PBaseSize | PMinSize;
+ size_hint->height = wh;
+ size_hint->width = ww;
+ size_hint->min_height = vbh + 1;
+ size_hint->min_width = tabwidth;
+
+ if (isfixed) {
+ size_hint->flags |= PMaxSize;
size_hint->min_width = size_hint->max_width = ww;
size_hint->min_height = size_hint->max_height = wh;
}
@@ -1194,8 +1238,11 @@ setup(void)
XFree(wmh);
XSetWMProtocols(dpy, win, &wmatom[WMDelete], 1);
+ XChangeProperty(dpy, win, XInternAtom(dpy, "_NET_WM_PID", False),
+ XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1);
snprintf(winid, sizeof(winid), "%lu", win);
+ snprintf(winpid, sizeof(winpid), "%X", pid);
setenv("XEMBED", winid, 1);
nextfocus = focusnew;
@@ -1254,9 +1301,21 @@ toggle(const Arg *arg)
*(Bool*) arg->v = !*(Bool*) arg->v;
}
+void
+togglebar(const Arg *arg)
+{
+ dc.visible = !dc.visible;
+ drawbar();
+}
+
void
unmanage(int c)
{
+ int i, j;
+ unsigned int modifiers[] = { 0, LockMask, numlockmask,
+ numlockmask | LockMask };
+ KeyCode code;
+
if (c < 0 || c >= nclients) {
drawbar();
XSync(dpy, False);
@@ -1266,6 +1325,15 @@ unmanage(int c)
if (!nclients)
return;
+ /* ungrab keys */
+ for (i = 0; i < LENGTH(keys); i++) {
+ if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) {
+ for (j = 0; j < LENGTH(modifiers); j++) {
+ XUngrabKey(dpy, code, keys[i].mod | modifiers[j], clients[c]->win);
+ }
+ }
+ }
+
if (c == 0) {
/* First client. */
nclients--;