hlfw.ca

9hkd

Download patch

ref: 61bacd1980b3b12703ee30ffd0752da1520ceeaa
parent: 79c1526d233373f4da4205a46731e51ce39629cd
author: Michael Misch <michaelmisch1985@gmail.com>
date: Tue Jul 18 05:40:21 PDT 2023

Modify riow to meet my own personal needs

--- /dev/null
+++ b/9hkd.c
@@ -1,0 +1,572 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <keyboard.h>
+#include <ctype.h>
+
+typedef struct W W;
+
+enum {
+	Mmod4 = 1<<0,
+	Mctl = 1<<1,
+	Mshift = 1<<2,
+
+	Step = 16,
+	Stepbig = 64,
+
+	Fvisible = 1<<0,
+	Fcurrent = 1<<1,
+	Fsticky = 1<<2,
+	Ffullscreen = 1<<3,
+	ntags = 6,
+};
+
+struct W {
+	int id;
+	Rectangle r;
+	int vd;
+	int tg;
+	int flags;
+	int stickyforced;
+};
+
+static int vd = 1; /* current virtual desktop */
+static int wsys; /* rios /dev/wsys fd */
+static int mod;
+static int usetags;
+static W *ws, *wcur;
+static int wsn;
+static int tgvis[ntags] = {-1};
+static int vd2wcur[10] = {-1};
+static int tg2wcur[ntags] = {-1};
+
+static char *sticky[32] = {
+	"bar",
+	"cat clock",
+	"clock",
+	"faces",
+	"kbmap",
+	"stats",
+	"winwatch",
+	nil,
+};
+
+static int
+wwctl(int id, int mode)
+{
+	char s[64];
+
+	snprint(s, sizeof(s), "/dev/wsys/%d/wctl", id);
+
+	return open(s, mode);
+}
+
+static void
+wsupdate(void)
+{
+	int i, k, n, f, seen, tn, dsn;
+	char s[256], *t[8];
+	W *newws, *w;
+	Dir *ds, *d;
+
+	seek(wsys, 0, 0);
+	if((dsn = dirreadall(wsys, &ds)) < 0)
+		sysfatal("/dev/wsys: %r");
+
+	newws = malloc(sizeof(W)*dsn);
+	wcur = nil;
+	for(i = 0, d = ds, w = newws; i < dsn; i++, d++){
+		if((f = wwctl(atoi(d->name), OREAD)) < 0)
+			continue;
+		n = read(f, s, sizeof(s)-1);
+		close(f);
+		if(n < 12)
+			continue;
+		s[n] = 0;
+		if((tn = tokenize(s, t, nelem(t))) < 6)
+			continue;
+
+		w->id = atoi(d->name);
+		w->r.min.x = atoi(t[0]);
+		w->r.min.y = atoi(t[1]);
+		w->r.max.x = atoi(t[2]);
+		w->r.max.y = atoi(t[3]);
+		w->vd = -1;
+		w->tg = -1;
+		w->flags = 0;
+		w->stickyforced = 0;
+
+		/* move over the current state of the window */
+		for(k = 0, seen = 0; k < wsn; k++){
+			if(ws[k].id == w->id){
+				w->vd = ws[k].vd;
+				w->tg = ws[k].tg;
+				w->flags = ws[k].flags & ~(Fvisible|Fcurrent);
+				w->stickyforced = ws[k].stickyforced;
+				if(w->flags & Ffullscreen)
+					w->r = ws[k].r;
+				seen = 1;
+				break;
+			}
+		}
+
+		/* update current state */
+		for(k = 4; k < tn; k++){
+			if(strcmp(t[k], "current") == 0){
+				w->flags |= Fcurrent;
+				wcur = w;
+				w->vd = vd;
+			}else if(strcmp(t[k], "visible") == 0){
+				w->flags |= Fvisible;
+				w->vd = vd;
+			}
+		}
+
+		if(!seen){
+			/* not seen previously - set the new state for it */
+			w->vd = vd;
+		}
+
+		/* because a different program can run in any window we have to re-read */
+		w->flags &= ~Fsticky;
+		if(w->stickyforced){
+			w->flags |= Fsticky;
+		}else{
+			snprint(s, sizeof(s), "/dev/wsys/%d/label", w->id);
+			if((f = open(s, OREAD)) >= 0){
+				n = read(f, s, sizeof(s)-1);
+				close(f);
+				if(n > 0){
+					s[n] = 0;
+					for(k = 0; k < nelem(sticky) && sticky[k] != nil; k++){
+						if(strcmp(sticky[k], s) == 0){
+							w->flags |= Fsticky;
+							break;
+						}
+					}
+				}
+			}
+		}
+		w++;
+	}
+
+	free(ds);
+	free(ws);
+	ws = newws;
+	wsn = w - newws;
+}
+
+static void
+spawn(char *s)
+{
+	if(rfork(RFPROC|RFNOWAIT|RFNAMEG|RFENVG|RFCFDG|RFREND) == 0)
+		execl("/bin/rc", "rc", s, nil);
+}
+
+static void
+closewindow(void)
+{
+	int f;
+
+	wsupdate();
+	if(wcur == nil || (f = wwctl(wcur->id, OWRITE)) < 0)
+		return;
+	fprint(f, "delete");
+	close(f);	
+}
+
+static void
+togglefullscreen(void)
+{
+	int f;
+
+	wsupdate();
+	if(wcur == nil || (f = wwctl(wcur->id, OWRITE)) < 0)
+		return;
+	wcur->flags ^= Ffullscreen;
+	if(wcur->flags & Ffullscreen)
+		fprint(f, "resize -r 0 0 9999 9999");
+	else
+		fprint(f, "resize -r %d %d %d %d", wcur->r.min.x, wcur->r.min.y, wcur->r.max.x, wcur->r.max.y);
+	close(f);
+}
+
+static void
+togglesticky(void)
+{
+	wsupdate();
+	if(wcur != nil)
+		wcur->stickyforced ^= 1;
+}
+
+static void
+tagaction(int nvd)
+{
+	int f, wcurf, flip;;
+	W *w;
+
+	wsupdate();
+	flip = 0;
+	if(mod == Mmod4){
+		wcurf = -1;
+		wcur = nil;
+		for(w = ws; w < ws+wsn; w++){
+			if(w->tg == nvd && (w->flags & Fsticky) == 0){
+				if(tgvis[nvd] > 0){
+					flip = -1;
+					if((f = wwctl(w->id, OWRITE)) >= 0){
+						fprint(f, "hide");
+						close(f);
+					}
+				} else {
+					flip = 1;	
+					if((f = wwctl(w->id, OWRITE)) >= 0){
+						fprint(f, "unhide");
+						if(tg2wcur[nvd] == w->id && wcurf < 0){
+							wcur = w;
+							wcurf = f;
+						}else
+							close(f);
+					}
+				}
+			}
+		}
+		if(wcur != nil){
+			fprint(wcurf, "top");
+			fprint(wcurf, "current");
+			close(wcurf);
+		}
+		tgvis[nvd] = flip;
+	} else if(mod == (Mmod4 | Mshift) && wcur != nil){
+		tgvis[nvd] = 1;
+		wcur->tg = nvd;
+		tg2wcur[nvd] = wcur->id;
+		wcur = nil;
+	}
+	int i;
+	fprint(3, "-- ");
+	for(i = 1; i <= ntags; i++) {
+		switch(tgvis[i]){
+		case -1:
+			fprint(3, "u ");
+			break;
+		case 0:
+			fprint(3, "o ");
+			break;
+		case 1:
+			fprint(3, "n ");
+			break;
+		}
+	}
+	fprint(3, "--\n");	
+}
+
+static void
+vdaction(int nvd)
+{
+	int f, wcurf;
+	W *w;
+
+	if(vd == nvd)
+		return;
+
+	wsupdate();
+	if(mod == Mmod4){
+		wcur = nil;
+		wcurf = -1;
+		vd2wcur[vd] = -1;
+		for(w = ws; w < ws+wsn; w++){
+			if(w->flags & Fvisible)
+				w->vd = vd;
+			else if(w->vd == vd)
+				w->vd = -1;
+
+			if(w->flags & Fcurrent)
+				vd2wcur[vd] = w->id;
+
+			if(w->vd == nvd && (w->flags & Fsticky) == 0){
+				if((f = wwctl(w->id, OWRITE)) >= 0){
+					fprint(f, "unhide");
+					if(vd2wcur[nvd] == w->id && wcurf < 0){
+						wcur = w;
+						wcurf = f;
+					}else
+						close(f);
+				}
+			}
+		}
+
+		if(wcur != nil){
+			fprint(wcurf, "top");
+			fprint(wcurf, "current");
+			close(wcurf);
+		}
+
+		for(w = ws; w < ws+wsn; w++){
+			if(w->vd != nvd && (w->flags & (Fsticky|Fvisible)) == Fvisible){
+				if((f = wwctl(w->id, OWRITE)) >= 0){
+					fprint(f, "hide");
+					close(f);
+				}
+			}
+		}
+
+		vd = nvd;
+		fprint(3, "%d\n", vd);
+	}else if(mod == (Mmod4 | Mshift) && wcur != nil && wcur->vd != nvd){
+		if((f = wwctl(wcur->id, OWRITE)) >= 0){
+			fprint(f, "hide");
+			wcur->vd = nvd;
+			vd2wcur[nvd] = wcur->id; /* bring to the top */
+			wcur = nil;
+			close(f);
+		}
+	}
+}
+
+static void
+arrowaction(int x, int y)
+{
+	int f;
+
+	wsupdate();
+	if(wcur == nil || (f = wwctl(wcur->id, OWRITE)) < 0)
+		return;
+
+	x *= (mod & Mctl) ? Stepbig : Step;
+	y *= (mod & Mctl) ? Stepbig : Step;
+	if((mod & Mshift) == 0)
+		fprint(f, "move -minx %+d -miny %+d", x, y);
+	else
+		fprint(f, "resize -maxx %+d -maxy %+d -minx %+d -miny %+d", x, y, -x, -y);
+	close(f);
+}
+
+static struct {
+	int x, y;
+}cyclectx;
+
+static int
+cyclecmp(void *a_, void *b_)
+{
+	W *a = a_, *b = b_;
+
+	return cyclectx.x*(a->r.min.x - b->r.min.x) + cyclectx.y*(a->r.min.y - b->r.min.y);
+}
+
+static void
+cycleaction(int x, int y)
+{
+	int wcurid, i, f;
+	W *w, *w₀;
+
+	wsupdate();
+	wcurid = wcur == nil ? -1 : wcur->id;
+	cyclectx.x = x;
+	cyclectx.y = y;
+	qsort(ws, wsn, sizeof(*ws), cyclecmp);
+	w₀ = nil;
+	wcur = nil;
+	for(i = 0, w = ws; i < wsn; i++, w++){
+		if(w->id == wcurid){
+			wcur = w;
+			continue;
+		}
+		if((w->flags & Fsticky) != 0 || w->vd != vd)
+			continue;
+		if(w₀ == nil)
+			w₀ = w;
+		if(wcur != nil)
+			break;
+	}
+	if(i >= wsn)
+		w = w₀;
+	if(w == nil || (f = wwctl(w->id, OWRITE)) < 0)
+		return;
+	fprint(f, "top");
+	fprint(f, "current");
+	close(f);
+	wcur = w;
+}
+
+static int
+keyevent(char c, Rune r)
+{
+	if(c == 'c'){
+		if(r == 'n' && mod == Mmod4){
+			spawn("fmenu");
+			return 0;
+		}
+		if(r == 'd' && mod == Mmod4){
+			spawn("dmenu");
+			return 0;
+		}
+		if(r == 't' && mod == Mmod4){
+			spawn("window");
+			return 0;
+		}
+		if(r == 'c' && mod == Mmod4){
+			closewindow();
+			return 0;
+		}
+		if(r == 'f' && mod == Mmod4){
+			togglefullscreen();
+			return 0;
+		}
+		if(r == 's' && mod == Mmod4){
+			togglesticky();
+			return 0;
+		}
+		if(r == Kup){
+			arrowaction(0, -1);
+			return 0;
+		}
+		if(r == Kdown){
+			arrowaction(0, 1);
+			return 0;
+		}
+		if(r == Kleft){
+			arrowaction(-1, 0);
+			return 0;
+		}
+		if(r == Kright){
+			arrowaction(1, 0);
+			return 0;
+		}
+		if(r == 'h' && mod == Mmod4){
+			cycleaction(-1, 0);
+			return 0;
+		}
+		if(r == 'l' && mod == Mmod4){
+			cycleaction(1, 0);
+			return 0;
+		}
+		if(r == 'j' && mod == Mmod4){
+			cycleaction(0, 1);
+			return 0;
+		}
+		if(r == 'k' && mod == Mmod4){
+			cycleaction(0, -1);
+			return 0;
+		}
+		if(r >= '0' && r <= '9' && (mod & Mctl) == 0){
+			if(usetags)
+				tagaction(r - '0');
+			else
+				vdaction(r - '0');
+			return 0;
+		}
+	}
+	/* mod4 + shift + 1…0 yields a shifted value on 'c': workaround */
+	if(c == 'k' && mod == (Mmod4|Mshift) && r >= '0' && r <= '9'){
+		if(usetags)
+			tagaction(r - '0');
+		else
+			vdaction(r - '0');
+		return 0;
+	}
+	/* don't bother to properly deal with handling shifted digit keys */
+	if((mod & Mshift) != 0 && (c == 'c' || c == 'k' || c == 'K'))
+		return ispunct(r) ? 0 : -1;
+
+	return -1;
+}
+
+static void
+process(char *s)
+{
+	char b[128], *p;
+	int n, o;
+	Rune r;
+
+	o = 0;
+	b[o++] = *s;
+	if(*s == 'k' || *s == 'K'){
+		mod = 0;
+		if(utfrune(s+1, Kmod4) != nil)
+			mod |= Mmod4;
+		if(utfrune(s+1, Kctl) != nil)
+			mod |= Mctl;
+		if(utfrune(s+1, Kshift) != nil)
+			mod |= Mshift;
+	}
+
+	for(p = s+1; *p != 0; p += n){
+		if((n = chartorune(&r, p)) == 1 && r == Runeerror){
+			/* bail out */
+			n = strlen(p);
+			memmove(b+o, p, n);
+			o += n;
+			p += n;
+			break;
+		}
+
+		if((mod & Mmod4) == 0 || keyevent(*s, r) != 0){
+			memmove(b+o, p, n);
+			o += n;
+		}
+	}
+
+	/* all runes filtered out - ignore completely */
+	if(o == 1 && p-s > 1)
+		return;
+
+	b[o++] = 0;
+	if(write(1, b, o) != o)
+		exits(nil);
+}
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s [-t] [-s label]\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	char b[128];
+	int i, j, n;
+
+	for(n = 0; sticky[n] != nil; n++)
+		;
+
+	ARGBEGIN{
+	case 's':
+		if(n >= nelem(sticky))
+			sysfatal("ewwww");
+		sticky[n++] = EARGF(usage());
+		break;
+	case 't':
+		usetags++;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if((wsys = open("/dev/wsys", OREAD)) < 0)
+		sysfatal("%r");
+
+	/* initial state */
+	wsupdate();
+	for(i = 0; i < wsn; i++)
+		ws[i].vd = vd;
+	fprint(3, "%d\n", vd);
+
+	for(i = 0;;){
+		if((n = read(0, b+i, sizeof(b)-i)) <= 0)
+			break;
+		n += i;
+		for(j = 0; j < n; j++){
+			if(b[j] == 0){
+				process(b+i);
+				i = j+1;
+			}
+		}
+		memmove(b, b+i, j-i);
+		i -= j;
+	}
+
+	exits(nil);
+}
--- /dev/null
+++ b/9hkd.man
@@ -1,0 +1,78 @@
+.TH RIOW 1
+.SH NAME
+riow \- keyboard-controller for rio(1)
+.SH SYNOPSIS
+.B riow
+[
+.I -s label
+]
+.SH DESCRIPTION
+.I riow
+provides keyboard controlling for
+.I rio(1)
+in the manner of
+.IR i3 ,
+.I sway
+and so on.  It does so by working with
+.I /dev/kbdtap
+(see \fIrio\fR(4)) and
+.IR /dev/wsys .
+.SS Running
+.I riow
+filters all key combinations that include
+.B Kmod4
+modifier, so it has to be placed
+.I last
+in the chain of programs using
+.IR /dev/kbdtap :
+.EX
+	</dev/kbdtap ktrans | \\
+		reform/shortcuts | \\
+		riow >/dev/kbdtap |[3] bar
+.EE
+Note that the current desktop number is printed to fd
+.IR 3 .
+.SS Keyboard shortcuts
+.TP
+.B Kmod4+0…9
+Switches to the specified virtual desktops. There are ten in total.
+.TP
+.B Kmod4+Shift+0…9
+Moves the current window to the specified virtual desktop.
+.TP
+.B Kmod4+f
+Toggle between fullscreen and normal mode for the current window.
+.TP
+.B Kmod4+s
+Toggle "sticky" mode for the current window. In this mode the window is staying
+while the user is switching between desktops. By default, programs like
+.IR winwatch ,
+.IR catclock ,
+.IR kbmap ,
+etc are in sticky mode. Additional programs can be added to that list on startup by
+specifying their labels with
+.I -s
+option.
+.TP
+.B Kmod4+enter
+Spawn a new
+.IR window(1) .
+.TP
+.B Kmod4+h/j/k/l
+Focus left/down/up/right.
+.TP
+.B Kmod4+arrows
+Move the current window in the specified direction.
+.TP
+.B Kmod4+control+arrows
+Same, but in bigger steps.
+.TP
+.B Kmod4+shift+arrows
+Resize the current window.
+.TP
+.B Kmod4+shift+control+arrows
+Same, but in bigger steps.
+.SH SOURCE
+https://git.sr.ht/~ft/riow
+.SH BUGS
+Yes.
--- a/README.md
+++ b/README.md
@@ -1,4 +1,2 @@
-# riow
+# Fork of riow from 9front
 
-*NOTE*: riow is included in 9front since Sep 2022.  No development will
-continue in this repo.
--- a/mkfile
+++ b/mkfile
@@ -1,11 +1,11 @@
 </$objtype/mkfile
 
-TARG=riow
+TARG=9hkd
 MAN=/sys/man/1
 BIN=/$objtype/bin
 
 OFILES=\
-	riow.$O\
+	9hkd.$O\
 
 default:V: all