Re: [hackers] [dwm][PATCH] drw: use cap height for optical text centering

From: Alessio Artoni <aartoni_AT_artixlinux.org>
Date: Tue, 19 May 2026 16:35:48 +0200

 From 4dace0d93eee428ca92069efd462de3450e955b5 Mon Sep 17 00:00:00 2001
From: aartoni <aartoni_AT_artixlinux.org>
Date: Tue, 19 May 2026 13:55:40 +0200
Subject: [dwm][PATCH] drw: use cap height for optical text centering

The current formula centers the font em box (ascent + descent)
within the drawing area. This assumes visible ink is symmetric
inside that box. Fonts whose ascent includes significant internal
leading above the cap line (e.g. Fira Code: ascent 894, capHeight
1377, upm 1950) cause text to ride above optical center.

Read the cap height by measuring a capital H via XftTextExtents8,
which is already linked. Center the cap height span instead of the
em box. For fonts where the measurement fails (ext.y <= 0), fall
back to 2*ascent - h, which is algebraically equivalent to the old
formula and produces pixel-identical output.

No new dependencies. No change for fonts with symmetric metrics.
---
  drw.c | 7 ++++++-
  drw.h | 1 +
  2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/drw.c b/drw.c
index 9fdd1a4..f94c2e6 100644
--- a/drw.c
+++ b/drw.c
_AT_@ -94,6 +94,7 @@ xfont_create(Drw *drw, const char *fontname, FcPattern
*fontpattern)
          Fnt *font;
          XftFont *xfont = NULL;
          FcPattern *pattern = NULL;
+ XGlyphInfo ext;

          if (fontname) {
                  /* Using the pattern found at font->xfont->pattern does not yield the
_AT_@ -123,6 +124,10 @@ xfont_create(Drw *drw, const char *fontname,
FcPattern *fontpattern)
          font->xfont = xfont;
          font->pattern = pattern;
          font->h = xfont->ascent + xfont->descent;
+ font->cap = MAX(xfont->ascent - xfont->descent, 0);
+ XftTextExtents8(drw->dpy, xfont, (FcChar8 *)"H", 1, &ext);
+ if (ext.y > 0)
+ font->cap = ext.y;
          font->dpy = drw->dpy;

          return font;
_AT_@ -330,7 +335,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w,
unsigned int h, unsigned int lp

                  if (utf8strlen) {
                          if (render) {
- ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
+ ty = y + (h + usedfont->cap) / 2;
                                  XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
                                                    usedfont->xfont, x, ty, (XftChar8 *)utf8str,
utf8strlen);
                          }
diff --git a/drw.h b/drw.h
index bda06f9..eea46ce 100644
--- a/drw.h
+++ b/drw.h
_AT_@ -6,6 +6,7 @@ typedef struct {

  typedef struct Fnt {
          Display *dpy;
+ unsigned int cap;
          unsigned int h;
          XftFont *xfont;
          FcPattern *pattern;
--
2.54.0

Definitely better now. Thanks!
--
aartoni




Received on Tue May 19 2026 - 16:35:48 CEST

This archive was generated by hypermail 2.3.0 : Tue May 19 2026 - 16:48:40 CEST