Raymond Toy pushed to branch master at cmucl / cmucl
Commits:
2e3b90ff by Raymond Toy at 2021-09-22T15:09:27-07:00
Update release notes from changes up to 2021/09/22
- - - - -
1 changed file:
- src/general-info/release-21e.md
Changes:
=====================================
src/general-info/release-21e.md
=====================================
@@ -43,8 +43,11 @@ public domain.
* ~~#98~~ fstpd is not an Intel instruction; disassemble as `fstp dword ptr [addr]`
* ~~#100~~ ldb prints out unicode base-chars correctly instead of just the low 8 bits.
* ~~#103~~ RANDOM-MT19937-UPDATE assembly routine still exists
+ * ~~#104~~ Single-stepping broken (fixed via #97).
* ~~#107~~ Replace u_int8_t with uint8_t
* ~~#108~~ Update ASDF
+ * ~~#112~~ CLX can't connect to X server via inet sockets
+ * ~~#113~~ REQUIRE on contribs can pull in the wrong things vai ASDF.
* Other changes:
* Improvements to the PCL implementation of CLOS:
* Changes to building procedure:
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/2e3b90ff9cc84de876fd993…
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/2e3b90ff9cc84de876fd993…
You're receiving this email because of your account on gitlab.common-lisp.net.
Raymond Toy pushed to branch master at cmucl / cmucl
Commits:
d2c70ec2 by Raymond Toy at 2021-09-20T23:11:06+00:00
Fix #112: Update CLX sources of 2021-09-19 and support inet sockets
- - - - -
263e9398 by Raymond Toy at 2021-09-20T23:11:07+00:00
Merge branch 'clx-update-2021-09-19' into 'master'
Fix #112: Update CLX sources of 2021-09-19 and support inet sockets
Closes #112
See merge request cmucl/cmucl!80
- - - - -
14 changed files:
- src/clx/README.md
- src/clx/attributes.lisp
- src/clx/buffer.lisp
- src/clx/clx.asd
- src/clx/clx.lisp
- src/clx/demo/clclock.lisp
- src/clx/demo/clx-demos.lisp
- src/clx/demo/mandel.lisp
- src/clx/demo/menu.lisp
- src/clx/dep-allegro.lisp
- src/clx/dep-lispworks.lisp
- src/clx/depdefs.lisp
- src/clx/dependent.lisp
- src/clx/display.lisp
The diff was not included because it is too large.
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/a47dbed7928a613539647b…
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/a47dbed7928a613539647b…
You're receiving this email because of your account on gitlab.common-lisp.net.
Raymond Toy pushed to branch master at cmucl / cmucl
Commits:
3824d74a by Raymond Toy at 2021-09-20T21:54:32+00:00
Fix #113: Search cmucl modules and libraries first
- - - - -
a47dbed7 by Raymond Toy at 2021-09-20T21:54:33+00:00
Merge branch 'issue-113-prefer-cmucl-modules' into 'master'
Fix #113: Search cmucl modules and libraries first
Closes #113
See merge request cmucl/cmucl!78
- - - - -
2 changed files:
- src/code/module.lisp
- src/i18n/locale/cmucl.pot
Changes:
=====================================
src/code/module.lisp
=====================================
@@ -37,8 +37,13 @@
(defvar *require-verbose* t
"*load-verbose* is bound to this before loading files.")
+(defvar *cmucl-provider-functions*
+ '(module-provide-cmucl-defmodule module-provide-cmucl-library)
+ "Provider functions for cmucl modules and libraries. These are
+ searched first before trying *module-provider-functions*")
+
(defvar *module-provider-functions*
- '(module-provide-cmucl-defmodule module-provide-cmucl-library)
+ nil
"See function documentation for REQUIRE")
;;;; Defmodule.
@@ -102,11 +107,6 @@
\"contrib-games-feebs\", \"contrib-hist\", \"contrib-psgraph\",
\"contrib-ops\", \"contrib-embedded-c\", \"contrib-sprof\", and
\"contrib-packed-sse2\". "
- ;; First, load asdf if it's not already loaded. This is needed to
- ;; load easily the contribs that use asdf. There are no contribs
- ;; that use defsystem, so we won't autoload defsystem.
- (unless (featurep :asdf)
- (load "modules:asdf/asdf"))
(let ((saved-modules (copy-list *modules*))
(module-name (module-name-string module-name)))
(unless (member module-name *modules* :test #'string=)
@@ -114,9 +114,20 @@
(if pathname
(dolist (file (if (consp pathname) pathname (list pathname)) t)
(load file))
- (unless (some (lambda (p) (funcall p module-name))
- *module-provider-functions*)
- (error (intl:gettext "Don't know how to load ~A") module-name)))))
+ ;; Search *cmucl-provider-functions* first so that we'll
+ ;; load our version of clx (and friends) before loading
+ ;; any asdf version, if asdf is loaded.
+ (or (some (lambda (p) (funcall p module-name))
+ *cmucl-provider-functions*)
+ (progn
+ ;; Load asdf if it's not already loaded. This is needed to
+ ;; load easily the contribs that use asdf. There are no contribs
+ ;; that use defsystem, so we won't autoload defsystem.
+ (unless (featurep :asdf)
+ (load "modules:asdf/asdf"))
+ (some (lambda (p) (funcall p module-name))
+ *module-provider-functions*))
+ (error (intl:gettext "Don't know how to load ~A") module-name)))))
(set-difference *modules* saved-modules)))
;;;; Default module providers
=====================================
src/i18n/locale/cmucl.pot
=====================================
@@ -10397,6 +10397,12 @@ msgstr ""
msgid "*load-verbose* is bound to this before loading files."
msgstr ""
+#: src/code/module.lisp
+msgid ""
+"Provider functions for cmucl modules and libraries. These are\n"
+" searched first before trying *module-provider-functions*"
+msgstr ""
+
#: src/code/module.lisp
msgid "See function documentation for REQUIRE"
msgstr ""
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/a2dfe20ddefc60bb9e55a4…
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/a2dfe20ddefc60bb9e55a4…
You're receiving this email because of your account on gitlab.common-lisp.net.
Raymond Toy pushed to branch issue-113-prefer-cmucl-modules at cmucl / cmucl
Commits:
af8841b4 by Raymond Toy at 2021-09-20T11:49:07-07:00
Only load ASDF if the Cmucl providers failed
If the cmucl providers succeed, don't load asdf so we don't
unnecessarily pollute the image if asdf isn't needed. If the cmucl
providers fail, then load asdf so we can use asdf to load the other
contribs or other asdf packages that might be available.
- - - - -
1 changed file:
- src/code/module.lisp
Changes:
=====================================
src/code/module.lisp
=====================================
@@ -107,11 +107,6 @@
\"contrib-games-feebs\", \"contrib-hist\", \"contrib-psgraph\",
\"contrib-ops\", \"contrib-embedded-c\", \"contrib-sprof\", and
\"contrib-packed-sse2\". "
- ;; First, load asdf if it's not already loaded. This is needed to
- ;; load easily the contribs that use asdf. There are no contribs
- ;; that use defsystem, so we won't autoload defsystem.
- (unless (featurep :asdf)
- (load "modules:asdf/asdf"))
(let ((saved-modules (copy-list *modules*))
(module-name (module-name-string module-name)))
(unless (member module-name *modules* :test #'string=)
@@ -124,8 +119,14 @@
;; any asdf version, if asdf is loaded.
(or (some (lambda (p) (funcall p module-name))
*cmucl-provider-functions*)
- (some (lambda (p) (funcall p module-name))
- *module-provider-functions*)
+ (progn
+ ;; Load asdf if it's not already loaded. This is needed to
+ ;; load easily the contribs that use asdf. There are no contribs
+ ;; that use defsystem, so we won't autoload defsystem.
+ (unless (featurep :asdf)
+ (load "modules:asdf/asdf"))
+ (some (lambda (p) (funcall p module-name))
+ *module-provider-functions*))
(error (intl:gettext "Don't know how to load ~A") module-name)))))
(set-difference *modules* saved-modules)))
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/af8841b424a38d43fe5debc…
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/af8841b424a38d43fe5debc…
You're receiving this email because of your account on gitlab.common-lisp.net.
Raymond Toy pushed to branch issue-111-fixes-for-motifd-clm at cmucl / cmucl
Commits:
81d8160b by Raymond Toy at 2021-09-19T14:05:13-07:00
Unify naming of Core X11 and Xft2 fonts in CLM, use in INTERFACE.
The substance of this commit is the new file,
src/motif/lisp/fonts.lisp. This file contains a couple of trivial
models of Core X11 and fontconfig names, heuristics for telling them
apart, a convention for deciding the ambiguous cases, and a utility
that uses that convention to generate corresponding resource strings
for OpenMotif. For the moment the only exported interfaces are
GENERATE-HEURISTICATED-FONT-RESOURCES and a
user-customizable *AMBIGUOUS-FONT-DISPOSITION*, exported in
src/motif/lisp/initial.lisp. src/tools/clmcom.lisp is adjusted to
include fonts.lisp.
src/interface/interface.lisp take advantage of the new font naming
functionality, by calling GENERATE-HEURISTICATED-FONT-RESOURCES with
some tag names and new user-customizable font name variables to create
fallback resources. src/interface/initial.lisp exports those font name
variables.
- - - - -
5 changed files:
- src/interface/initial.lisp
- src/interface/interface.lisp
- + src/motif/lisp/fonts.lisp
- src/motif/lisp/initial.lisp
- src/tools/clmcom.lisp
Changes:
=====================================
src/interface/initial.lisp
=====================================
@@ -22,6 +22,8 @@
(:use "TOOLKIT" "LISP" "EXTENSIONS" "KERNEL")
(:shadow "CLASS-DIRECT-SUPERCLASSES")
(:export "*INTERFACE-STYLE*" "+HEADER-TAG+" "+ITALIC-TAG+"
+ "*DEFAULT-FONT-NAME*" "*HEADER-FONT-NAME*" "*ITALIC-FONT-NAME*"
+ "*AMBIGUOUS-FONT-DISPOSITION*"
"USE-GRAPHICS-INTERFACE" "VERIFY-SYSTEM-SERVER-EXISTS"
"CREATE-INTERFACE-SHELL" "POPUP-INTERFACE-PANE"
"CREATE-INTERFACE-PANE-SHELL" "FIND-INTERFACE-PANE"
=====================================
src/interface/interface.lisp
=====================================
@@ -64,6 +64,13 @@
(defconstant +header-tag+ "header")
(defconstant +italic-tag+ "italic")
+;; Default fonts. Users are allowed to customize these. Note that
+;; changing them only takes effect the next time these interface
+;; programs start a fresh motifd process.
+(defvar *default-font-name* "Helvetica-12:Regular")
+(defvar *header-font-name* "Helvetica-12:Bold")
+(defvar *italic-font-name* "Helvetica-12:Italic")
+
;;;; Functions for dealing with interface widgets
@@ -74,7 +81,10 @@
(let ((con (xt::open-motif-connection
*default-server-host* *default-display*
"lisp" "Lisp"
- nil ;; fallback resources go here.
+ (generate-heuristicated-font-resources
+ (list "" +header-tag+ +italic-tag+)
+ (list *default-font-name* *header-font-name*
+ *italic-font-name*))
(and *system-motif-server*
(ext:process-pid *system-motif-server*)))))
(with-motif-connection (con)
=====================================
src/motif/lisp/fonts.lisp
=====================================
@@ -0,0 +1,646 @@
+;;;; -*- Mode: Lisp ; Package: Toolkit -*-
+
+(ext:file-comment "$Header: src/motif/lisp/fonts.lisp $")
+
+;;; fonts.lisp -- some machinery for unifying the naming of
+;;; traditional Core X11 Fonts with Xft2 fonts. Conceptually almost
+;;; all of this this file is not specific to CLM (it's mostly parsing
+;;; and some invented heuristics/conventions that could be useful in
+;;; X11 context), but it currently only models the minimum properties
+;;; of font names necessary to generate the resource specifications
+;;; OpenMotif uses to configure fonts. However, the interfaces in this
+;;; file were designed to permit retrofitting in a richer model
+;;; non-disruptively.
+
+(in-package "TOOLKIT")
+
+;; For reasons that'll be explained as we go, we need to parse (or at
+;; least validate) font name strings. Here's the base class for
+;; parsing errors.
+(define-condition font-name-parse-error (parse-error)
+ ((kind :initarg :kind :reader font-name-parse-error-kind)
+ (string :initarg :string :reader font-name-parse-error-string)
+ (index :initarg :index :reader font-name-parse-error-index)
+ (description :initarg :description
+ :reader font-name-parse-error-description))
+ (:default-initargs :kind nil :description nil)
+ (:documentation "Class of error signaled when a string can't be parsed as a font name.")
+ (:report
+ (lambda (error stream)
+ (format stream
+ "Parsing ~S as a font-name~@[ according to ~A syntax~] ended at ~D~@[ ~A~]."
+ (font-name-parse-error-string error)
+ (font-name-parse-error-kind error)
+ (font-name-parse-error-index error)
+ (font-name-parse-error-description error)))))
+
+;; As mentioned, this file currently only offers a trivial model of
+;; font specifications. The representation of parsed font names is
+;; *not* part of the interface, and subject to change. To insulate
+;; prospective clients from that detail, here are some types.
+(deftype core-font-name ()
+ "Instances of this type are for use with the Core X11 Font system."
+ '(satisfies core-font-name-p))
+(deftype xlfd-name ()
+ "Subtype of CORE-FONT-NAME for XLFD names."
+ '(satisfies xlfd-name-p))
+(deftype fontconfig-name ()
+ "Instances of this type are for use with the Xft2 font system."
+ '(satisfies fontconfig-name-p))
+
+;; Core X11 Font names are just strings, ultimately transmitted to the
+;; X server for resolution. In general core fonts' names are strings
+;; that are opaque to clients. We'll wrap them in an object for
+;; discrimination, and let DEFSTRUCT define the predicate we use for
+;; the DEFTYPE above.
+(defstruct (core-font-name (:type vector) :named (:copier nil))
+ (string "" :type string :read-only t))
+
+;; Core X11 Font names can be in XLFD format, but they might
+;; not be (e.g., aliases are unlikely to be in XLFD format). Here's
+;; the XLFD spec:
+
+;; https://www.x.org/releases/X11R7.6/doc/xorg-docs/specs/XLFD/xlfd.html
+
+;; For now, we don't really need a detailed parse of an XLFD, but
+;; we'll pretend as if we've got one. In fact our parser will merely
+;; validate the string and then cons up an object for which we've got
+;; a predicate.
+(defstruct (xlfd-name (:type vector) :named (:copier nil)
+ (:include core-font-name)))
+
+(define-condition xlfd-name-parse-error
+ (font-name-parse-error)
+ ()
+ (:default-initargs :kind "XLFD"))
+
+;; A proper XLFD has 14 hyphens, so 15 fields (inclusive of the
+;; registry, which must be the empty string).
+(defconstant +xlfd-field-count+ 15)
+
+;; Even though we don't really need a structured XLFD parse, our
+;; heuristics require code for validating well-formedness of an XLFD
+;; (14 hyphens, optionally excluding wildcards). JUNK-ALLOWED follows
+;; the ANSI CL convention. WILDCARD-ALLOWED is just a convenience. It
+;; seems that Xorg and Xquartz treat subsets of well-formed XLFDs as
+;; usable font names, so this also supports a keyword to make it okay
+;; to have fewer than 15 fields).
+(defun parse-xlfd-name (string &key (start 0) end
+ junk-allowed subsequence-allowed
+ wildcard-allowed)
+ "Parse STRING bounded by START and END as an X Logical Font
+Description. If parsing succeeds, return an object for which
+XLFD-NAME-P returns true and the index at which parsing
+ended. Exceptional conditions: if STRING has a registry but doesn't
+have enough fields (13), then signal an error if SUBSEQUENCE-ALLOWED
+is false (the default); if string contains a delimiter after the 13th
+field, signal an error if JUNK-ALLOWED is false (the default). If
+SUBSEQUENCE-ALLOWED is true or JUNK-ALLOWED is true, then return NIL
+and the index at which parsing stopped. If WILDCARD-ALLOWED is
+false (the default), wildcard characters will cause parsing to end at
+the first wildcard character (and so the consequences will depend on
+JUNK-ALLOWED); otherwise, wildcard characters will be treated as field
+contents."
+ (setq end (or end (length string)))
+ (let ((index start) (field-count 0))
+ (labels
+ (;; This is the only way out of PARSE-XLFD-NAME. It
+ ;; implements all the SUBSEQUENCE-ALLOWED and JUNK-ALLOWED
+ ;; logic. Callers can supply arguments to enrich the error
+ ;; report, though it's not the caller's job to decide whether
+ ;; we've succeeded or not.
+ (finish-parsing (&rest error-description)
+ (if (and (or (= field-count +xlfd-field-count+)
+ (and (plusp field-count) subsequence-allowed))
+ (or (= index end) junk-allowed))
+ (return-from parse-xlfd-name
+ (values
+ (make-xlfd-name
+ :string (subseq string start index))
+ index))
+ (error 'xlfd-name-parse-error
+ :string (subseq string start end)
+ :index (- index start)
+ :description
+ (apply #'format nil
+ (if error-description
+ error-description
+ (if (< field-count
+ +xlfd-field-count+)
+ (list "with too few fields (~D)"
+ field-count)
+ '("with trailing junk")))))))
+ (next-token ()
+ (loop
+ (when (= index end)
+ (return))
+ (when (> (- index start) 255)
+ (finish-parsing "due to length limits"))
+ (let ((char (char string index)))
+ (cond
+ ;; Fields must be ISO-8859-1 strings.
+ ((> (char-code char) 255)
+ (finish-parsing "due to non-ISO-8859-1 character, ~@C" char))
+ ;; Explicitly disallowed in field values.
+ ((char= #\" char)
+ (finish-parsing "due to a double-quote"))
+ ;; Conditionally allowed.
+ ((and (find (char string index) '(#\? #\*))
+ (not wildcard-allowed))
+ (finish-parsing "due to wildcard character, ~@C" char))
+ ;; Field delimiter character, unescapable.
+ ((char= #\- char)
+ (return))
+ (t (incf index)))))
+ (progn (incf field-count)
+ (values index
+ ;; Leave INDEX at END when we're at end of string
+ (when (< index end)
+ (prog1 (char string index)
+ (incf index)))))))
+ (unless (< index end)
+ (finish-parsing "because the bounded string was empty"))
+ (let ((registry-end (next-token)))
+ (when (> registry-end start)
+ (finish-parsing "due to unsupported font name registry ~S"
+ (subseq string start registry-end))))
+ (loop
+ (let ((delimiter (nth-value 1 (next-token))))
+ (when (= field-count +xlfd-field-count+)
+ (when delimiter
+ (decf index))
+ (finish-parsing))
+ (when (null delimiter)
+ (finish-parsing)))))))
+
+;; Several test cases for PARSE-XLFD-NAME.
+#+(or)
+(macrolet
+ ((test-okay (results string &rest args)
+ `(assert (equalp (ignore-errors
+ (multiple-value-list
+ (parse-xlfd-name ,string ,@args)))
+ ',(if results
+ results
+ (list (vector 'core-font-name string 'xlfd-name)
+ (length string))))))
+ (test-fail (msg string &rest args &aux (result (gensym)) (error (gensym)))
+ `(multiple-value-bind (,result ,error)
+ (ignore-errors
+ (multiple-value-list
+ (parse-xlfd-name ,string ,@args)))
+ (assert (null ,result))
+ (assert (typep ,error 'xlfd-name-parse-error))
+ ,(when msg
+ `(assert (search ',msg (princ-to-string ,error)))))))
+ (test-okay nil "--------------")
+ ;; By default, an XLFD with fewer than 14 hyphens is an error.
+ (test-fail nil "--------")
+ ;; But :SUBSEQUENCE-ALLOWED T will make it allowed.
+ (test-okay nil "--------" :subsequence-allowed t)
+ ;; By default, a string that has more than 14 fields is an error
+ (test-fail nil "--------------nope-")
+ ;; But :JUNK-ALLOWED T will make it allowed.
+ (test-okay (#(core-font-name "--------------nope" xlfd-name)
+ 18)
+ "--------------nope" :junk-allowed t)
+ ;; By default, wildcards are disallowed.
+ (test-fail nil "-*-------------")
+ (test-okay nil "-*-------------" :wildcard-allowed t)
+ (test-fail nil "--------------*")
+ (test-okay nil "--------------*" :wildcard-allowed t))
+
+;; Xft2 doesn't strictly have its own font names; it uses fontconfig
+;; for naming. Fontconfig has a syntax for specifying fonts; here's
+;; the spec for that:
+
+;; https://www.freedesktop.org/software/fontconfig/fontconfig-user.html
+
+;; For Motif-y reasons explained below, we must parse a few properties
+;; out of fontconfig names. We'll ignore properties we don't care
+;; about. We'll use the same basic idea as above: a lightweight
+;; representation of the stuff we need, a PARSE-ERROR subclass, and a
+;; parsing function.
+(defstruct (fontconfig-name (:type vector) :named (:copier nil))
+ (foundry nil :type (or null string) :read-only t)
+ (family "" :type string :read-only t)
+ ;; TODO: SIZE is really a number, but the fontconfig spec doesn't
+ ;; document the number format, so for the moment it's a string.
+ ;; Probably this ought to get fixed before contemplating exporting
+ ;; the accessor name.
+ (size nil :type (or null string) :read-only t)
+ (weight nil :type (or null string) :read-only t)
+ (slant nil :type (or null string) :read-only t)
+ ;; This isn't a proper part of a model of a fontconfig name, just an
+ ;; internal trick for the heuristics that follow.
+ (has-properties-p nil :type boolean :read-only t))
+
+(define-condition fontconfig-name-parse-error
+ (font-name-parse-error)
+ ()
+ (:default-initargs :kind "fontconfig"))
+
+;; This routine attempts to implement a fairly strict idea of
+;; well-formedness for fontconfig specs. Any functional disagreement
+;; with fontconfig over the domain of well-formed fontconfig names is
+;; a bug. (fontconfig's matching of strings that aren't well-formed
+;; fontconfig names is none of our business.)
+(defun parse-fontconfig-name (string &key (start 0) end junk-allowed)
+ (setq end (or end (length string)))
+ (let (foundry family size weight slant has-properties-p
+ (index start) part-end)
+ (labels
+ (;; This is the only way out of
+ ;; PARSE-FONTCONFIG-NAME.
+ (finish-parsing (&rest error-description)
+ (if (or (= part-end end) junk-allowed)
+ (return-from parse-fontconfig-name
+ (values
+ (when family
+ (make-fontconfig-name
+ :family family :foundry foundry :size size
+ :weight weight :slant slant
+ :has-properties-p
+ (or has-properties-p slant weight foundry)))
+ ;; Parsing always ends at the index of the end of
+ ;; the part of the name that parsed, even if there's
+ ;; junk after.
+ part-end))
+ (error 'fontconfig-name-parse-error
+ :string (subseq string start end)
+ :index (- index start)
+ :description (when error-description
+ (apply #'format nil error-description)))))
+ ;; Parse the next token starting at INDEX, delimited by any
+ ;; character in DELIMITERS. Note that the family and any
+ ;; property value use backslash to escape the delimiter, but
+ ;; the size and property name are not documented as allowing
+ ;; an escape character. Returns a non-empty token, the
+ ;; delimiter that ended the token, and the delimiter's index.
+ (next-token (delimiters &optional (escapep t))
+ (do ((chars)
+ (char (and (< index end) (char string index))
+ (and (< index end) (char string index))))
+ ((or (null char) (find char delimiters))
+ (multiple-value-prog1
+ (values (when chars
+ (coerce (nreverse chars) 'string))
+ char
+ index)
+ (incf index)))
+ (when (and escapep (char= #\\ char))
+ (when (= index end)
+ (finish-parsing "after the escape character"))
+ (incf index)
+ (setq char (char string index)))
+ (push char chars)
+ (incf index)))
+ ;; The fontconfig spec doesn't say whether names & their
+ ;; components are matched case-sensitively or
+ ;; case-insensitively. It seems as if it's insensitive, but
+ ;; let's factor it here just in case.
+ (string-equiv (s1 s2)
+ (string-equal s1 s2)))
+ (let (delimiter token-end)
+ (multiple-value-setq (family delimiter token-end)
+ (next-token '(#\- #\:)))
+ (when (null family)
+ (finish-parsing "without any family"))
+ ;; fontconfig names allow for a comma-separated list of
+ ;; families. TODO: check if Motif can handle such lists.
+ ;; Pending that, make it an error to find a comma in the name.
+ ;; This is a defect in this parser.
+ (when (find #\, family)
+ (finish-parsing "with an unsupported syntax (list of families))"))
+ ;; If we're here, the family is acceptable, so we've reached
+ ;; the end of this part. Save it for FINISH-PARSING.
+ (setq part-end token-end)
+ (when (eql #\- delimiter)
+ (multiple-value-setq (size delimiter token-end)
+ (next-token '(#\:) nil))
+ ;; TODO, maybe: validate that SIZE parses as a number. (But
+ ;; first figure out what the number syntax is; the
+ ;; fontconfig spec doesn't say.)
+ (unless size
+ (finish-parsing "with a hyphen")))
+ ;; TODO: check if Motif supports lists of sizes.
+ ;; This is a defect in this parser.
+ (when (find #\, size)
+ (finish-parsing "with an unsupported syntax (list of sizes))"))
+ (setq part-end token-end)
+ (when (eql #\: delimiter) ;There are properties to parse.
+ (let (name value tmp-end)
+ (loop
+ (setq part-end token-end)
+ ;; We must not set TOKEN-END until we know we've parsed
+ ;; a whole property. So we'll use TMP-END.
+ (multiple-value-setq (name delimiter tmp-end)
+ (next-token '(#\= #\:) nil))
+ (if (null name)
+ (ecase delimiter
+ (#\=
+ (finish-parsing "with an empty property name"))
+ (#\:
+ (finish-parsing "with an empty property"))
+ ((nil)
+ (finish-parsing "with a colon")))
+ (ecase delimiter
+ (#\=
+ (multiple-value-setq (value delimiter tmp-end)
+ (next-token '(#\:)))
+ (when (null value)
+ (finish-parsing "with an empty property value"))
+ (setq token-end tmp-end
+ has-properties-p t)
+ ;; These are the only properties we care about.
+ (cond ((string-equiv name "weight")
+ (setq weight value))
+ ((string-equiv name "slant")
+ (setq slant value))
+ ((string-equiv name "foundry")
+ (setq foundry value))))
+ ((#\: nil)
+ ;; In this case, the property might be a
+ ;; "symbolic constant" The fontconfig spec says
+ ;; "there are symbolic constants that
+ ;; simultaneously indicate both a name and a
+ ;; value", but it's not clear what those
+ ;; constants are. We'll assume that any
+ ;; construct is both syntactically valid here.
+ (setq token-end tmp-end
+ has-properties-p t)
+ ;; We need to recognize whatever symbolic
+ ;; constants are defined for the weight and
+ ;; slant properties. These are taken from the
+ ;; description of the <const> element of the
+ ;; configuration file format, in case that's
+ ;; what's intended in the fontconfig spec.
+ (cond ((member name
+ '("thin"
+ "extralight"
+ "ultralight"
+ "light"
+ "demilight"
+ "semilight"
+ "book"
+ "regular"
+ "normal"
+ "medium"
+ "demibold"
+ "semibold"
+ "bold"
+ "extrabold"
+ "black"
+ "heavy")
+ :test #'string-equiv)
+ (setq weight name))
+ ((member name
+ '("roman"
+ "italic"
+ "oblique"
+ "ultracondensed"
+ "extracondensed"
+ "condensed"
+ "semicondensed"
+ "normal"
+ "semiexpanded"
+ "expanded"
+ "extraexpanded"
+ "ultraexpanded")
+ :test #'string-equiv)
+ (setq slant name))))))))))
+ (finish-parsing))))
+
+;; Some test cases for PARSE-FONTCONFIG-NAME.
+#+(or)
+(macrolet
+ ((test-okay (results string &rest args)
+ `(assert (equalp (ignore-errors
+ (multiple-value-list
+ (parse-fontconfig-name ,string ,@args)))
+ ',(if (listp results)
+ results
+ (list results (length string))))))
+ (test-fail (msg string &rest args &aux (result (gensym)) (error (gensym)))
+ `(multiple-value-bind (,result ,error)
+ (ignore-errors
+ (multiple-value-list
+ (parse-fontconfig-name ,string ,@args)))
+ (assert (null ,result))
+ (assert (typep ,error 'fontconfig-name-parse-error))
+ ,(when msg
+ `(assert (search ',msg (princ-to-string ,error)))))))
+ ;; Just a name
+ (test-okay #(fontconfig-name nil "Foo" nil nil nil nil) "Foo")
+ ;; Name and size
+ (test-okay #(fontconfig-name nil "Foo" "12" nil nil nil) "Foo-12")
+ ;; This fully specifies everything we care about.
+ (test-okay #(fontconfig-name "Bar" "Foo" "12" "bold" "italic" t)
+ "Foo-12:foundry=Bar:slant=italic:weight=bold")
+ ;; Same as previous, but with extra junk (which should be ignored).
+ (test-okay #(fontconfig-name "Bar" "Foo" "12" "bold" "italic" t)
+ "Foo-12:abc=def:foundry=Bar:xyz=123:slant=italic:weight=bold")
+ ;; Test recognition of symbolic constants for weight and slant.
+ (test-okay #(fontconfig-name nil "Foo" "12" "bold" "italic" t)
+ "Foo-12:italic:bold")
+ ;; Test recognition that a font has properties (even if we don't
+ ;; know what they are).
+ (test-okay #(fontconfig-name nil "Foo" "12" nil nil t)
+ "Foo-12:bar=baz")
+ ;; Test various invalid (I think) things.
+ (test-fail "with a hyphen" "Foo-")
+ (test-fail "with a colon" "Foo:")
+ (test-fail "with a colon" "Foo-12:")
+ (test-fail "empty property" "Foo::")
+ (test-fail "empty property" "Foo-12::")
+ (test-fail "empty property name" "Foo:=bar")
+ (test-fail "empty property value" "Foo:bar="))
+
+;; Now that we have font name parsers, let's build a convention for
+;; figuring out when to apply them. Every octet string up to length
+;; 255 is a syntactically valid Core X11 Font name; and fontconfig
+;; appears not to care whether its input strings are well-formed
+;; fontconfig names. So in principle all strings (modulo length and
+;; encoding) might be "usable" as a font names in either system.
+;;
+;; However, in practice, most Core X11 Fonts have XLFD names, and
+;; fontconfig's behavior is more predictable when its inputs are
+;; well-formed and detailed fontconfig names. Therefore, it seems
+;; reasonable to build up some heuristics:
+;;
+;; 1. a string that starts with a hyphen is an XLFD (fontconfig name
+;; can't start with hyphens).
+;;
+;; 2. a string that's a well-formed fontconfig name containing a colon
+;; is a fontconfig name (colons don't seem much used in Core X11 Font
+;; names).
+;;
+;; Here are two helper routines that implement those heuristics. Note
+;; that these two don't partition all strings, e.g., "Times" or
+;; "Helvetica-12" won't satisfy either predicate. We'll address those
+;; "ambiguous" cases below.
+(defun xlfdp (thing)
+ "Returns true if THING represents an X Logical Font Description, either
+as an XLFD string or the parse of one."
+ (etypecase thing
+ (xlfd-name
+ ;; Note that objects that satisfy this predicate might have been
+ ;; created by PARSE-XLFD-NAME calls with non-default
+ ;; flags, and so may not be well-formed XLFDs on their own. If
+ ;; the user had the context to do that, then we're not going to
+ ;; overrule the decision.
+ thing)
+ (string (nth-value
+ 0
+ (ignore-errors
+ (parse-xlfd-name
+ thing
+ ;; These initargs are arbitrary, but appear to agree
+ ;; with what my X server seems to consider acceptable
+ ;; arguments to XOpenFont.
+ :junk-allowed nil :subsequence-allowed t
+ :wildcard-allowed t))))))
+
+(defun fontconfigp (thing)
+ "Returns true in case THING is probably a fontconfig name:
+either a parsed fontconfig name, or a string that parses to a
+fontconfig name having explicit properties."
+ (etypecase thing
+ (fontconfig-name
+ thing)
+ (string
+ (let ((thing (ignore-errors
+ (parse-fontconfig-name thing))))
+ (when (and thing (fontconfig-name-has-properties-p thing))
+ thing)))))
+
+;; So now we've got heuristic detection of XLFD and fontconfig
+;; names. Disambiguating other strings in isolation is inherently
+;; arbitrary. However, when we've got an opportunity to look at a set
+;; of strings, we can disambiguate using context: let's assume that if
+;; any string is an XLFD, then all ambiguous strings are meant as Core
+;; X11 Font names; that if any string is a well-formed fontconfig name
+;; with properties, then all ambiguous strings are also for Xft2; that
+;; if all strings are ambiguous, we'll fallthru to consulting a
+;; variable.
+(defvar *ambiguous-font-disposition* :xft2)
+(declaim (type (member :xft2 :core) *ambiguous-font-disposition*))
+
+;; Finally, it seems that using Core X11 Fonts with Xft2 fonts within
+;; a single RenderTable that doesn't work in OpenMotif circa 2021. (I
+;; couldn't figure it out, anyhow.) And maybe nobody would want to do
+;; so anyway. So for now we'll rule out mix-and-match scenarios.
+(defun heuristicate-font-name-types (names)
+ (assert (every #'stringp names))
+ (flet ((parse-as-core-fonts ()
+ (mapcar #'(lambda (spec)
+ (or (xlfdp spec) (make-core-font-name :string spec)))
+ names))
+ (parse-as-xft2-fonts ()
+ (mapcar #'parse-fontconfig-name names)))
+ (cond ((some #'xlfdp names)
+ (when (some #'fontconfigp names)
+ (error "Can't mix fontconfig and Core X11 font names."))
+ (parse-as-core-fonts))
+ ((some #'fontconfigp names)
+ (when (some #'xlfdp names)
+ (error "Can't mix fontconfig and Core X11 font names."))
+ (parse-as-xft2-fonts))
+ (t (ecase *ambiguous-font-disposition*
+ (:core (parse-as-core-fonts))
+ (:xft2 (parse-as-xft2-fonts)))))))
+
+;; Here's the OpenMotif-specific bit. Now that we can heuristically
+;; classify a list of fonts, we can pair up tags with heuristicated
+;; font names in order to generate OpenMotif resource strings suitable
+;; for either fallback resources or writing into X resource files.
+(defun generate-heuristicated-font-resources
+ (tags fonts &key application-name application-class)
+ "Generate a list of OpenMotif RenderTable & Rendition resources
+associating FONTS with TAGS. If APPLICATION-NAME or APPLICATION-CLASS
+is supplied, the resource keys will be prefixed by that string;
+otherwise, the resource key will start with the loose binding
+operator, asterisk."
+ (declare (type list tags fonts)
+ (type (or null string) application-name application-class))
+ (let ((ntags (length tags))
+ (nfonts (length fonts)))
+ (assert (= ntags nfonts) (tags fonts)
+ "Too ~:[many~;few~] tags (~A) for fonts (~A)."
+ (> ntags nfonts) tags fonts))
+ (let ((name/class (or application-name application-class)))
+ (nconc
+ (mapcan
+ (lambda (tag spec)
+ (let* ((rendition (if (or (string= "" tag) (null tag))
+ ;; Accept NIL or "" as a the default
+ ;; tag. Default tags' resources are
+ ;; resources of the RenderTable itself.
+ "renderTable"
+ ;; Non-default tags get used as resource
+ ;; names.
+ tag)))
+ ((lambda (resources)
+ (loop for (resname resval) on resources by #'cddr
+ collect (format nil "~(a)[~A~]*~A.~A: ~A"
+ name/class rendition resname resval)))
+ ;; Core fonts are specified by 2 resource name/value pairs.
+ ;; Xft2 fonts are specified by 4 such pairs.
+ (if (core-font-name-p spec)
+ (list "fontName" (core-font-name-string spec)
+ "fontType" "FONT_IS_FONT")
+ (list* "fontName" (fontconfig-name-family spec)
+ "fontType" "FONT_IS_XFT"
+ (nconc
+ (when (fontconfig-name-foundry spec)
+ (list "foundryName" (fontconfig-name-foundry spec)))
+ (when (fontconfig-name-size spec)
+ (list "fontSize" (fontconfig-name-size spec)))
+ (when (or (fontconfig-name-weight spec)
+ (fontconfig-name-slant spec))
+ (list "fontStyle"
+ (format nil "~:[~@[~A~]~;~:*~A~@[ ~A~]~]"
+ (fontconfig-name-weight spec)
+ (fontconfig-name-slant spec))))))))))
+ tags (heuristicate-font-name-types fonts))
+ (list (format nil "~@[~A~]*renderTable: ~{~A~^ ~}"
+ name/class
+ (remove "" tags))))))
+
+;; Test cases for GENERATE-HEURISTICATED-FONT-RESOURCES.
+#+(or)
+(assert
+ (equal
+ ;; These are the Core X11 Fonts that the CLM Debugger/Inspector have
+ ;; used.
+ (let ((fonts '("-adobe-helvetica-medium-r-normal--*-120-75-*"
+ "-adobe-helvetica-bold-r-normal--*-120-75-*"
+ "-adobe-helvetica-medium-o-normal--*-120-75-*"))
+ (tags '("" "header" "italic")))
+ (generate-heuristicated-font-resources tags fonts))
+ '("*renderTable.fontName: -adobe-helvetica-medium-r-normal--*-120-75-*"
+ "*renderTable.fontType: FONT_IS_FONT"
+ "*header.fontName: -adobe-helvetica-bold-r-normal--*-120-75-*"
+ "*header.fontType: FONT_IS_FONT"
+ "*italic.fontName: -adobe-helvetica-medium-o-normal--*-120-75-*"
+ "*italic.fontType: FONT_IS_FONT" "*renderTable: header italic")))
+
+#+(or)
+(assert
+ (equal
+ ;; Here are some fontconfig names.
+ (let ((fonts '("Sans-12:regular"
+ "Sans-12:bold"
+ "Sans-12:italic"
+ "Sans-12:bold:italic"))
+ (tags '("" "header" "italic" "foo")))
+ (generate-heuristicated-font-resources tags fonts))
+ '("*renderTable.fontName: Sans" "*renderTable.fontType: FONT_IS_XFT"
+ "*renderTable.fontSize: 12" "*renderTable.fontStyle: regular"
+ "*header.fontName: Sans" "*header.fontType: FONT_IS_XFT"
+ "*header.fontSize: 12" "*header.fontStyle: bold"
+ "*italic.fontName: Sans" "*italic.fontType: FONT_IS_XFT"
+ "*italic.fontSize: 12" "*italic.fontStyle: italic"
+ "*foo.fontName: Sans" "*foo.fontType: FONT_IS_XFT"
+ "*foo.fontSize: 12" "*foo.fontStyle: bold italic"
+ "*renderTable: header italic foo")))
=====================================
src/motif/lisp/initial.lisp
=====================================
@@ -220,7 +220,8 @@
"IS-APPLICATION-SHELL" "IS-COMPOSITE" "IS-CONSTRAINT" "IS-OBJECT"
"IS-OVERRIDE-SHELL" "IS-RECT-OBJ" "IS-SHELL" "IS-TOP-LEVEL-SHELL"
"IS-TRANSIENT-SHELL" "IS-VENDOR-SHELL" "IS-W-M-SHELL"
- "XT-WIDGET-PARENT"))
+ "XT-WIDGET-PARENT" "*AMBIGUOUS-FONT-DISPOSITION*"
+ "GENERATE-HEURISTICATED-FONT-RESOURCES"))
=====================================
src/tools/clmcom.lisp
=====================================
@@ -48,6 +48,7 @@
"target:motif/lisp/callbacks"
"target:motif/lisp/widgets"
; "target:motif/lisp/timer-support"
+ "target:motif/lisp/fonts"
"target:motif/lisp/main"))
(defparameter interface-files
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/81d8160b79e78ebd9821ed5…
--
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/81d8160b79e78ebd9821ed5…
You're receiving this email because of your account on gitlab.common-lisp.net.