9front - general discussion about 9front
 help / color / mirror / Atom feed
From: igor@9lab.org
To: 9front@9front.org
Subject: Re: [9front] hidpi
Date: Mon, 20 Dec 2021 18:59:09 +0100	[thread overview]
Message-ID: <4828C18115F30E3A05899AE665C7651F@9lab.org> (raw)
In-Reply-To: <fY4WlDcUa0tGFTLGmEv-NDWLzJwXsUPnq2RK3-w9N1E35Bo3N8nIXTI-BwvNAmMRQtDb_oIH63c0uucUhbK38DilSs3LuWfGeJ1vAluIggw=@protonmail.com>

Hi Philip,

This reminds me of a plan9port feature to change DPI (useful
on a high res display, e.g. Retina display). Are you trying
to achieve something similar as this:

• https://groups.google.com/g/plan9port-dev/c/rXtpIufTrbMhttps://github.com/9fans/plan9port/blob/master/src/cmd/devdraw/devdraw.c#L976

Cheers,
Igor

Quoth Philip Silva <philip.silva@protonmail.com>:
> I've been creating patches to enable hidpi to make scrollbars bigger when using > 100 dpi. It's basically 3 patches: 1st one for adding int displaydpi, 2nd one for adding an entry to plan9.ini and a 3rd very experimental one that changes scrollbar and border widths including some glitches. (And a 4th one that hardcodes 200 dpi in drawterm-metal-cocoa) The extra fields and most code is just copied from plan9port. (d0e0701, c96d832) I'm using this since a few months now and it works, the only problems I had:
> 
> - system wouldn't boot anymore when only applying the libdraw part of the 1st patch (I fixed that and checked in a fresh install in a VM that it would just ignore when the new draw command q1d isn't present in devdraw)
> - glitches: the borders aren't calculated correctly (3rd patch for rio and acme is very wip)
> - despite the glitches it works reasonably well with acme and rio but some applications are quite small then. Not sure how much effort it would be to patch for compat. with dpi != 100
> 
> There is also the field forcedpi that is left largely ignored but generally is supposed to override displaydpi when necessary.
> 
> Greetings, Philip
> 
> 
> --
> 
> 
> 1st Patch for libdraw and devdraw:
> 
> diff c7dcc82b0be805717efbe77c98eaadf3ee1e31af uncommitted
> --- a/sys/include/ape/draw.h
> +++ b/sys/include/ape/draw.h
> @@ -208,6 +208,7 @@
>  	Image		*windows;
>  	Image		*screenimage;
>  	int			_isnewdisplay;
> +	int			dpi;
>  };
> 
>  struct Image
> --- a/sys/include/draw.h
> +++ b/sys/include/draw.h
> @@ -200,6 +200,7 @@
>  	Image		*windows;
>  	Image		*screenimage;
>  	int		_isnewdisplay;
> +	int		dpi;
>  };
> 
>  struct Image
> --- a/sys/src/9/port/devdraw.c
> +++ b/sys/src/9/port/devdraw.c
> @@ -77,6 +77,8 @@
>  	int		refreshme;
>  	int		infoid;
>  	int		op;
> +	int		displaydpi;
> +	int		forcedpi;
>  };
> 
>  struct Refresh
> @@ -785,6 +789,7 @@
>  	cl->slot = i;
>  	cl->clientid = ++sdraw.clientid;
>  	cl->op = SoverD;
> +	cl->displaydpi=100;
>  	sdraw.client[i] = cl;
>  	return cl;
>  }
> @@ -1396,6 +1401,7 @@
>  	int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
>  	uchar *u, *a, refresh;
>  	char *fmt;
> +	Fmt f;
>  	ulong value, chan;
>  	Rectangle r, clipr;
>  	Point p, q, *pp, sp;
> @@ -1643,6 +1649,35 @@
>  			font->nfchar = ni;
>  			font->ascent = a[9];
>  			continue;
> +
> +		/* query: 'Q' n[1] queryspec[n] */
> +		case 'q':
> +			if(n < 2){
> +				error(Eshortdraw);
> +			}
> +			m = 1+1+a[1];
> +			if(n < m){
> +				error(Eshortdraw);
> +			}
> +			fmtstrinit(&f);
> +			for(c=0; c<a[1]; c++){
> +				switch(a[2+c]){
> +				default:
> +					error("unknown query");
> +				case 'd':       /* dpi */
> +					if(client->forcedpi)
> +						fmtprint(&f, "%11d ", client->forcedpi);
> +					else
> +						fmtprint(&f, "%11d ", client->displaydpi);
> +					break;
> +				}
> +			}
> +			client->readdata = (uchar*)fmtstrflush(&f);
> +			if(client->readdata == nil)
> +				error(Enomem);
> +			client->nreaddata = strlen((char*)client->readdata);
> +			continue;
> +
> 
>  		/* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
>  		case 'l':
> --- a/sys/src/libdraw/init.c
> +++ b/sys/src/libdraw/init.c
> @@ -197,6 +197,7 @@
>  Display*
>  initdisplay(char *dev, char *win, void(*error)(Display*, char*))
>  {
> +	uchar *a;
>  	char buf[128], info[NINFO+1], *t, isnew;
>  	int n, datafd, ctlfd, reffd;
>  	Display *disp;
> @@ -319,6 +320,18 @@
>  	if(dir!=nil && dir->qid.vers==1)	/* other way to tell */
>  		disp->_isnewdisplay = 1;
>  	free(dir);
> +
> +	a = bufimage(disp, 3);
> +	if(a == nil)
> +		goto Error5;
> +	a[0] = 'q';
> +	a[1] = 1;
> +	a[2] = 'd';
> +	disp->dpi = 100;
> +	if(flushimage(disp, 0) >= 0){
> +		if((read(datafd, info, sizeof info)) == 12)
> +			disp->dpi = atoi(info);
> +	}
> 
>  	return disp;
>  }
> 
> --
> 
> 2nd Patch for plan9.ini:
> 
> diff c7dcc82b0be805717efbe77c98eaadf3ee1e31af uncommitted
> --- a/sys/man/8/plan9.ini
> +++ b/sys/man/8/plan9.ini
> @@ -971,6 +971,8 @@
>  .BR off .
>  The first two specify differing levels of power saving;
>  the third turns the monitor off completely.
> +.SS \fL*dpi=\fIvalue\fP
> +This is used to specify the screen dpi.
>  .SS NVRAM
>  .SS \fLnvram=\fIfile\fP
>  .SS \fLnvrlen=\fIlength\fP
> --- a/sys/src/9/port/devdraw.c
> +++ b/sys/src/9/port/devdraw.c
> @@ -765,6 +765,7 @@
>  drawnewclient(void)
>  {
>  	Client *cl, **cp;
> +	char *p;
>  	int i;
> 
>  	for(i=0; i<sdraw.nclient; i++){
> @@ -789,7 +790,9 @@
>  	cl->slot = i;
>  	cl->clientid = ++sdraw.clientid;
>  	cl->op = SoverD;
> -	cl->displaydpi=100;
> +	if((p = getconf("dpi")) == nil || (cl->displaydpi = atoi(p)) == 0){
> +		cl->displaydpi=100;
> +	}
>  	sdraw.client[i] = cl;
>  	return cl;
>  }
> 
> --
> 
> 3rd Patch for rio/acme (proof-of-concept, just to provide an example)
> 
> diff 75d8e460a00505c2b21a0d06ceb4300c93d9c4d6 uncommitted
> --- a/sys/include/ape/draw.h
> +++ b/sys/include/ape/draw.h
> @@ -69,6 +69,7 @@
>  	Displaybufsize	= 8000,
>  	ICOSSCALE	= 1024,
>  	Borderwidth =	4,
> +	DefaultDPI  =	100,
>  };
> 
>  enum
> @@ -358,6 +359,7 @@
>  extern Image*	namedimage(Display*, char*);
>  extern int	nameimage(Image*, char*, int);
>  extern Image* allocimagemix(Display*, ulong, ulong);
> +extern int scalesize(Display*, int);
> 
>  /*
>   * Colors
> --- a/sys/include/draw.h
> +++ b/sys/include/draw.h
> @@ -61,6 +61,7 @@
>  	Displaybufsize	= 8000,
>  	ICOSSCALE	= 1024,
>  	Borderwidth =	4,
> +	DefaultDPI  =	100,
>  };
> 
>  enum
> @@ -354,6 +355,7 @@
>  extern Image*	namedimage(Display*, char*);
>  extern int	nameimage(Image*, char*, int);
>  extern Image* allocimagemix(Display*, ulong, ulong);
> +extern int scalesize(Display*, int);
> 
>  /*
>   * Colors
> --- a/sys/src/cmd/acme/dat.h
> +++ b/sys/src/cmd/acme/dat.h
> @@ -473,11 +473,14 @@
>  	BUFSIZE = Maxblock+IOHDRSZ,	/* size from fbufalloc() */
>  	RBUFSIZE = BUFSIZE/sizeof(Rune),
>  	EVENTSIZE = 256,
> -	Scrollwid = 12,	/* width of scroll bar */
> -	Scrollgap = 4,	/* gap right of scroll bar */
> -	Margin = 4,	/* margin around text */
> -	Border = 2,	/* line between rows, cols, windows */
>  };
> +
> +// like in p9p c96d832
> +#define Scrollwid scalesize(display, 12)	/* width of scroll bar */
> +#define Scrollgap scalesize(display, 4)	/* gap right of scroll bar */
> +#define Margin scalesize(display, 4)	/* margin around text */
> +#define Border scalesize(display, 2)	/* line between rows, cols, windows */
> +#define ButtonBorder scalesize(display, 2)
> 
>  #define	QID(w,q)	((w<<8)|(q))
>  #define	WIN(q)	((((ulong)(q).path)>>8) & 0xFFFFFF)
> --- a/sys/src/cmd/rio/wind.c
> +++ b/sys/src/cmd/rio/wind.c
> @@ -12,6 +12,14 @@
>  #include "dat.h"
>  #include "fns.h"
> 
> +static int
> +wscale(Window *w, int n)
> +{
> +        if(w == nil || w->i == nil)
> +                return n;
> +        return scalesize(w->i->display, n);
> +}
> +
>  Window*
>  wlookid(int id)
>  {
> @@ -308,7 +316,7 @@
>  		else
>  			col = lighttitlecol;
>  	}
> -	border(w->i, w->i->r, Selborder, col, ZP);
> +	border(w->i, w->i->r, wscale(w, Selborder), col, ZP);
>  }
> 
>  static void
> @@ -353,17 +361,17 @@
> 
>  	w->i = i;
>  	w->mc.image = i;
> -	r = insetrect(i->r, Selborder+1);
> +	r = insetrect(i->r, wscale(w, Selborder)+wscale(w, 1));
>  	w->scrollr = r;
> -	w->scrollr.max.x = r.min.x+Scrollwid;
> +	w->scrollr.max.x = r.min.x+wscale(w, Scrollwid);
>  	w->lastsr = ZR;
> -	r.min.x += Scrollwid+Scrollgap;
> +	r.min.x += wscale(w, Scrollwid)+wscale(w, Scrollgap);
>  	frclear(w, FALSE);
>  	frinit(w, r, w->font, w->i, cols);
>  	wsetcols(w, w == input);
>  	w->maxtab = maxtab*stringwidth(w->font, "0");
>  	if(!w->mouseopen || !w->winnameread){
> -		r = insetrect(w->i->r, Selborder);
> +		r = insetrect(w->i->r, wscale(w, Selborder));
>  		draw(w->i, r, cols[BACK], nil, w->entire.min);
>  		wfill(w);
>  		wsetselect(w, w->q0, w->q1);
> @@ -370,7 +378,7 @@
>  		wscrdraw(w);
>  	}
>  	if(w == input)
> -		wborder(w, Selborder);
> +		wborder(w, wscale(w, Selborder));
>  	else
>  		wborder(w, Unselborder);
>  	flushimage(display, 1);
> @@ -390,9 +398,9 @@
>  	if(!w->mouseopen || !w->winnameread)
>  		frredraw(w);
>  	if(w == input)
> -		wborder(w, Selborder);
> +		wborder(w, wscale(w, Selborder));
>  	else
> -		wborder(w, Unselborder);
> +		wborder(w, wscale(w, Unselborder));
>  }
> 
>  static void
> @@ -401,9 +409,9 @@
>  	Rectangle r;
> 
>  	if(w == input)
> -		wborder(w, Selborder);
> +		wborder(w, wscale(w, Selborder));
>  	else
> -		wborder(w, Unselborder);
> +		wborder(w, wscale(w, Unselborder));
>  	r = insetrect(w->i->r, Selborder);
>  	draw(w->i, r, w->cols[BACK], nil, w->entire.min);
>  	wfill(w);
> @@ -1249,7 +1257,7 @@
> 
>  	w = emalloc(sizeof(Window));
>  	w->screenr = i->r;
> -	r = insetrect(i->r, Selborder+1);
> +	r = insetrect(i->r, wscale(w, Selborder)+wscale(w, 1));
>  	w->i = i;
>  	w->mc = *mc;
>  	w->ck = ck;
> @@ -1263,9 +1271,9 @@
>  	w->complete = chancreate(sizeof(Completion*), 0);
>  	w->gone = chancreate(sizeof(char*), 0);
>  	w->scrollr = r;
> -	w->scrollr.max.x = r.min.x+Scrollwid;
> +	w->scrollr.max.x = r.min.x+wscale(w, Scrollwid);
>  	w->lastsr = ZR;
> -	r.min.x += Scrollwid+Scrollgap;
> +	r.min.x += wscale(w, Scrollwid)+wscale(w, Scrollgap);
>  	frinit(w, r, font, i, cols);
>  	w->maxtab = maxtab*stringwidth(font, "0");
>  	w->topped = ++topped;
> @@ -1274,9 +1282,9 @@
>  	w->scrolling = scrolling;
>  	w->dir = estrdup(startdir);
>  	w->label = estrdup("<unnamed>");
> -	r = insetrect(w->i->r, Selborder);
> +	r = insetrect(w->i->r, wscale(w, Selborder));
>  	draw(w->i, r, cols[BACK], nil, w->entire.min);
> -	wborder(w, Selborder);
> +	wborder(w, wscale(w, Selborder));
>  	wscrdraw(w);
>  	incref(w);	/* ref will be removed after mounting; avoids delete before ready to be deleted */
>  	return w;
> --- a/sys/src/libdraw/init.c
> +++ b/sys/src/libdraw/init.c
> @@ -452,5 +465,13 @@
>  	p = d->bufp;
>  	d->bufp += n;
>  	return p;
> +}
> +
> +int
> +scalesize(Display *d, int n)
> +{
> +	if(d == nil || d->dpi <= DefaultDPI)
> +		return n;
> +	return (n*d->dpi+DefaultDPI/2)/DefaultDPI;
>  }
> 
> --
> 
> 4th Patch (drawterm-metal-cocoa - I've been using this most of the time):
> 
> diff 0b7990cf2b84e7a80cf3f3a9e7eadca10d51a2c5 uncommitted
> --- a/include/draw.h
> +++ b/include/draw.h
> @@ -193,6 +193,7 @@
>  	Image		*windows;
>  	Image		*screenimage;
>  	int		_isnewdisplay;
> +	int		dpi;
>  };
> 
>  struct Image
> --- a/kern/devdraw.c
> +++ b/kern/devdraw.c
> @@ -76,6 +76,8 @@
>  	int		refreshme;
>  	int		infoid;
>  	int		op;
> +	int		displaydpi;
> +	int		forcedpi;
>  };
> 
>  struct Refresh
> @@ -166,6 +168,8 @@
>  	Client*		drawclientofpath(ulong);
>  	DImage*	allocdimage(Memimage*);
> 
> +int displaydpi = 200;
> +
>  static	char Enodrawimage[] =	"unknown id for draw image";
>  static	char Enodrawscreen[] =	"unknown id for draw screen";
>  static	char Eshortdraw[] =	"short draw message";
> @@ -783,6 +787,7 @@
>  	cl->slot = i;
>  	cl->clientid = ++sdraw.clientid;
>  	cl->op = SoverD;
> +	cl->displaydpi = displaydpi;
>  	sdraw.client[i] = cl;
>  	return cl;
>  }
> @@ -1408,6 +1413,7 @@
>  	int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
>  	uchar *u, *a, refresh;
>  	char *fmt;
> +	Fmt f;
>  	ulong value, chan;
>  	Rectangle r, clipr;
>  	Point p, q, *pp, sp;
> @@ -1654,6 +1660,34 @@
>  			memset(font->fchar, 0, ni*sizeof(FChar));
>  			font->nfchar = ni;
>  			font->ascent = a[9];
> +			continue;
> +
> +		/* query: 'Q' n[1] queryspec[n] */
> +		case 'q':
> +			if(n < 2)
> +				error(Eshortdraw);
> +			m = 1+1+a[1];
> +			if(n < m)
> +				error(Eshortdraw);
> +			fmtstrinit(&f);
> +			for(c=0; c<a[1]; c++){
> +				switch(a[2+c]){
> +				default:
> +					error("unknown query");
> +					break;
> +				case 'd':       /* dpi */
> +					if(client->forcedpi)
> +						fmtprint(&f, "%11d ", client->forcedpi);
> +					else {
> +						fmtprint(&f, "%11d ", client->displaydpi);
> +					}
> +					break;
> +				}
> +			}
> +			client->readdata = (uchar*)fmtstrflush(&f);
> +			if(client->readdata == nil)
> +				error(Enomem);
> +			client->nreaddata = strlen((char*)client->readdata);
>  			continue;
> 
>  		/* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
> 
> 


  parent reply	other threads:[~2021-12-20 18:07 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-20 16:13 Philip Silva
2021-12-20 16:34 ` hiro
2021-12-20 17:04 ` [9front] hidpi Philip Silva
2021-12-20 17:29   ` hiro
2021-12-20 19:15   ` Noam Preil
2021-12-20 19:34     ` ori
2021-12-20 20:50       ` ori
2021-12-20 21:10         ` hiro
2021-12-20 21:19           ` ori
2021-12-20 22:02             ` sirjofri
2021-12-21  0:29         ` Philip Silva
2021-12-21  8:37           ` hiro
2021-12-20 21:47       ` Noam Preil
2021-12-20 17:59 ` igor [this message]
2021-12-20 18:28   ` [9front] hidpi hiro
2021-12-20 19:27     ` Noam Preil
2021-12-20 19:02   ` Philip Silva
2021-12-22  8:39 ` igor
2021-12-22 11:31   ` Philip Silva
2021-12-23 13:11 igor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4828C18115F30E3A05899AE665C7651F@9lab.org \
    --to=igor@9lab.org \
    --cc=9front@9front.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).