+static char *x11font_size_increment(unifont *font, int increment)
+{
+ struct x11font *xfont = (struct x11font *)font;
+ Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ Atom fontprop = XInternAtom(disp, "FONT", False);
+ char *returned_name = NULL;
+ unsigned long ret;
+ if (XGetFontProperty(xfont->fonts[0].xfs, fontprop, &ret)) {
+ struct xlfd_decomposed *xlfd;
+ struct xlfd_decomposed *xlfd_best;
+ char *wc;
+ char **fontnames;
+ int nnames, i, max;
+
+ xlfd = xlfd_decompose(XGetAtomName(disp, (Atom)ret));
+ if (!xlfd)
+ return NULL;
+
+ /*
+ * Form a wildcard consisting of everything in the
+ * original XLFD except for the size-related fields.
+ */
+ {
+ struct xlfd_decomposed xlfd_wc = *xlfd; /* structure copy */
+ xlfd_wc.pixel_size = XLFD_INT_WILDCARD;
+ xlfd_wc.point_size = XLFD_INT_WILDCARD;
+ xlfd_wc.average_width = XLFD_INT_WILDCARD;
+ wc = xlfd_recompose(&xlfd_wc);
+ }
+
+ /*
+ * Fetch all the font names matching that wildcard.
+ */
+ max = 32768;
+ while (1) {
+ fontnames = XListFonts(disp, wc, max, &nnames);
+ if (nnames >= max) {
+ XFreeFontNames(fontnames);
+ max *= 2;
+ } else
+ break;
+ }
+
+ sfree(wc);
+
+ /*
+ * Iterate over those to find the one closest in size to the
+ * original font, in the correct direction.
+ */
+
+#define FLIPPED_SIZE(xlfd) \
+ (((xlfd)->pixel_size + (xlfd)->point_size) * \
+ (increment < 0 ? -1 : +1))
+
+ xlfd_best = NULL;
+ for (i = 0; i < nnames; i++) {
+ struct xlfd_decomposed *xlfd2 = xlfd_decompose(fontnames[i]);
+ if (!xlfd2)
+ continue;
+
+ if (xlfd2->pixel_size != 0 &&
+ FLIPPED_SIZE(xlfd2) > FLIPPED_SIZE(xlfd) &&
+ (!xlfd_best || FLIPPED_SIZE(xlfd2)<FLIPPED_SIZE(xlfd_best))) {
+ sfree(xlfd_best);
+ xlfd_best = xlfd2;
+ xlfd2 = NULL;
+ }
+
+ sfree(xlfd2);
+ }
+
+#undef FLIPPED_SIZE
+
+ if (xlfd_best) {
+ char *bare_returned_name = xlfd_recompose(xlfd_best);
+ returned_name = dupcat(
+ xfont->u.vt->prefix, ":", bare_returned_name,
+ (const char *)NULL);
+ sfree(bare_returned_name);
+ }
+
+ XFreeFontNames(fontnames);
+ sfree(xlfd);
+ sfree(xlfd_best);
+ }
+ return returned_name;
+}
+