Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large strings

2022-03-21 Thread Stein Gunnar Bakkeby
Hi NRK,

you make some interesting points. I am curious as to what your queueing
approach would look like.

I played around some more simplifying the ellipsis drawing and removing buf
as you suggested.
This would solve all of the aforementioned problems as far as I can tell,
but it can result in a partly drawn
emoji for example when the ellipsis cuts it off (which I think is a fair
tradeoff).

Thanks,

-Stein


On Mon, Mar 21, 2022 at 8:15 PM NRK  wrote:

> On Mon, Mar 21, 2022 at 07:00:32PM +0600, NRK wrote:
> > The only "issue" is that it doesn't render the ellipsis in case font
> > changes, but current upstream dmenu doesn't seem to do it either.
>
> OK, I think I have a solution to this. The problem here, as far as I
> understand, is this:
>
> Let's say we have a maxwidth of 100, and printing the ellipsis takes 20.
> In this case as long as our string is below 80, we're fine; and if it's
> above 100 then we should print up to 80 and then print the ellipsis.
>
> The problem case is when we're between 80-100, and we need to change
> font. The current code always renders whatever is available when we
> change font, so if the text turns out to be bigger than 100 we've
> already rendered some of the text into the problem area where the
> ellipsis should've been.
>
> The solution I came up with is to simply not render anything if we're at
> the problem case, and instead put the problem cases into a queue and
> keep going forwards until either:
>
> 1) The text overflows, in which case we discard the queue and just print
>the ellipsis instead.
> 2) Encounter the end of text, which means the text barely fit into our
>maxwidth (this would happen with the prompt); in which case we just
>render the queue and don't print any ellipsis.
>
> I already have a patch that *roughly* does what I described above and
> with it applied I don't see any truncation problems anymore.
>
> However the patch is quite messy atm, and in order to do things cleanly
> and avoid special casing, I think a good portion of drw_text() will need
> to be overhauled to use a queue like this:
>
> struct { const char *str; int len; Fnt *fnt; } q[32] = {0};
>
> I'm not sure if such overhaul is going to be welcome or not, but if all
> of this sounds acceptable then I can proceed with cleaning things up and
> supplying the patch.
>
> - NRK
>
>

-- 
Stein Gunnar Bakkeby
OpenBet Developer
bakk...@gmail.com
From d52d59bc32a9e5bb3f7dfc0a88a0271b9870 Mon Sep 17 00:00:00 2001
From: Bakkeby 
Date: Mon, 21 Mar 2022 22:25:51 +0100
Subject: [PATCH] drw_text: print whole utf-8 characters only and simplify
 ellipsis handling

---
 drw.c | 50 +-
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/drw.c b/drw.c
index 4cdbcbe..ccb3b9a 100644
--- a/drw.c
+++ b/drw.c
@@ -251,12 +251,10 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
 int
 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
 {
-	char buf[1024];
 	int ty;
 	unsigned int ew;
 	XftDraw *d = NULL;
 	Fnt *usedfont, *curfont, *nextfont;
-	size_t i, len;
 	int utf8strlen, utf8charlen, render = x || y || w || h;
 	long utf8codepoint = 0;
 	const char *utf8str;
@@ -264,7 +262,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
 	FcPattern *fcpattern;
 	FcPattern *match;
 	XftResult result;
-	int charexists = 0;
+	int charexists = 0, overflow = 0;
+	XGlyphInfo ext;
+	const char *ellipsis = "...";
 
 	if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
 		return 0;
@@ -278,7 +278,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
 		  DefaultVisual(drw->dpy, drw->screen),
 		  DefaultColormap(drw->dpy, drw->screen));
 		x += lpad;
-		w -= lpad;
+		w -= lpad * 2;
 	}
 
 	usedfont = drw->fonts;
@@ -286,12 +286,19 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
 		utf8strlen = 0;
 		utf8str = text;
 		nextfont = NULL;
+		ew = 0;
 		while (*text) {
 			utf8charlen = utf8decode(text, , UTF_SIZ);
 			for (curfont = drw->fonts; curfont; curfont = curfont->next) {
 charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
 if (charexists) {
 	if (curfont == usedfont) {
+		XftTextExtentsUtf8(usedfont->dpy, usedfont->xfont, (XftChar8 *)text, utf8charlen, );
+		if (ew + ext.xOff > w) {
+			overflow = 1;
+			break;
+		}
+		ew += ext.xOff;
 		utf8strlen += utf8charlen;
 		text += utf8charlen;
 	} else {
@@ -301,36 +308,29 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
 }
 			}
 
-			if (!charexists || nextfont)
+			if (overflow || !charexists || nextfont)
 break;
 			else
 charexists = 0;
 		}
 
 		if (utf8strlen) {
-			drw_font_getexts(usedfont, utf8str, utf8strlen, , NULL);
-			

Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large strings

2022-03-21 Thread NRK
On Mon, Mar 21, 2022 at 07:00:32PM +0600, NRK wrote:
> The only "issue" is that it doesn't render the ellipsis in case font
> changes, but current upstream dmenu doesn't seem to do it either.

OK, I think I have a solution to this. The problem here, as far as I
understand, is this:

Let's say we have a maxwidth of 100, and printing the ellipsis takes 20.
In this case as long as our string is below 80, we're fine; and if it's
above 100 then we should print up to 80 and then print the ellipsis.

The problem case is when we're between 80-100, and we need to change
font. The current code always renders whatever is available when we
change font, so if the text turns out to be bigger than 100 we've
already rendered some of the text into the problem area where the
ellipsis should've been.

The solution I came up with is to simply not render anything if we're at
the problem case, and instead put the problem cases into a queue and
keep going forwards until either:

1) The text overflows, in which case we discard the queue and just print
   the ellipsis instead.
2) Encounter the end of text, which means the text barely fit into our
   maxwidth (this would happen with the prompt); in which case we just
   render the queue and don't print any ellipsis.

I already have a patch that *roughly* does what I described above and
with it applied I don't see any truncation problems anymore.

However the patch is quite messy atm, and in order to do things cleanly
and avoid special casing, I think a good portion of drw_text() will need
to be overhauled to use a queue like this:

struct { const char *str; int len; Fnt *fnt; } q[32] = {0};

I'm not sure if such overhaul is going to be welcome or not, but if all
of this sounds acceptable then I can proceed with cleaning things up and
supplying the patch.

- NRK



Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large strings

2022-03-21 Thread NRK
+   if (ew + ext.xOff + lpad > w || 
b + utf8charlen > sizeof(buf) - 1) {
+   /* Only draw ellipsis 
if we have not recently started another font */
+   if (render && 
ellipsis_b > 3) {
+   ew = 
ellipsis_ew;
[...]
+   /* Record the last buffer index 
where the ellipsis would still fit */
+   if (ew + ellipsis_width + lpad 
<= w) {
+   ellipsis_ew = ew;
+   ellipsis_b = b;
+   }

I think both of the `+ lpad` needs be removed. Otherwise it incorrectly
truncates the prompt as well.

./dmenu < /dev/null -p "p" # empty prompt
./dmenu < /dev/null -p "prompt" # truncated prompt

Also, I didn't quite get why there's a `ellipsis_b > 3` in there.

+   for (i = 0; i < utf8charlen; 
i++)
+   buf[b++] = *text++;

I'm kinda wondering if `buf` is even worth it or not. We could just render the
"..." separately. On my system atleast, there is no noticeable performance
difference, but removing `buf` from the equation (IMO) makes things more
simpler and easier to follow.

The following is what I've gotten so far, it's working fine and I haven't
noticed any regressions. The only "issue" is that it doesn't render the
ellipsis in case font changes, but current upstream dmenu doesn't seem to do it
either.

- NRK

diff --git a/drw.c b/drw.c
index 4cdbcbe..80dcad2 100644
--- a/drw.c
+++ b/drw.c
@@ -251,20 +251,17 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned 
int h, int filled, int
 int
 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int 
lpad, const char *text, int invert)
 {
-   char buf[1024];
-   int ty;
-   unsigned int ew;
+   unsigned int ew = 0, ellipsis_ew = 0, ellipsis_width = 0, tmpw;
XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont;
-   size_t i, len;
-   int utf8strlen, utf8charlen, render = x || y || w || h;
+   int utf8strlen, utf8charlen, ellipsis_len, render = x || y || w || h;
long utf8codepoint = 0;
const char *utf8str;
FcCharSet *fccharset;
FcPattern *fcpattern;
FcPattern *match;
XftResult result;
-   int charexists = 0;
+   int charexists = 0, truncate = 0;
 
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
return 0;
@@ -283,7 +280,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned 
int h, unsigned int lp
 
usedfont = drw->fonts;
while (1) {
-   utf8strlen = 0;
+   utf8strlen = ellipsis_len = ew = ellipsis_ew = 0;
utf8str = text;
nextfont = NULL;
while (*text) {
@@ -292,8 +289,27 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned 
int h, unsigned int lp
charexists = charexists || 
XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) {
if (curfont == usedfont) {
+   if (!ellipsis_width)
+   
drw_font_getexts(curfont, "...", 3, _width, NULL);
+   drw_font_getexts(curfont, text, 
utf8charlen, , NULL);
+   if (ew + tmpw > w) {
+   /* Only draw ellipsis 
if we have not recently started another font */
+   if (render && 
ellipsis_len > 0) {
+   ew = 
ellipsis_ew;
+   utf8strlen = 
ellipsis_len;
+   }
+   truncate = 1;
+   break;
+   }
+
+   /* Record the last text index 
where the ellipsis would still fit */
+   if (ew + ellipsis_width <= w) {
+   ellipsis_ew = ew;
+   ellipsis_len = 
utf8strlen;
+   }
utf8strlen += utf8charlen;
  

Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large strings

2022-03-21 Thread NRK
On Sun, Mar 20, 2022 at 02:56:33PM +0100, Stein Gunnar Bakkeby wrote:
> I have attached the changes I was experimenting with.
> I still don't like the amount of effort required for drawing an ellipsis
> though so I attached another patch file that doesn't try to draw the
> ellipsis for comparison.
> 
> -Stein

Hi Bakkeby,

I haven't looked too deeply into the patch, but I see that you've moved
the ew calculation inside the first loop rather than looping through
again later down. This was more or less what I was planning to do as
well, although I was motivated by performance reasons, while you seemed
to be motivated by correctness reasons.

Anyhow, it's a good thing that you've sent this mail as it would prevent
some duplicated work on my end.

As for your patch, I think it (just using a single loop instead of two)
is a better approach than the one I sent, although the `ellipsis_width`
shenanigan a bit questionable; I wonder if there's a cleaner way to do
it.

Anyhow, your patch also solves the performance problem with large
strings on my end, and additionally I'm also seeing some startup time
improvement when dumping large non-ascii strings into dmenu.

- NRK



Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large strings

2022-03-20 Thread Stein Gunnar Bakkeby
Hi NRK,

I think you've gotten it backwards, this patch should *faster* if the
> string is too long, since we're incrementing up to w instead of
> decerementing down it it.


Yes you are right of course, I was mixing up the two approaches.

I have attached the changes I was experimenting with.
I still don't like the amount of effort required for drawing an ellipsis
though so I attached another patch file that doesn't try to draw the
ellipsis for comparison.

-Stein


On Sat, Mar 19, 2022 at 5:18 PM Silvan Jegen  wrote:

> Hi
>
> On Sat, Mar 19, 2022 at 12:59 PM Stein Gunnar Bakkeby 
> wrote:
> >
> > Hi NRK,
> >
> > I was tinkering with this for a few hours earlier this week and there
> are several issues with this area of code and not specifically related to
> this modification of the patch.
> >
> > The handling of adding the ellipsis (...) when the text is too long is
> rather hacky and can cause several issues.
> >
> > The general idea is that:
> >- we work out how many consecutive characters we can print for the
> same font
> >- then we check if the length of the string exceeds the remaining
> drawable space
> >- if it is too long then we check the length of the string for every
> character until we find that it no longer fits
> >- then we replace the last three bytes with periods (.)
> >
> > These are the problematic areas I have found:
> >
> > 1. In the original code the text is allowed to bleed into the right
> padding as long as it fits (I presume this is intentional). If you add one
> more character then the text is too long and it will crop of four
> characters to add the ellipsis. This has to do with that the for loop
> reduces len once more than necessary.
> >
> > 2. The adding of the ellipsis naively assumes that the last characters
> in the string are single-byte UTF-8 characters. As such when it replaces
> the last bytes of the string then you can end up with split multi-byte
> UTF-8 characters which can have various effects.
>
> I *think* I somewhat improved this issue in `vis-menu` (which is based
> on `dmenu`, IIRC):
>
>
> https://github.com/Shugyousha/vis/commit/d59b98d934815e54320ad000eebfdaaf8fee344d
>
> Note that this is not well tested and still has issues though.
>
>
> Cheers,
>
> Silvan
>
>

-- 
Stein Gunnar Bakkeby
OpenBet Developer
bakk...@gmail.com
From a69c9a63ae08b2201ee3ef615a356ace129b7f48 Mon Sep 17 00:00:00 2001
From: Bakkeby 
Date: Sun, 20 Mar 2022 13:59:23 +0100
Subject: [PATCH] Fixing split multi-byte issue when drawing ellipsis

---
 dmenu.c |  9 +++---
 drw.c   | 85 ++---
 drw.h   |  3 +-
 3 files changed, 46 insertions(+), 51 deletions(-)

diff --git a/dmenu.c b/dmenu.c
index eca67ac..5e1edd6 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -541,7 +541,7 @@ readstdin(void)
 {
 	char buf[sizeof text], *p;
 	size_t i, imax = 0, size = 0;
-	unsigned int tmpmax = 0;
+	XGlyphInfo ext;
 
 	/* read each line from stdin and add it to the item list */
 	for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
@@ -553,9 +553,9 @@ readstdin(void)
 		if (!(items[i].text = strdup(buf)))
 			die("cannot strdup %u bytes:", strlen(buf) + 1);
 		items[i].out = 0;
-		drw_font_getexts(drw->fonts, buf, strlen(buf), , NULL);
-		if (tmpmax > inputw) {
-			inputw = tmpmax;
+		XftTextExtentsUtf8(drw->fonts->dpy, drw->fonts->xfont, (XftChar8 *)buf, strlen(buf), );
+		if (ext.xOff > inputw) {
+			inputw = ext.xOff;
 			imax = i;
 		}
 	}
@@ -768,6 +768,7 @@ main(int argc, char *argv[])
 	drw = drw_create(dpy, screen, root, wa.width, wa.height);
 	if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
 		die("no fonts could be loaded.");
+	ellipsis_width = TEXTW("...") - lrpad;
 	lrpad = drw->fonts->h;
 
 #ifdef __OpenBSD__
diff --git a/drw.c b/drw.c
index 4cdbcbe..b82dab4 100644
--- a/drw.c
+++ b/drw.c
@@ -15,6 +15,7 @@ static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80,0, 0xC0, 0xE0, 0xF0}
 static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
 static const long utfmin[UTF_SIZ + 1] = {   0,0,  0x80,  0x800,  0x1};
 static const long utfmax[UTF_SIZ + 1] = {0x10, 0x7F, 0x7FF, 0x, 0x10};
+unsigned int ellipsis_width = 0;
 
 static long
 utf8decodebyte(const char c, size_t *i)
@@ -252,18 +253,18 @@ int
 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
 {
 	char buf[1024];
-	int ty;
-	unsigned int ew;
+	int ty, stop = 0;
+	unsigned int ew = 0, ellipsis_ew = 0;
 	XftDraw *d = NULL;
 	Fnt *usedfont, *curfont, *nextfont;
-	size_t i, len;
-	int utf8strlen, utf8charlen, render = x || y || w || h;
+	size_t i, b = 0, ellipsis_b = 0;
+	int utf8charlen, render = x || y || w || h;
 	long utf8codepoint = 0;
-	const char *utf8str;
 	FcCharSet *fccharset;
 	FcPattern *fcpattern;
 	FcPattern *match;
 	XftResult result;
+	XGlyphInfo ext;
 	int charexists = 0;
 
 	if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
@@ -283,8 +284,8 

Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large strings

2022-03-19 Thread Silvan Jegen
Hi

On Sat, Mar 19, 2022 at 12:59 PM Stein Gunnar Bakkeby  wrote:
>
> Hi NRK,
>
> I was tinkering with this for a few hours earlier this week and there are 
> several issues with this area of code and not specifically related to this 
> modification of the patch.
>
> The handling of adding the ellipsis (...) when the text is too long is rather 
> hacky and can cause several issues.
>
> The general idea is that:
>- we work out how many consecutive characters we can print for the same 
> font
>- then we check if the length of the string exceeds the remaining drawable 
> space
>- if it is too long then we check the length of the string for every 
> character until we find that it no longer fits
>- then we replace the last three bytes with periods (.)
>
> These are the problematic areas I have found:
>
> 1. In the original code the text is allowed to bleed into the right padding 
> as long as it fits (I presume this is intentional). If you add one more 
> character then the text is too long and it will crop of four characters to 
> add the ellipsis. This has to do with that the for loop reduces len once more 
> than necessary.
>
> 2. The adding of the ellipsis naively assumes that the last characters in the 
> string are single-byte UTF-8 characters. As such when it replaces the last 
> bytes of the string then you can end up with split multi-byte UTF-8 
> characters which can have various effects.

I *think* I somewhat improved this issue in `vis-menu` (which is based
on `dmenu`, IIRC):

https://github.com/Shugyousha/vis/commit/d59b98d934815e54320ad000eebfdaaf8fee344d

Note that this is not well tested and still has issues though.


Cheers,

Silvan



Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large strings

2022-03-19 Thread NRK
On Sat, Mar 19, 2022 at 11:06:25AM +0100, Stein Gunnar Bakkeby wrote:
> Given that it is asking XftTextExtentsUtf8 to calculate the width of every
> character every time this is checked I assume that it would be less
> performant (though possibly not so easy to measure).

Hi Bakkeby,

You can test this patch with the following script:

for _ in $(seq 20); do
cat /dev/urandom | base64 | tr -d '\n' | head -c 100
echo
done | ./dmenu -l 10

Try moving up and down, without the patch there should be noticeable
amount of lag; with the patch it's pretty much instant for me.

> Now as for the patch. It is meant as a performance improvement when strings
> are too long to fit and I can see how it might be an improvement when the
> string is just a little bit too long for the drawable area, but what if it
> is twice as long?

I think you've gotten it backwards, this patch should *faster* if the
string is too long, since we're incrementing up to w instead of
decerementing down it it.

> In an attempt to address some of these issues I played around with moving
> the XftTextExtentsUtf8 call to the section before that calculates
> utf8strlen and maintaining the ew variable manually. In practice means that
> the call to XftTextExtentsUtf8 is made for every single UTF-8 character
> (but only one character at a time).
> 
> In addition to this I recorded the width of "..." to calculate and keep
> track of the last full UTF-8 character where the ellipsis would still fit
> so that I know where to go back to should the ellipsis need to be drawn.
> 
> I can show the implementation of that should there be any interest.

Sure, I'm interested in seeing what you've come up with, especially
since I've been thinking of making some changes to drw_text() myself.

- NRK



Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large strings

2022-03-19 Thread Stein Gunnar Bakkeby
Hi NRK,

I was tinkering with this for a few hours earlier this week and there are
several issues with this area of code and not specifically related to this
modification of the patch.

The handling of adding the ellipsis (...) when the text is too long is
rather hacky and can cause several issues.

The general idea is that:
   - we work out how many consecutive characters we can print for the same
font
   - then we check if the length of the string exceeds the remaining
drawable space
   - if it is too long then we check the length of the string for every
character until we find that it no longer fits
   - then we replace the last three bytes with periods (.)

These are the problematic areas I have found:

1. In the original code the text is allowed to bleed into the right padding
as long as it fits (I presume this is intentional). If you add one more
character then the text is too long and it will crop of four characters to
add the ellipsis. This has to do with that the for loop reduces len once
more than necessary.

2. The adding of the ellipsis naively assumes that the last characters in
the string are single-byte UTF-8 characters. As such when it replaces the
last bytes of the string then you can end up with split multi-byte UTF-8
characters which can have various effects.

3. Even if the ellipsis has been drawn and it is not possible to draw
anything else the code will continue as long as there is more text to
process.

4. If there is a font change right before the ellipsis is drawn then the
ellipsis will not be drawn (or not completely). More so if I am reading it
right then if len is 1 it may be writing '.' to bad areas of memory.

5. When attempting to shorten the text it also assumes single-byte
characters, which means that if you have a string of euro symbols (€) then
it will call drw_font_getexts for each of the four bytes in that character.


Now as for the patch. It is meant as a performance improvement when strings
are too long to fit and I can see how it might be an improvement when the
string is just a little bit too long for the drawable area, but what if it
is twice as long?

Given that it is asking XftTextExtentsUtf8 to calculate the width of every
character every time this is checked I assume that it would be less
performant (though possibly not so easy to measure).


In an attempt to address some of these issues I played around with moving
the XftTextExtentsUtf8 call to the section before that calculates
utf8strlen and maintaining the ew variable manually. In practice means that
the call to XftTextExtentsUtf8 is made for every single UTF-8 character
(but only one character at a time).

In addition to this I recorded the width of "..." to calculate and keep
track of the last full UTF-8 character where the ellipsis would still fit
so that I know where to go back to should the ellipsis need to be drawn.

I can show the implementation of that should there be any interest.


All in all I think the drawing of the ellipsis should either simply be
dropped or a more simple solution should be found to indicate that the
string (typically window title) is cut.



Thanks,

-Stein



On Sat, Mar 19, 2022 at 9:09 AM NRK  wrote:

> Hi all,
>
> Adding to this: I've been using this patch, both in dmenu and dwm, for
> the past week or so and haven't run into any issues. If someone finds
> any, feel free to send some reproduction steps.
>
> Also noticed some small white-space issue in drw.h, don't think it's
> worth sending another mail for, so I've attached the patch for it in
> this mail.
>
> - NRK
>


-- 
Stein Gunnar Bakkeby
OpenBet Developer
bakk...@gmail.com


Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large strings

2022-03-19 Thread NRK
Hi all,

Adding to this: I've been using this patch, both in dmenu and dwm, for
the past week or so and haven't run into any issues. If someone finds
any, feel free to send some reproduction steps.

Also noticed some small white-space issue in drw.h, don't think it's
worth sending another mail for, so I've attached the patch for it in
this mail.

- NRK
>From 69c55a03a7efe8f4157388f0ad9d02b7b97c7520 Mon Sep 17 00:00:00 2001
From: NRK 
Date: Thu, 17 Mar 2022 18:24:29 +0600
Subject: [PATCH 2/3] small white space fix

---
 drw.c | 2 +-
 drw.h | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drw.c b/drw.c
index bbce179..6240865 100644
--- a/drw.c
+++ b/drw.c
@@ -166,7 +166,7 @@ xfont_free(Fnt *font)
 	free(font);
 }
 
-Fnt*
+Fnt *
 drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
 {
 	Fnt *cur, *ret = NULL;
diff --git a/drw.h b/drw.h
index 4c67419..89872ba 100644
--- a/drw.h
+++ b/drw.h
@@ -32,8 +32,8 @@ void drw_resize(Drw *drw, unsigned int w, unsigned int h);
 void drw_free(Drw *drw);
 
 /* Fnt abstraction */
-Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
-void drw_fontset_free(Fnt* set);
+Fnt *drw_fontset_create(Drw *drw, const char *fonts[], size_t fontcount);
+void drw_fontset_free(Fnt *set);
 unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
 void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
 
-- 
2.34.1