Subject: 30.0.50; Font update for no toolkit menu

From: Manuel Giraud <[email-masked]>
Date: Sat, 24 Jun 2023 19:00:04 +0200

Hi,

I'd like to be able to update the menu font (for the no toolkit build)
at runtime.  For this, my idea was to pass the font (from say the menu
face) to the XMenuCreate call in x_menu_show.

I thought that the font's XLFD string would be a good candidate to pass
this information since it should be understood by XLoadQueryFont.  But
unfortunately, the XLFD returned by font_unparse_xlfd are not.

For instance, XLoadQueryFont can understand
"-misc-fixed-medium-r-normal-*-22-*-*-*-*-*-*-*" but not
"-misc-fixed-regular-r-normal-*-22-*-*-*-*-*-*-*".  Do you think I need
a function to « normalize » the XLFD returned by font_unparse_xlfd?  Or
maybe I'm missing something?

FTR, here is a patch of what I have started:
diff --git a/oldXMenu/Create.c b/oldXMenu/Create.c
index 9518b2833a2..27cf14b0529 100644
--- a/oldXMenu/Create.c
+++ b/oldXMenu/Create.c
@@ -120,7 +120,8 @@ XAllocDisplayColor(Display *display, Colormap map, char const *colorName,

 XMenu *
-XMenuCreate(Display *display, Window parent, register char const *def_env)
+XMenuCreate(Display *display, Window parent, register char const *def_env,
+	    register char const *def_font)
                                 /* ID of previously opened display */
                   		/* Window ID of the menu's parent window. */
                            	/* X Defaults program environment name. */
@@ -322,7 +323,10 @@ XMenuCreate(Display *display, Window parent, register char const *def_env)
   }
 
   def_val = x_get_resource_string ("paneFont", "PaneFont");
-  if (def_val != NULL) p_fnt_name = def_val;
+  if (def_val != NULL)
+    p_fnt_name = def_val;
+  else if (def_font != NULL)
+    p_fnt_name = def_font;
 
   def_val = x_get_resource_string ("paneForeground", "PaneForeground");
   if (
@@ -378,7 +382,10 @@ XMenuCreate(Display *display, Window parent, register char const *def_env)
   }
 
   def_val = x_get_resource_string ("selectionFont", "SelectionFont");
-  if (def_val != NULL) s_fnt_name = def_val;
+  if (def_val != NULL)
+    s_fnt_name = def_val;
+  else if (def_font != NULL)
+    s_fnt_name = def_font;
 
   def_val = x_get_resource_string ("selectionForeground", "SelectionForeground");
   if (
@@ -568,15 +575,22 @@ XMenuCreate(Display *display, Window parent, register char const *def_env)
 
   p_fnt_info = XLoadQueryFont(display, p_fnt_name);
   if (p_fnt_info == NULL) {
-    _XMErrorCode = XME_OPEN_FONT;
-    return(NULL);
-
+    /* Retry with most basic default.  */
+    p_fnt_info = XLoadQueryFont(display, DEF_P_FNT_NAME);
+    if (p_fnt_info == NULL) {
+      _XMErrorCode = XME_OPEN_FONT;
+      return(NULL);
+    }
   }
 
   s_fnt_info = XLoadQueryFont(display, s_fnt_name);
   if (s_fnt_info == NULL) {
-    _XMErrorCode = XME_OPEN_FONT;
-    return(NULL);
+    /* Retry with most basic default.  */
+    s_fnt_info = XLoadQueryFont(display, DEF_S_FNT_NAME);
+    if (s_fnt_info == NULL) {
+      _XMErrorCode = XME_OPEN_FONT;
+      return(NULL);
+    }
   }
   /*
    * Calculate the fixed padding value in pixels for each font.
diff --git a/oldXMenu/XMenu.h b/oldXMenu/XMenu.h
index 2eee18a3844..e920f266697 100644
--- a/oldXMenu/XMenu.h
+++ b/oldXMenu/XMenu.h
@@ -263,7 +263,7 @@ #define XME_CREATE_TRANSP	16
 /*
  * XMenu library routine declarations.
  */
-XMenu *XMenuCreate(Display *display, Window parent, char const *def_env);
+XMenu *XMenuCreate(Display *display, Window parent, char const *def_env, char const *def_font);
 int XMenuAddPane(Display *display, XMenu *menu, char const *label, int active);
 int XMenuAddSelection(Display *display, XMenu *menu, int p_num, char *data, char *label, int active, char const *help);
 int XMenuInsertPane(XMenu *menu, int p_num, char *label, int active);
diff --git a/src/msdos.c b/src/msdos.c
index 75a39045cee..f380bef7c51 100644
--- a/src/msdos.c
+++ b/src/msdos.c
@@ -2947,7 +2947,7 @@ IT_menu_display (XMenu *menu, int y, int x, int pn, int *faces, int disp_help)
 /* Create a brand new menu structure.  */
 
 XMenu *
-XMenuCreate (Display *foo1, Window foo2, char *foo3)
+XMenuCreate (Display *foo1, Window foo2, char *foo3, char *foo4)
 {
   return IT_menu_create ();
 }
diff --git a/src/msdos.h b/src/msdos.h
index 94878d25b35..aac6d8d65ca 100644
--- a/src/msdos.h
+++ b/src/msdos.h
@@ -143,7 +143,7 @@ #define ButtonReleaseMask 0
   const char **help_text;
 } XMenu;
 
-XMenu *XMenuCreate (Display *, Window, char *);
+XMenu *XMenuCreate (Display *, Window, char *, char *);
 int XMenuAddPane (Display *, XMenu *, char const *, int);
 int XMenuAddSelection (Display *, XMenu *, int, int, char *, int, char const *);
 void XMenuLocate (Display *, XMenu *, int, int, int, int,
diff --git a/src/xmenu.c b/src/xmenu.c
index 6d32aa3e078..8beb6534bdf 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -2564,6 +2564,11 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
   int maxwidth;
   int dummy_int;
   unsigned int dummy_uint;
+  struct face *face;
+  Lisp_Object font_object;
+  /* char xlfd[512] = "-misc-fixed-medium-r-normal-*-22-*-*-*-*-*-*-*"; */
+  char xlfd[512];
+
   specpdl_ref specpdl_count = SPECPDL_INDEX ();
 
   eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
@@ -2586,8 +2591,20 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
 		&dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
 		&dummy_uint, &dummy_uint);
 
-  /* Make the menu on that window.  */
-  menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
+  /* Get default frame font's XLFD and make the menu on that
+     window.  */
+  face = FACE_FROM_ID_OR_NULL (f, MENU_FACE_ID);
+  if (face && face->font) {
+    XSETFONT (font_object, face->font);
+    if (font_unparse_xlfd (font_object, 0, xlfd, 512) <= 0)
+      {
+	*error_name = "XLFD unparse failed";
+	return Qnil;
+      }
+    menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs", xlfd);
+  } else
+    menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs", NULL);
+
   if (menu == NULL)
     {
       *error_name = "Can't create menu";

Best regards,

In GNU Emacs 30.0.50 (build 2, x86_64-unknown-openbsd7.3, cairo version
 1.17.8) of 2023-06-23 built on computer
Repository revision: c31688cb061bf76c5300abadaf6fe589603b0184
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101006
System Description: OpenBSD computer 7.3 GENERIC.MP#1125 amd64

Configured using:
 'configure --prefix=/home/manuel/emacs --bindir=/home/manuel/bin
 --with-x-toolkit=no --without-sound --without-compress-install
 CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib'

Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG JSON
LCMS2 LIBOTF LIBXML2 MODULES NOTIFY KQUEUE OLDXMENU PDUMPER PNG RSVG
SQLITE3 THREADS TIFF TREE_SITTER WEBP X11 XDBE XIM XINPUT2 XPM ZLIB

Important settings:
  value of $LC_ALL: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Message

Minor modes in effect:
  gnus-message-citation-mode: t
  global-git-commit-mode: t
  magit-auto-revert-mode: t
  gdb-many-windows: t
  display-time-mode: t
  display-battery-mode: t
  server-mode: t
  mml-mode: t
  shell-dirtrack-mode: t
  override-global-mode: t
  repeat-mode: t
  desktop-save-mode: t
  global-eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  line-number-mode: t
  auto-fill-function: message-do-auto-fill
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  abbrev-mode: t

Load-path shadows:
/home/manuel/.el/nov hides /home/manuel/.emacs.d/elpa/nov-20230421.1548/nov
/home/manuel/.emacs.d/elpa/ef-themes-1.1.1/theme-loaddefs hides /home/manuel/emacs/share/emacs/30.0.50/lisp/theme-loaddefs

Features:
(shadow emacsbug whitespace vc-annotate mailalias flow-fill sort
gnus-cite mail-extr textsec uni-scripts idna-mapping ucs-normalize
uni-confusable textsec-check gnus-async gnus-bcklg gnus-ml gnus-topic
mm-archive url-cache qp utf-7 imap rfc2104 nndoc nndraft nnmh
network-stream nnfolder nnml gnus-agent gnus-srvr gnus-score score-mode
nnvirtual nntp gnus-cache nnrss find-dired ffap two-column
detached-shell dabbrev magit-extras face-remap magit-submodule
magit-obsolete magit-blame magit-stash magit-reflog magit-bisect
magit-push magit-pull magit-fetch magit-clone magit-remote magit-commit
magit-sequence magit-notes magit-worktree magit-tag magit-merge
magit-branch magit-reset magit-files magit-refs magit-status magit
magit-repos magit-apply magit-wip magit-log which-func magit-diff
smerge-mode diff git-commit log-edit add-log magit-core magit-autorevert
magit-margin magit-transient magit-process with-editor magit-mode
transient magit-git magit-section magit-utils dash gdb-mi bindat gud
misearch multi-isearch pulse descr-text ibuf-ext ibuffer
ibuffer-loaddefs asm-mode css-mode imenu make-mode org-indent org-agenda
warnings rng-xsd xsd-regexp rng-cmpct rng-nxml rng-valid rng-loc rng-uri
rng-parse nxml-parse rng-match rng-dt rng-util rng-pttrn nxml-ns
nxml-mode nxml-outln nxml-rap sgml-mode facemenu nxml-util nxml-enc
xmltok sh-script smie treesit executable pascal view org-element
org-persist org-id org-refile avl-tree oc-basic ol-eww eww url-queue
mm-url ol-rmail ol-mhe ol-irc ol-info ol-gnus nnselect ol-docview
doc-view jka-compr image-mode exif ol-bibtex bibtex ol-bbdb ol-w3m
ol-doi org-link-doi org ob ob-tangle ob-ref ob-lob ob-table ob-exp
org-macro org-src ob-comint org-pcomplete org-list org-footnote
org-faces org-entities ob-emacs-lisp ob-core ob-eval org-cycle org-table
ol org-fold org-fold-core org-keys oc org-loaddefs org-version
org-compat org-macs mule-util gnus-dired vc-cvs vc-rcs log-view
pcvs-util vc-hg conf-mode vc-git diff-mode vc bug-reference
vc-dispatcher vc-svn paredit time battery cus-load exwm-randr xcb-randr
exwm-config ido exwm exwm-input xcb-keysyms xcb-xkb exwm-manage
exwm-floating xcb-cursor xcb-render exwm-layout exwm-workspace exwm-core
xcb-ewmh xcb-icccm xcb xcb-xproto xcb-types xcb-debug server
modus-operandi-theme modus-themes zone speed-type url-http url-auth
url-gw nsm compat ytdious mingus libmpdee reporter edebug debug
backtrace detached-init detached autorevert filenotify transmission
color calc-bin calc-ext calc calc-loaddefs rect calc-macs supercite regi
ebdb-message ebdb-gnus gnus-msg gnus-art mm-uu mml2015 mm-view mml-smime
smime gnutls dig gnus-sum shr pixel-fill kinsoku url-file svg dom
gnus-group gnus-undo gnus-start gnus-dbus gnus-cloud nnimap nnmail
mail-source utf7 nnoo gnus-spec gnus-int gnus-range message sendmail
yank-media puny rfc822 mml mml-sec epa epg rfc6068 epg-config mm-decode
mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045 ietf-drums
gmm-utils mailheader gnus-win gnus nnheader gnus-util mail-utils range
mm-util mail-prsvr wid-edit ebdb-mua ebdb-com crm ebdb-format ebdb
mailabbrev eieio-opt speedbar ezimage dframe find-func eieio-base pcase
timezone icalendar visual-basic-mode cl web-mode derived disp-table
erlang-start smart-tabs-mode skeleton cc-mode cc-fonts cc-guess cc-menus
cc-cmds cc-styles cc-align cc-engine cc-vars cc-defs slime-asdf grep
slime-tramp tramp rx tramp-loaddefs trampver tramp-integration files-x
tramp-compat xdg shell pcomplete parse-time iso8601 time-date
format-spec slime-fancy slime-indentation slime-cl-indent cl-indent
slime-trace-dialog slime-fontifying-fu slime-package-fu slime-references
slime-compiler-notes-tree advice slime-scratch slime-presentations
bridge slime-macrostep macrostep slime-mdot-fu slime-enclosing-context
slime-fuzzy slime-fancy-trace slime-fancy-inspector slime-c-p-c
slime-editing-commands slime-autodoc slime-repl slime-parse slime
apropos compile text-property-search etags fileloop generator xref
project arc-mode archive-mode noutline outline icons pp comint ansi-osc
ansi-color ring hyperspec thingatpt slime-autoloads edmacro kmacro
use-package-bind-key bind-key appt diary-lib diary-loaddefs cal-menu
calendar cal-loaddefs dired-x dired-aux dired dired-loaddefs
notifications dbus xml cl-extra help-mode use-package-core repeat
easy-mmode desktop frameset debbugs-autoloads detached-autoloads
ebdb-autoloads ef-themes-autoloads exwm-autoloads hyperbole-autoloads
magit-autoloads git-commit-autoloads finder-inf magit-section-autoloads
dash-autoloads nov-autoloads esxml-autoloads kv-autoloads osm-autoloads
paredit-autoloads rust-mode-autoloads speed-type-autoloads
transmission-autoloads visual-fill-column-autoloads
with-editor-autoloads info compat-autoloads ytdious-autoloads package
browse-url url url-proxy url-privacy url-expand url-methods url-history
url-cookie generate-lisp-file url-domsuf url-util mailcap url-handlers
url-parse auth-source cl-seq eieio eieio-core cl-macs password-cache
json subr-x map byte-opt gv bytecomp byte-compile url-vars cl-loaddefs
cl-lib rmc iso-transl tooltip cconv eldoc paren electric uniquify
ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win
term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe
tabulated-list replace newcomment text-mode lisp-mode prog-mode register
page tab-bar menu-bar rfn-eshadow isearch easymenu timer select
scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors
frame minibuffer nadvice seq simple cl-generic indonesian philippine
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese composite emoji-zwj charscript
charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure
cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp
files window text-properties overlay sha1 md5 base64 format env
code-pages mule custom widget keymap hashtable-print-readable backquote
threads dbusbind kqueue lcms2 dynamic-setting system-font-setting
font-render-setting cairo xinput2 x multi-tty make-network-process
emacs)

Memory information:
((conses 16 2106933 883109) (symbols 48 78760 81)
 (strings 32 379449 53218) (string-bytes 1 11549873)
 (vectors 16 201452) (vector-slots 8 3851627 142928)
 (floats 8 717 6576) (intervals 56 260191 18474) (buffers 984 187))

-- 
Manuel Giraud