shithub: lola

Download patch

ref: ed2124f31c1951c787469a9b140733c8cd024984
parent: 224c03c17e5c664b1b5b8417d1940301d9fccfd5
author: aap <aap@papnet.eu>
date: Wed Feb 21 05:30:08 EST 2024

implemented new kbdtap

--- a/fs.c
+++ b/fs.c
@@ -340,6 +340,7 @@
 fsopen(Req *r)
 {
 	Window *w;
+	int rd, wr;
 
 	w = XF(r->fid)->w;
 
@@ -354,6 +355,8 @@
 	if(QFILE(r->fid->qid.path) != Qtext)
 		r->ifcall.mode &= (OREAD|OWRITE|ORDWR);		
 
+	rd = r->ifcall.mode==ORDWR || r->ifcall.mode==OREAD;
+	wr = r->ifcall.mode==ORDWR || r->ifcall.mode==OWRITE;
 	switch(QFILE(r->fid->qid.path)){
 	case Qtext:
 		if(r->ifcall.mode & OTRUNC)
@@ -361,7 +364,7 @@
 		break;
 
 	case Qsnarf:
-		if(r->ifcall.mode==ORDWR || r->ifcall.mode==OWRITE)
+		if(wr)
 			ntsnarf = 0;
 		break;
 
@@ -391,7 +394,7 @@
 		break;
 
 	case Qwctl:
-		if(w && (r->ifcall.mode==ORDWR || r->ifcall.mode==OREAD)){
+		if(wr && rd){
 			/* can only have one reader of wctl */
 			if(w->wctlopen){
 				respond(r, Einuse);
@@ -404,9 +407,19 @@
 		break;
 
 	case Qtap:
-		chanprint(ctltap, "%c%c", Tapon, r->ifcall.mode);
-		respond(r, recvp(resptap));
-		return;
+		if(rd && totap || wr && fromtap){
+			respond(r, Einuse);
+			return;
+		}
+		if(rd){
+			totap = chancreate(sizeof(Channel**), 0);
+			sendp(opentap, totap);
+		}
+		if(wr){
+			fromtap = chancreate(sizeof(char*), 32);
+			sendp(opentap, fromtap);
+		}
+		break;
 	}
 
 	respond(r, nil);
@@ -418,6 +431,7 @@
 	Xfid *xf;
 	Window *w;
 	Text *x;
+	int rd, wr;
 
 	xf = XF(fid);
 	if(xf == nil)
@@ -425,10 +439,12 @@
 	w = xf->w;
 	x = &w->text;
 
+	rd = fid->omode==ORDWR || fid->omode==OREAD;
+	wr = fid->omode==ORDWR || fid->omode==OWRITE;
 	switch(QFILE(fid->qid.path)){
 	/* replace snarf buffer when /dev/snarf is closed */
 	case Qsnarf:
-		if(fid->omode==ORDWR || fid->omode==OWRITE){
+		if(wr){
 			setsnarf(tsnarf, ntsnarf);
 			ntsnarf = 0;
 		}
@@ -462,13 +478,15 @@
 		break;
 
 	case Qwctl:
-		if(w && (fid->omode==ORDWR || fid->omode==OREAD))
+		if(w && rd)
 			w->wctlopen = FALSE;
 		break;
 
 	case Qtap:
-		chanprint(ctltap, "%c%c", Tapoff, fid->omode);
-		recvp(resptap);
+		if(wr && fromtap)
+			sendp(closetap, fromtap);
+		if(rd && totap)
+			sendp(closetap, totap);
 		break;
 	}
 
@@ -820,8 +838,8 @@
 				r->ofcall.count = p - data;
 				respond(r, "null message type");
 				return;
-			case Tapfocus:
-				/* cleanup our own pollution */
+			case 'z':
+				/* ignore context change */
 				break;
 			default:
 				chanprint(fromtap, "%s", p);
--- a/inc.h
+++ b/inc.h
@@ -165,8 +165,8 @@
 	bool	full;	/* filled the queue; no more recording until client comes back */	
 };
 
-typedef struct Kbdqueue Kbdqueue;
-struct Kbdqueue
+typedef struct Queue Queue;
+struct Queue
 {
 	char *q[32];
 	int ri;
@@ -173,6 +173,9 @@
 	int wi;
 	bool full;
 };
+int qadd(Queue *q, char *data);
+char *qget(Queue *q);
+int qempty(Queue *q);
 
 enum
 {
@@ -223,7 +226,7 @@
 	Cursor cursor;
 
 	Channel *kbd;
-	Kbdqueue kq;
+	Queue kq;
 	bool consctlopen;
 	bool kbdopen;
 
@@ -288,16 +291,11 @@
 Wctlcmd parsewctl(char *s, Rectangle r);
 char *writewctl(Window *w, char *data);
 
-enum{
-	Tapon = 'b',
-	Tapoff = 'e',
-	Tapfocus = 'z',
-};
-extern Channel *ctltap;	/* open/close */
-extern Channel *resptap;	/* open/close err */
-extern Channel	*fromtap;	/* input from kbd tap program to window */
+
+extern Channel *opentap;	/* open fromtap or totap */
+extern Channel *closetap;	/* close fromtap or totap */
+extern Channel *fromtap;	/* input from kbd tap program to window */
 extern Channel *totap;		/* our keyboard input to tap program */
-extern Channel *wintap;	/* tell the tapthread which Window to send to */
 
 
 extern Srv fsys;
--- a/main.c
+++ b/main.c
@@ -655,150 +655,112 @@
  * from tap  --------+----> window
  */
 
-Channel *ctltap;	/* open/close */
-Channel *resptap;	/* open/close err */
-Channel	*fromtap;	/* input from kbd tap program to window */
+Channel *opentap;	/* open fromtap or totap */
+Channel *closetap;	/* close fromtap or totap */
+Channel *fromtap;	/* input from kbd tap program to window */
 Channel *totap;		/* our keyboard input to tap program */
-Channel *wintap;	/* tell the tapthread which Window to send to */
 
-static int tapseats[] = { [OREAD] Tapoff, [OWRITE] Tapoff };
-
-char*
-tapctlmsg(char *msg)
-{
-	int perm;
-
-	perm = msg[1];
-	switch(msg[0]){
-	case Tapoff:
-		if(perm == ORDWR)
-			tapseats[OREAD] = Tapoff, tapseats[OWRITE] = Tapoff;
-		else
-			tapseats[perm] = Tapoff;
-		break;
-	case Tapon:
-		switch(perm){
-		case ORDWR:
-			if(tapseats[OREAD] != Tapoff || tapseats[OWRITE] != Tapoff)
-				return "seat taken";
-			tapseats[OREAD] = Tapon, tapseats[OWRITE] = Tapon;
-			break;
-		case OREAD: case OWRITE:
-			if(tapseats[perm] != Tapoff)
-				return "seat taken";
-			tapseats[perm] = Tapon;
-			break;
-		}
-		break;
-	}
-	return nil;
-}
-
 void
 keyboardtap(void*)
 {
-	char *s, *ctl;
-	char *e;
-	char *watched;
-	Channel *fschan;
+	char *s, *z;
+	Channel *fschan, *chan;
 	int n;
 	Stringpair pair;
-	Window *w, *cur;
+	Window *cur, *prev;
+	Queue tapq;
 
 	threadsetname("keyboardtap");
+
 	fschan = chancreate(sizeof(Stringpair), 0);
-	enum { Awin, Actl, Afrom, Adev, Ato, Ainp, Awatch, NALT };
+	enum { Akbd, Afromtap, Atotap, Aopen, Aclose,  NALT };
 	Alt alts[NALT+1] = {
-		[Awin]	{.c = wintap, .v = &w, .op = CHANRCV},
-		[Actl]	{.c = ctltap, .v = &ctl, .op = CHANRCV},
-		[Afrom]	{.c = fromtap, .v = &s, .op = CHANRCV},
-		[Adev]	{.c = kbctl->c, .v = &s, .op = CHANRCV},
-		[Ato]	{.c = totap, .v = &fschan, .op = CHANNOP},
-		[Ainp]	{.c = nil, .v = &s, .op = CHANNOP},
-		[Awatch]{.c = totap, .v = &fschan, .op = CHANNOP},
-		[NALT]	{.op = CHANEND},
+		[Akbd]		{.c = kbctl->c, .v = &s, .op = CHANRCV},
+		[Afromtap]	{.c = nil, .v = &s, .op = CHANNOP},
+		[Atotap]	{.c = nil, .v = &fschan, .op = CHANNOP},
+		[Aopen]		{.c = opentap, .v = &chan, .op = CHANRCV},
+		[Aclose]	{.c = closetap, .v = &chan, .op = CHANRCV},
+		[NALT]		{.op = CHANEND},
 	};
 
+	memset(&tapq, 0, sizeof(tapq));
 	cur = nil;
-	watched = nil;
-	for(;;)
+	for(;;){
+		if(alts[Atotap].c && !qempty(&tapq))
+			alts[Atotap].op = CHANSND;
+		else
+			alts[Atotap].op = CHANNOP;
 		switch(alt(alts)){
-		case Awin:
-			cur = w;
-			if(cur != nil){
-				alts[Ainp].c = cur->kbd;
-				if(tapseats[OREAD] == Tapoff)	
-					goto Reset;
-				if(alts[Awatch].op == CHANSND)
-					free(watched);
-				watched = smprint("%c%d", Tapfocus, cur->id);
-				alts[Awatch].op = CHANSND;
+		case Akbd:
+			/* from keyboard to tap or to window */
+			if(*s == 'k' || *s == 'K')
+				shiftdown = utfrune(s+1, Kshift) != nil;
+			prev = cur;
+			cur = focused;
+			if(totap){
+				if(cur != prev && cur){
+					/* notify tap of focus change */
+					z = smprint("z%d", cur->id);
+					if(!qadd(&tapq, z))
+						free(z);
+				}
+				/* send to tap */
+				if(qadd(&tapq, s))
+					break;
+				/* tap is wedged, send directly instead */
 			}
-			if(alts[Ainp].op != CHANNOP || alts[Ato].op != CHANNOP)
+			if(cur)
+				sendp(cur->kbd, s);
+			else
 				free(s);
-			goto Reset;
-		case Actl:
-			e = tapctlmsg(ctl);
-			sendp(resptap, e);
-			if(e != nil || *ctl != Tapoff){
-				free(ctl);
-				break;
-			}
-			free(ctl);
-			goto Reset;
-		case Afrom:
-			if(cur == nil){
-				free(s);
-				break;
-			}
-			alts[Afrom].op = CHANNOP;
-			alts[Adev].op = CHANNOP;
-			alts[Ato].op = CHANNOP;
-			alts[Ainp].op = CHANSND;
 			break;
-		case Adev:
-			if(tapseats[OWRITE] == Tapoff && cur == nil){
-				free(s);
-				break;
-			}
-			alts[Afrom].op = CHANNOP;
-			alts[Adev].op = CHANNOP;
-			if(tapseats[OWRITE] == Tapoff)
-				alts[Ainp].op = CHANSND;
+
+		case Afromtap:
+			/* from tap to window */
+			if(cur && cur == focused)
+				sendp(cur->kbd, s);
 			else
-				alts[Ato].op = CHANSND;
+				free(s);
 			break;
 
-		/* These two do the xreq channel dance
-		 * ugly... */
-		case Ato:
+		case Atotap:
+			/* send queued up messages */
 			recv(fschan, &pair);
+			s = qget(&tapq);
 			n = strlen(s)+1;
 			pair.ns = min(n, pair.ns);
 			memmove(pair.s, s, pair.ns);
 			free(s);
 			send(fschan, &pair);
-			goto Reset;
-		case Awatch:
-			recv(fschan, &pair);
-			n = strlen(watched)+1;
-			pair.ns = min(n, pair.ns);
-			memmove(pair.s, watched, pair.ns);
-			free(watched);
-			send(fschan, &pair);
-			alts[Awatch].op = CHANNOP;
 			break;
 
-		case Ainp:
-			if(*s == 'k' || *s == 'K')
-				shiftdown = utfrune(s+1, Kshift) != nil;
-		Reset:
-			alts[Ainp].op = CHANNOP;
-			alts[Ato].op = CHANNOP;
-			alts[Afrom].op = CHANRCV;
-			alts[Adev].op = CHANRCV;
+		case Aopen:
+			if(chan == fromtap){
+				alts[Afromtap].c = fromtap;
+				alts[Afromtap].op = CHANRCV;
+			}
+			if(chan == totap)
+				alts[Atotap].c = totap;
 			break;
+
+		case Aclose:
+			if(chan == fromtap){
+				fromtap = nil;
+				alts[Afromtap].c = nil;
+				alts[Afromtap].op = CHANNOP;
+				// TODO: empty chan
+			}
+			if(chan == totap){
+				totap = nil;
+				alts[Atotap].c = nil;
+				alts[Atotap].op = CHANNOP;
+				while(!qempty(&tapq))
+					free(qget(&tapq));
+			}
+			chanfree(chan);
+			break;
 		}
+	}
 }
 
 void
@@ -820,11 +782,8 @@
 	mctl = initmouse(nil, screen);
 	if(mctl == nil)
 		sysfatal("initmouse: %r");
-	totap = chancreate(sizeof(Channel**), 0);
-	fromtap = chancreate(sizeof(char*), 32);
-	wintap = chancreate(sizeof(Window*), 0);
-	ctltap = chancreate(sizeof(char*), 0);
-	resptap = chancreate(sizeof(char*), 0);
+	opentap = chancreate(sizeof(Channel*), 0);
+	closetap = chancreate(sizeof(Channel*), 0);
 
 	servekbd = kbctl->kbdfd >= 0;
 	snarffd = open("/dev/snarf", OREAD|OCEXEC);
@@ -840,8 +799,7 @@
 
 	threadcreate(mthread, nil, mainstacksize);
 	threadcreate(resthread, nil, mainstacksize);
-	/* proc so mouse keeps working if tap program crashes */
-	proccreate(keyboardtap, nil, mainstacksize);
+	threadcreate(keyboardtap, nil, mainstacksize);
 
 	flushimage(display, 1);
 
--- a/util.c
+++ b/util.c
@@ -126,3 +126,30 @@
 	return pair;
 }
 
+int
+qadd(Queue *q, char *data)
+{
+	if(q->full)
+		return 0;
+	q->q[q->wi++] = data;
+	q->wi %= nelem(q->q);
+	q->full = q->wi == q->ri;
+	return 1;
+}
+
+char*
+qget(Queue *q)
+{
+	char *data;
+
+	data = q->q[q->ri++];
+	q->ri %= nelem(q->q);
+	q->full = FALSE;
+	return data;
+}
+
+int
+qempty(Queue *q)
+{
+	return q->ri == q->wi && !q->full;
+}
--- a/wind.c
+++ b/wind.c
@@ -369,7 +369,6 @@
 		return;
 	prev = focused;
 	focused = w;
-	sendp(wintap, w);
 	/* TODO a bit ugly the repetition,
 	 * but this might not stay anyways */
 	if(prev){
@@ -827,7 +826,7 @@
 				alts[AConsWrite].op = CHANSND;
 			else
 				alts[AConsWrite].op = CHANNOP;
-			if(w->kbdopen && (w->kq.ri != w->kq.wi || w->kq.full))
+			if(w->kbdopen && !qempty(&w->kq))
 				alts[AKbdRead].op = CHANSND;
 			else
 				alts[AKbdRead].op = CHANNOP;
@@ -840,17 +839,11 @@
 
 		switch(alt(alts)){
 		case AKbd:
-			if(!w->kq.full){
-				w->kq.q[w->kq.wi++] = s;
-				w->kq.wi %= nelem(w->kq.q);
-				w->kq.full = w->kq.wi == w->kq.ri;
-			}else
+			if(!qadd(&w->kq, s))
 				free(s);
 			if(!w->kbdopen)
-			while(w->kq.ri != w->kq.wi || w->kq.full){
-				s = w->kq.q[w->kq.ri++];
-				w->kq.ri %= nelem(w->kq.q);
-				w->kq.full = FALSE;
+			while(!qempty(&w->kq)){
+				s = qget(&w->kq);
 				if(*s == 'c'){
 					chartorune(&r, s+1);
 					if(r)
@@ -863,13 +856,12 @@
 		case AKbdRead:
 			recv(fsc, &pair);
 			nb = 0;
-			while(w->kq.ri != w->kq.wi || w->kq.full){
+			while(!qempty(&w->kq)){
 				s = w->kq.q[w->kq.ri];
 				i = strlen(s)+1;
 				if(nb+i > pair.ns)
 					break;
-				w->kq.ri = (w->kq.ri+1) % nelem(w->kq.q);
-				w->kq.full = FALSE;
+				qget(&w->kq);
 				memmove((char*)pair.s + nb, s, i);
 				free(s);
 				nb += i;