;;; -*- Mode: LISP; Syntax: Common-lisp; Package: XLIB; Base: 10; Lowercase: Yes -*- ;;; ;;; TEXAS INSTRUMENTS INCORPORATED ;;; P.O. BOX 2909 ;;; AUSTIN, TEXAS 78769 ;;; ;;; Copyright (C) 1987 Texas Instruments Incorporated. ;;; ;;; Permission is granted to any individual or institution to use, copy, modify, ;;; and distribute this software, provided that this complete copyright and ;;; permission notice is maintained, intact, in all copies and supporting ;;; documentation. ;;; ;;; Texas Instruments Incorporated provides this software "as is" without ;;; express or implied warranty. ;;; (in-package :xlib) ;; The char-info stuff is here instead of CLX because of uses of int16->card16. ; To allow efficient storage representations, the type char-info is not ; required to be a structure. ;; For each of left-bearing, right-bearing, width, ascent, descent, attributes: ;(defun char- (font index) ; ;; Note: I have tentatively chosen to return nil for an out-of-bounds index ; ;; (or an in-bounds index on a pseudo font), although returning zero or ; ;; signalling might be better. ; (declare (type font font) ; (type integer index) ; (values (or null integer)))) ;(defun max-char- (font) ; ;; Note: I have tentatively chosen separate accessors over allowing :min and ; ;; :max as an index above. ; (declare (type font font) ; (values integer))) ;(defun min-char- (font) ; (declare (type font font) ; (values integer))) ;; Note: char16- accessors could be defined to accept two-byte indexes. (deftype char-info-vec () '(simple-array int16 (6))) (macrolet ((def-char-info-accessors (useless-name &body fields) `(within-definition (,useless-name def-char-info-accessors) ,@(do ((field fields (cdr field)) (n 0 (1+ n)) (name) (type) (result nil)) ((endp field) result) (setq name (xintern 'char- (caar field))) (setq type (cadar field)) (flet ((from (form) (if (eq type 'int16) form `(,(xintern 'int16-> type) ,form)))) (push `(defun ,name (font index) (declare (type font font) (type array-index index)) (declare (values (or null ,type))) (when (and (font-name font) (index>= (font-max-char font) index (font-min-char font))) (the ,type ,(from `(the int16 (let ((char-info-vector (font-char-infos font))) (declare (type char-info-vec char-info-vector)) (if (index-zerop (length char-info-vector)) ;; Fixed width font (aref (the char-info-vec (font-max-bounds font)) ,n) ;; Variable width font (aref char-info-vector (index+ (index* 6 (index- index (font-min-char font))) ,n))))))))) result) (setq name (xintern 'min-char- (caar field))) (push `(defun ,name (font) (declare (type font font)) (declare (values (or null ,type))) (when (font-name font) (the ,type ,(from `(the int16 (aref (the char-info-vec (font-min-bounds font)) ,n)))))) result) (setq name (xintern 'max-char- (caar field))) (push `(defun ,name (font) (declare (type font font)) (declare (values (or null ,type))) (when (font-name font) (the ,type ,(from `(the int16 (aref (the char-info-vec (font-max-bounds font)) ,n)))))) result))) (defun make-char-info (&key ,@(mapcar #'(lambda (field) `(,(car field) (required-arg ,(car field)))) fields)) (declare ,@(mapcar #'(lambda (field) `(type ,@(reverse field))) fields)) (let ((result (make-array ,(length fields) :element-type 'int16))) (declare (type char-info-vec result) (array-register result)) ,@(do* ((field fields (cdr field)) (var (caar field) (caar field)) (type (cadar field) (cadar field)) (n 0 (1+ n)) (result nil)) ((endp field) (nreverse result)) (push `(setf (aref result ,n) ,(if (eq type 'int16) var `(,(xintern type '->int16) ,var))) result)) result))))) (def-char-info-accessors ignore (left-bearing int16) (right-bearing int16) (width int16) (ascent int16) (descent int16) (attributes card16))) (defun open-font (display name) ;; Font objects may be cached and reference counted locally within the display ;; object. This function might not execute a with-display if the font is cached. ;; The protocol QueryFont request happens on-demand under the covers. (declare (type display display) (type stringable name)) (declare (values font)) (let* ((name-string (string-downcase (string name))) (font (car (member name-string (display-font-cache display) :key 'font-name :test 'equal))) font-id) (unless font (setq font (make-font :display display :name name-string)) (setq font-id (allocate-resource-id display font 'font)) (setf (font-id-internal font) font-id) (with-buffer-request (display *x-openfont*) (resource-id font-id) (card16 (length name-string)) (pad16 nil) (string name-string)) (push font (display-font-cache display))) (incf (font-reference-count font)) font)) (defun open-font-internal (font) ;; Called "under the covers" to open a font object (declare (type font font)) (declare (values resource-id)) (let* ((name-string (font-name font)) (display (font-display font)) (id (allocate-resource-id display font 'font))) (setf (font-id-internal font) id) (with-buffer-request (display *x-openfont*) (resource-id id) (card16 (length name-string)) (pad16 nil) (string name-string)) (push font (display-font-cache display)) (incf (font-reference-count font)) id)) (defun discard-font-info (font) ;; Discards any state that can be re-obtained with QueryFont. This is ;; simply a performance hint for memory-limited systems. (declare (type font font)) (setf (font-font-info-internal font) nil (font-char-infos-internal font) nil)) (defun query-font (font) ;; Internal function called by font and char info accessors (declare (type font font)) (declare (values font-info)) (let ((display (font-display font)) font-id font-info props) (setq font-id (font-id font)) ;; May issue an open-font request (with-buffer-request-and-reply (display *x-queryfont* 60) ((resource-id font-id)) (let* ((min-byte2 (card16-get 40)) (max-byte2 (card16-get 42)) (min-byte1 (card8-get 49)) (max-byte1 (card8-get 50)) (min-char min-byte2) (max-char (index+ (index-ash max-byte1 8) max-byte2)) (nfont-props (card16-get 46)) (nchar-infos (index* (card32-get 56) 6)) (char-info (make-array nchar-infos :element-type 'int16))) (setq font-info (make-font-info :direction (member8-get 48 :left-to-right :right-to-left) :min-char min-char :max-char max-char :min-byte1 min-byte1 :max-byte1 max-byte1 :min-byte2 min-byte2 :max-byte2 max-byte2 :all-chars-exist-p (boolean-get 51) :default-char (card16-get 44) :ascent (int16-get 52) :descent (int16-get 54) :min-bounds (char-info-get 8) :max-bounds (char-info-get 24))) (setq props (sequence-get :length (index* 2 nfont-props) :format int32 :result-type 'list :index 60)) (sequence-get :length nchar-infos :format int16 :data char-info :index (index+ 60 (index* 2 nfont-props 4))) (setf (font-char-infos-internal font) char-info) (setf (font-font-info-internal font) font-info))) ;; Replace atom id's with keywords in the plist (do ((p props (cddr p))) ((endp p)) (setf (car p) (atom-name display (car p)))) (setf (font-info-properties font-info) props) font-info)) (defun close-font (font) ;; This might not generate a protocol request if the font is reference ;; counted locally. (declare (type font font)) (when (and (not (plusp (decf (font-reference-count font)))) (font-id-internal font)) (let ((display (font-display font)) (id (font-id-internal font))) (declare (type display display)) ;; Remove font from cache (setf (display-font-cache display) (delete font (display-font-cache display))) ;; Close the font (with-buffer-request (display *x-closefont*) (resource-id id))))) (defun list-font-names (display pattern &key (max-fonts 65535) (result-type 'list)) (declare (type display display) (type string pattern) (type card16 max-fonts) (type t result-type)) ;; CL type (declare (values (sequence string))) (let ((string (string pattern))) (with-buffer-request-and-reply (display *x-listfonts* size :sizes (8 16)) ((card16 max-fonts (length string)) (string string)) (values (read-sequence-string buffer-bbuf (index- size *replysize*) (card16-get 8) result-type *replysize*))))) (defun list-fonts (display pattern &key (max-fonts 65535) (result-type 'list)) ;; Note: Was called list-fonts-with-info. ;; Returns "pseudo" fonts that contain basic font metrics and properties, but ;; no per-character metrics and no resource-ids. These pseudo fonts will be ;; converted (internally) to real fonts dynamically as needed, by issuing an ;; OpenFont request. However, the OpenFont might fail, in which case the ;; invalid-font error can arise. (declare (type display display) (type string pattern) (type card16 max-fonts) (type t result-type)) ;; CL type (declare (values (sequence font))) (let ((string (string pattern)) (result nil)) (with-buffer-request-and-reply (display *x-listfontswithinfo* 60 :sizes (8 16) :multiple-reply t) ((card16 max-fonts (length string)) (string string)) (cond ((zerop (card8-get 1)) t) (t (let* ((name-len (card8-get 1)) (min-byte2 (card16-get 40)) (max-byte2 (card16-get 42)) (min-byte1 (card8-get 49)) (max-byte1 (card8-get 50)) (min-char min-byte2) (max-char (index+ (index-ash max-byte1 8) max-byte2)) (nfont-props (card16-get 46)) (font (make-font :display display :name nil :font-info-internal (make-font-info :direction (member8-get 48 :left-to-right :right-to-left) :min-char min-char :max-char max-char :min-byte1 min-byte1 :max-byte1 max-byte1 :min-byte2 min-byte2 :max-byte2 max-byte2 :all-chars-exist-p (boolean-get 51) :default-char (card16-get 44) :ascent (int16-get 52) :descent (int16-get 54) :min-bounds (char-info-get 8) :max-bounds (char-info-get 24) :properties (sequence-get :length (index* 2 nfont-props) :format int32 :result-type 'list :index 60))))) (setf (font-name font) (string-get name-len (index+ 60 (index* 2 nfont-props 4)))) (push font result)) nil))) ;; Replace atom id's with keywords in the plist (dolist (font result) (do ((p (font-properties font) (cddr p))) ((endp p)) (setf (car p) (atom-name display (car p))))) (coerce (nreverse result) result-type))) (defun font-path (display &key (result-type 'list)) (declare (type display display) (type t result-type)) ;; CL type (declare (values (sequence (or string pathname)))) (with-buffer-request-and-reply (display *x-getfontpath* size :sizes (8 16)) () (values (read-sequence-string buffer-bbuf (index- size *replysize*) (card16-get 8) result-type *replysize*)))) (defun set-font-path (display paths) (declare (type display display) (type sequence paths)) ;; (sequence (or string pathname)) (let ((path-length (length paths)) (request-length 8)) ;; Find the request length (dotimes (i path-length) (let* ((string (string (elt paths i))) (len (length string))) (incf request-length (1+ len)))) (with-buffer-request (display *x-setfontpath* :length request-length) (length (ceiling request-length 4)) (card16 path-length) (pad16 nil) (progn (incf buffer-boffset 8) (dotimes (i path-length) (let* ((string (string (elt paths i))) (len (length string))) (card8-put 0 len) (string-put 1 string :appending t :header-length 1) (incf buffer-boffset (1+ len)))) (setf (buffer-boffset display) (lround buffer-boffset))))) paths) (defsetf font-path set-font-path)