9front - general discussion about 9front
 help / color / mirror / Atom feed
* [9front] Mouse clipping patch
@ 2021-07-12 19:50 José Miguel Sánchez García
  2021-07-13  2:36 ` ori
  2021-07-14 22:57 ` ori
  0 siblings, 2 replies; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-12 19:50 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 2822 bytes --]

Hello everyone,

After talking with some people about the need of proper mouse grabbing
for some programs (think about vncv, qwx's quake ports, screenlock),
I've implemented it. The devmouse and libdraw patches modify
/dev/mousectl to accept two new commands: "clip x0 y0 x1 y1" and
"release".

The "clip" command confines the mouse inside the given rect. It must
be a subrect of the current screen, otherwise the operation will fail.
Release undoes that operation (and it's a no-op if there is no grab
active). Subsequent clip and release commands override each other, and
a grab is automatically released if the fd that made it is closed (in
order to prevent a grab to trap the mouse after a program crash).

The rio patch modifies rio so that it multiplexes the new grabbing
capabilities among its windows. This is transparent to the underlying
program: they can clip and release the mouse at will (provided that
the clipping rect lies inside their window). Mouse grab in rio follows
this rules:

- The grab is released after a Reshape event. It's up to the running
program to recover that grab in its resize handler. That guarantees
the active grab to be always correct (and gives the program a chance
to fix it once it isn't anymore)
- Only the current window's grab is active at any moment. If some
other window is grabbing the mouse, it doesn't have any effect. This
keeps rio transparent to the underlying programs grabbing the mouse:
they all think they have the global grab at the same time, but focus
alone is what ultimately decides which one is active, like it already
does for keyboard/mouse input. This proves to be useful when windows
are opened while a grab is held (after a plumb, or after spawning a
new window).
- Rio menus temporarily release the mouse, so options outside of the
grabbing rect can be accessed. The grab is restored if needed after
the menu is closed.
- Windows holding the mouse have a different border color, so they can
be clearly identified. Currently it overrides the blue hold color,
although I believe that the event of having a text window grabbing the
mouse and also holding the input is unlikely.

In order to make these changes possible, I had to alter the behavior
of rio when handling a reshape done using the window borders: right
now it tops the window, and then handles the reshape. I changed that
behavior to be the opposite: first handle the resize and then top the
window. This allows resizing unfocused windows which would grab the
mouse when topped. As far as I know, and after some testing, it looks
like I didn't break anything.

I'm open to feedback, as there has been interesting alternatives
proposed during the development of this patch. I hope that, by
bringing my work to the public, any improvements can be shared and
reviewed by everyone.

Cheers,
jmi2k

[-- Attachment #2: libdraw-mousegrab.diff --]
[-- Type: application/octet-stream, Size: 1845 bytes --]

--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/include/mouse.h
+++ /sys/include/mouse.h
@@ -22,6 +22,7 @@
 
 	char		*file;
 	int		mfd;		/* to mouse file */
+	int		mctlfd;		/* to mousectl file */
 	int		cfd;		/* to cursor file */
 	int		pid;		/* of slave proc */
 	Image*	image;	/* of associated window/display */
@@ -39,6 +40,8 @@
  */
 extern Mousectl*	initmouse(char*, Image*);
 extern void		moveto(Mousectl*, Point);
+extern int		clipmouse(Mousectl*, Rectangle);
+extern void		releasemouse(Mousectl*);
 extern int			readmouse(Mousectl*);
 extern void		closemouse(Mousectl*);
 extern void		setcursor(Mousectl*, Cursor*);
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree/sys/src/libdraw/mouse.c
+++ sys/src/libdraw/mouse.c
@@ -12,14 +12,29 @@
 	m->xy = pt;
 }
 
+int
+clipmouse(Mousectl *m, Rectangle clipr)
+{
+	return fprint(m->mctlfd, "clip %d %d %d %d",
+		clipr.min.x, clipr.min.y,
+		clipr.max.x, clipr.max.y);
+}
+
 void
+releasemouse(Mousectl *m)
+{
+	fprint(m->mctlfd, "release");
+}
+
+void
 closemouse(Mousectl *mc)
 {
 	if(mc == nil)
 		return;
 	close(mc->mfd);
+	close(mc->mctlfd);
 	close(mc->cfd);
-	mc->mfd = mc->cfd = -1;
+	mc->mfd = mc->mctlfd = mc->cfd = -1;
 	threadint(mc->pid);
 }
 
@@ -106,18 +121,24 @@
 		free(mc);
 		return nil;
 	}
-	t = malloc(strlen(file)+16);
+	n = strlen(file)+16;
+	t = malloc(n);
 	if (t == nil) {
 		close(mc->mfd);
 		free(mc);
 		return nil;
 	}
-	strcpy(t, file);
+	seprint(t, t+n, "%s", file);
 	sl = utfrrune(t, '/');
 	if(sl)
-		strcpy(sl, "/cursor");
+		seprint(sl, t+n, "/mousectl");
 	else
-		strcpy(t, "/dev/cursor");
+		seprint(t, t+n, "/dev/mousectl");
+	mc->mctlfd = open(t, ORDWR|OCEXEC);
+	if(sl)
+		seprint(sl, t+n, "/cursor");
+	else
+		seprint(t, t+n, "/dev/cursor");
 	mc->cfd = open(t, ORDWR|OCEXEC);
 	free(t);
 	mc->image = i;

[-- Attachment #3: rio-mousegrab.diff --]
[-- Type: application/octet-stream, Size: 7944 bytes --]

--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/dat.h
+++ /sys/src/cmd/rio/dat.h
@@ -10,6 +10,7 @@
 	Qlabel,
 	Qkbd,
 	Qmouse,
+	Qmousectl,
 	Qnew,
 	Qscreen,
 	Qsnarf,
@@ -154,6 +155,9 @@
 	 * Now they're always the same but the code doesn't assume so.
 	*/
 	Rectangle		screenr;	/* screen coordinates of window */
+	Rectangle	grabr;
+	Fid			*grabfid;
+	int			grab;
 	int			resized;
 	int			wctlready;
 	Rectangle		lastsr;
@@ -304,11 +308,14 @@
 Image	*lightholdcol;
 Image	*paleholdcol;
 Image	*paletextcol;
+Image	*grabcol;
+Image	*lightgrabcol;
 Image	*sizecol;
 int	reverse;	/* there are no pastel paints in the dungeons and dragons world -- rob pike */
 
 Window	**window;
 Window	*wkeyboard;	/* window of simulated keyboard */
+Window	*wgrab;
 int		nwindow;
 int		snarffd;
 int		gotscreen;
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/data.c
+++ /sys/src/cmd/rio/data.c
@@ -195,6 +195,8 @@
 	lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreyblue);
 	paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreyblue);
 	paletextcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF^reverse);
+	grabcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xB22222FF);
+	lightgrabcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCD5C5CFF);
 	sizecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DRed);
 
 	if(reverse == 0)
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/fns.h
+++ /sys/src/cmd/rio/fns.h
@@ -5,6 +5,7 @@
 int	writewctl(Xfid*, char*);
 Window *new(Image*, int, int, int, char*, char*, char**);
 void	riosetcursor(Cursor*);
+void	updategrab(void);
 int	min(int, int);
 int	max(int, int);
 Rune*	strrune(Rune*, Rune);
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/fsys.c
+++ /sys/src/cmd/rio/fsys.c
@@ -30,6 +30,7 @@
 	{ "label",		QTFILE,	Qlabel,		0600 },
 	{ "kbd",	QTFILE,	Qkbd,		0600 },
 	{ "mouse",	QTFILE,	Qmouse,		0600 },
+	{ "mousectl",	QTFILE,	Qmousectl,		0600 },
 	{ "screen",		QTFILE,	Qscreen,		0400 },
 	{ "snarf",		QTFILE,	Qsnarf,		0600 },
 	{ "text",		QTFILE,	Qtext,		0600 },
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/rio.c
+++ /sys/src/cmd/rio/rio.c
@@ -327,6 +327,27 @@
 }
 
 void
+updategrab(void)
+{
+	Window *w;
+
+	if(input == nil || !input->grab || menuing || sweeping)
+		w = nil;
+	else
+		w = input;
+	if(w == wgrab)
+		return;
+	if(w != nil){
+		clipmouse(mousectl, w->grabr);
+		wsendctlmesg(w, Repaint, ZR, nil);
+	}else
+		releasemouse(mousectl);
+	if(wgrab)
+		wsendctlmesg(wgrab, Repaint, ZR, nil);
+	wgrab = w;
+}
+
+void
 killprocs(void)
 {
 	int i;
@@ -489,6 +510,9 @@
 				wtopme(wkeyboard);
 				winput = wkeyboard;
 			}
+			w = wpointto(mouse->xy);
+			if(sending == FALSE && !scrolling && w!=nil && !w->deleted && inborder(w->screenr, mouse->xy))
+				moving = TRUE;
 			if(winput!=nil && !winput->deleted && winput->i!=nil){
 				/* convert to logical coordinates */
 				xy.x = mouse->xy.x + (winput->i->r.min.x-winput->screenr.min.x);
@@ -505,10 +529,7 @@
 					scrolling = mouse->buttons;
 				else
 					scrolling = mouse->buttons && ptinrect(xy, winput->scrollr);
-				/* topped will be zero or less if window has been bottomed */
-				if(sending == FALSE && !scrolling && inborder(winput->screenr, mouse->xy) && winput->topped>0)
-					moving = TRUE;
-				else if(inside && (scrolling || winput->mouseopen || (mouse->buttons&1)))
+				if(inside && (scrolling || winput->mouseopen || (mouse->buttons&1)))
 					sending = TRUE;
 			}else
 				sending = FALSE;
@@ -523,21 +544,20 @@
 				continue;
 			}
 			if(moving && (mouse->buttons&7)){
-				incref(winput);
+				incref(w);
 				sweeping = TRUE;
 				if(mouse->buttons & 3)
-					i = bandsize(winput);
+					i = bandsize(w);
 				else
-					i = drag(winput);
+					i = drag(w);
 				sweeping = FALSE;
 				if(i != nil){
-					wcurrent(winput);
-					wsendctlmesg(winput, Reshaped, i->r, i);
+					wcurrent(w);
+					wsendctlmesg(w, Reshaped, i->r, i);
 				}
-				wclose(winput);
+				wclose(w);
 				continue;
 			}
-			w = wpointto(mouse->xy);
 			if(w!=nil && inborder(w->screenr, mouse->xy))
 				riosetcursor(corners[whichcorner(w->screenr, mouse->xy)]);
 			else
@@ -715,6 +735,7 @@
 		menu3str[i] = nil;
 	}
 	sweeping = TRUE;
+	updategrab();
 	switch(i = menuhit(3, mousectl, &menu3, wscreen)){
 	case -1:
 		break;
@@ -744,6 +765,7 @@
 		break;
 	}
 	sweeping = FALSE;
+	updategrab();
 }
 
 void
@@ -753,6 +775,8 @@
 		menu2str[Scroll] = "noscroll";
 	else
 		menu2str[Scroll] = "scroll";
+	sweeping = TRUE;
+	updategrab();
 	switch(menuhit(2, mousectl, &menu2, wscreen)){
 	case Cut:
 		wsnarf(w);
@@ -787,6 +811,8 @@
 			wshow(w, w->nr);
 		break;
 	}
+	sweeping = FALSE;
+	updategrab();
 	flushimage(display, 1);
 	wsendctlmesg(w, Wakeup, ZR, nil);
 }
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/wind.c
+++ /sys/src/cmd/rio/wind.c
@@ -302,6 +302,11 @@
 			col = holdcol;
 		else
 			col = paleholdcol;
+	}else if(w->grab){
+		if(type == Selborder)
+			col = grabcol;
+		else
+			col = lightgrabcol;
 	}else{
 		if(type == Selborder)
 			col = titlecol;
@@ -358,6 +363,8 @@
 	w->scrollr.max.x = r.min.x+Scrollwid;
 	w->lastsr = ZR;
 	r.min.x += Scrollwid+Scrollgap;
+	w->grab = FALSE;
+	updategrab();
 	frclear(w, FALSE);
 	frinit(w, r, w->font, w->i, cols);
 	wsetcols(w, w == input);
@@ -1264,6 +1271,7 @@
 	w->gone = chancreate(sizeof(char*), 0);
 	w->scrollr = r;
 	w->scrollr.max.x = r.min.x+Scrollwid;
+	w->grab = FALSE;
 	w->lastsr = ZR;
 	r.min.x += Scrollwid+Scrollgap;
 	frinit(w, r, font, i, cols);
@@ -1306,6 +1314,7 @@
 		input = nil;
 		riosetcursor(nil);
 	}
+	updategrab();
 	if(w == wkeyboard)
 		wkeyboard = nil;
 	for(i=0; i<nhidden; i++)
@@ -1390,6 +1399,7 @@
 
 			sendp(c, w);
 		}
+		updategrab();
 		if(w->i==nil || Dx(w->screenr)<=0)
 			break;
 		wrepaint(w);
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/xfid.c
+++ /sys/src/cmd/rio/xfid.c
@@ -18,6 +18,7 @@
 char Elong[] = 		"snarf buffer too long";
 char Eunkid[] = 	"unknown id in attach";
 char Ebadrect[] = 	"bad rectangle in attach";
+char Egrab[] =		"invalid grab rectangle";
 char Ewindow[] = 	"cannot make window";
 char Enowindow[] = 	"window has no image";
 char Ebadmouse[] = 	"bad format on /dev/mouse";
@@ -342,6 +343,14 @@
 	case Qkbd:
 		w->kbdopen = FALSE;
 		break;
+	case Qmousectl:
+		if(w->grab && w->grabfid == x->f){
+			w->grab = FALSE;
+			w->grabfid = nil;
+			updategrab();
+			wsendctlmesg(w, Repaint, ZR, nil);
+		}
+		break;
 	case Qmouse:
 		w->resized = FALSE;
 		w->mouseopen = FALSE;
@@ -372,6 +381,7 @@
 	Fcall fc;
 	int cnt, qid, nb, off, nr;
 	char err[ERRMAX], *p;
+	Rectangle grabr;
 	Point pt;
 	Window *w;
 	Rune *r;
@@ -500,6 +510,46 @@
 		w->label = p;
 		w->label[cnt] = 0;
 		memmove(w->label, x->data, cnt);
+		break;
+
+	case Qmousectl:
+		if(strncmp(x->data, "clip", 4)==0){
+			grabr.min.x = strtol(x->data+4, &p, 0);
+			if(p == nil){
+				filsysrespond(x->fs, x, &fc, Egrab);
+				return;
+			}
+			grabr.min.y = strtol(p, &p, 0);
+			if(p == nil){
+				filsysrespond(x->fs, x, &fc, Egrab);
+				return;
+			}
+			grabr.max.x = strtol(p, &p, 0);
+			if(p == nil){
+				filsysrespond(x->fs, x, &fc, Egrab);
+				return;
+			}
+			grabr.max.y = strtol(p, &p, 0);
+			if(p == nil){
+				filsysrespond(x->fs, x, &fc, Egrab);
+				return;
+			}
+			if(!rectinrect(grabr, w->screenr)){
+				filsysrespond(x->fs, x, &fc, Egrab);
+				return;
+			}
+			w->grabr = grabr;
+			w->grabfid = x->f;
+			w->grab = TRUE;
+			updategrab();
+			wsendctlmesg(w, Repaint, ZR, nil);
+		}else if(strncmp(x->data, "release", 7)==0){
+			w->grab = FALSE;
+			w->grabfid = nil;
+			updategrab();
+			wsendctlmesg(w, Repaint, ZR, nil);
+		}else
+			write(mousectl->mctlfd, x->data, cnt);
 		break;
 
 	case Qmouse:

[-- Attachment #4: devmouse-grab.diff --]
[-- Type: application/octet-stream, Size: 2411 bytes --]

--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/9/port/devmouse.c
+++ /sys/src/9/port/devmouse.c
@@ -18,6 +18,8 @@
 	ScrollRight = 0x40,
 };
 
+char Egrab[] = "invalid grab rectangle";
+
 typedef struct Mouseinfo	Mouseinfo;
 typedef struct Mousestate	Mousestate;
 
@@ -53,6 +55,8 @@
 	CMbuttonmap,
 	CMscrollswap,
 	CMswap,
+	CMclip,
+	CMrelease,
 	CMblank,
 	CMblanktime,
 	CMtwitch,
@@ -64,6 +68,8 @@
 	CMbuttonmap,	"buttonmap",	0,
 	CMscrollswap,	"scrollswap",	0,
 	CMswap,		"swap",		1,
+	CMclip,		"clip",		0,
+	CMrelease,	"release",	1,
 	CMblank,	"blank",	1,
 	CMblanktime,	"blanktime",	2,
 	CMtwitch,	"twitch",	1,
@@ -95,6 +101,9 @@
 static uchar buttonmap[8] = {
 	0, 1, 2, 3, 4, 5, 6, 7,
 };
+static Rectangle grabr;
+static Chan *grabchan;
+static int grab;
 static int mouseswap;
 static int scrollswap;
 static ulong mousetime;
@@ -206,6 +215,10 @@
 	if((c->qid.type&QTDIR)!=0 || (c->flag&COPEN)==0)
 		return;
 	switch((ulong)c->qid.path){
+	case Qmousectl:
+		if(c == grabchan)
+			grab = 0;
+		break;
 	case Qmousein:
 		mouse.inbuttons &= ~((Mousestate*)c->aux)->buttons;
 		free(c->aux);	/* Mousestate */
@@ -344,6 +357,7 @@
 mousewrite(Chan *c, void *va, long n, vlong)
 {
 	char *p;
+	Rectangle r;
 	Point pt;
 	Cmdbuf *cb;
 	Cmdtab *ct;
@@ -403,6 +417,37 @@
 			mouseblankscreen(1);
 			break;
 
+		case CMclip:
+			if(cb->nf < 5)
+				error(Eshort);
+			if(!gscreen)
+				break;
+			r.min.x = strtol(cb->f[1], &p, 0);
+			if(p == nil)
+				error(Egrab);
+			r.min.y = strtol(cb->f[2], &p, 0);
+			if(p == nil)
+				error(Egrab);
+			r.max.x = strtol(cb->f[3], &p, 0);
+			if(p == nil)
+				error(Egrab);
+			r.max.y = strtol(cb->f[4], &p, 0);
+			if(p == nil)
+				error(Egrab);
+			if(!rectinrect(r, gscreen->clipr))
+				error(Egrab);
+			grabr = r;
+			grabchan = c;
+			grab = 1;
+			if(!ptinrect(mouse.xy, grabr))
+				absmousetrack(mouse.xy.x, mouse.xy.y, 0, 0);
+			break;
+
+		case CMrelease:
+			grab = 0;
+			grabchan = nil;
+			break;
+
 		case CMblanktime:
 			blanktime = strtoul(cb->f[1], 0, 0);
 			/* wet floor */
@@ -609,6 +654,17 @@
 		y = gscreen->clipr.min.y;
 	if(y >= gscreen->clipr.max.y)
 		y = gscreen->clipr.max.y-1;
+
+	if(grab){
+		if(x < grabr.min.x)
+			x = grabr.min.x;
+		if(x >= grabr.max.x)
+			x = grabr.max.x-1;
+		if(y < grabr.min.y)
+			y = grabr.min.y;
+		if(y >= grabr.max.y)
+			y = grabr.max.y-1;
+	}
 
 
 	ilock(&mouse);

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-12 19:50 [9front] Mouse clipping patch José Miguel Sánchez García
@ 2021-07-13  2:36 ` ori
  2021-07-13  2:45   ` ori
                     ` (2 more replies)
  2021-07-14 22:57 ` ori
  1 sibling, 3 replies; 42+ messages in thread
From: ori @ 2021-07-13  2:36 UTC (permalink / raw)
  To: 9front

Quoth José Miguel Sánchez García <soy.jmi2k@gmail.com>:
> think about vncv, qwx's quake ports, screenlock

Don't do this to vncv! Not grabbing the mouse makes it
much more usable.

For the other programs that can use it, I assume the
patches will follow up once we're happy with this patch
set?

> - Windows holding the mouse have a different border color,
> so they can be clearly identified.

Not sure that this is necessary. Your mouse being
constrained to the window is probably enough hint.

> +			write(mousectl->mctlfd, x->data, cnt);

This will hide all errors from the write, so
a malformed mousectl message will get silently
dropped.

> +extern int		clipmouse(Mousectl*, Rectangle);
> +extern void		releasemouse(Mousectl*);

This naming lacks symmetry.

How about constrainmouse()/releasemouse()?
Or if you feel cute: mousetrap()/mouserelease()?

Same with the ctl messages: trap/release, or clip/unclip?

> +			grabr.min.x = strtol(x->data+4, &p, 0);
> +			if(p == nil){

This isn't how strtol behaves -- if it can't convert
the number, it leaves p untouched. you need to do:

	grabr.min.x = strtol(p, &e, 0);
	if(p == e || *e != ' ')
		// error
	p = e;

You can probably clean it up a bit with tokenize(),
and then ensure that *e == '\0':

	if(tokenize(x->data+4, coords, 4) != 4)
		error()
	n = strtol(coords[0], &e, 0);
	if(*e != 0)
		error()

But also, do we need to do it? Is there any case
where we want to constrain the grab to anything
other than the whole window? What if the ctl
messages were just

	trap
	release

with no further parameters?


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13  2:36 ` ori
@ 2021-07-13  2:45   ` ori
  2021-07-13 14:03     ` Stuart Morrow
  2021-07-13  3:14   ` José Miguel Sánchez García
  2021-07-13 12:43   ` kvik
  2 siblings, 1 reply; 42+ messages in thread
From: ori @ 2021-07-13  2:45 UTC (permalink / raw)
  To: 9front

Quoth ori@eigenstate.org:
> 
> But also, do we need to do it? Is there any case
> where we want to constrain the grab to anything
> other than the whole window? What if the ctl
> messages were just
> 
> 	trap
> 	release
> 
> with no further parameters?
> 

Also: in addition to dropping rect parsing and
validation, we can keep the clip across resizes,
since there's no ambiguity around where it should
go: the client has no choice.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13  2:36 ` ori
  2021-07-13  2:45   ` ori
@ 2021-07-13  3:14   ` José Miguel Sánchez García
  2021-07-13  8:25     ` hiro
  2021-07-13 12:00     ` José Miguel Sánchez García
  2021-07-13 12:43   ` kvik
  2 siblings, 2 replies; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-13  3:14 UTC (permalink / raw)
  To: 9front

Let's see if I can do this quote thing correctly:

First of all: I'm aware of some bugs (and you pointed out others)!
I'll send the corrected patchset tomorrow.
The naming scheme is a bit messy as a result of a dropped feature.
I'll improve it too.

> Don't do this to vncv! Not grabbing the mouse makes it
> much more usable.

I'm aware of someone who will respectfully disagree :-)

> For the other programs that can use it, I assume the
> patches will follow up once we're happy with this patch
> set?

Sure, they'll come later. I wanted to keep them separated from these.

> Not sure that this is necessary. Your mouse being
> constrained to the window is probably enough hint.

Keep in mind that the border changes not only for the window currently
grabbing the window, but for any non-current window "grabbing" it too
(even if it doesn't apply because it's not focused). The different
border color serves as an indicator that, when you focus it, it will
grab your mouse. It might avoid an unpleasant surprise. However, if
you feel like it's redundant, it can be easily removed.

> But also, do we need to do it? Is there any case
> where we want to constrain the grab to anything
> other than the whole window? What if the ctl
> messages were just
>
>         trap
>         release
>
> with no further parameters?

The point of allowing arbitrary clip rects is to make the grabbing
program unaware of the existence of a window manager. Rio itself would
be an example of a program which doesn't grab the whole "window" (the
whole screen), but only subrects of it. In order to maintain an
uniform interface which works regardless of the presence of rio or
not, I've decided to go down the simplest route and just allow any
subrect of the whole screen to be clipped. It didn't require more code
or more complex handling, and it even allows future programs to take
advantage of this feature.

Hope it makes sense!

On Tue, Jul 13, 2021 at 4:53 AM <ori@eigenstate.org> wrote:
>
> Quoth José Miguel Sánchez García <soy.jmi2k@gmail.com>:
> > think about vncv, qwx's quake ports, screenlock
>
> Don't do this to vncv! Not grabbing the mouse makes it
> much more usable.
>
> For the other programs that can use it, I assume the
> patches will follow up once we're happy with this patch
> set?
>
> > - Windows holding the mouse have a different border color,
> > so they can be clearly identified.
>
> Not sure that this is necessary. Your mouse being
> constrained to the window is probably enough hint.
>
> > +                     write(mousectl->mctlfd, x->data, cnt);
>
> This will hide all errors from the write, so
> a malformed mousectl message will get silently
> dropped.
>
> > +extern int           clipmouse(Mousectl*, Rectangle);
> > +extern void          releasemouse(Mousectl*);
>
> This naming lacks symmetry.
>
> How about constrainmouse()/releasemouse()?
> Or if you feel cute: mousetrap()/mouserelease()?
>
> Same with the ctl messages: trap/release, or clip/unclip?
>
> > +                     grabr.min.x = strtol(x->data+4, &p, 0);
> > +                     if(p == nil){
>
> This isn't how strtol behaves -- if it can't convert
> the number, it leaves p untouched. you need to do:
>
>         grabr.min.x = strtol(p, &e, 0);
>         if(p == e || *e != ' ')
>                 // error
>         p = e;
>
> You can probably clean it up a bit with tokenize(),
> and then ensure that *e == '\0':
>
>         if(tokenize(x->data+4, coords, 4) != 4)
>                 error()
>         n = strtol(coords[0], &e, 0);
>         if(*e != 0)
>                 error()
>
> But also, do we need to do it? Is there any case
> where we want to constrain the grab to anything
> other than the whole window? What if the ctl
> messages were just
>
>         trap
>         release
>
> with no further parameters?
>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13  3:14   ` José Miguel Sánchez García
@ 2021-07-13  8:25     ` hiro
  2021-07-13 10:27       ` José Miguel Sánchez García
  2021-07-13 12:00     ` José Miguel Sánchez García
  1 sibling, 1 reply; 42+ messages in thread
From: hiro @ 2021-07-13  8:25 UTC (permalink / raw)
  To: 9front

so hitting delete will always make the user escape if an unbehaving
evil program does the clip?
or is there another standard way for the end-user to escape this?

On 7/13/21, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> Let's see if I can do this quote thing correctly:
>
> First of all: I'm aware of some bugs (and you pointed out others)!
> I'll send the corrected patchset tomorrow.
> The naming scheme is a bit messy as a result of a dropped feature.
> I'll improve it too.
>
>> Don't do this to vncv! Not grabbing the mouse makes it
>> much more usable.
>
> I'm aware of someone who will respectfully disagree :-)
>
>> For the other programs that can use it, I assume the
>> patches will follow up once we're happy with this patch
>> set?
>
> Sure, they'll come later. I wanted to keep them separated from these.
>
>> Not sure that this is necessary. Your mouse being
>> constrained to the window is probably enough hint.
>
> Keep in mind that the border changes not only for the window currently
> grabbing the window, but for any non-current window "grabbing" it too
> (even if it doesn't apply because it's not focused). The different
> border color serves as an indicator that, when you focus it, it will
> grab your mouse. It might avoid an unpleasant surprise. However, if
> you feel like it's redundant, it can be easily removed.
>
>> But also, do we need to do it? Is there any case
>> where we want to constrain the grab to anything
>> other than the whole window? What if the ctl
>> messages were just
>>
>>         trap
>>         release
>>
>> with no further parameters?
>
> The point of allowing arbitrary clip rects is to make the grabbing
> program unaware of the existence of a window manager. Rio itself would
> be an example of a program which doesn't grab the whole "window" (the
> whole screen), but only subrects of it. In order to maintain an
> uniform interface which works regardless of the presence of rio or
> not, I've decided to go down the simplest route and just allow any
> subrect of the whole screen to be clipped. It didn't require more code
> or more complex handling, and it even allows future programs to take
> advantage of this feature.
>
> Hope it makes sense!
>
> On Tue, Jul 13, 2021 at 4:53 AM <ori@eigenstate.org> wrote:
>>
>> Quoth José Miguel Sánchez García <soy.jmi2k@gmail.com>:
>> > think about vncv, qwx's quake ports, screenlock
>>
>> Don't do this to vncv! Not grabbing the mouse makes it
>> much more usable.
>>
>> For the other programs that can use it, I assume the
>> patches will follow up once we're happy with this patch
>> set?
>>
>> > - Windows holding the mouse have a different border color,
>> > so they can be clearly identified.
>>
>> Not sure that this is necessary. Your mouse being
>> constrained to the window is probably enough hint.
>>
>> > +                     write(mousectl->mctlfd, x->data, cnt);
>>
>> This will hide all errors from the write, so
>> a malformed mousectl message will get silently
>> dropped.
>>
>> > +extern int           clipmouse(Mousectl*, Rectangle);
>> > +extern void          releasemouse(Mousectl*);
>>
>> This naming lacks symmetry.
>>
>> How about constrainmouse()/releasemouse()?
>> Or if you feel cute: mousetrap()/mouserelease()?
>>
>> Same with the ctl messages: trap/release, or clip/unclip?
>>
>> > +                     grabr.min.x = strtol(x->data+4, &p, 0);
>> > +                     if(p == nil){
>>
>> This isn't how strtol behaves -- if it can't convert
>> the number, it leaves p untouched. you need to do:
>>
>>         grabr.min.x = strtol(p, &e, 0);
>>         if(p == e || *e != ' ')
>>                 // error
>>         p = e;
>>
>> You can probably clean it up a bit with tokenize(),
>> and then ensure that *e == '\0':
>>
>>         if(tokenize(x->data+4, coords, 4) != 4)
>>                 error()
>>         n = strtol(coords[0], &e, 0);
>>         if(*e != 0)
>>                 error()
>>
>> But also, do we need to do it? Is there any case
>> where we want to constrain the grab to anything
>> other than the whole window? What if the ctl
>> messages were just
>>
>>         trap
>>         release
>>
>> with no further parameters?
>>
>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13  8:25     ` hiro
@ 2021-07-13 10:27       ` José Miguel Sánchez García
  2021-07-13 14:05         ` Stuart Morrow
  0 siblings, 1 reply; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-13 10:27 UTC (permalink / raw)
  To: 9front

There is none, but that's a different issue (it could be easily solved
if rio provided an "uncurrent" key or an alt-tab-like key. I feel like
that belongs to another patch). Unfocusing the window deactivates the
grab, and I'm trying hard not to say release: the grab is still there,
just doesn't apply if the window is not focused. Focus that window
again and its grab will be applied again like nothing happened.

On Tue, Jul 13, 2021 at 12:19 PM hiro <23hiro@gmail.com> wrote:
>
> so hitting delete will always make the user escape if an unbehaving
> evil program does the clip?
> or is there another standard way for the end-user to escape this?
>
> On 7/13/21, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> > Let's see if I can do this quote thing correctly:
> >
> > First of all: I'm aware of some bugs (and you pointed out others)!
> > I'll send the corrected patchset tomorrow.
> > The naming scheme is a bit messy as a result of a dropped feature.
> > I'll improve it too.
> >
> >> Don't do this to vncv! Not grabbing the mouse makes it
> >> much more usable.
> >
> > I'm aware of someone who will respectfully disagree :-)
> >
> >> For the other programs that can use it, I assume the
> >> patches will follow up once we're happy with this patch
> >> set?
> >
> > Sure, they'll come later. I wanted to keep them separated from these.
> >
> >> Not sure that this is necessary. Your mouse being
> >> constrained to the window is probably enough hint.
> >
> > Keep in mind that the border changes not only for the window currently
> > grabbing the window, but for any non-current window "grabbing" it too
> > (even if it doesn't apply because it's not focused). The different
> > border color serves as an indicator that, when you focus it, it will
> > grab your mouse. It might avoid an unpleasant surprise. However, if
> > you feel like it's redundant, it can be easily removed.
> >
> >> But also, do we need to do it? Is there any case
> >> where we want to constrain the grab to anything
> >> other than the whole window? What if the ctl
> >> messages were just
> >>
> >>         trap
> >>         release
> >>
> >> with no further parameters?
> >
> > The point of allowing arbitrary clip rects is to make the grabbing
> > program unaware of the existence of a window manager. Rio itself would
> > be an example of a program which doesn't grab the whole "window" (the
> > whole screen), but only subrects of it. In order to maintain an
> > uniform interface which works regardless of the presence of rio or
> > not, I've decided to go down the simplest route and just allow any
> > subrect of the whole screen to be clipped. It didn't require more code
> > or more complex handling, and it even allows future programs to take
> > advantage of this feature.
> >
> > Hope it makes sense!
> >
> > On Tue, Jul 13, 2021 at 4:53 AM <ori@eigenstate.org> wrote:
> >>
> >> Quoth José Miguel Sánchez García <soy.jmi2k@gmail.com>:
> >> > think about vncv, qwx's quake ports, screenlock
> >>
> >> Don't do this to vncv! Not grabbing the mouse makes it
> >> much more usable.
> >>
> >> For the other programs that can use it, I assume the
> >> patches will follow up once we're happy with this patch
> >> set?
> >>
> >> > - Windows holding the mouse have a different border color,
> >> > so they can be clearly identified.
> >>
> >> Not sure that this is necessary. Your mouse being
> >> constrained to the window is probably enough hint.
> >>
> >> > +                     write(mousectl->mctlfd, x->data, cnt);
> >>
> >> This will hide all errors from the write, so
> >> a malformed mousectl message will get silently
> >> dropped.
> >>
> >> > +extern int           clipmouse(Mousectl*, Rectangle);
> >> > +extern void          releasemouse(Mousectl*);
> >>
> >> This naming lacks symmetry.
> >>
> >> How about constrainmouse()/releasemouse()?
> >> Or if you feel cute: mousetrap()/mouserelease()?
> >>
> >> Same with the ctl messages: trap/release, or clip/unclip?
> >>
> >> > +                     grabr.min.x = strtol(x->data+4, &p, 0);
> >> > +                     if(p == nil){
> >>
> >> This isn't how strtol behaves -- if it can't convert
> >> the number, it leaves p untouched. you need to do:
> >>
> >>         grabr.min.x = strtol(p, &e, 0);
> >>         if(p == e || *e != ' ')
> >>                 // error
> >>         p = e;
> >>
> >> You can probably clean it up a bit with tokenize(),
> >> and then ensure that *e == '\0':
> >>
> >>         if(tokenize(x->data+4, coords, 4) != 4)
> >>                 error()
> >>         n = strtol(coords[0], &e, 0);
> >>         if(*e != 0)
> >>                 error()
> >>
> >> But also, do we need to do it? Is there any case
> >> where we want to constrain the grab to anything
> >> other than the whole window? What if the ctl
> >> messages were just
> >>
> >>         trap
> >>         release
> >>
> >> with no further parameters?
> >>
> >

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13  3:14   ` José Miguel Sánchez García
  2021-07-13  8:25     ` hiro
@ 2021-07-13 12:00     ` José Miguel Sánchez García
  1 sibling, 0 replies; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-13 12:00 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 5229 bytes --]

Here are the fixed patches:

- The libdraw patch wouldn't compile due to a missing declaration. Oops!
- Fixed a bug where clicking a window border wouldn't focus it (kvik
noticed it right away).
- Fixed the rect parsing code in rio.
- Changed naming convention to clip/unclip.
- Documented my changes in mouse(2) and mouse(3).

I've included a patch for qwx's quake2
(https://shithub.us/qwx/qk2/HEAD/info.html) which, while not replacing
the old grabbing behavior, makes it impossible for the cursor to
escape the window. It relies on the forced unclip (no unclipmouse to
be seen in the code), so it also serves as a demonstration of that
feature.
Finally, I've also included a simple rc script to clip the mouse. I've
used it to test all the interactions of this new clip feature with
rio, as it's easy to invoke, easy to kill with Del, and you have
access to rio menus (so you can "exit the clip" by creating a new
window which unfocuses the current one).

On Tue, Jul 13, 2021 at 5:14 AM José Miguel Sánchez García
<soy.jmi2k@gmail.com> wrote:
>
> Let's see if I can do this quote thing correctly:
>
> First of all: I'm aware of some bugs (and you pointed out others)!
> I'll send the corrected patchset tomorrow.
> The naming scheme is a bit messy as a result of a dropped feature.
> I'll improve it too.
>
> > Don't do this to vncv! Not grabbing the mouse makes it
> > much more usable.
>
> I'm aware of someone who will respectfully disagree :-)
>
> > For the other programs that can use it, I assume the
> > patches will follow up once we're happy with this patch
> > set?
>
> Sure, they'll come later. I wanted to keep them separated from these.
>
> > Not sure that this is necessary. Your mouse being
> > constrained to the window is probably enough hint.
>
> Keep in mind that the border changes not only for the window currently
> grabbing the window, but for any non-current window "grabbing" it too
> (even if it doesn't apply because it's not focused). The different
> border color serves as an indicator that, when you focus it, it will
> grab your mouse. It might avoid an unpleasant surprise. However, if
> you feel like it's redundant, it can be easily removed.
>
> > But also, do we need to do it? Is there any case
> > where we want to constrain the grab to anything
> > other than the whole window? What if the ctl
> > messages were just
> >
> >         trap
> >         release
> >
> > with no further parameters?
>
> The point of allowing arbitrary clip rects is to make the grabbing
> program unaware of the existence of a window manager. Rio itself would
> be an example of a program which doesn't grab the whole "window" (the
> whole screen), but only subrects of it. In order to maintain an
> uniform interface which works regardless of the presence of rio or
> not, I've decided to go down the simplest route and just allow any
> subrect of the whole screen to be clipped. It didn't require more code
> or more complex handling, and it even allows future programs to take
> advantage of this feature.
>
> Hope it makes sense!
>
> On Tue, Jul 13, 2021 at 4:53 AM <ori@eigenstate.org> wrote:
> >
> > Quoth José Miguel Sánchez García <soy.jmi2k@gmail.com>:
> > > think about vncv, qwx's quake ports, screenlock
> >
> > Don't do this to vncv! Not grabbing the mouse makes it
> > much more usable.
> >
> > For the other programs that can use it, I assume the
> > patches will follow up once we're happy with this patch
> > set?
> >
> > > - Windows holding the mouse have a different border color,
> > > so they can be clearly identified.
> >
> > Not sure that this is necessary. Your mouse being
> > constrained to the window is probably enough hint.
> >
> > > +                     write(mousectl->mctlfd, x->data, cnt);
> >
> > This will hide all errors from the write, so
> > a malformed mousectl message will get silently
> > dropped.
> >
> > > +extern int           clipmouse(Mousectl*, Rectangle);
> > > +extern void          releasemouse(Mousectl*);
> >
> > This naming lacks symmetry.
> >
> > How about constrainmouse()/releasemouse()?
> > Or if you feel cute: mousetrap()/mouserelease()?
> >
> > Same with the ctl messages: trap/release, or clip/unclip?
> >
> > > +                     grabr.min.x = strtol(x->data+4, &p, 0);
> > > +                     if(p == nil){
> >
> > This isn't how strtol behaves -- if it can't convert
> > the number, it leaves p untouched. you need to do:
> >
> >         grabr.min.x = strtol(p, &e, 0);
> >         if(p == e || *e != ' ')
> >                 // error
> >         p = e;
> >
> > You can probably clean it up a bit with tokenize(),
> > and then ensure that *e == '\0':
> >
> >         if(tokenize(x->data+4, coords, 4) != 4)
> >                 error()
> >         n = strtol(coords[0], &e, 0);
> >         if(*e != 0)
> >                 error()
> >
> > But also, do we need to do it? Is there any case
> > where we want to constrain the grab to anything
> > other than the whole window? What if the ctl
> > messages were just
> >
> >         trap
> >         release
> >
> > with no further parameters?
> >

[-- Attachment #2: rio-mouseclip.diff --]
[-- Type: application/octet-stream, Size: 8225 bytes --]

--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/dat.h
+++ /sys/src/cmd/rio/dat.h
@@ -10,6 +10,7 @@
 	Qlabel,
 	Qkbd,
 	Qmouse,
+	Qmousectl,
 	Qnew,
 	Qscreen,
 	Qsnarf,
@@ -154,6 +155,9 @@
 	 * Now they're always the same but the code doesn't assume so.
 	*/
 	Rectangle		screenr;	/* screen coordinates of window */
+	Rectangle	mclipr;
+	Fid			*mclipfid;
+	int			mclip;
 	int			resized;
 	int			wctlready;
 	Rectangle		lastsr;
@@ -304,11 +308,14 @@
 Image	*lightholdcol;
 Image	*paleholdcol;
 Image	*paletextcol;
+Image	*grabcol;
+Image	*lightgrabcol;
 Image	*sizecol;
 int	reverse;	/* there are no pastel paints in the dungeons and dragons world -- rob pike */
 
 Window	**window;
 Window	*wkeyboard;	/* window of simulated keyboard */
+Window	*wclip;
 int		nwindow;
 int		snarffd;
 int		gotscreen;
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/data.c
+++ /sys/src/cmd/rio/data.c
@@ -195,6 +195,8 @@
 	lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreyblue);
 	paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreyblue);
 	paletextcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF^reverse);
+	grabcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xB22222FF);
+	lightgrabcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCD5C5CFF);
 	sizecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DRed);
 
 	if(reverse == 0)
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/fns.h
+++ /sys/src/cmd/rio/fns.h
@@ -5,6 +5,7 @@
 int	writewctl(Xfid*, char*);
 Window *new(Image*, int, int, int, char*, char*, char**);
 void	riosetcursor(Cursor*);
+void	updatemclip(void);
 int	min(int, int);
 int	max(int, int);
 Rune*	strrune(Rune*, Rune);
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/fsys.c
+++ /sys/src/cmd/rio/fsys.c
@@ -30,6 +30,7 @@
 	{ "label",		QTFILE,	Qlabel,		0600 },
 	{ "kbd",	QTFILE,	Qkbd,		0600 },
 	{ "mouse",	QTFILE,	Qmouse,		0600 },
+	{ "mousectl",	QTFILE,	Qmousectl,		0600 },
 	{ "screen",		QTFILE,	Qscreen,		0400 },
 	{ "snarf",		QTFILE,	Qsnarf,		0600 },
 	{ "text",		QTFILE,	Qtext,		0600 },
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/rio.c
+++ /sys/src/cmd/rio/rio.c
@@ -327,6 +327,27 @@
 }
 
 void
+updatemclip(void)
+{
+	Window *w;
+
+	if(input == nil || !input->mclip || menuing || sweeping)
+		w = nil;
+	else
+		w = input;
+	if(w == wclip)
+		return;
+	if(w != nil){
+		clipmouse(mousectl, w->mclipr);
+		wsendctlmesg(w, Repaint, ZR, nil);
+	}else
+		unclipmouse(mousectl);
+	if(wclip)
+		wsendctlmesg(wclip, Repaint, ZR, nil);
+	wclip = w;
+}
+
+void
 killprocs(void)
 {
 	int i;
@@ -489,6 +510,9 @@
 				wtopme(wkeyboard);
 				winput = wkeyboard;
 			}
+			w = wpointto(mouse->xy);
+			if(sending == FALSE && !scrolling && w!=nil && !w->deleted && inborder(w->screenr, mouse->xy))
+				moving = TRUE;
 			if(winput!=nil && !winput->deleted && winput->i!=nil){
 				/* convert to logical coordinates */
 				xy.x = mouse->xy.x + (winput->i->r.min.x-winput->screenr.min.x);
@@ -505,10 +529,7 @@
 					scrolling = mouse->buttons;
 				else
 					scrolling = mouse->buttons && ptinrect(xy, winput->scrollr);
-				/* topped will be zero or less if window has been bottomed */
-				if(sending == FALSE && !scrolling && inborder(winput->screenr, mouse->xy) && winput->topped>0)
-					moving = TRUE;
-				else if(inside && (scrolling || winput->mouseopen || (mouse->buttons&1)))
+				if(inside && (scrolling || winput->mouseopen || (mouse->buttons&1)))
 					sending = TRUE;
 			}else
 				sending = FALSE;
@@ -523,21 +544,21 @@
 				continue;
 			}
 			if(moving && (mouse->buttons&7)){
-				incref(winput);
+				incref(w);
 				sweeping = TRUE;
 				if(mouse->buttons & 3)
-					i = bandsize(winput);
+					i = bandsize(w);
 				else
-					i = drag(winput);
+					i = drag(w);
 				sweeping = FALSE;
-				if(i != nil){
-					wcurrent(winput);
-					wsendctlmesg(winput, Reshaped, i->r, i);
-				}
-				wclose(winput);
+				if(i != nil)
+					wsendctlmesg(w, Reshaped, i->r, i);
+				wcurrent(w);
+				wtopme(w);
+				wsendctlmesg(w, Topped, ZR, nil);
+				wclose(w);
 				continue;
 			}
-			w = wpointto(mouse->xy);
 			if(w!=nil && inborder(w->screenr, mouse->xy))
 				riosetcursor(corners[whichcorner(w->screenr, mouse->xy)]);
 			else
@@ -715,6 +736,7 @@
 		menu3str[i] = nil;
 	}
 	sweeping = TRUE;
+	updatemclip();
 	switch(i = menuhit(3, mousectl, &menu3, wscreen)){
 	case -1:
 		break;
@@ -744,6 +766,7 @@
 		break;
 	}
 	sweeping = FALSE;
+	updatemclip();
 }
 
 void
@@ -753,6 +776,8 @@
 		menu2str[Scroll] = "noscroll";
 	else
 		menu2str[Scroll] = "scroll";
+	sweeping = TRUE;
+	updatemclip();
 	switch(menuhit(2, mousectl, &menu2, wscreen)){
 	case Cut:
 		wsnarf(w);
@@ -787,6 +812,8 @@
 			wshow(w, w->nr);
 		break;
 	}
+	sweeping = FALSE;
+	updatemclip();
 	flushimage(display, 1);
 	wsendctlmesg(w, Wakeup, ZR, nil);
 }
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/wind.c
+++ /sys/src/cmd/rio/wind.c
@@ -302,6 +302,11 @@
 			col = holdcol;
 		else
 			col = paleholdcol;
+	}else if(w->mclip){
+		if(type == Selborder)
+			col = grabcol;
+		else
+			col = lightgrabcol;
 	}else{
 		if(type == Selborder)
 			col = titlecol;
@@ -358,6 +363,8 @@
 	w->scrollr.max.x = r.min.x+Scrollwid;
 	w->lastsr = ZR;
 	r.min.x += Scrollwid+Scrollgap;
+	w->mclip = FALSE;
+	updatemclip();
 	frclear(w, FALSE);
 	frinit(w, r, w->font, w->i, cols);
 	wsetcols(w, w == input);
@@ -1264,6 +1271,7 @@
 	w->gone = chancreate(sizeof(char*), 0);
 	w->scrollr = r;
 	w->scrollr.max.x = r.min.x+Scrollwid;
+	w->mclip = FALSE;
 	w->lastsr = ZR;
 	r.min.x += Scrollwid+Scrollgap;
 	frinit(w, r, font, i, cols);
@@ -1306,6 +1314,7 @@
 		input = nil;
 		riosetcursor(nil);
 	}
+	updatemclip();
 	if(w == wkeyboard)
 		wkeyboard = nil;
 	for(i=0; i<nhidden; i++)
@@ -1390,6 +1399,7 @@
 
 			sendp(c, w);
 		}
+		updatemclip();
 		if(w->i==nil || Dx(w->screenr)<=0)
 			break;
 		wrepaint(w);
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/cmd/rio/xfid.c
+++ /sys/src/cmd/rio/xfid.c
@@ -18,6 +18,7 @@
 char Elong[] = 		"snarf buffer too long";
 char Eunkid[] = 	"unknown id in attach";
 char Ebadrect[] = 	"bad rectangle in attach";
+char Eclip[] =		"invalid clip rectangle";
 char Ewindow[] = 	"cannot make window";
 char Enowindow[] = 	"window has no image";
 char Ebadmouse[] = 	"bad format on /dev/mouse";
@@ -342,6 +343,14 @@
 	case Qkbd:
 		w->kbdopen = FALSE;
 		break;
+	case Qmousectl:
+		if(w->mclip && w->mclipfid == x->f){
+			w->mclip = FALSE;
+			w->mclipfid = nil;
+			updatemclip();
+			wsendctlmesg(w, Repaint, ZR, nil);
+		}
+		break;
 	case Qmouse:
 		w->resized = FALSE;
 		w->mouseopen = FALSE;
@@ -371,7 +380,8 @@
 {
 	Fcall fc;
 	int cnt, qid, nb, off, nr;
-	char err[ERRMAX], *p;
+	char err[ERRMAX], *coords[4], *p;
+	Rectangle mclipr;
 	Point pt;
 	Window *w;
 	Rune *r;
@@ -500,6 +510,50 @@
 		w->label = p;
 		w->label[cnt] = 0;
 		memmove(w->label, x->data, cnt);
+		break;
+
+	case Qmousectl:
+		if(strncmp(x->data, "clip", 4)==0){
+			if(tokenize(x->data+4, coords, 4)!=4){
+				filsysrespond(x->fs, x, &fc, Eclip);
+				return;
+			}
+			mclipr.min.x = strtol(coords[0], &p, 0);
+			if(*p != '\0'){
+				filsysrespond(x->fs, x, &fc, Eclip);
+				return;
+			}
+			mclipr.min.y = strtol(coords[1], &p, 0);
+			if(*p != '\0'){
+				filsysrespond(x->fs, x, &fc, Eclip);
+				return;
+			}
+			mclipr.max.x = strtol(coords[2], &p, 0);
+			if(*p != '\0'){
+				filsysrespond(x->fs, x, &fc, Eclip);
+				return;
+			}
+			mclipr.max.y = strtol(coords[3], &p, 0);
+			if(*p != '\0'){
+				filsysrespond(x->fs, x, &fc, Eclip);
+				return;
+			}
+			if(!rectinrect(mclipr, w->screenr)){
+				filsysrespond(x->fs, x, &fc, Eclip);
+				return;
+			}
+			w->mclipr = mclipr;
+			w->mclipfid = x->f;
+			w->mclip = TRUE;
+			updatemclip();
+			wsendctlmesg(w, Repaint, ZR, nil);
+		}else if(strncmp(x->data, "unclip", 6)==0){
+			w->mclip = FALSE;
+			w->mclipfid = nil;
+			updatemclip();
+			wsendctlmesg(w, Repaint, ZR, nil);
+		}else
+			write(mousectl->mctlfd, x->data, cnt);
 		break;
 
 	case Qmouse:

[-- Attachment #3: devmouse-clip.diff --]
[-- Type: application/octet-stream, Size: 2407 bytes --]

--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/9/port/devmouse.c
+++ /sys/src/9/port/devmouse.c
@@ -18,6 +18,8 @@
 	ScrollRight = 0x40,
 };
 
+char Eclip[] = "invalid clip rectangle";
+
 typedef struct Mouseinfo	Mouseinfo;
 typedef struct Mousestate	Mousestate;
 
@@ -53,6 +55,8 @@
 	CMbuttonmap,
 	CMscrollswap,
 	CMswap,
+	CMclip,
+	CMunclip,
 	CMblank,
 	CMblanktime,
 	CMtwitch,
@@ -64,6 +68,8 @@
 	CMbuttonmap,	"buttonmap",	0,
 	CMscrollswap,	"scrollswap",	0,
 	CMswap,		"swap",		1,
+	CMclip,		"clip",		0,
+	CMunclip,	"unclip",	1,
 	CMblank,	"blank",	1,
 	CMblanktime,	"blanktime",	2,
 	CMtwitch,	"twitch",	1,
@@ -95,6 +101,9 @@
 static uchar buttonmap[8] = {
 	0, 1, 2, 3, 4, 5, 6, 7,
 };
+static Rectangle clipr;
+static Chan *clipchan;
+static int clip;
 static int mouseswap;
 static int scrollswap;
 static ulong mousetime;
@@ -206,6 +215,10 @@
 	if((c->qid.type&QTDIR)!=0 || (c->flag&COPEN)==0)
 		return;
 	switch((ulong)c->qid.path){
+	case Qmousectl:
+		if(c == clipchan)
+			clip = 0;
+		break;
 	case Qmousein:
 		mouse.inbuttons &= ~((Mousestate*)c->aux)->buttons;
 		free(c->aux);	/* Mousestate */
@@ -344,6 +357,7 @@
 mousewrite(Chan *c, void *va, long n, vlong)
 {
 	char *p;
+	Rectangle r;
 	Point pt;
 	Cmdbuf *cb;
 	Cmdtab *ct;
@@ -403,6 +417,37 @@
 			mouseblankscreen(1);
 			break;
 
+		case CMclip:
+			if(cb->nf < 5)
+				error(Eshort);
+			if(!gscreen)
+				break;
+			r.min.x = strtol(cb->f[1], &p, 0);
+			if(p == nil)
+				error(Eclip);
+			r.min.y = strtol(cb->f[2], &p, 0);
+			if(p == nil)
+				error(Eclip);
+			r.max.x = strtol(cb->f[3], &p, 0);
+			if(p == nil)
+				error(Eclip);
+			r.max.y = strtol(cb->f[4], &p, 0);
+			if(p == nil)
+				error(Eclip);
+			if(!rectinrect(r, gscreen->clipr))
+				error(Eclip);
+			clipr = r;
+			clipchan = c;
+			clip = 1;
+			if(!ptinrect(mouse.xy, clipr))
+				absmousetrack(mouse.xy.x, mouse.xy.y, 0, 0);
+			break;
+
+		case CMunclip:
+			clip = 0;
+			clipchan = nil;
+			break;
+
 		case CMblanktime:
 			blanktime = strtoul(cb->f[1], 0, 0);
 			/* wet floor */
@@ -609,6 +654,17 @@
 		y = gscreen->clipr.min.y;
 	if(y >= gscreen->clipr.max.y)
 		y = gscreen->clipr.max.y-1;
+
+	if(clip){
+		if(x < clipr.min.x)
+			x = clipr.min.x;
+		if(x >= clipr.max.x)
+			x = clipr.max.x-1;
+		if(y < clipr.min.y)
+			y = clipr.min.y;
+		if(y >= clipr.max.y)
+			y = clipr.max.y-1;
+	}
 
 
 	ilock(&mouse);

[-- Attachment #4: grab.rc --]
[-- Type: application/octet-stream, Size: 120 bytes --]

#!/bin/rc

read -c 59 /dev/window | awk '{print "clip", $2+4, $3+4, $4-4, $5-4}' |[3=1] cat /fd/3 /fd/0 >>/dev/mousectl

[-- Attachment #5: man-mouseclip.diff --]
[-- Type: application/octet-stream, Size: 1826 bytes --]

--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/man/2/mouse
+++ /sys/man/2/mouse
@@ -29,6 +29,12 @@
 void		moveto(Mousectl *mc, Point pt)
 .PP
 .B
+int		clipmouse(Mousectl *mc, Rectangle r)
+.PP
+.B
+void		unclipmouse(Mousectl *mc)
+.PP
+.B
 void		setcursor(Mousectl *mc, Cursor *c)
 .PP
 .B
@@ -96,6 +102,7 @@
 
 	char	*file;
 	int	mfd;		/* to mouse file */
+	int	mctlfd;		/* to mousectl file */
 	int	cfd;		/* to cursor file */
 	int	pid;		/* of slave proc */
 	Image*	image;	/* of associated window/display */
@@ -164,6 +171,12 @@
 .I Moveto
 moves the mouse cursor on the display to the position specified by
 .IR pt .
+.PP
+.I Clipmouse
+restricts the mouse movement to the area inside
+.IR r .
+.I Unclipmouse
+frees the mouse of any previous clip operation.
 .PP
 .I Setcursor
 sets the image of the cursor to that specified by
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/man/3/mouse
+++ /sys/man/3/mouse
@@ -171,6 +171,15 @@
 .B twitch
 unblanks the screen and resets the idle timeout as if the
 mouse was twitched.
+.TP
+.BI clip " x0" " y0" " x1" " y1"
+restricts the mouse movement to the area inside the provided rectangle.
+The provided rectangle must be fully contained inside the screen.
+.TP
+.BI unclip
+undoes any previous
+.I clip
+operations, letting the mouse move freely across the screen.
 .PD
 .PP
 Not all mice interpret all messages; with some devices,
@@ -203,6 +212,13 @@
 file sets the current cursor information.
 A write of fewer than 72 bytes sets the
 cursor to the default, an arrow.
+.PP
+A
+.I clip
+is valid as long as the file that requested it is kept open.
+When it's closed, the clip is forcibly released.
+This is a security mechanism against crashing apps,
+which would otherwise leave an unwanted active grab.
 .PP
 The
 .B mouse

[-- Attachment #6: libdraw-mouseclip.diff --]
[-- Type: application/octet-stream, Size: 2061 bytes --]

--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/include/mouse.h
+++ /sys/include/mouse.h
@@ -22,6 +22,7 @@
 
 	char		*file;
 	int		mfd;		/* to mouse file */
+	int		mctlfd;		/* to mousectl file */
 	int		cfd;		/* to cursor file */
 	int		pid;		/* of slave proc */
 	Image*	image;	/* of associated window/display */
@@ -39,6 +40,8 @@
  */
 extern Mousectl*	initmouse(char*, Image*);
 extern void		moveto(Mousectl*, Point);
+extern int		clipmouse(Mousectl*, Rectangle);
+extern void		unclipmouse(Mousectl*);
 extern int			readmouse(Mousectl*);
 extern void		closemouse(Mousectl*);
 extern void		setcursor(Mousectl*, Cursor*);
--- //.git/fs/object/2f8a59f4b5bfe028c022855acc19666d69eed909/tree//sys/src/libdraw/mouse.c
+++ /sys/src/libdraw/mouse.c
@@ -12,14 +12,35 @@
 	m->xy = pt;
 }
 
+int
+clipmouse(Mousectl *m, Rectangle r)
+{
+	char buf[128];
+	long n;
+
+	n = snprint(buf, sizeof(buf), "clip %d %d %d %d",
+		r.min.x, r.min.y,
+		r.max.x, r.max.y);
+	if(write(m->mctlfd, buf, n) != n)
+		return -1;
+	return 0;
+}
+
 void
+unclipmouse(Mousectl *m)
+{
+	fprint(m->mctlfd, "unclip");
+}
+
+void
 closemouse(Mousectl *mc)
 {
 	if(mc == nil)
 		return;
 	close(mc->mfd);
+	close(mc->mctlfd);
 	close(mc->cfd);
-	mc->mfd = mc->cfd = -1;
+	mc->mfd = mc->mctlfd = mc->cfd = -1;
 	threadint(mc->pid);
 }
 
@@ -96,6 +117,7 @@
 {
 	Mousectl *mc;
 	char *t, *sl;
+	long n;
 
 	mc = mallocz(sizeof(Mousectl), 1);
 	if(file == nil)
@@ -106,18 +128,25 @@
 		free(mc);
 		return nil;
 	}
-	t = malloc(strlen(file)+16);
+	n = strlen(file)+16;
+	t = malloc(n);
 	if (t == nil) {
 		close(mc->mfd);
 		free(mc);
 		return nil;
 	}
-	strcpy(t, file);
+	seprint(t, t+n, "%s", file);
+	strcat(t, "ctl");
 	sl = utfrrune(t, '/');
 	if(sl)
-		strcpy(sl, "/cursor");
+		seprint(sl, t+n, "/mousectl");
 	else
-		strcpy(t, "/dev/cursor");
+		seprint(t, t+n, "/dev/mousectl");
+	mc->mctlfd = open(t, ORDWR|OCEXEC);
+	if(sl)
+		seprint(sl, t+n, "/cursor");
+	else
+		seprint(t, t+n, "/dev/cursor");
 	mc->cfd = open(t, ORDWR|OCEXEC);
 	free(t);
 	mc->image = i;

[-- Attachment #7: qk2-mouseclip.diff --]
[-- Type: application/octet-stream, Size: 1113 bytes --]

--- /usr/glenda/qk2/.git/fs/object/a4c4b45d8b2136733c76a4b86c7896bfa939ad25/tree/dat.h
+++ dat.h
@@ -2930,3 +2930,4 @@
 
 extern edict_t *sv_player;
 extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
+extern int mctlfd;
--- /usr/glenda/qk2/.git/fs/object/a4c4b45d8b2136733c76a4b86c7896bfa939ad25/tree/sys.c
+++ sys.c
@@ -7,6 +7,7 @@
 #include "fns.h"
 
 void KBD_Update(void);
+int mctlfd;
 
 mainstacksize = 512*1024;
 int curtime;
@@ -398,6 +399,7 @@
 	int time, oldtime, newtime;
 
 	setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV));	/* assumed ignored in code */
+	mctlfd = open("/dev/mousectl", OWRITE);
 	notify(croak);
 
 	srand(getpid());
--- /usr/glenda/qk2/.git/fs/object/a4c4b45d8b2136733c76a4b86c7896bfa939ad25/tree/vid.c
+++ vid.c
@@ -86,6 +86,7 @@
 		sysfatal("allocimage: %r");
 	vid.buffer = fb;
 	vid.rowbytes = vid.width * sizeof *fbpal;
+	fprint(mctlfd, "clip %d %d %d %d", screen->r.min.x, screen->r.min.y, screen->r.max.x, screen->r.max.y);
 	center = addpt(screen->r.min, Pt(vid.width/2, vid.height/2));
 	p = Pt(vid.width/4, vid.height/4);
 	grabr = Rpt(subpt(center, p), addpt(center, p));

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13  2:36 ` ori
  2021-07-13  2:45   ` ori
  2021-07-13  3:14   ` José Miguel Sánchez García
@ 2021-07-13 12:43   ` kvik
  2021-07-13 13:36     ` hiro
  2 siblings, 1 reply; 42+ messages in thread
From: kvik @ 2021-07-13 12:43 UTC (permalink / raw)
  To: 9front

Quoth ori@eigenstate.org:
> Don't do this to vncv! Not grabbing the mouse makes it
> much more usable.

vncv(1) grabbing was my prime use-case!

There's no need for it to autograb either.
It could grow an option to enable autograb or grab / ungrab
could be done manually with a key -- which is what it does
right now.

>> - Windows holding the mouse have a different border color,
>> so they can be clearly identified.

> Not sure that this is necessary. Your mouse being
> constrained to the window is probably enough hint.

During a day of using these patches I found the border hint
to be quite helpful.  In particular after switching my focus
away from the terminal I'd often forget about the state I
left it in; the border hint reminded me that the mouse is
(or isn't) grabbed so I could continue working without
having to probe around to determine the state.

Overall I think this patchset is a very useful addition
to the system. I hope we can agree on the details that make
sense and have it merged soon.

Praise to jmi2k for this work!


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 12:43   ` kvik
@ 2021-07-13 13:36     ` hiro
  2021-07-13 13:40       ` hiro
  0 siblings, 1 reply; 42+ messages in thread
From: hiro @ 2021-07-13 13:36 UTC (permalink / raw)
  To: 9front

maybe it's possible to overload the "Hold" state with this?
the reason i think it could be part of the patch is bec. then it
serves as a standard/convention, which we generally like to have here,
as otherwise, other programs developed in parallel might do it
differently and the user will be confused.

even though my short responses here contain only complaining, I like
the writeup, it's a very rarely seen clean description of all the
mechanisms!

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 13:36     ` hiro
@ 2021-07-13 13:40       ` hiro
  0 siblings, 0 replies; 42+ messages in thread
From: hiro @ 2021-07-13 13:40 UTC (permalink / raw)
  To: 9front

(more specifically hold has a menu item in rio and a dedicated hotkey
already (ESC).

I imagine that that menu item or at least the ESC hotkey would not be
used for anything inside a graphical application and thus it becomes
free for this overloading...

On 7/13/21, hiro <23hiro@gmail.com> wrote:
> maybe it's possible to overload the "Hold" state with this?
> the reason i think it could be part of the patch is bec. then it
> serves as a standard/convention, which we generally like to have here,
> as otherwise, other programs developed in parallel might do it
> differently and the user will be confused.
>
> even though my short responses here contain only complaining, I like
> the writeup, it's a very rarely seen clean description of all the
> mechanisms!
>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13  2:45   ` ori
@ 2021-07-13 14:03     ` Stuart Morrow
  2021-08-11  0:56       ` Stuart Morrow
  0 siblings, 1 reply; 42+ messages in thread
From: Stuart Morrow @ 2021-07-13 14:03 UTC (permalink / raw)
  To: 9front

> But also, do we need to do it? Is there any case
> where we want to constrain the grab to anything
> other than the whole window? What if the ctl
> messages were just
>
> 	trap
> 	release
>
> with no further parameters?
>
> Also: in addition to dropping rect parsing and
> validation, we can keep the clip across resizes,
> since there's no ambiguity around where it should
> go: the client has no choice.

Nice idea, but on the Blit dragging the scrollbar with button 2
constrained the mouse (to the scroll bar).  I don't really care.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 10:27       ` José Miguel Sánchez García
@ 2021-07-13 14:05         ` Stuart Morrow
       [not found]           ` <CAFSF3XPhDeKiKXdsL0Abnderm45Uc2GCPYsi6ygSaBkf7gDBmA@mail.gmail.com>
  2021-07-13 15:27           ` kvik
  0 siblings, 2 replies; 42+ messages in thread
From: Stuart Morrow @ 2021-07-13 14:05 UTC (permalink / raw)
  To: 9front

On 13/07/2021, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> There is none, but that's a different issue (it could be easily solved
> if rio provided an "uncurrent" key or an alt-tab-like key.

I can make the case, without appealing to personal preference, that
keyboard-driven wm doesn't belong in Plan 9: we nest window managers.
How do you get keyboard commands into the inner rio?

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
       [not found]           ` <CAFSF3XPhDeKiKXdsL0Abnderm45Uc2GCPYsi6ygSaBkf7gDBmA@mail.gmail.com>
@ 2021-07-13 15:09             ` José Miguel Sánchez García
  2021-07-13 15:34               ` José Miguel Sánchez García
  2021-07-13 15:11             ` Stuart Morrow
  2021-07-13 16:29             ` ori
  2 siblings, 1 reply; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-13 15:09 UTC (permalink / raw)
  To: 9front

We have a problem too: there are programs which we don't want to
release their grab EVER. screenlock would be pretty lame if you could
just "ungrab" the mouse.

I think that different programs have different needs, so maybe
convention is enough? Follow it, unless it makes no sense...

On Tue, Jul 13, 2021 at 5:07 PM hiro <23hiro@gmail.com> wrote:
>
> no, that is never a problem as rio forwards the keyboard commands to
> the relevant selected subprocess (scrollock, DEL and ESC keys for
> example).
>
> On 7/13/21, Stuart Morrow <morrow.stuart@gmail.com> wrote:
> > On 13/07/2021, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> >> There is none, but that's a different issue (it could be easily solved
> >> if rio provided an "uncurrent" key or an alt-tab-like key.
> >
> > I can make the case, without appealing to personal preference, that
> > keyboard-driven wm doesn't belong in Plan 9: we nest window managers.
> > How do you get keyboard commands into the inner rio?
> >

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
       [not found]           ` <CAFSF3XPhDeKiKXdsL0Abnderm45Uc2GCPYsi6ygSaBkf7gDBmA@mail.gmail.com>
  2021-07-13 15:09             ` José Miguel Sánchez García
@ 2021-07-13 15:11             ` Stuart Morrow
  2021-07-13 16:16               ` José Miguel Sánchez García
  2021-07-13 16:21               ` hiro
  2021-07-13 16:29             ` ori
  2 siblings, 2 replies; 42+ messages in thread
From: Stuart Morrow @ 2021-07-13 15:11 UTC (permalink / raw)
  To: 9front

On 13/07/2021, hiro <23hiro@gmail.com> wrote:
> no, that is never a problem as rio forwards the keyboard commands to
> the relevant selected subprocess (scrollock, DEL and ESC keys for
> example).

How about keyboard-based resizing, deleting, etc that some people seem
to want? Which rio do *those* commands go to? How do you decide? You
can't just give up being able to close any window where cons is set to
raw - most of the time it *won't* be a subrio.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 14:05         ` Stuart Morrow
       [not found]           ` <CAFSF3XPhDeKiKXdsL0Abnderm45Uc2GCPYsi6ygSaBkf7gDBmA@mail.gmail.com>
@ 2021-07-13 15:27           ` kvik
  2021-07-13 16:28             ` ori
  1 sibling, 1 reply; 42+ messages in thread
From: kvik @ 2021-07-13 15:27 UTC (permalink / raw)
  To: 9front

> How do you get keyboard commands into the inner rio?

Same as you do mouse commands: you pass them in based
on some sort of focus.

The only difference is the focus mechanism, which must
be something other than the cursor position for the
keyboard commands.

For example, I use sigrid's riow manager with plenty
of subrios and it works fine.  The focus mechanism used
is based on window labels: if the window has a label
starting with "rio:" then the outer rio doesn't "spill"
the prefixed key events into its own riow instance but passes
them as usual to the inner rio, which can do the same again.
The label mechanism *is* hacky and it's just something that
I implemented on the spot to do what I wanted. There's no
inherent reason that something more graceful couldn't be
done.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 15:09             ` José Miguel Sánchez García
@ 2021-07-13 15:34               ` José Miguel Sánchez García
  2021-07-14 12:04                 ` Stuart Morrow
  0 siblings, 1 reply; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-13 15:34 UTC (permalink / raw)
  To: 9front

Thinking about it, seems like screenlock is the odd one here: I can't
think about other use case which would require that level of control
over the mouse. Ideally, a system which could "navigate up" the stack
of rio (unfocusing them from their container) would be a good idea to
both escape the clip prison and also to open the door to future
keyboard-based interactions in an elegant way. If that didn't get in
the way of screenlock, I would undoubtely implement that.

On Tue, Jul 13, 2021 at 5:09 PM José Miguel Sánchez García
<soy.jmi2k@gmail.com> wrote:
>
> We have a problem too: there are programs which we don't want to
> release their grab EVER. screenlock would be pretty lame if you could
> just "ungrab" the mouse.
>
> I think that different programs have different needs, so maybe
> convention is enough? Follow it, unless it makes no sense...
>
> On Tue, Jul 13, 2021 at 5:07 PM hiro <23hiro@gmail.com> wrote:
> >
> > no, that is never a problem as rio forwards the keyboard commands to
> > the relevant selected subprocess (scrollock, DEL and ESC keys for
> > example).
> >
> > On 7/13/21, Stuart Morrow <morrow.stuart@gmail.com> wrote:
> > > On 13/07/2021, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> > >> There is none, but that's a different issue (it could be easily solved
> > >> if rio provided an "uncurrent" key or an alt-tab-like key.
> > >
> > > I can make the case, without appealing to personal preference, that
> > > keyboard-driven wm doesn't belong in Plan 9: we nest window managers.
> > > How do you get keyboard commands into the inner rio?
> > >

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 15:11             ` Stuart Morrow
@ 2021-07-13 16:16               ` José Miguel Sánchez García
  2021-07-13 16:27                 ` Stuart Morrow
  2021-07-13 17:26                 ` Xiao-Yong Jin
  2021-07-13 16:21               ` hiro
  1 sibling, 2 replies; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-13 16:16 UTC (permalink / raw)
  To: 9front

Innermost-focused rio gets the control, with a key for "giving up" the
focus (going then a "level" up in the stack) is what i propose.

On Tue, Jul 13, 2021 at 6:14 PM Stuart Morrow <morrow.stuart@gmail.com> wrote:
>
> On 13/07/2021, hiro <23hiro@gmail.com> wrote:
> > no, that is never a problem as rio forwards the keyboard commands to
> > the relevant selected subprocess (scrollock, DEL and ESC keys for
> > example).
>
> How about keyboard-based resizing, deleting, etc that some people seem
> to want? Which rio do *those* commands go to? How do you decide? You
> can't just give up being able to close any window where cons is set to
> raw - most of the time it *won't* be a subrio.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 15:11             ` Stuart Morrow
  2021-07-13 16:16               ` José Miguel Sánchez García
@ 2021-07-13 16:21               ` hiro
  1 sibling, 0 replies; 42+ messages in thread
From: hiro @ 2021-07-13 16:21 UTC (permalink / raw)
  To: 9front

ah, only now i understand the point. agreed.
for the few shortcuts that we have the rule is to give it on as deep
as possible.
if anything else is wished, it is not possible.

ESC, DEL and scrolllock seem to be the few rare exceptions where this
doesn't matter.

maybe this is actually the stronger reason why historically keyboard
shortcuts have rarely been used/implemented in rio.

On 7/13/21, Stuart Morrow <morrow.stuart@gmail.com> wrote:
> On 13/07/2021, hiro <23hiro@gmail.com> wrote:
>> no, that is never a problem as rio forwards the keyboard commands to
>> the relevant selected subprocess (scrollock, DEL and ESC keys for
>> example).
>
> How about keyboard-based resizing, deleting, etc that some people seem
> to want? Which rio do *those* commands go to? How do you decide? You
> can't just give up being able to close any window where cons is set to
> raw - most of the time it *won't* be a subrio.
>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 16:16               ` José Miguel Sánchez García
@ 2021-07-13 16:27                 ` Stuart Morrow
  2021-07-13 17:42                   ` José Miguel Sánchez García
  2021-07-13 17:26                 ` Xiao-Yong Jin
  1 sibling, 1 reply; 42+ messages in thread
From: Stuart Morrow @ 2021-07-13 16:27 UTC (permalink / raw)
  To: 9front

> Innermost-focused rio gets the control, with a key for "giving up" the
> focus (going then a "level" up in the stack) is what i propose.

But it's so _untransparent_

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 15:27           ` kvik
@ 2021-07-13 16:28             ` ori
  0 siblings, 0 replies; 42+ messages in thread
From: ori @ 2021-07-13 16:28 UTC (permalink / raw)
  To: 9front

Quoth kvik@a-b.xyz:
> 
> Same as you do mouse commands: you pass them in based
> on some sort of focus.

What focus does 'alt-tab' have?


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
       [not found]           ` <CAFSF3XPhDeKiKXdsL0Abnderm45Uc2GCPYsi6ygSaBkf7gDBmA@mail.gmail.com>
  2021-07-13 15:09             ` José Miguel Sánchez García
  2021-07-13 15:11             ` Stuart Morrow
@ 2021-07-13 16:29             ` ori
  2021-07-14  8:42               ` hiro
  2 siblings, 1 reply; 42+ messages in thread
From: ori @ 2021-07-13 16:29 UTC (permalink / raw)
  To: 9front

Quoth hiro <23hiro@gmail.com>:
> no, that is never a problem as rio forwards the keyboard commands to
> the relevant selected subprocess (scrollock, DEL and ESC keys for
> example).

It's easy when rio just forwards to the program. What
happens when rio starts consuming the commands? That's
when things become messy.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 16:16               ` José Miguel Sánchez García
  2021-07-13 16:27                 ` Stuart Morrow
@ 2021-07-13 17:26                 ` Xiao-Yong Jin
  2021-07-13 17:45                   ` Stuart Morrow
                                     ` (2 more replies)
  1 sibling, 3 replies; 42+ messages in thread
From: Xiao-Yong Jin @ 2021-07-13 17:26 UTC (permalink / raw)
  To: 9front


> On Jul 13, 2021, at 11:16 AM, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> 
> Innermost-focused rio gets the control, with a key for "giving up" the
> focus (going then a "level" up in the stack) is what i propose.

Now you are breaking the fourth wall and making rio aware that there
may (or may not?) be another world outside it.  By default rio
passes input down to its children, after breaking this fourth wall,
rio has to process the input somehow and determine if it wants to
"give up" the focus to its parent.  What if its child that has the
focus is a rio?  How does it know how many of its descendent rios
have "given up"?

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 16:27                 ` Stuart Morrow
@ 2021-07-13 17:42                   ` José Miguel Sánchez García
  2021-07-13 21:20                     ` hiro
  2021-07-13 21:57                     ` ori
  0 siblings, 2 replies; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-13 17:42 UTC (permalink / raw)
  To: 9front

The concept of focus itself is a rio invention, so it's natural that
the way of giving it up is also rio-specific.

Again: mouse comes with two sets of inputs: the pointer location and
the buttons. The pointer location can decide the receiver end of the
mouse events (well, not quite in the case of rio, because its focus
doesn't follow the mouse, but you get the idea). On the other hand,
keyboard can't "point" to where the input should be processed, so the
concept of a "current window" fills that hole. It's natural that, if
we have invented a synthetic way of "pointing to" a window with the
keyboard (focus), we should also have a way of "pointing out" of a
window with the keyboard (a "uncurrent" key).

Maybe I'm overthinking it, but that's how I feel about it. Needless to
say, feel free to offer any other alternative to escape the mouse
clip. Feedback is very welcome :)

On Tue, Jul 13, 2021 at 7:32 PM Stuart Morrow <morrow.stuart@gmail.com> wrote:
>
> > Innermost-focused rio gets the control, with a key for "giving up" the
> > focus (going then a "level" up in the stack) is what i propose.
>
> But it's so _untransparent_

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 17:26                 ` Xiao-Yong Jin
@ 2021-07-13 17:45                   ` Stuart Morrow
  2021-07-13 18:29                   ` José Miguel Sánchez García
  2021-07-13 21:22                   ` Benjamin Purcell
  2 siblings, 0 replies; 42+ messages in thread
From: Stuart Morrow @ 2021-07-13 17:45 UTC (permalink / raw)
  To: 9front

On 13/07/2021, Xiao-Yong Jin <meta.jxy@gmail.com> wrote:
> Now you are breaking the fourth wall and making rio aware that there
> may (or may not?) be another world outside it.

To be fair, it already checks for pre-existing snarf. (It kind of has
to for drawterm, if nothing else)

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 17:26                 ` Xiao-Yong Jin
  2021-07-13 17:45                   ` Stuart Morrow
@ 2021-07-13 18:29                   ` José Miguel Sánchez García
  2021-07-13 21:32                     ` hiro
  2021-07-13 21:22                   ` Benjamin Purcell
  2 siblings, 1 reply; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-13 18:29 UTC (permalink / raw)
  To: 9front

That's actually true, if I want that key to both unfocus a window and
unfocus rio if there is no focused window. It would require special
treatment for rio windows... Back to the drawing board...


On Tue, Jul 13, 2021 at 7:47 PM Xiao-Yong Jin <meta.jxy@gmail.com> wrote:
>
>
> > On Jul 13, 2021, at 11:16 AM, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> >
> > Innermost-focused rio gets the control, with a key for "giving up" the
> > focus (going then a "level" up in the stack) is what i propose.
>
> Now you are breaking the fourth wall and making rio aware that there
> may (or may not?) be another world outside it.  By default rio
> passes input down to its children, after breaking this fourth wall,
> rio has to process the input somehow and determine if it wants to
> "give up" the focus to its parent.  What if its child that has the
> focus is a rio?  How does it know how many of its descendent rios
> have "given up"?

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 17:42                   ` José Miguel Sánchez García
@ 2021-07-13 21:20                     ` hiro
  2021-07-13 21:57                     ` ori
  1 sibling, 0 replies; 42+ messages in thread
From: hiro @ 2021-07-13 21:20 UTC (permalink / raw)
  To: 9front

so again, what is the problem with just using ESC (hold mode) for this?

On 7/13/21, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> The concept of focus itself is a rio invention, so it's natural that
> the way of giving it up is also rio-specific.
>
> Again: mouse comes with two sets of inputs: the pointer location and
> the buttons. The pointer location can decide the receiver end of the
> mouse events (well, not quite in the case of rio, because its focus
> doesn't follow the mouse, but you get the idea). On the other hand,
> keyboard can't "point" to where the input should be processed, so the
> concept of a "current window" fills that hole. It's natural that, if
> we have invented a synthetic way of "pointing to" a window with the
> keyboard (focus), we should also have a way of "pointing out" of a
> window with the keyboard (a "uncurrent" key).
>
> Maybe I'm overthinking it, but that's how I feel about it. Needless to
> say, feel free to offer any other alternative to escape the mouse
> clip. Feedback is very welcome :)
>
> On Tue, Jul 13, 2021 at 7:32 PM Stuart Morrow <morrow.stuart@gmail.com>
> wrote:
>>
>> > Innermost-focused rio gets the control, with a key for "giving up" the
>> > focus (going then a "level" up in the stack) is what i propose.
>>
>> But it's so _untransparent_
>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 17:26                 ` Xiao-Yong Jin
  2021-07-13 17:45                   ` Stuart Morrow
  2021-07-13 18:29                   ` José Miguel Sánchez García
@ 2021-07-13 21:22                   ` Benjamin Purcell
  2 siblings, 0 replies; 42+ messages in thread
From: Benjamin Purcell @ 2021-07-13 21:22 UTC (permalink / raw)
  To: 9front

If rio becomes self-aware we all die.

On Tue, Jul 13, 2021, at 13:26, Xiao-Yong Jin wrote:
> 
> > On Jul 13, 2021, at 11:16 AM, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> > 
> > Innermost-focused rio gets the control, with a key for "giving up" the
> > focus (going then a "level" up in the stack) is what i propose.
> 
> Now you are breaking the fourth wall and making rio aware that there
> may (or may not?) be another world outside it.  By default rio
> passes input down to its children, after breaking this fourth wall,
> rio has to process the input somehow and determine if it wants to
> "give up" the focus to its parent.  What if its child that has the
> focus is a rio?  How does it know how many of its descendent rios
> have "given up"?

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 18:29                   ` José Miguel Sánchez García
@ 2021-07-13 21:32                     ` hiro
  0 siblings, 0 replies; 42+ messages in thread
From: hiro @ 2021-07-13 21:32 UTC (permalink / raw)
  To: 9front

just ignore empty rios. only non-rio clients would be supported.

or is there a reason why one might want to constrain somebody's mouse
to a rio ?!

On 7/13/21, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> That's actually true, if I want that key to both unfocus a window and
> unfocus rio if there is no focused window. It would require special
> treatment for rio windows... Back to the drawing board...
>
>
> On Tue, Jul 13, 2021 at 7:47 PM Xiao-Yong Jin <meta.jxy@gmail.com> wrote:
>>
>>
>> > On Jul 13, 2021, at 11:16 AM, José Miguel Sánchez García
>> > <soy.jmi2k@gmail.com> wrote:
>> >
>> > Innermost-focused rio gets the control, with a key for "giving up" the
>> > focus (going then a "level" up in the stack) is what i propose.
>>
>> Now you are breaking the fourth wall and making rio aware that there
>> may (or may not?) be another world outside it.  By default rio
>> passes input down to its children, after breaking this fourth wall,
>> rio has to process the input somehow and determine if it wants to
>> "give up" the focus to its parent.  What if its child that has the
>> focus is a rio?  How does it know how many of its descendent rios
>> have "given up"?
>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 17:42                   ` José Miguel Sánchez García
  2021-07-13 21:20                     ` hiro
@ 2021-07-13 21:57                     ` ori
  2021-07-14 11:55                       ` Stuart Morrow
  1 sibling, 1 reply; 42+ messages in thread
From: ori @ 2021-07-13 21:57 UTC (permalink / raw)
  To: 9front

Quoth José Miguel Sánchez García <soy.jmi2k@gmail.com>:
> Maybe I'm overthinking it, but that's how I feel about it. Needless to
> say, feel free to offer any other alternative to escape the mouse
> clip. Feedback is very welcome :)

I'm not fully convinced we need one. If a program grabs
your mouse and won't let it go, kill it, and then fix
the bug.

A broken can already so something similar by warping
the cursor repeatedly. We don't have a key to disable
cursor warping.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 16:29             ` ori
@ 2021-07-14  8:42               ` hiro
  2021-07-14 11:52                 ` Stuart Morrow
  2021-07-14 14:26                 ` ori
  0 siblings, 2 replies; 42+ messages in thread
From: hiro @ 2021-07-14  8:42 UTC (permalink / raw)
  To: 9front

i still don't see it. either rio consumes the commands or it forwards
them. i don't see anything inbetween.
where is the complication?

On 7/13/21, ori@eigenstate.org <ori@eigenstate.org> wrote:
> Quoth hiro <23hiro@gmail.com>:
>> no, that is never a problem as rio forwards the keyboard commands to
>> the relevant selected subprocess (scrollock, DEL and ESC keys for
>> example).
>
> It's easy when rio just forwards to the program. What
> happens when rio starts consuming the commands? That's
> when things become messy.
>
>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-14  8:42               ` hiro
@ 2021-07-14 11:52                 ` Stuart Morrow
  2021-07-14 12:17                   ` hiro
  2021-07-14 12:53                   ` José Miguel Sánchez García
  2021-07-14 14:26                 ` ori
  1 sibling, 2 replies; 42+ messages in thread
From: Stuart Morrow @ 2021-07-14 11:52 UTC (permalink / raw)
  To: 9front

On 14/07/2021, hiro <23hiro@gmail.com> wrote:
> i still don't see it. either rio consumes the commands or it forwards
> them. i don't see anything inbetween.
> where is the complication?

It's not a complication in terms of code, it's that it's an
untransparent interface.  If we think that window management : the
windows :: the line discipline : the shell, then keyboard-driven wm is
like when the line discipline used to interpret # and @.

There's nothing obvious about Unix commands, which one you want for
what you're trying to do. But knowing the command is *all* the
difficulty - there's no further difficulty in the "transmit the
command from the user to the shell" layer, it's just "for each letter
in the command, type that letter on the keyboard".

The outermost layer needs to be transparent, perhaps so that stuff on
the other side of it can get more leeway to be confusing.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 21:57                     ` ori
@ 2021-07-14 11:55                       ` Stuart Morrow
  0 siblings, 0 replies; 42+ messages in thread
From: Stuart Morrow @ 2021-07-14 11:55 UTC (permalink / raw)
  To: 9front

On 13/07/2021, ori@eigenstate.org <ori@eigenstate.org> wrote:
> A broken can already so something similar by warping
> the cursor repeatedly.

Did you know this from pure reason, or find out the hard way that it
needs to be 'screenlock -d'?

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 15:34               ` José Miguel Sánchez García
@ 2021-07-14 12:04                 ` Stuart Morrow
  2021-07-15  2:06                   ` Xiao-Yong Jin
  0 siblings, 1 reply; 42+ messages in thread
From: Stuart Morrow @ 2021-07-14 12:04 UTC (permalink / raw)
  To: 9front

On 13/07/2021, José Miguel Sánchez García <soy.jmi2k@gmail.com> wrote:
> Thinking about it, seems like screenlock is the odd one here: I can't
> think about other use case which would require that level of control
> over the mouse. Ideally, a system which could "navigate up" the stack
> of rio (unfocusing them from their container) would be a good idea to
> both escape the clip prison and also to open the door to future
> keyboard-based interactions in an elegant way. If that didn't get in
> the way of screenlock, I would undoubtely implement that.

There's no reason screenlock *has* to start using the clip prison
instead of to keep doing what it's doing. If I were you I'd just do
what you wanna do and ignore screenlock.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-14 11:52                 ` Stuart Morrow
@ 2021-07-14 12:17                   ` hiro
  2021-07-15  3:13                     ` ori
  2021-07-14 12:53                   ` José Miguel Sánchez García
  1 sibling, 1 reply; 42+ messages in thread
From: hiro @ 2021-07-14 12:17 UTC (permalink / raw)
  To: 9front

yes i like the idea and all that, but the reality is that rio is
already *not* transparent. and this is the case in multiple ways, both
architectural and in the user interface.

once you allow recursion, the mind has to start counting higher
numbers, which the mind is not good at. recursion is not easy to think
about and thus not transparent.

and more to the point, Window focus, hold mode, DEL key are all
examples for actions that follow as a result of a mouse or keyboard
trigger, yet for the user it's not always clear which (sub?)window it
will affect.

in case of subsubsubrio i'm sure most here already have noticed that
it's very hard to figure out which window will actually be active. to
me what happens most often is that a subrio (so a mostly grey window)
gets activated, whereas i wanted a window inside (a white, from my
point of view a REAL window) to be activated.

sure we have active-window-borders, but they stay in "active" color
even if the parent subrio gets defocused!

clearly the visual cues do not suffice for deeper layering.

On 7/14/21, Stuart Morrow <morrow.stuart@gmail.com> wrote:
> On 14/07/2021, hiro <23hiro@gmail.com> wrote:
>> i still don't see it. either rio consumes the commands or it forwards
>> them. i don't see anything inbetween.
>> where is the complication?
>
> It's not a complication in terms of code, it's that it's an
> untransparent interface.  If we think that window management : the
> windows :: the line discipline : the shell, then keyboard-driven wm is
> like when the line discipline used to interpret # and @.
>
> There's nothing obvious about Unix commands, which one you want for
> what you're trying to do. But knowing the command is *all* the
> difficulty - there's no further difficulty in the "transmit the
> command from the user to the shell" layer, it's just "for each letter
> in the command, type that letter on the keyboard".
>
> The outermost layer needs to be transparent, perhaps so that stuff on
> the other side of it can get more leeway to be confusing.
>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-14 11:52                 ` Stuart Morrow
  2021-07-14 12:17                   ` hiro
@ 2021-07-14 12:53                   ` José Miguel Sánchez García
  2021-07-15  7:36                     ` hiro
  1 sibling, 1 reply; 42+ messages in thread
From: José Miguel Sánchez García @ 2021-07-14 12:53 UTC (permalink / raw)
  To: 9front

Okay, now I think the best way to solve it while keeping transparency
is to rely on convention, just like ESC and Del. Programs clipping the
mouse should unclip it if a particular key is pressed. Programs like
screenlock can choose to ignore this convention, as they rely on
having a permanent grab.

Rio would simply pass the event to the focused window (if it's a
window grabbing the mouse, it'll release it; if it's a nested rio, it
will also pass down the event, if it's a regular window it will do
whatever it wants with it). Does that sound good?

On Wed, Jul 14, 2021 at 2:28 PM Stuart Morrow <morrow.stuart@gmail.com> wrote:
>
> On 14/07/2021, hiro <23hiro@gmail.com> wrote:
> > i still don't see it. either rio consumes the commands or it forwards
> > them. i don't see anything inbetween.
> > where is the complication?
>
> It's not a complication in terms of code, it's that it's an
> untransparent interface.  If we think that window management : the
> windows :: the line discipline : the shell, then keyboard-driven wm is
> like when the line discipline used to interpret # and @.
>
> There's nothing obvious about Unix commands, which one you want for
> what you're trying to do. But knowing the command is *all* the
> difficulty - there's no further difficulty in the "transmit the
> command from the user to the shell" layer, it's just "for each letter
> in the command, type that letter on the keyboard".
>
> The outermost layer needs to be transparent, perhaps so that stuff on
> the other side of it can get more leeway to be confusing.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-14  8:42               ` hiro
  2021-07-14 11:52                 ` Stuart Morrow
@ 2021-07-14 14:26                 ` ori
  1 sibling, 0 replies; 42+ messages in thread
From: ori @ 2021-07-14 14:26 UTC (permalink / raw)
  To: 9front

Quoth hiro <23hiro@gmail.com>:
> 
> i still don't see it. either rio consumes the commands or it forwards
> them. i don't see anything inbetween.
> where is the complication?

How do I alt-tab in a nested rio?


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-12 19:50 [9front] Mouse clipping patch José Miguel Sánchez García
  2021-07-13  2:36 ` ori
@ 2021-07-14 22:57 ` ori
  2021-07-15  7:40   ` hiro
  1 sibling, 1 reply; 42+ messages in thread
From: ori @ 2021-07-14 22:57 UTC (permalink / raw)
  To: 9front

Quoth José Miguel Sánchez García <soy.jmi2k@gmail.com>:
> After talking with some people about the need of proper mouse grabbing
> for some programs (think about vncv, qwx's quake ports, screenlock),
> I've implemented it. The devmouse and libdraw patches modify
> /dev/mousectl to accept two new commands: "clip x0 y0 x1 y1" and
> "release".

Mentioned elsewhere -- but what if instead of this,
we did a "raw" or "relative" command, which did two
things:

	1. Made mouse updates provide deltas from the
	   previous position.
	2. Disabled automatic cursor position updates.

This would mean that an application which requested
relative motion commands would be responsible for
warping the cursor to where it wanted it to be.

That would allow the application to emulate clipping,
but would also be what games want, allowing infinite
side scrolling (for example).


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-14 12:04                 ` Stuart Morrow
@ 2021-07-15  2:06                   ` Xiao-Yong Jin
  0 siblings, 0 replies; 42+ messages in thread
From: Xiao-Yong Jin @ 2021-07-15  2:06 UTC (permalink / raw)
  To: 9front


> On Jul 14, 2021, at 7:04 AM, Stuart Morrow <morrow.stuart@gmail.com> wrote:
> 
> There's no reason screenlock *has* to start using the clip prison
> instead of to keep doing what it's doing. If I were you I'd just do
> what you wanna do and ignore screenlock.

The issue is that, if rio starts to manage focus by keyboard input,
it has to know its children well in order not to steal focus from
its special child.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-14 12:17                   ` hiro
@ 2021-07-15  3:13                     ` ori
  0 siblings, 0 replies; 42+ messages in thread
From: ori @ 2021-07-15  3:13 UTC (permalink / raw)
  To: 9front

Quoth hiro <23hiro@gmail.com>:
> 
> yes i like the idea and all that, but the reality is that rio is
> already *not* transparent. and this is the case in multiple ways, both
> architectural and in the user interface.

Yes. How do we simplify that situation, instead of making it worse?


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-14 12:53                   ` José Miguel Sánchez García
@ 2021-07-15  7:36                     ` hiro
  0 siblings, 0 replies; 42+ messages in thread
From: hiro @ 2021-07-15  7:36 UTC (permalink / raw)
  To: 9front

> Rio would simply pass the event to the focused window (if it's a
> window grabbing the mouse, it'll release it; if it's a nested rio, it
> will also pass down the event, if it's a regular window it will do
> whatever it wants with it). Does that sound good?

yes, that's what i meant

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-14 22:57 ` ori
@ 2021-07-15  7:40   ` hiro
  0 siblings, 0 replies; 42+ messages in thread
From: hiro @ 2021-07-15  7:40 UTC (permalink / raw)
  To: 9front

> Mentioned elsewhere -- but what if instead of this,
> we did a "raw" or "relative" command, which did two
> things:
>
> 	1. Made mouse updates provide deltas from the
> 	   previous position.
> 	2. Disabled automatic cursor position updates.
>
> This would mean that an application which requested
> relative motion commands would be responsible for
> warping the cursor to where it wanted it to be.
>
> That would allow the application to emulate clipping,
> but would also be what games want, allowing infinite
> side scrolling (for example).
>
>

all this complexity would have only a slight benefit: a bigger maximum
mouse speed. as right now per mouse event we can already move
maximally by as many pixels as the screen has space... for most
fast-paced games this should suffice already.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [9front] Mouse clipping patch
  2021-07-13 14:03     ` Stuart Morrow
@ 2021-08-11  0:56       ` Stuart Morrow
  0 siblings, 0 replies; 42+ messages in thread
From: Stuart Morrow @ 2021-08-11  0:56 UTC (permalink / raw)
  To: 9front

On 13/07/2021, Stuart Morrow <morrow.stuart@gmail.com> wrote:
> ... on the Blit dragging the scrollbar with button 2
> constrained the mouse (to the scroll bar).

Actually, Plan 9 used to do this:
https://code.9front.org/hg/plan9front/rev/4983319acdaf

FWIW

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2021-08-11  2:36 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-12 19:50 [9front] Mouse clipping patch José Miguel Sánchez García
2021-07-13  2:36 ` ori
2021-07-13  2:45   ` ori
2021-07-13 14:03     ` Stuart Morrow
2021-08-11  0:56       ` Stuart Morrow
2021-07-13  3:14   ` José Miguel Sánchez García
2021-07-13  8:25     ` hiro
2021-07-13 10:27       ` José Miguel Sánchez García
2021-07-13 14:05         ` Stuart Morrow
     [not found]           ` <CAFSF3XPhDeKiKXdsL0Abnderm45Uc2GCPYsi6ygSaBkf7gDBmA@mail.gmail.com>
2021-07-13 15:09             ` José Miguel Sánchez García
2021-07-13 15:34               ` José Miguel Sánchez García
2021-07-14 12:04                 ` Stuart Morrow
2021-07-15  2:06                   ` Xiao-Yong Jin
2021-07-13 15:11             ` Stuart Morrow
2021-07-13 16:16               ` José Miguel Sánchez García
2021-07-13 16:27                 ` Stuart Morrow
2021-07-13 17:42                   ` José Miguel Sánchez García
2021-07-13 21:20                     ` hiro
2021-07-13 21:57                     ` ori
2021-07-14 11:55                       ` Stuart Morrow
2021-07-13 17:26                 ` Xiao-Yong Jin
2021-07-13 17:45                   ` Stuart Morrow
2021-07-13 18:29                   ` José Miguel Sánchez García
2021-07-13 21:32                     ` hiro
2021-07-13 21:22                   ` Benjamin Purcell
2021-07-13 16:21               ` hiro
2021-07-13 16:29             ` ori
2021-07-14  8:42               ` hiro
2021-07-14 11:52                 ` Stuart Morrow
2021-07-14 12:17                   ` hiro
2021-07-15  3:13                     ` ori
2021-07-14 12:53                   ` José Miguel Sánchez García
2021-07-15  7:36                     ` hiro
2021-07-14 14:26                 ` ori
2021-07-13 15:27           ` kvik
2021-07-13 16:28             ` ori
2021-07-13 12:00     ` José Miguel Sánchez García
2021-07-13 12:43   ` kvik
2021-07-13 13:36     ` hiro
2021-07-13 13:40       ` hiro
2021-07-14 22:57 ` ori
2021-07-15  7:40   ` hiro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).