;;; -*- Mode: LISP; Syntax: Common-lisp; Package: XLIB; Base: 10; Lowercase: Yes -*- ;; This file contains some of the system dependent code for CLX ;;; ;;; 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) ;;;------------------------------------------------------------------------- ;;; Declarations ;;;------------------------------------------------------------------------- ;;; fix a bug in kcl's RATIONAL... ;;; redefine both the function and the type. #+(or kcl ibcl) (progn (defun rational (x) (if (rationalp x) x (lisp:rational x))) (deftype rational (&optional l u) `(lisp:rational ,l ,u))) ;;; DECLAIM #-clx-ansi-common-lisp (defmacro declaim (&rest decl-specs) (if (cdr decl-specs) `(progn ,@(mapcar #'(lambda (decl-spec) `(proclaim ',decl-spec)) decl-specs)) `(proclaim ',(car decl-specs)))) ;;; VALUES value1 value2 ... -- Documents the values returned by the function. #-lispm (declaim (declaration values)) ;;; ARGLIST arg1 arg2 ... -- Documents the arglist of the function. Overrides ;;; the documentation that might get generated by the real arglist of the ;;; function. #-(or lispm lcl3.0) (declaim (declaration arglist)) ;;; DYNAMIC-EXTENT var -- Tells the compiler that the rest arg var has ;;; dynamic extent and therefore can be kept on the stack and not copied to ;;; the heap, even though the value is passed out of the function. #-(or clx-ansi-common-lisp lcl3.0) (declaim (declaration dynamic-extent)) ;;; IGNORABLE var -- Tells the compiler that the variable might or might not be used. #-clx-ansi-common-lisp (declaim (declaration ignorable)) ;;; ARRAY-REGISTER var1 var2 ... -- The variables mentioned are locals (not ;;; args) that hold vectors. #-Genera (declaim (declaration array-register)) ;;; INDENTATION argpos1 arginden1 argpos2 arginden2 --- Tells the lisp editor how to ;;; indent calls to the function or macro containing the declaration. #-genera (declaim (declaration indentation)) ;;;------------------------------------------------------------------------- ;;; Declaration macros ;;;------------------------------------------------------------------------- ;;; WITH-VECTOR (variable type) &body body --- ensures the variable is a local ;;; and then does a type declaration and array register declaration (defmacro with-vector ((var type) &body body) `(let ((,var ,var)) (declare (type ,type ,var) (array-register ,var)) ,@body)) ;;; WITHIN-DEFINITION (name type) &body body --- Includes definitions for ;;; Meta-. #+lispm (defmacro within-definition ((name type) &body body) `(zl:local-declare ((sys:function-parent ,name ,type)) (sys:record-source-file-name ',name ',type) ,@body)) #-lispm (defmacro within-definition ((name type) &body body) (declare (ignore name type)) `(progn ,@body)) ;;;------------------------------------------------------------------------- ;;; CLX can maintain a mapping from X server ID's to local data types. If ;;; one takes the view that CLX objects will be instance variables of ;;; objects at the next higher level, then PROCESS-EVENT will typically map ;;; from resource-id to higher-level object. In that case, the lower-level ;;; CLX mapping will almost never be used (except in rare cases like ;;; query-tree), and only serve to consume space (which is difficult to ;;; GC), in which case always-consing versions of the make-s will ;;; be better. Even when maps are maintained, it isn't clear they are ;;; useful for much beyond xatoms and windows (since almost nothing else ;;; ever comes back in events). ;;;-------------------------------------------------------------------------- (defconstant *clx-cached-types* '( drawable window pixmap ; gcontext cursor colormap font)) (defmacro resource-id-map-test () #+excl '#'equal #-excl '#'eql) ; (eq fixnum fixnum) is not guaranteed. (defmacro atom-cache-map-test () #+excl '#'equal #-excl '#'eq) (defmacro keysym->character-map-test () #+excl '#'equal #-excl '#'eql) ;;; You must define this to match the real byte order. It is used by ;;; overlapping array and image code. #+(or lispm vax little-endian Minima) (eval-when (eval compile load) (pushnew :clx-little-endian *features*)) #+lcl3.0 (eval-when (compile eval load) (ecase lucid::machine-endian (:big nil) (:little (pushnew :clx-little-endian *features*)))) ;;; Steele's Common-Lisp states: "It is an error if the array specified ;;; as the :displaced-to argument does not have the same :element-type ;;; as the array being created" If this is the case on your lisp, then ;;; leave the overlapping-arrays feature turned off. Lisp machines ;;; (Symbolics TI and LMI) don't have this restriction, and allow arrays ;;; with different element types to overlap. CLX will take advantage of ;;; this to do fast array packing/unpacking when the overlapping-arrays ;;; feature is enabled. #+(and clx-little-endian lispm) (eval-when (eval compile load) (pushnew :clx-overlapping-arrays *features*)) #+(and clx-overlapping-arrays genera) (progn (deftype overlap16 () '(unsigned-byte 16)) (deftype overlap32 () '(signed-byte 32)) ) #+(and clx-overlapping-arrays (or explorer lambda cadr)) (progn (deftype overlap16 () '(unsigned-byte 16)) (deftype overlap32 () '(unsigned-byte 32)) ) (deftype buffer-bytes () `(simple-array (unsigned-byte 8) (*))) #+clx-overlapping-arrays (progn (deftype buffer-words () `(vector overlap16)) (deftype buffer-longs () `(vector overlap32)) ) ;;; This defines a type which is a subtype of the integers. ;;; This type is used to describe all variables that can be array indices. ;;; It is here because it is used below. ;;; This is inclusive because start/end can be 1 past the end. (deftype array-index () `(integer 0 ,array-dimension-limit)) ;; this is the best place to define these? #-Genera (progn (defun make-index-typed (form) (if (constantp form) form `(the array-index ,form))) (defun make-index-op (operator args) `(the array-index (values ,(case (length args) (0 `(,operator)) (1 `(,operator ,(make-index-typed (first args)))) (2 `(,operator ,(make-index-typed (first args)) ,(make-index-typed (second args)))) (otherwise `(,operator ,(make-index-op operator (subseq args 0 (1- (length args)))) ,(make-index-typed (first (last args))))))))) (defmacro index+ (&rest numbers) (make-index-op '+ numbers)) (defmacro index-logand (&rest numbers) (make-index-op 'logand numbers)) (defmacro index-logior (&rest numbers) (make-index-op 'logior numbers)) (defmacro index- (&rest numbers) (make-index-op '- numbers)) (defmacro index* (&rest numbers) (make-index-op '* numbers)) (defmacro index1+ (number) (make-index-op '1+ (list number))) (defmacro index1- (number) (make-index-op '1- (list number))) (defmacro index-incf (place &optional (delta 1)) (make-index-op 'incf (list place delta))) (defmacro index-decf (place &optional (delta 1)) (make-index-op 'decf (list place delta))) (defmacro index-min (&rest numbers) (make-index-op 'min numbers)) (defmacro index-max (&rest numbers) (make-index-op 'max numbers)) (defmacro index-floor (number divisor) (make-index-op 'floor (list number divisor))) (defmacro index-ceiling (number divisor) (make-index-op 'ceiling (list number divisor))) (defmacro index-truncate (number divisor) (make-index-op 'truncate (list number divisor))) (defmacro index-mod (number divisor) (make-index-op 'mod (list number divisor))) (defmacro index-ash (number count) (make-index-op 'ash (list number count))) (defmacro index-plusp (number) `(plusp (the array-index ,number))) (defmacro index-zerop (number) `(zerop (the array-index ,number))) (defmacro index-evenp (number) `(evenp (the array-index ,number))) (defmacro index-oddp (number) `(oddp (the array-index ,number))) (defmacro index> (&rest numbers) `(> ,@(mapcar #'make-index-typed numbers))) (defmacro index= (&rest numbers) `(= ,@(mapcar #'make-index-typed numbers))) (defmacro index< (&rest numbers) `(< ,@(mapcar #'make-index-typed numbers))) (defmacro index>= (&rest numbers) `(>= ,@(mapcar #'make-index-typed numbers))) (defmacro index<= (&rest numbers) `(<= ,@(mapcar #'make-index-typed numbers))) ) #+Genera (progn (defmacro index+ (&rest numbers) `(+ ,@numbers)) (defmacro index-logand (&rest numbers) `(logand ,@numbers)) (defmacro index-logior (&rest numbers) `(logior ,@numbers)) (defmacro index- (&rest numbers) `(- ,@numbers)) (defmacro index* (&rest numbers) `(* ,@numbers)) (defmacro index1+ (number) `(1+ ,number)) (defmacro index1- (number) `(1- ,number)) (defmacro index-incf (place &optional (delta 1)) `(setf ,place (index+ ,place ,delta))) (defmacro index-decf (place &optional (delta 1)) `(setf ,place (index- ,place ,delta))) (defmacro index-min (&rest numbers) `(min ,@numbers)) (defmacro index-max (&rest numbers) `(max ,@numbers)) (defun positive-power-of-two-p (x) (when (symbolp x) (multiple-value-bind (constantp value) (lt:named-constant-p x) (when constantp (setq x value)))) (and (typep x 'fixnum) (plusp x) (zerop (logand x (1- x))))) (defmacro index-floor (number divisor) (cond ((eql divisor 1) number) ((and (positive-power-of-two-p divisor) (fboundp 'si:%fixnum-floor)) `(si:%fixnum-floor ,number ,divisor)) (t `(floor ,number ,divisor)))) (defmacro index-ceiling (number divisor) (cond ((eql divisor 1) number) ((and (positive-power-of-two-p divisor) (fboundp 'si:%fixnum-ceiling)) `(si:%fixnum-ceiling ,number ,divisor)) (t `(ceiling ,number ,divisor)))) (defmacro index-truncate (number divisor) (cond ((eql divisor 1) number) ((and (positive-power-of-two-p divisor) (fboundp 'si:%fixnum-floor)) `(si:%fixnum-floor ,number ,divisor)) (t `(truncate ,number ,divisor)))) (defmacro index-mod (number divisor) (cond ((and (positive-power-of-two-p divisor) (fboundp 'si:%fixnum-mod)) `(si:%fixnum-mod ,number ,divisor)) (t `(mod ,number ,divisor)))) (defmacro index-ash (number count) (cond ((eql count 0) number) ((and (typep count 'fixnum) (minusp count) (fboundp 'si:%fixnum-floor)) `(si:%fixnum-floor ,number ,(expt 2 (- count)))) ((and (typep count 'fixnum) (plusp count) (fboundp 'si:%fixnum-multiply)) `(si:%fixnum-multiply ,number ,(expt 2 count))) (t `(ash ,number ,count)))) (defmacro index-plusp (number) `(plusp ,number)) (defmacro index-zerop (number) `(zerop ,number)) (defmacro index-evenp (number) `(evenp ,number)) (defmacro index-oddp (number) `(oddp ,number)) (defmacro index> (&rest numbers) `(> ,@numbers)) (defmacro index= (&rest numbers) `(= ,@numbers)) (defmacro index< (&rest numbers) `(< ,@numbers)) (defmacro index>= (&rest numbers) `(>= ,@numbers)) (defmacro index<= (&rest numbers) `(<= ,@numbers)) ) ;;;; Stuff for BUFFER definition (defconstant *replysize* 32.) ;; used in defstruct initializations to avoid compiler warnings (defvar *empty-bytes* (make-sequence 'buffer-bytes 0)) (declaim (type buffer-bytes *empty-bytes*)) #+clx-overlapping-arrays (progn (defvar *empty-words* (make-sequence 'buffer-words 0)) (declaim (type buffer-words *empty-words*)) ) #+clx-overlapping-arrays (progn (defvar *empty-longs* (make-sequence 'buffer-longs 0)) (declaim (type buffer-longs *empty-longs*)) ) (defstruct (reply-buffer (:conc-name reply-) (:constructor make-reply-buffer-internal) (:copier nil) (:predicate nil)) (size 0 :type array-index) ;Buffer size ;; Byte (8 bit) input buffer (ibuf8 *empty-bytes* :type buffer-bytes) ;; Word (16bit) input buffer #+clx-overlapping-arrays (ibuf16 *empty-words* :type buffer-words) ;; Long (32bit) input buffer #+clx-overlapping-arrays (ibuf32 *empty-longs* :type buffer-longs) (next nil #-explorer :type #-explorer (or null reply-buffer)) (data-size 0 :type array-index) ) (defconstant *buffer-text16-size* 256) (deftype buffer-text16 () `(simple-array (unsigned-byte 16) (,*buffer-text16-size*))) ;; These are here because. (defparameter *xlib-package* (find-package :xlib)) (defun xintern (&rest parts) (intern (apply #'concatenate 'string (mapcar #'string parts)) *xlib-package*)) (defparameter *keyword-package* (find-package :keyword)) (defun kintern (name) (intern (string name) *keyword-package*)) ;;; Pseudo-class mechanism. (eval-when (eval compile load) (defvar *def-clx-class-use-defclass* #+Genera t #-Genera nil "Controls whether DEF-CLX-CLASS uses DEFCLASS. If it is a list, it is interpreted by DEF-CLX-CLASS to be a list of type names for which DEFCLASS should be used. If it is not a list, then DEFCLASS is always used. If it is NIL, then DEFCLASS is never used, since NIL is the empty list.") ) (defmacro def-clx-class ((name &rest options) &body slots) (if (or (not (listp *def-clx-class-use-defclass*)) (member name *def-clx-class-use-defclass*)) (let ((clos-package #+clx-ansi-common-lisp (find-package :common-lisp) #-clx-ansi-common-lisp (or (find-package :clos) (find-package :pcl) (let ((lisp-pkg (find-package :lisp))) (and (find-symbol (string 'defclass) lisp-pkg) lisp-pkg)))) (constructor t) (constructor-args t) (include nil) (print-function nil) (copier t) (predicate t)) (dolist (option options) (ecase (pop option) (:constructor (setf constructor (pop option)) (setf constructor-args (if (null option) t (pop option)))) (:include (setf include (pop option))) (:print-function (setf print-function (pop option))) (:copier (setf copier (pop option))) (:predicate (setf predicate (pop option))))) (flet ((cintern (&rest symbols) (intern (apply #'concatenate 'simple-string (mapcar #'symbol-name symbols)) *package*)) (kintern (symbol) (intern (symbol-name symbol) (find-package :keyword))) (closintern (symbol) (intern (symbol-name symbol) clos-package))) (when (eq constructor t) (setf constructor (cintern 'make- name))) (when (eq copier t) (setf copier (cintern 'copy- name))) (when (eq predicate t) (setf predicate (cintern name '-p))) (when include (setf slots (append (get include 'def-clx-class) slots))) (let* ((n-slots (length slots)) (slot-names (make-list n-slots)) (slot-initforms (make-list n-slots)) (slot-types (make-list n-slots))) (dotimes (i n-slots) (let ((slot (elt slots i))) (setf (elt slot-names i) (pop slot)) (setf (elt slot-initforms i) (pop slot)) (setf (elt slot-types i) (getf slot :type t)))) `(progn (eval-when (compile load eval) (setf (get ',name 'def-clx-class) ',slots)) ;; From here down are the system-specific expansions: (within-definition (,name def-clx-class) (,(closintern 'defclass) ,name ,(and include `(,include)) (,@(map 'list #'(lambda (slot-name slot-initform slot-type) `(,slot-name :initform ,slot-initform :type ,slot-type :accessor ,(cintern name '- slot-name) ,@(when (and constructor (or (eq constructor-args t) (member slot-name constructor-args))) `(:initarg ,(kintern slot-name))) )) slot-names slot-initforms slot-types))) ,(when constructor (if (eq constructor-args t) `(defun ,constructor (&rest args) (apply #',(closintern 'make-instance) ',name args)) `(defun ,constructor ,constructor-args (,(closintern 'make-instance) ',name ,@(mapcan #'(lambda (slot-name) (and (member slot-name slot-names) `(,(kintern slot-name) ,slot-name))) constructor-args))))) ,(when predicate #+allegro `(progn (,(closintern 'defmethod) ,predicate (object) (declare (ignore object)) nil) (,(closintern 'defmethod) ,predicate ((object ,name)) t)) #-allegro `(defun ,predicate (object) (typep object ',name))) ,(when copier `(,(closintern 'defmethod) ,copier ((.object. ,name)) (,(closintern 'with-slots) ,slot-names .object. (,(closintern 'make-instance) ',name ,@(mapcan #'(lambda (slot-name) `(,(kintern slot-name) ,slot-name)) slot-names))))) ,(when print-function `(,(closintern 'defmethod) ,(closintern 'print-object) ((object ,name) stream) (,print-function object stream 0)))))))) `(within-definition (,name def-clx-class) (defstruct (,name ,@options) ,@slots)))) #+Genera (progn (scl:defprop def-clx-class "CLX Class" si:definition-type-name) (scl:defprop def-clx-class zwei:defselect-function-spec-finder zwei:definition-function-spec-finder)) ;; We need this here so we can define DISPLAY for CLX. ;; ;; This structure is :INCLUDEd in the DISPLAY structure. ;; Overlapping (displaced) arrays are provided for byte ;; half-word and word access on both input and output. ;; (def-clx-class (buffer (:constructor nil) (:copier nil) (:predicate nil)) ;; Lock for multi-processing systems (lock (make-process-lock "CLX Buffer Lock")) #-excl (output-stream nil :type (or null stream)) #+excl (output-stream -1 :type fixnum) ;; Buffer size (size 0 :type array-index) (request-number 0 :type (unsigned-byte 16)) ;; Byte position of start of last request ;; used for appending requests and error recovery (last-request nil :type (or null array-index)) ;; Byte position of start of last flushed request (last-flushed-request nil :type (or null array-index)) ;; Current byte offset (boffset 0 :type array-index) ;; Byte (8 bit) output buffer (obuf8 *empty-bytes* :type buffer-bytes) ;; Word (16bit) output buffer #+clx-overlapping-arrays (obuf16 *empty-words* :type buffer-words) ;; Long (32bit) output buffer #+clx-overlapping-arrays (obuf32 *empty-longs* :type buffer-longs) ;; Holding buffer for 16-bit text (tbuf16 (make-sequence 'buffer-text16 *buffer-text16-size* :initial-element 0)) ;; Probably EQ to Output-Stream #-excl (input-stream nil :type (or null stream)) #+excl (input-stream -1 :type fixnum) ;; T when the host connection has gotten errors (dead nil :type (or null (not null))) ;; T makes buffer-flush a noop. Manipulated with with-buffer-flush-inhibited. (flush-inhibit nil :type (or null (not null))) ;; Change these functions when using shared memory buffers to the server ;; Function to call when writing the buffer (write-function 'buffer-write-default) ;; Function to call when flushing the buffer (force-output-function 'buffer-force-output-default) ;; Function to call when closing a connection (close-function 'buffer-close-default) ;; Function to call when reading the buffer (input-function 'buffer-read-default) ;; Function to call to wait for data to be input (input-wait-function 'buffer-input-wait-default) ;; Function to call to listen for input data (listen-function 'buffer-listen-default) #+Genera (debug-io nil :type (or null stream)) ) ;;----------------------------------------------------------------------------- ;; Printing routines. ;;----------------------------------------------------------------------------- #-(or clx-ansi-common-lisp Genera) (defun print-unreadable-object-function (object stream type identity function) (declare #+lispm (sys:downward-funarg function)) (princ "#<" stream) (when type (let ((type (type-of object)) (pcl-package (find-package :pcl))) ;; Handle pcl type-of lossage (when (and pcl-package (symbolp type) (eq (symbol-package type) pcl-package) (string-equal (symbol-name type) "STD-INSTANCE")) (setq type (funcall (intern (symbol-name 'class-name) pcl-package) (funcall (intern (symbol-name 'class-of) pcl-package) object)))) (prin1 type stream))) (when (and type function) (princ " " stream)) (when function (funcall function)) (when (and (or type function) identity) (princ " " stream)) (when identity (princ "???" stream)) (princ ">" stream) nil) #-(or clx-ansi-common-lisp Genera) (defmacro print-unreadable-object ((object stream &key type identity) &body body) (if body `(flet ((.print-unreadable-object-body. () ,@body)) (print-unreadable-object-function ,object ,stream ,type ,identity #'.print-unreadable-object-body.)) `(print-unreadable-object-function ,object ,stream ,type ,identity nil))) ;;----------------------------------------------------------------------------- ;; Image stuff ;;----------------------------------------------------------------------------- (defconstant *image-bit-lsb-first-p* #+clx-little-endian t #-clx-little-endian nil) (defconstant *image-byte-lsb-first-p* #+clx-little-endian t #-clx-little-endian nil) (defconstant *image-unit* 32) (defconstant *image-pad* 32) ;;----------------------------------------------------------------------------- ;; Foreign Functions ;;----------------------------------------------------------------------------- #+(and lucid apollo (not lcl3.0)) (lucid::define-foreign-function '(connect-to-server "connect_to_server") '((:val host :string) (:val display :integer32)) :integer32) #+(and lucid (not apollo) (not lcl3.0)) (lucid::define-c-function connect-to-server (host display) :result-type :integer) #+lcl3.0 (lucid::def-foreign-function (connect-to-server (:language :c) (:return-type :signed-32bit)) (host :simple-string) (display :signed-32bit))