git.fiddlerwoaroof.com
Raw Blame History
;;; xlibclx.scm -- Lisp support for Haskell/CLX interface

;; general

(define-syntax (nth-value n form)
  (cond ((eqv? n 0)
	 `(values ,form))
	((number? n)
	 (let ((temps  '()))
	   (dotimes (i n)
	     (declare (ignorable i))
	     (push (gensym) temps))
	   `(multiple-value-bind ,(reverse temps) ,form
	      (declare (ignore ,@(reverse (cdr temps))))
	      ,(car temps))))
	(else
	 `(lisp:nth ,n (lisp:multiple-value-list ,form)))
	))


(define-local-syntax (keywordify string)
  `(lisp:intern ,string (lisp:find-package "KEYWORD")))

(define-local-syntax (xlibify string)
  `(lisp:intern ,string (lisp:find-package "XLIB")))



;;; This is stuff to support slots that consist of a keyword/value
;;; pair.  Note that the value is always unboxed.

(define-syntax (make-keyword key value)
  `(cons ,key ,value))

(define-syntax (is-keyword? x key)
  `(eq? (car ,x) ,key))

(define-syntax (keyword-key x) `(car ,x))
(define-syntax (keyword-val x) `(cdr ,x))

(define-syntax (define-keyword-constructor name)
  (let* ((name-str (symbol->string name))
	 (key      (keywordify name-str))
	 (is-name  (string->symbol (string-append "IS-" name-str)))
	 (mk-name  (string->symbol (string-append "MK-" name-str))))
    `(begin
       (define (,mk-name x) (make-keyword ,key x))
       (define (,is-name x) (is-keyword? x ,key)))
    ))

(define-syntax (define-event-slot-finder slot)
  (let* ((slot-str (symbol->string slot))
	 (slot-key (keywordify slot-str))
	 (fun      (string->symbol (string-append "X-EVENT-" slot-str))))
    `(define (,fun event) (lookup-event-slot (cdr event) ,slot-key))))    
    
(define (lookup-event-slot event key)
  (if (null? event)
      (error "non-existent event slot: ~A" key)
      (if (eq? key (car event))
	  (cadr event)
	  (lookup-event-slot (cddr event) key))))


(define-syntax (define-attribute-setter entity attribute)
  (let* ((entity-attr (string-append (symbol->string entity)
				     "-"
				     (symbol->string attribute)))
	 (fun-name    (string->symbol (string-append "X-SET-" entity-attr)))
	 (xfun-name   (xlibify entity-attr)))
    `(define (,fun-name ,entity ,attribute)
       (setf (,xfun-name ,entity) ,attribute))))

(define-syntax (make-h-tuple . args)
  (let ((nargs (map (lambda (arg) `(box ,arg)) args)))
    `(make-tuple ,@nargs)))

;; type XError

(define (cons-xerror x)
  (declare (ignore x))
  (error "can't construct XError"))

(define (x-error-string c)
  (make-haskell-string (format '#f "~A" c)))


;;; The forces here are necessary because the thing being funcalled
;;; returns a data structure of type (IO a), and we need to do
;;; an  IO a -> a transformation.

#+lucid
(define (x-handle-error handler body)
  (lisp:catch 'x-error-handle
	      (lcl:handler-bind ((lisp:error (mk-handler handler)))
				(force (funcall body (box 'state))))))

#+(or cmu allegro lispworks)
(define (x-handle-error handler body)
  (lisp:catch 'x-error-handle
	      (lisp:handler-bind ((lisp:error (mk-handler handler)))
				 (force (funcall body (box 'state))))))

#+akcl
(define (x-handle-error handler body)
  (error "AKCL does not support HANDLER-BIND!"))

(define (mk-handler handler)
  (lambda (c) 
    (lisp:throw 'x-error-handle 
		(force (funcall handler 
				(box c)
				(box 'state))))))

;; for type XMaybe

(define (not-null? x) (not (null? x)))


;; For Bitmap, Pixarray, KeysymTable

(define (array2->haskell-list a)
  (let* ((dims    (lisp:array-dimensions a))
	 (i1max   (car dims))
	 (i2max   (cadr dims)))
    (declare (type fixnum i1max i2max))
    (do ((i1     (the fixnum (1- i1max)) (the fixnum (1- i1)))
	 (outer  '()))
	((< i1 0) outer)
	(declare (type fixnum i1))
	(setf outer
	      (cons
	        (box
		  (do ((i2    (the fixnum (1- i2max)) (the fixnum (1- i2)))
		       (inner '()))
		      ((< i2 0) inner)
		      (declare (type fixnum i2))
		      (setf inner
			    (cons (box (lisp:aref a i1 i2))
				  (box inner)))))
		(box outer))))
    ))


;; Bitmap

(define (mk-bitmap ll)
  (let ((l (haskell-list->list #'haskell-list->list/identity ll)))
    (lisp:make-array `(,(length l) , (length (car l))) 
		     :element-type 'lisp:bit
		     :initial-contents l)))

(define (sel-bitmap l)
  (array2->haskell-list l))


;; XKeysymTable

(define (mk-keysym-table ll)
  (let ((l (haskell-list->list #'haskell-list->list/identity ll)))
    (lisp:make-array `(,(length l) , (length (car l))) 
		     :element-type 'xlib:card32
		     :initial-contents l)))

(define (sel-keysym-table l)
  (array2->haskell-list l))

;; XPixarray

(define (mk-pixarray ll)
  (let ((l (haskell-list->list #'haskell-list->list/identity ll)))
    (let* ((max-num  (find-max l))
	   (pix-type (cond ((<= max-num 1) 'lisp:bit)
			   ((<= max-num 15) '(lisp:unsigned-byte 4))
			   ((<= max-num 255) 'xlib:card8)
			   ((<= max-num 65535) 'xlib:card16)
			   (else 'xlib:card32))))
      (declare (type integer max-num))
      (lisp:make-array `(,(length l) , (length (car l)))
		       :element-type pix-type
		       :initial-contents l))))

(define (find-max l)
  (let ((max  0))
    (dolist (ll l)
      (dolist (lll ll)
	(when (> (the integer lll) (the integer max))
	  (setf max lll))))
    max))

(define (sel-pixarray l)
  (array2->haskell-list l))




;;; Can't use mumble vector primitives on arrays of specialized types!

(define (array1->haskell-list a)
  (declare (type lisp:vector a))
  (let ((imax  (lisp:length a)))
    (declare (type fixnum imax))
    (do ((i      (the fixnum (1- imax)) (the fixnum (1- i)))
	 (result '()))
	((< i 0) result)
	(declare (type fixnum i))
	(setf result
	      (cons (box (lisp:aref a i))
		    (box result))))))

;; BitVec

(define (mk-bitvec ll)
  (let ((l (haskell-list->list/identity ll)))
    (lisp:make-array `(,(length l)) :element-type 'lisp:bit
		     :initial-contents l)))

(define (sel-bitvec l)
  (array1->haskell-list l))

;; ByteVec

(define (mk-bytevec ll)
  (let ((l (haskell-list->list/identity ll)))
    (lisp:make-array `(,(length l)) :element-type 'xlib:card8
		     :initial-contents l)))

(define (sel-bytevec l)
  (array1->haskell-list l))


;; XAtom
(define (mk-atom name)
  (keywordify (haskell-string->string name)))

(define (sel-atom atom)
  (make-haskell-string (symbol->string atom)))

;; XProperty
;;; watch out for name conflict with :property keyword stuff
(define (mk-xproperty d ty f) (list (haskell-list->list/identity d) ty f))
(define (sel-xproperty-data p) (list->haskell-list/identity (car p)))
(define (sel-xproperty-type p) (cadr p))
(define (sel-xproperty-format p) (caddr p))

(define (mk-event type slots)
  (cons type (slots->keywords (haskell-list->list/identity slots))))

(define (sel-event-type event) (car event))

(define (sel-event-slots event) 
  (list->haskell-list/identity (keywords->slots (car event) (cdr event) event)))

;; XEventSlot

(define-keyword-constructor window)
(define-keyword-constructor event-window)
(define-keyword-constructor code)
(define-keyword-constructor pos)
(define-keyword-constructor state)
(define-keyword-constructor time)
(define-keyword-constructor root)
(define-keyword-constructor root-pos)
(define-keyword-constructor child)
(define-keyword-constructor same-screen-p)
(define-keyword-constructor hint-p)
(define-keyword-constructor mode)
(define-keyword-constructor kind)
(define-keyword-constructor focus-p)
(define-keyword-constructor keymap)
(define-keyword-constructor request)
(define-keyword-constructor start)
(define-keyword-constructor count)
(define-keyword-constructor rect)
(define-keyword-constructor drawable)
(define-keyword-constructor graph-fun)
(define-keyword-constructor place)
(define-keyword-constructor border-width)
(define-keyword-constructor above-sibling)
(define-keyword-constructor override-redirect-p)
(define-keyword-constructor parent)
(define-keyword-constructor configure-p)
(define-keyword-constructor visibility)
(define-keyword-constructor new-p)
(define-keyword-constructor installed-p)
(define-keyword-constructor stack-mode)
(define-keyword-constructor value-mask)
(define-keyword-constructor size)
(define-keyword-constructor message)
(define-keyword-constructor property-state)
(define-keyword-constructor atom)
(define-keyword-constructor selection)
(define-keyword-constructor target)
(define-keyword-constructor property)
(define-keyword-constructor requestor)

(define-event-slot-finder window)
(define-event-slot-finder event-window)
(define-event-slot-finder code)
(define-event-slot-finder x)
(define-event-slot-finder y)
(define-event-slot-finder state)
(define-event-slot-finder time)
(define-event-slot-finder root)
(define-event-slot-finder root-x)
(define-event-slot-finder root-y)
(define-event-slot-finder child)
(define-event-slot-finder same-screen-p)
(define-event-slot-finder hint-p)
(define-event-slot-finder mode)
(define-event-slot-finder kind)
(define-event-slot-finder focus-p)
(define-event-slot-finder keymap)
(define-event-slot-finder request)
(define-event-slot-finder start)
(define-event-slot-finder count)
(define-event-slot-finder width)
(define-event-slot-finder height)
(define-event-slot-finder drawable)
(define-event-slot-finder major)
(define-event-slot-finder minor)
(define-event-slot-finder place)
(define-event-slot-finder border-width)
(define-event-slot-finder above-sibling)
(define-event-slot-finder override-redirect-p)
(define-event-slot-finder parent)
(define-event-slot-finder configure-p)
(define-event-slot-finder new-p)
(define-event-slot-finder installed-p)
(define-event-slot-finder stack-mode)
(define-event-slot-finder value-mask)
(define-event-slot-finder data)
(define-event-slot-finder type)
(define-event-slot-finder format)
(define-event-slot-finder atom)
(define-event-slot-finder selection)
(define-event-slot-finder target)
(define-event-slot-finder property)
(define-event-slot-finder requestor)

(define (x-event-pos event) (mk-xpoint (x-event-x event) (x-event-y event)))

(define (x-event-root-pos event) 
  (mk-xpoint (x-event-root-x event) (x-event-root-y event)))

(define (x-event-size event) 
  (mk-xsize (x-event-width event) (x-event-height event)))

(define (x-event-rect event) 
  (mk-xrect (x-event-x event) (x-event-y event)
	    (x-event-width event) (x-event-height event)))

(define (x-event-graph-fun event)
  (cons (x-event-major event) (x-event-minor event)))

(define (x-event-message event)
  (list (sequence->list (x-event-data event))
	(x-event-type event)
	(x-event-format event)))


;; XEventMask

(define (x-make-event-mask keys)
  (apply (function xlib:make-event-mask) (haskell-list->list/identity keys)))

(define (x-event-mask-key-list mask)
  (list->haskell-list/identity (xlib:make-event-keys mask)))

;; XStateMask

(define (x-make-state-mask keys)
  (apply (function xlib:make-state-mask) (haskell-list->list/identity keys)))

(define (x-state-mask-key-list mask)
  (list->haskell-list/identity (xlib:make-state-keys mask)))


(define-keyword-constructor background)
(define-keyword-constructor foreground)
(define-keyword-constructor event-mask)
(define-keyword-constructor depth)
(define-keyword-constructor border-width)
(define-keyword-constructor class)
(define-keyword-constructor visual)
(define-keyword-constructor border)
(define-keyword-constructor backing-store)
(define-keyword-constructor backing-planes)
(define-keyword-constructor backing-pixel)
(define-keyword-constructor save-under)
(define-keyword-constructor do-not-propagate-mask)
(define-keyword-constructor override-redirect)
(define-keyword-constructor colormap)
(define-keyword-constructor cursor)

(define-keyword-constructor arc-mode)
(define-keyword-constructor cap-style)
(define-keyword-constructor clip-mask)
(define-keyword-constructor clip-origin)
(define-keyword-constructor dash-offset)
(define-keyword-constructor dashes)
(define-keyword-constructor exposures)
(define-keyword-constructor fill-rule)
(define-keyword-constructor fill-style)
(define-keyword-constructor font)
(define-keyword-constructor function)
(define-keyword-constructor join-style)
(define-keyword-constructor line-style)
(define-keyword-constructor line-width)
(define-keyword-constructor plane-mask)
(define-keyword-constructor stipple)
(define-keyword-constructor subwindow-mode)
(define-keyword-constructor tile)
(define-keyword-constructor tile-origin)

(define-keyword-constructor bit-lsb-first-p)
(define-keyword-constructor bits-per-pixel)
(define-keyword-constructor blue-mask)
(define-keyword-constructor byte-lsb-first-p)
(define-keyword-constructor bytes-per-line)
(define-keyword-constructor data)
(define-keyword-constructor format)
(define-keyword-constructor green-mask)
(define-keyword-constructor size)
(define-keyword-constructor name)
(define-keyword-constructor red-mask)
(define-keyword-constructor hot-spot)


(define-keyword-constructor owner-p)
(define-keyword-constructor sync-pointer-p)
(define-keyword-constructor sync-keyboard-p)
(define-keyword-constructor confine-to)


;; XClipMask

(define (not-pixmap-and-list-p x) 
  (and (pair? x) (not (xlib:pixmap-p x))))
(define (mk-clip-mask-rects rects) 
  (rects->point-seq (haskell-list->list/identity rects)))
(define (sel-clip-mask-rects point-seq) 
  (list->haskell-list/identity (point-seq->rects point-seq)))

;; XPoint

(define (mk-xpoint x y) (cons x y))
(define (xpoint-x x) (car x))
(define (xpoint-y x) (cdr x))

;; XSize

(define (mk-xsize x y) (cons x y))
(define (xsize-w x) (car x))
(define (xsize-h x) (cdr x))

;; XRect
(define (mk-xrect x y w h) (vector x y w h))
(define (xrect-x x) (vector-ref x 0))
(define (xrect-y x) (vector-ref x 1))
(define (xrect-w x) (vector-ref x 2))
(define (xrect-h x) (vector-ref x 3))

;; XArc

(define (mk-xarc x y w h a1 a2) (vector x y w h a1 a2))

(define (xarc-x x) (vector-ref x 0))
(define (xarc-y x) (vector-ref x 1))
(define (xarc-w x) (vector-ref x 2))
(define (xarc-h x) (vector-ref x 3))
(define (xarc-a1 x) (vector-ref x 4))
(define (xarc-a2 x) (vector-ref x 5))

;; BitmapFormat

(define (mk-bitmap-format u p l) 
  (xlib::make-bitmap-format :unit u :pad p :lsb-first-p l))

;; PixmapFormat

(define (mk-pixmap-format u p l) 
  (xlib::make-pixmap-format :depth u :bits-per-pixel p :scanline-pad l))

;; XVisualInfo

(define (mk-xvisual-info id cl rm gm bm bs es) 
  (xlib::make-visual-info :id id :class cl :red-mask rm :green-mask gm 
			  :blue-mask bm :bits-per-rgb bs :colormap-entries es))

;; XFillContent

(define (is-fill-pixel x) (not (or (xlib:pixmap-p x) (symbol? x))))

;; XBackingStore

;; XImageData

(define (bitmap-list-p x) (pair? x))
(define (pixarray-p x) (and (not (pair? x)) (eq? (lisp:array-rank x) 2)))
(define (bytevec-p x) (and (not (pair? x)) (eq? (lisp:array-rank x) 1)))

;; XColor
(define (mk-color r g b) 
  (xlib:make-color :red r :green g :blue b))


(define (x-print x)
  (print x))

(define (x-set-event-mask-key mask key-sym) 
  (lisp:logior mask (xlib:make-event-mask key-sym)))

(define (x-clear-event-mask-key mask key-sym) 
  (lisp:logand mask (lisp:lognot (xlib:make-event-mask key-sym))))


(define (x-test-event-mask-key mask key-sym)
  (if (eqv? 0 (lisp:logand mask (xlib:make-event-mask key-sym))) '#f '#t))

(define (x-set-state-mask-key mask key-sym) 
  (lisp:logior mask (xlib:make-state-mask key-sym)))

(define (x-clear-state-mask-key mask key-sym) 
  (lisp:logand mask (lisp:lognot (xlib:make-state-mask key-sym))))

(define (x-test-state-mask-key mask key-sym)
  (if (eqv? 0 (lisp:logand mask (xlib:make-state-mask key-sym))) '#f '#t))


;;; Display is a string of the format name:d.s
;;; ignore s; if d is omitted, default it to zero.

(define (x-open-display display)
  (let* ((end    (string-length display))
	 (colon  (or (string-position #\: display 0 end) end))
	 (dot    (or (string-position #\. display colon end) end)))
    (declare (type fixnum end colon dot))
    (xlib:open-display
      (substring display 0 colon)
      :display (if (eqv? colon dot)
		   0
		   (string->number (substring display (1+ colon) dot))))))

(define (x-set-display-error-handler display error-fun)
  (declare (ignore display error-fun))
  (error "not implemented"))

(define (x-set-display-after-function display after-fun)
  (declare (ignore display after-fun))
  (error "not implemented"))

(define (x-screen-depths screen)
  (let ((depths (xlib:screen-depths screen)))
    (map (lambda (l) (make-h-tuple (car l) (list->haskell-list/identity (cdr l))))
	 depths)))

(define (x-screen-size screen)
  (mk-xsize (xlib:screen-width screen) (xlib:screen-height screen)))

(define (x-screen-mmsize screen)
  (mk-xsize (xlib:screen-width-in-millimeters screen) 
	    (xlib:screen-height-in-millimeters screen)))

(define (x-create-window parent rect attrs)
  (apply (function XLIB:CREATE-WINDOW)
	 `(:parent ,parent :x ,(xrect-x rect) :y ,(xrect-y rect)
	   :width ,(xrect-w rect) :height ,(xrect-h rect)
	   ,@(attrs->keywords attrs))))

(define-attribute-setter drawable border-width)

(define (x-drawable-size drawable)
  (mk-xsize (xlib:drawable-width drawable) (xlib:drawable-height drawable)))

(define (x-drawable-resize drawable size)
  (setf (xlib:drawable-width drawable) (xsize-w size))
  (setf (xlib:drawable-height drawable) (xsize-h size)))

(define (x-window-pos window)
  (mk-xpoint (xlib:drawable-x window) (xlib:drawable-y window)))

(define (x-window-move window point)
  (setf (xlib:drawable-x window) (xpoint-x point))
  (setf (xlib:drawable-y window) (xpoint-y point)))

(define-attribute-setter window background)
(define-attribute-setter window backing-pixel)
(define-attribute-setter window backing-planes)
(define-attribute-setter window backing-store)
(define-attribute-setter window bit-gravity)
(define-attribute-setter window border)
(define-attribute-setter window colormap)

(define (x-set-window-cursor window cursor)
  (let ((val (if (null? cursor) :none cursor)))
    (setf (xlib:window-cursor window) val)))

(define-attribute-setter window do-not-propagate-mask)
(define-attribute-setter window event-mask)
(define-attribute-setter window gravity)
(define-attribute-setter window override-redirect)
(define-attribute-setter window priority)
(define-attribute-setter window save-under)

(define (x-query-tree window)
  (multiple-value-bind (children parent root)
		       (xlib:query-tree window)
     (make-h-tuple (list->haskell-list/identity children) parent root)))

(define (x-reparent-window window parent point)
  (xlib:reparent-window window parent (xpoint-x point) (xpoint-y point)))

(define (x-translate-coordinates source point dest)
  (xlib:translate-coordinates source (xpoint-x point) (xpoint-y point) dest))

(define (x-create-pixmap size depth drawable)
  (xlib:create-pixmap :width (xsize-w size)
		      :height (xsize-h size)
		      :depth depth
		      :drawable drawable))

(define (x-create-gcontext drawable attrs)
  (apply (function XLIB:CREATE-GCONTEXT)
	 `(:drawable ,drawable ,@(attrs->keywords attrs))))

(define (x-update-gcontext gcontext attrs)
  (do ((keys (attrs->keywords attrs) (cddr keys)))
      ((null? keys))
    (x-update-gcontext-attr gcontext (car keys) (cadr keys))))

(define (x-update-gcontext-attr gcontext key attr)
  (case key
    (:arc-mode (setf (xlib:gcontext-arc-mode gcontext) attr))
    (:background (setf (xlib:gcontext-background gcontext) attr))
    (:cap-style (setf (xlib:gcontext-cap-style gcontext) attr))
    (:fill-style (setf (xlib:gcontext-fill-style gcontext) attr))
    (:clip-mask (setf (xlib:gcontext-clip-mask gcontext) attr))
    (:clip-x (setf (xlib:gcontext-clip-x gcontext) attr))
    (:clip-y (setf (xlib:gcontext-clip-y gcontext) attr))
    (:dash-offset (setf (xlib:gcontext-dash-offset gcontext) attr))
    (:dashes (setf (xlib:gcontext-dashes gcontext) attr))
    (:exposures (setf (xlib:gcontext-exposures gcontext) attr))
    (:fill-rule (setf (xlib:gcontext-fill-rule gcontext) attr))
    (:font (setf (xlib:gcontext-font gcontext) attr))
    (:foreground (setf (xlib:gcontext-foreground gcontext) attr))
;    (:function (setf (xlib:gcontext-function gcontext) attr))
    (:join-style (setf (xlib:gcontext-join-style gcontext) attr))
    (:line-style (setf (xlib:gcontext-line-style gcontext) attr))
;    (:line-width (setf (xlib:gcontext-line-width gcontext) attr))
;    (:plane-mask (setf (xlib:gcontext-plane-mask gcontext) attr))
;    (:stipple (setf (xlib:gcontext-stipple gcontext) attr))
    (:subwindow-mode (setf (xlib:gcontext-subwindow-mode gcontext) attr))
;    (:tile (setf (xlib:gcontext-tile gcontext) attr))
;    (:ts-x (setf (xlib:gcontext-ts-x gcontext) attr))
;    (:ts-y (setf (xlib:gcontext-ts-y gcontext) attr))
    (else (format '#t "Graphics context attribute ~A is not settable.~%"
		  key))))

(define (x-query-best-stipple dsize drawable)
  (multiple-value-bind (w h) 
        (xlib:query-best-stipple (xsize-w dsize) (xsize-h dsize) drawable)
     (mk-xsize w h)))

(define (x-query-best-tile dsize drawable)
  (multiple-value-bind (w h) 
        (xlib:query-best-tile (xsize-w dsize) (xsize-h dsize) drawable)
     (mk-xsize w h)))

(define (x-clear-area window rect exposures-p)
  (xlib:clear-area window 
		   :x (xrect-x rect)
		   :y (xrect-y rect)
		   :width (xrect-w rect)
		   :height (xrect-h rect)
		   :exposures-p exposures-p))

(define (x-copy-area src gcontext rect dest point)
  (xlib:copy-area src 
		  gcontext 
		  (xrect-x rect) (xrect-y rect) 
		  (xrect-w rect) (xrect-h rect) 
		  dest 
		  (xpoint-x point) (xpoint-y point)))

(define (x-copy-plane src gcontext plane rect dest point)
  (xlib:copy-plane src 
		   gcontext 
		   plane 
		   (xrect-x rect) (xrect-y rect) 
		   (xrect-w rect) (xrect-h rect) 
		   dest 
		   (xpoint-x point) (xpoint-y point)))

(define (x-draw-point drawable gcontext point)
  (xlib:draw-point drawable gcontext (xpoint-x point) (xpoint-y point)))

(define (x-draw-points drawable gcontext points)
  (xlib:draw-points drawable gcontext (points->point-seq points)))

(define (points->point-seq points)
  (if (null? points)
      '()
      (let ((point (car points)))
	(lisp:list* (xpoint-x point)
		    (xpoint-y point)
		    (points->point-seq (cdr points))))))

(define (segments->point-seq segments)
  (if (null? segments)
      '()
      (let* ((first-pair (car segments))
	     (point-1 (force (tuple-select 2 0 first-pair)))
	     (point-2 (force (tuple-select 2 1 first-pair))))
	(lisp:list* (xpoint-x point-1)
		    (xpoint-y point-1) 
		    (xpoint-x point-2)
		    (xpoint-y point-2) 
		    (segments->point-seq (cdr segments))))))

(define (rects->point-seq rects)
  (if (null? rects)
      '()
      (let ((rect (car rects)))
	(lisp:list* (xrect-x rect)
		    (xrect-y rect)
		    (xrect-w rect)
		    (xrect-h rect)
		    (rects->point-seq (cdr rects))))))

(define (point-seq->rects point-seq)
  (if (null? point-seq)
      '()
      (cons (mk-xrect (car point-seq) (cadr point-seq) 
		      (caddr point-seq) (cadddr point-seq))
	    (point-seq->rects (cddddr point-seq)))))

(define (arcs->point-seq arcs)
  (if (null? arcs)
      '()
      (let ((arc (car arcs)))
	(lisp:list* (xarc-x arc)
		    (xarc-y arc)
		    (xarc-w arc)
		    (xarc-h arc)
		    (xarc-a1 arc)
		    (xarc-a2 arc)
		    (arcs->point-seq (cdr arcs))))))

(define (x-draw-line drawable gcontext point-1 point-2)
  (xlib:draw-line drawable gcontext (xpoint-x point-1) (xpoint-y point-1)
		  (xpoint-x point-2) (xpoint-y point-2)))

(define (x-draw-lines drawable gcontext points fill-p)
  (xlib:draw-lines drawable gcontext 
		   (points->point-seq points) :fill-p fill-p))

(define (x-draw-segments drawable gcontext segments)
  (xlib:draw-segments drawable gcontext (segments->point-seq segments)))

(define (x-draw-rectangle drawable gcontext rect fill-p)
  (xlib:draw-rectangle drawable gcontext
		       (xrect-x rect) (xrect-y rect) 
		       (xrect-w rect) (xrect-h rect)
		       fill-p))

(define (x-draw-rectangles drawable gcontext rects fill-p)
  (xlib:draw-rectangles drawable gcontext
			(rects->point-seq rects)
			fill-p))

(define (x-draw-arc drawable gcontext arc fill-p)
  (xlib:draw-arc drawable gcontext
		 (xarc-x arc) (xarc-y arc) 
		 (xarc-w arc) (xarc-h arc)
		 (xarc-a1 arc) (xarc-a2 arc)
		 fill-p))

(define (x-draw-arcs drawable gcontext arcs fill-p)
  (xlib:draw-arcs drawable gcontext
		  (arcs->point-seq arcs)
		  fill-p))

(define (x-draw-glyph drawable gcontext point element)
  (nth-value 1
	     (xlib:draw-glyph drawable gcontext (xpoint-x point) 
			      (xpoint-y point) element)))

(define (x-draw-glyphs drawable gcontext point element)
  (nth-value 1 (xlib:draw-glyphs drawable gcontext (xpoint-x point) 
				 (xpoint-y point) element)))

(define (x-draw-image-glyph drawable gcontext point element)
  (nth-value 1 (xlib:draw-image-glyph drawable gcontext (xpoint-x point) 
				      (xpoint-y point) element)))

(define (x-draw-image-glyphs drawable gcontext point element)
  (nth-value 1 (xlib:draw-image-glyphs drawable gcontext (xpoint-x point) 
				       (xpoint-y point) element)))

(define (x-image-size image)
  (mk-xsize (xlib:image-width image) (xlib:image-height image)))

(define (x-image-name image)
  (let ((lisp-name (xlib:image-name image)))
    (cond ((null? lisp-name) "")
	  ((symbol? lisp-name) (symbol->string lisp-name))
	  (else lisp-name))))
    
(define-attribute-setter image name)

(define (x-image-hot-spot image)
  (mk-xpoint (xlib:image-x-hot image) (xlib:image-y-hot image)))

(define (x-set-image-hot-spot image point)
  (setf (xlib:image-x-hot image) (xpoint-x point))
  (setf (xlib:image-y-hot image) (xpoint-y point)))

(define-attribute-setter image xy-bitmap-list)
(define-attribute-setter image z-bits-per-pixel)
(define-attribute-setter image z-pixarray)

(define (x-create-image attrs)
  (apply (function xlib:create-image) (attrs->keywords attrs)))

(define (x-copy-image image rect type)
  (xlib:copy-image image :x (xrect-x rect) :y (xrect-y rect)
		   :width (xrect-w rect) :height (xrect-h rect)
		   :result-type type))

(define (x-get-image drawable rect pmask format type)
  (xlib:get-image drawable :x (xrect-x rect) :y (xrect-y rect)
		  :width (xrect-w rect) :height (xrect-h rect)
		  :plane-mask pmask :format format :result-type type))

(define (x-put-image drawable gcontext image point rect)
  (xlib:put-image drawable gcontext image 
		  :src-x (xpoint-x point) :src-y (xpoint-y point)
		  :x (xrect-x rect) :y (xrect-y rect)
		  :width (xrect-w rect) :height (xrect-h rect)))

(define (x-get-raw-image drawable rect pmask format)
  (xlib:get-raw-image drawable 
		      :x (xrect-x rect) :y (xrect-y rect) 
		      :width (xrect-w rect) :height (xrect-h rect)
		      :plane-mask pmask :format format))

(define (x-put-raw-image drawable gcontext data depth rect left-pad format)
  (xlib:put-raw-image drawable gcontext data
		      :depth depth 
		      :x (xrect-x rect) :y (xrect-y rect) 
		      :width (xrect-w rect) :height (xrect-h rect)
		      :left-pad left-pad :format format))

(define (x-font-name font)
  (let ((lisp-name (xlib:font-name font)))
    (cond ((null? lisp-name) "")
	  ((symbol? lisp-name) (symbol->string lisp-name))
	  (else lisp-name))))

(define (x-alloc-color colormap color)
  (multiple-value-bind (pixel screen-color exact-color)
       (xlib:alloc-color colormap color)
     (make-h-tuple pixel screen-color exact-color)))

(define (x-alloc-color-cells colormap colors planes contiguous-p)
  (multiple-value-bind (pixels mask)
       (xlib:alloc-color-cells colormap colors :planes planes 
			       :contiguous-p contiguous-p)
     (make-h-tuple (list->haskell-list/identity pixels) (list->haskell-list/identity mask))))

(define (x-alloc-color-planes colormap colors reds greens blues contiguous-p)
  (multiple-value-bind (pixels red-mask green-mask blue-mask)
       (xlib:alloc-color-planes colormap colors :reds reds :greens greens
				:blues blues :contiguous-p contiguous-p)
     (make-h-tuple (list->haskell-list/identity pixels) 
		   red-mask
		   green-mask
		   blue-mask)))

(define (x-lookup-color colormap name)
  (multiple-value-bind (screen-color exact-color)
      (xlib:lookup-color colormap name)
    (make-h-tuple screen-color exact-color)))

(define (unzip l)
  (if (null? l)
      '()
      (let ((h (car l)))
	(lisp:list* (force (tuple-select 2 0 h))
		    (force (tuple-select 2 1 h))
		    (unzip (cdr l))))))

(define (x-store-colors colormap pixel-colors)
  (xlib:store-colors colormap (unzip pixel-colors)))

(define (x-create-cursor source mask point foreground background)
  (apply (function xlib:create-cursor)
	 `(:source ,source
	   ,@(if mask `(:mask ,mask) '())
	   :x ,(xpoint-x point) :y ,(xpoint-y point)
	   :foreground ,foreground :background ,background)))

(define (x-create-glyph-cursor src mask foreground background)
  (apply (function xlib:create-glyph-cursor)
	 `(:source-font ,(force (tuple-select 2 0 src))
	   :source-char ,(integer->char (force (tuple-select 2 1 src)))
	   ,@(if mask 
		 `(:mask-font ,(force (tuple-select 2 0 mask))
		 :mask-char ,(integer->char (force (tuple-select 2 1 mask))))
		 '())
	   :foreground ,foreground :background ,background)))

(define (x-query-best-cursor size display)
  (multiple-value-bind (w h)
      (xlib:query-best-cursor (xsize-w size) (xsize-h size) display)
    (mk-xsize w h)))

(define (x-change-property window property content)
  (xlib:change-property window property 
			(car content) (cadr content) 
			(caddr content)))

(define (x-get-property window property)
  (lisp:multiple-value-bind (data type format) 
			    (xlib:get-property window property)
	 (list (sequence->list data) type format)))

(define (x-convert-selection selection type requestor property time)
  (apply (function xlib:convert-selection)
	 `(,selection ,type ,requestor ,property ,@(if time `(,time) '()))))

(define (x-set-selection-owner display selection time owner)
  (if time
      (setf (xlib:selection-owner display selection time) owner)
      (setf (xlib:selection-owner display selection) owner)))

(define (sequence->list seq)
  (if (list? seq) seq
      (do ((i (1- (lisp:length seq)) (1- i))
	   (res '() (cons (lisp:elt seq i) res)))
	  ((< i 0) res))))

(define *this-event* '())

(define (translate-event lisp:&rest event-slots lisp:&key event-key 
			 lisp:&allow-other-keys)
  (setf *this-event* (cons event-key event-slots))
  '#t)


(define (x-get-event display)
  (xlib:process-event display :handler #'translate-event :force-output-p '#t)
  *this-event*)

(define (x-queue-event display event append-p)
  (apply (function xlib:queue-event)
	 `(,display ,(car event) ,@(cdr event) :append-p ,append-p)))

(define (x-event-listen display)
  (let ((res (xlib:event-listen display)))
    (if (null? res) 0 res)))

(define (x-send-event window event mask)
  (apply (function xlib:send-event)
	 `(,window ,(car event) ,mask ,@(cdr event))))

(define (x-global-pointer-position display)
  (multiple-value-bind (x y) (xlib:global-pointer-position display)
    (mk-xpoint x y)))

(define (x-pointer-position window)
  (multiple-value-bind (x y same) (xlib:pointer-position window)
    (if same (mk-xpoint x y) '())))

(define (x-motion-events window start stop)
  (do ((npos '() (cons (mk-xpoint (car pos) (cadr pos)) npos))
       (pos (xlib:motion-events window :start start :stop stop) 
	    (cdddr pos)))
      ((null? pos) (nreverse npos))))

(define (x-warp-pointer dest-win point)
  (xlib:warp-pointer dest-win (xpoint-x point) (xpoint-y point)))

(define (x-set-input-focus display focus revert-to time)
  (apply (function xlib:set-input-focus)
	 `(,display ,focus ,revert-to ,@(if time `(,time) '()))))

(define (x-input-focus display)
  (multiple-value-bind (focus revert-to) (xlib:input-focus display)
    (make-h-tuple focus revert-to)))

(define (x-grab-pointer window event-mask attrs time)
  (apply (function xlib:grab-pointer)
	 `(,window ,event-mask
           ,@(attrs->keywords attrs)
	   ,@(if time `(:time ,time) '()))))

(define (x-ungrab-pointer display time)
  (if time
      (xlib:ungrab-pointer display :time time)
      (xlib:ungrab-pointer display)))
      
(define (x-change-active-pointer-grab display event-mask attrs time)
  (apply (function xlib:change-active-pointer-grab)
	 `(,display ,event-mask
           ,@(attrs->keywords attrs)
	   ,@(if time `(,time) '()))))

(define (x-grab-button window button event-mask state-mask attrs)
  (apply (function xlib:grab-button)
	 `(,window ,button ,event-mask :modifiers ,state-mask
	   ,@(attrs->keywords attrs))))

(define (x-ungrab-button window button modifiers)
  (xlib:ungrab-button window button :modifiers modifiers))

(define (x-grab-keyboard window attrs time)
  (apply (function xlib:grab-keyboard)
	 `(,window ,@(attrs->keywords attrs)
	   ,@(if time `(:time ,time) '()))))

(define (x-ungrab-keyboard display time)
  (if time
      (xlib:ungrab-keyboard display :time time)
      (xlib:ungrab-keyboard display)))
      
(define (x-grab-key window key state-mask attrs)
  (apply (function xlib:grab-key)
	 `(,window ,key :modifiers ,state-mask ,@(attrs->keywords attrs))))

(define (x-ungrab-key window key modifiers)
  (xlib:ungrab-button window key :modifiers modifiers))

(define (x-set-pointer-acceleration display val)
  (xlib:change-pointer-control display :acceleration val))

(define (x-set-pointer-threshold display val)
  (xlib:change-pointer-control display :threshold val))

(define (x-pointer-acceleration display)
  (lisp:coerce (nth-value 0 (xlib:pointer-control display)) 
	       'lisp:single-float))

(define (x-pointer-threshold display)
  (lisp:coerce (nth-value 1 (xlib:pointer-control display)) 
	       'lisp:single-float))

(define-attribute-setter pointer mapping)

(define (x-set-keyboard-key-click-percent display v)
  (xlib:change-keyboard-control display :key-click-percent v))

(define (x-set-keyboard-bell-percent display v)
  (xlib:change-keyboard-control display :bell-percent v))

(define (x-set-keyboard-bell-pitch display v)
  (xlib:change-keyboard-control display :bell-pitch v))

(define (x-set-keyboard-bell-duration display v)
  (xlib:change-keyboard-control display :bell-duration v))


;;; Yes, leds are really counted from 1 rather than 0.

(define (x-set-keyboard-led display v)
  (declare (type integer v))
  (do ((led 1 (1+ led))
       (vv v (lisp:ash vv -1)))
      ((> led 32))
      (declare (type fixnum led) (type integer vv))
      (xlib:change-keyboard-control display
        :led led
	:led-mode (if (lisp:logand vv 1) :on :off))))

(define (x-set-keyboard-auto-repeat-mode display v)
  (do ((key 0 (1+ key)))
      ((>= key (lisp:length v)))
      (declare (type fixnum key))
      (xlib:change-keyboard-control display
        :key key
	:auto-repeat-mode (if (eqv? (the fixnum (lisp:aref v key)) 1) :on :off)
	)))

(define (x-keyboard-key-click-percent display)
  (nth-value 0 (xlib:keyboard-control display)))

(define (x-keyboard-bell-percent display)
  (nth-value 1 (xlib:keyboard-control display)))

(define (x-keyboard-bell-pitch display)
  (nth-value 2 (xlib:keyboard-control display)))

(define (x-keyboard-bell-duration display)
  (nth-value 3 (xlib:keyboard-control display)))

(define (x-keyboard-led display)
  (nth-value 4 (xlib:keyboard-control display)))

(define (x-keyboard-auto-repeat-mode display)
  (nth-value 6 (xlib:keyboard-control display)))

(define (x-modifier-mapping display)
  (lisp:multiple-value-list (xlib:modifier-mapping display)))

(define (x-set-modifier-mapping display l)
  (let ((l1 (cddddr l)))
    (xlib:set-modifier-mapping display 
			       :shift (car l)
			       :lock (cadr l)
			       :control (caddr l)
			       :mod1 (cadddr l)
			       :mod2 (car l1)
			       :mod3 (cadr l1)
			       :mod4 (caddr l1)
			       :mod5 (cadddr l1))))

(define (x-keysym-character display keysym state)
  (let ((res (xlib:keysym->character display keysym state)))
    (if (char? res) (char->integer res) '())))

(define (x-keycode-character display keycode state)
  (let ((res (xlib:keycode->character display keycode state)))
    (if (char? res) (char->integer res) '())))

(define-attribute-setter close-down mode)

(define-attribute-setter access control)

(define (x-screen-saver display)
  (lisp:multiple-value-list (xlib:screen-saver display)))

(define (x-set-screen-saver display ss)
  (xlib:set-screen-saver display (car ss) (cadr ss) (caddr ss) (cadddr ss)))

(define (slots->keywords slots)
  (if (null slots) '()
      `(,@(slot->keyword (car slots)) ,@(slots->keywords (cdr slots)))))

(define (slot->keyword slot)
  (let* ((tag (keyword-key slot))
	 (val (keyword-val slot)))
    (case tag
      (:pos `(:x ,(xpoint-x val) :y ,(xpoint-y val)))
      (:root-pos `(:root-x ,(xpoint-x val) :root-y ,(xpoint-y val)))
      (:size `(:width ,(xsize-w val) :height ,(xsize-h val)))
      (:rect `(:x ,(xrect-x val) :y ,(xrect-y val)
	       :width ,(xrect-w val) :height ,(xrect-h val)))
      (:graph-fun `(:major ,(car val) :minor ,(cdr val)))
      (:visibility `(:state ,val))
      (:property-state `(:state ,val))
      (:message `(:data ,(car val) :type ,(cadr val) :format ,(caddr val)))
      (else `(,tag ,val)))))

(define (keywords->slots type keywords event)
  (let* ((slots (keywords->slots1 type keywords))
	 (has-root-xy (memq type '(:key-press :key-release :button-press 
					      :button-release :motion-notify 
					      :enter-notify :leave-notify)))
	 (has-xy (or has-root-xy 
		     (memq type '(:gravity-notify :reparent-notify))))
	 (has-graph-fun (memq type '(:graphics-exposure :no-exposure)))
	 (has-rect (memq type '(:exposure :graphics-exposure 
					  :configure-notify
					  :create-notify :configure-request)))
	 (has-size (memq type '(:resize-request)))
	 (has-message (memq type '(:client-message))))
    (when has-xy
      (push (make-keyword :pos (x-event-pos event)) slots))
    (when has-root-xy
      (push (make-keyword :root-pos (x-event-root-pos event))	slots))
    (when has-graph-fun
      (push (make-keyword :graph-fun (x-event-graph-fun event)) slots))
    (when has-rect
      (push (make-keyword :rect (x-event-rect event))	slots))
    (when has-size
      (push (make-keyword :size (x-event-size event))	slots))
    (when has-message
      (push (make-keyword :message (x-event-message event)) slots))
    slots))
      
(define (keywords->slots1 type keywords)
  (if (null? keywords)
      '()
      (if (memq (car keywords) 
		'(:x :y :width :height :root-x :root-y 
		     :major :minor :type :data :format))
	  (keywords->slots1 type (cddr keywords))
	  (cons (keyword->slot type (car keywords) (cadr keywords))
		(keywords->slots1 type (cddr keywords))))))

(define (keyword->slot type slot val)
  (if (eq? slot :state)
      (case type
	(:property-state (make-keyword :property-state val))
	(:visibility (make-keyword :visibility val))
	(else (make-keyword :state val)))
      (make-keyword slot val)))
		 
(define (attrs->keywords attrs)
  (if (null attrs)
      '()
      (nconc (attr->keyword (car attrs))
	     (attrs->keywords (cdr attrs)))))

(define (attr->keyword attr)
  (let* ((tag (keyword-key attr))
	 (val (keyword-val attr)))
    (case tag
      (:clip-origin `(:clip-x ,(xpoint-x val) :clip-y ,(xpoint-y val)))
      (:dashes `(,tag ,(haskell-list->list/identity val)))
      (:tile-origin `(:ts-x ,(xpoint-x val) :ts-y ,(xpoint-y val)))
      (:size `(:width ,(xsize-w val) :height ,(xsize-h val)))
      (:name `(:name ,(haskell-string->string val)))
      (:hot-spot `(:x-hot ,(xpoint-x val) :y-hot ,(xpoint-y val)))
      (else `(,tag ,val)))))

(define (x-mutable-array-create inits)
  (list->vector inits))

(define (x-mutable-array-lookup a i)
  (vector-ref a i))

(define (x-mutable-array-update a i x)
  (setf (vector-ref a i) x))

(define (x-mutable-array-length a)
  (vector-length a))

(define (get-time-zone)
  (nth-value 8 (lisp:get-decoded-time)))

(define (decode-time time zone)
  (multiple-value-bind (sec min hour date mon year week ds-p)
		       (if zone
			   (lisp:decode-universal-time time zone)
			   (lisp:decode-universal-time time))   
    (make-h-tuple
      (list->haskell-list/identity (list sec min hour date mon year week))
      ds-p)))

(define (encode-time time zone)
  (apply (function lisp:encode-universal-time)
	 (if (null? zone) time (append time (list zone)))))

(define (get-run-time)
  (/ (lisp:coerce (lisp:get-internal-run-time) 'lisp:single-float)
     (lisp:coerce lisp:internal-time-units-per-second 'lisp:single-float)))

(define (get-elapsed-time)
  (/ (lisp:coerce (lisp:get-internal-real-time) 'lisp:single-float)
     (lisp:coerce lisp:internal-time-units-per-second 'lisp:single-float)))

(define (prim.thenio---1 x fn)
  (lambda (state)
    (declare (ignore state))
    (let ((res (funcall x (box 'state))))
      (format '#t "~A~%" res)
      (funcall fn res (box 'state)))))

(define-attribute-setter wm name)
(define-attribute-setter wm icon-name)