;;; -*- Mode: LISP; Syntax: Common-lisp; Package: XLIB; Base: 10; Lowercase: Yes -*- ;;; Window Attributes ;;; ;;; 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. ;;; ;;; The special variable *window-attributes* is an alist containg: ;;; (drawable attributes attribute-changes geometry geometry-changes) ;;; Where DRAWABLE is the associated window or pixmap ;;; ATTRIBUTES is NIL or a reply-buffer containing the drawable's ;;; attributes for use by the accessors. ;;; ATTRIBUTE-CHANGES is NIL or an array. The first element ;;; of the array is a "value-mask", indicating which ;;; attributes have changed. The other elements are ;;; integers associated with the changed values, ready ;;; for insertion into a server request. ;;; GEOMETRY is like ATTRIBUTES, but for window geometry ;;; GEOMETRY-CHANGES is like ATTRIBUTE-CHANGES, but for window geometry ;;; ;;; Attribute and Geometry accessors and SETF's look on the special variable ;;; *window-attributes* for the drawable. If its not there, the accessor is ;;; NOT within a WITH-STATE, and a server request is made to get or put a value. ;;; If an entry is found in *window-attributes*, the cache buffers are used ;;; for the access. ;;; ;;; All WITH-STATE has to do (re)bind *Window-attributes* to a list including ;;; the new drawable. The caches are initialized to NIL and allocated as needed. (in-package :xlib) (eval-when (compile load eval) ;needed by Franz Lisp (defconstant *attribute-size* 44) (defconstant *geometry-size* 24) (defconstant *context-size* (max *attribute-size* *geometry-size* (* 16 4)))) (defvar *window-attributes* nil) ;; Bound to an alist of (drawable . state) within WITH-STATE ;; Window Attribute reply buffer resource (defvar *context-free-list* nil) ;; resource of free reply buffers (defun allocate-context () (or (threaded-atomic-pop *context-free-list* reply-next reply-buffer) (make-reply-buffer *context-size*))) (defun deallocate-context (context) (declare (type reply-buffer context)) (threaded-atomic-push context *context-free-list* reply-next reply-buffer)) (defmacro state-attributes (state) `(second ,state)) (defmacro state-attribute-changes (state) `(third ,state)) (defmacro state-geometry (state) `(fourth ,state)) (defmacro state-geometry-changes (state) `(fifth ,state)) (defmacro drawable-equal-function () (if (member 'drawable *clx-cached-types*) ''eq ;; Allows the compiler to use the microcoded ASSQ primitive on LISPM's ''drawable-equal)) (defmacro window-equal-function () (if (member 'window *clx-cached-types*) ''eq ''drawable-equal)) (defmacro with-state ((drawable) &body body) ;; Allows a consistent view to be obtained of data returned by GetWindowAttributes ;; and GetGeometry, and allows a coherent update using ChangeWindowAttributes and ;; ConfigureWindow. The body is not surrounded by a with-display. Within the ;; indefinite scope of the body, on a per-process basis in a multi-process ;; environment, the first call within an Accessor Group on the specified drawable ;; (the object, not just the variable) causes the complete results of the protocol ;; request to be retained, and returned in any subsequent accessor calls. Calls ;; within a Setf Group are delayed, and executed in a single request on exit from ;; the body. In addition, if a call on a function within an Accessor Group follows ;; a call on a function in the corresponding Setf Group, then all delayed setfs for ;; that group are executed, any retained accessor information for that group is ;; discarded, the corresponding protocol request is (re)issued, and the results are ;; (again) retained, and returned in any subsequent accessor calls. ;; Accessor Group A (for GetWindowAttributes): ;; window-visual, window-visual-info, window-class, window-gravity, window-bit-gravity, ;; window-backing-store, window-backing-planes, window-backing-pixel, ;; window-save-under, window-colormap, window-colormap-installed-p, ;; window-map-state, window-all-event-masks, window-event-mask, ;; window-do-not-propagate-mask, window-override-redirect ;; Setf Group A (for ChangeWindowAttributes): ;; window-gravity, window-bit-gravity, window-backing-store, window-backing-planes, ;; window-backing-pixel, window-save-under, window-event-mask, ;; window-do-not-propagate-mask, window-override-redirect, window-colormap, ;; window-cursor ;; Accessor Group G (for GetGeometry): ;; drawable-root, drawable-depth, drawable-x, drawable-y, drawable-width, ;; drawable-height, drawable-border-width ;; Setf Group G (for ConfigureWindow): ;; drawable-x, drawable-y, drawable-width, drawable-height, drawable-border-width, ;; window-priority (let ((state-entry (gensym))) ;; alist of (drawable attributes attribute-changes geometry geometry-changes) `(with-stack-list (,state-entry ,drawable nil nil nil nil) (with-stack-list* (*window-attributes* ,state-entry *window-attributes*) (multiple-value-prog1 (progn ,@body) (cleanup-state-entry ,state-entry)))))) (defun cleanup-state-entry (state) ;; Return buffers to the free-list (let ((entry (state-attributes state))) (when entry (deallocate-context entry))) (let ((entry (state-attribute-changes state))) (when entry (put-window-attribute-changes (car state) entry) (deallocate-gcontext-state entry))) (let ((entry (state-geometry state))) (when entry (deallocate-context entry))) (let ((entry (state-geometry-changes state))) (when entry (put-drawable-geometry-changes (car state) entry) (deallocate-gcontext-state entry)))) (defun change-window-attribute (window number value) ;; Called from window attribute SETF's to alter an attribute value ;; number is the change-attributes request mask bit number (declare (type window window) (type card8 number) (type card32 value)) (let ((state-entry nil) (changes nil)) (if (and *window-attributes* (setq state-entry (assoc window (the list *window-attributes*) :test (window-equal-function)))) (progn ; Within a WITH-STATE - cache changes (setq changes (state-attribute-changes state-entry)) (unless changes (setq changes (allocate-gcontext-state)) (setf (state-attribute-changes state-entry) changes) (setf (aref changes 0) 0)) ;; Initialize mask to zero (setf (aref changes 0) (logior (aref changes 0) (ash 1 number))) ;; set mask bit (setf (aref changes (1+ number)) value)) ;; save value ; Send change to the server (with-buffer-request ((window-display window) *x-changewindowattributes*) (window window) (card32 (ash 1 number) value))))) ;; ;; These two are twins (change-window-attribute change-drawable-geometry) ;; If you change one, you probably need to change the other... ;; (defun change-drawable-geometry (drawable number value) ;; Called from drawable geometry SETF's to alter an attribute value ;; number is the change-attributes request mask bit number (declare (type drawable drawable) (type card8 number) (type card29 value)) (let ((state-entry nil) (changes nil)) (if (and *window-attributes* (setq state-entry (assoc drawable (the list *window-attributes*) :test (drawable-equal-function)))) (progn ; Within a WITH-STATE - cache changes (setq changes (state-geometry-changes state-entry)) (unless changes (setq changes (allocate-gcontext-state)) (setf (state-geometry-changes state-entry) changes) (setf (aref changes 0) 0)) ;; Initialize mask to zero (setf (aref changes 0) (logior (aref changes 0) (ash 1 number))) ;; set mask bit (setf (aref changes (1+ number)) value)) ;; save value ; Send change to the server (with-buffer-request ((drawable-display drawable) *x-configurewindow*) (drawable drawable) (card16 (ash 1 number)) (card29 value))))) (defun get-window-attributes-buffer (window) (declare (type window window)) (let ((state-entry nil) (changes nil)) (or (and *window-attributes* (setq state-entry (assoc window (the list *window-attributes*) :test (window-equal-function))) (null (setq changes (state-attribute-changes state-entry))) (state-attributes state-entry)) (let ((display (window-display window))) (with-display (display) ;; When SETF's have been done, flush changes to the server (when changes (put-window-attribute-changes window changes) (deallocate-gcontext-state (state-attribute-changes state-entry)) (setf (state-attribute-changes state-entry) nil)) ;; Get window attributes (with-buffer-request-and-reply (display *x-getwindowattributes* size :sizes (8)) ((window window)) (let ((repbuf (or (state-attributes state-entry) (allocate-context)))) (declare (type reply-buffer repbuf)) ;; Copy into repbuf from reply buffer (buffer-replace (reply-ibuf8 repbuf) buffer-bbuf 0 size) (when state-entry (setf (state-attributes state-entry) repbuf)) repbuf))))))) ;; ;; These two are twins (get-window-attributes-buffer get-drawable-geometry-buffer) ;; If you change one, you probably need to change the other... ;; (defun get-drawable-geometry-buffer (drawable) (declare (type drawable drawable)) (let ((state-entry nil) (changes nil)) (or (and *window-attributes* (setq state-entry (assoc drawable (the list *window-attributes*) :test (drawable-equal-function))) (null (setq changes (state-geometry-changes state-entry))) (state-geometry state-entry)) (let ((display (drawable-display drawable))) (with-display (display) ;; When SETF's have been done, flush changes to the server (when changes (put-drawable-geometry-changes drawable changes) (deallocate-gcontext-state (state-geometry-changes state-entry)) (setf (state-geometry-changes state-entry) nil)) ;; Get drawable attributes (with-buffer-request-and-reply (display *x-getgeometry* size :sizes (8)) ((drawable drawable)) (let ((repbuf (or (state-geometry state-entry) (allocate-context)))) (declare (type reply-buffer repbuf)) ;; Copy into repbuf from reply buffer (buffer-replace (reply-ibuf8 repbuf) buffer-bbuf 0 size) (when state-entry (setf (state-geometry state-entry) repbuf)) repbuf))))))) (defun put-window-attribute-changes (window changes) ;; change window attributes ;; Always from Called within a WITH-DISPLAY (declare (type window window) (type gcontext-state changes)) (let* ((display (window-display window)) (mask (aref changes 0))) (declare (type display display) (type mask32 mask)) (with-buffer-request (display *x-changewindowattributes*) (window window) (card32 mask) (progn ;; Insert a word in the request for each one bit in the mask (do ((bits mask (ash bits -1)) (request-size 2) ;Word count (i 1 (index+ i 1))) ;Entry count ((zerop bits) (card16-put 2 (index-incf request-size)) (index-incf (buffer-boffset display) (index* request-size 4))) (declare (type mask32 bits) (type array-index i request-size)) (when (oddp bits) (card32-put (index* (index-incf request-size) 4) (aref changes i)))))))) ;; ;; These two are twins (put-window-attribute-changes put-drawable-geometry-changes) ;; If you change one, you probably need to change the other... ;; (defun put-drawable-geometry-changes (window changes) ;; change window attributes or geometry (depending on request-number...) ;; Always from Called within a WITH-DISPLAY (declare (type window window) (type gcontext-state changes)) (let* ((display (window-display window)) (mask (aref changes 0))) (declare (type display display) (type mask16 mask)) (with-buffer-request (display *x-configurewindow*) (window window) (card16 mask) (progn ;; Insert a word in the request for each one bit in the mask (do ((bits mask (ash bits -1)) (request-size 2) ;Word count (i 1 (index+ i 1))) ;Entry count ((zerop bits) (card16-put 2 (incf request-size)) (index-incf (buffer-boffset display) (* request-size 4))) (declare (type mask16 bits) (type fixnum request-size) (type array-index i)) (when (oddp bits) (card29-put (* (incf request-size) 4) (aref changes i)))))))) (defmacro with-attributes ((window &rest options) &body body) `(let ((.with-attributes-reply-buffer. (get-window-attributes-buffer ,window))) (declare (type reply-buffer .with-attributes-reply-buffer.)) (prog1 (with-buffer-input (.with-attributes-reply-buffer. ,@options) ,@body) (unless *window-attributes* (deallocate-context .with-attributes-reply-buffer.))))) ;; ;; These two are twins (with-attributes with-geometry) ;; If you change one, you probably need to change the other... ;; (defmacro with-geometry ((window &rest options) &body body) `(let ((.with-geometry-reply-buffer. (get-drawable-geometry-buffer ,window))) (declare (type reply-buffer .with-geometry-reply-buffer.)) (prog1 (with-buffer-input (.with-geometry-reply-buffer. ,@options) ,@body) (unless *window-attributes* (deallocate-context .with-geometry-reply-buffer.))))) ;;;----------------------------------------------------------------------------- ;;; Group A: (for GetWindowAttributes) ;;;----------------------------------------------------------------------------- (defun window-visual (window) (declare (type window window)) (declare (values resource-id)) (with-attributes (window :sizes 32) (resource-id-get 8))) (defun window-visual-info (window) (declare (type window window)) (declare (values visual-info)) (with-attributes (window :sizes 32) (visual-info (window-display window) (resource-id-get 8)))) (defun window-class (window) (declare (type window window)) (declare (values (member :input-output :input-only))) (with-attributes (window :sizes 16) (member16-get 12 :copy :input-output :input-only))) (defun set-window-background (window background) (declare (type window window) (type (or (member :none :parent-relative) pixel pixmap) background)) (cond ((eq background :none) (change-window-attribute window 0 0)) ((eq background :parent-relative) (change-window-attribute window 0 1)) ((integerp background) ;; Background pixel (change-window-attribute window 0 0) ;; pixmap :NONE (change-window-attribute window 1 background)) ((type? background 'pixmap) ;; Background pixmap (change-window-attribute window 0 (pixmap-id background))) (t (x-type-error background '(or (member :none :parent-relative) integer pixmap)))) background) #+Genera (eval-when (compile) (compiler:function-defined 'window-background)) (defsetf window-background set-window-background) (defun set-window-border (window border) (declare (type window window) (type (or (member :copy) pixel pixmap) border)) (cond ((eq border :copy) (change-window-attribute window 2 0)) ((type? border 'pixmap) ;; Border pixmap (change-window-attribute window 2 (pixmap-id border))) ((integerp border) ;; Border pixel (change-window-attribute window 3 border)) (t (x-type-error border '(or (member :copy) integer pixmap)))) border) #+Genera (eval-when (compile) (compiler:function-defined 'window-border)) (defsetf window-border set-window-border) (defun window-bit-gravity (window) ;; setf'able (declare (type window window)) (declare (values bit-gravity)) (with-attributes (window :sizes 8) (member8-vector-get 14 *bit-gravity-vector*))) (defun set-window-bit-gravity (window gravity) (change-window-attribute window 4 (encode-type (member-vector *bit-gravity-vector*) gravity)) gravity) (defsetf window-bit-gravity set-window-bit-gravity) (defun window-gravity (window) ;; setf'able (declare (type window window)) (declare (values win-gravity)) (with-attributes (window :sizes 8) (member8-vector-get 15 *win-gravity-vector*))) (defun set-window-gravity (window gravity) (change-window-attribute window 5 (encode-type (member-vector *win-gravity-vector*) gravity)) gravity) (defsetf window-gravity set-window-gravity) (defun window-backing-store (window) ;; setf'able (declare (type window window)) (declare (values (member :not-useful :when-mapped :always))) (with-attributes (window :sizes 8) (member8-get 1 :not-useful :when-mapped :always))) (defun set-window-backing-store (window when) (change-window-attribute window 6 (encode-type (member :not-useful :when-mapped :always) when)) when) (defsetf window-backing-store set-window-backing-store) (defun window-backing-planes (window) ;; setf'able (declare (type window window)) (declare (values pixel)) (with-attributes (window :sizes 32) (card32-get 16))) (defun set-window-backing-planes (window planes) (change-window-attribute window 7 (encode-type card32 planes)) planes) (defsetf window-backing-planes set-window-backing-planes) (defun window-backing-pixel (window) ;; setf'able (declare (type window window)) (declare (values pixel)) (with-attributes (window :sizes 32) (card32-get 20))) (defun set-window-backing-pixel (window pixel) (change-window-attribute window 8 (encode-type card32 pixel)) pixel) (defsetf window-backing-pixel set-window-backing-pixel) (defun window-save-under (window) ;; setf'able (declare (type window window)) (declare (values (member :off :on))) (with-attributes (window :sizes 8) (member8-get 24 :off :on))) (defun set-window-save-under (window when) (change-window-attribute window 10 (encode-type (member :off :on) when)) when) (defsetf window-save-under set-window-save-under) (defun window-override-redirect (window) ;; setf'able (declare (type window window)) (declare (values (member :off :on))) (with-attributes (window :sizes 8) (member8-get 27 :off :on))) (defun set-window-override-redirect (window when) (change-window-attribute window 9 (encode-type (member :off :on) when)) when) (defsetf window-override-redirect set-window-override-redirect) (defun window-event-mask (window) ;; setf'able (declare (type window window)) (declare (values mask32)) (with-attributes (window :sizes 32) (card32-get 36))) (defsetf window-event-mask (window) (event-mask) (let ((em (gensym))) `(let ((,em ,event-mask)) (declare (type event-mask ,em)) (change-window-attribute ,window 11 (encode-event-mask ,em)) ,em))) (defun window-do-not-propagate-mask (window) ;; setf'able (declare (type window window)) (declare (values mask32)) (with-attributes (window :sizes 32) (card32-get 40))) (defsetf window-do-not-propagate-mask (window) (device-event-mask) (let ((em (gensym))) `(let ((,em ,device-event-mask)) (declare (type device-event-mask ,em)) (change-window-attribute ,window 12 (encode-device-event-mask ,em)) ,em))) (defun window-colormap (window) (declare (type window window)) (declare (values (or null colormap))) (with-attributes (window :sizes 32) (let ((id (resource-id-get 28))) (if (zerop id) nil (lookup-colormap (window-display window) id))))) (defun set-window-colormap (window colormap) (change-window-attribute window 13 (encode-type (or (member :copy) colormap) colormap)) colormap) (defsetf window-colormap set-window-colormap) (defun window-cursor (window) (declare (type window window)) (declare (values cursor)) window (error "~S can only be set" 'window-cursor)) (defun set-window-cursor (window cursor) (change-window-attribute window 14 (encode-type (or (member :none) cursor) cursor)) cursor) (defsetf window-cursor set-window-cursor) (defun window-colormap-installed-p (window) (declare (type window window)) (declare (values boolean)) (with-attributes (window :sizes 8) (boolean-get 25))) (defun window-all-event-masks (window) (declare (type window window)) (declare (values mask32)) (with-attributes (window :sizes 32) (card32-get 32))) (defun window-map-state (window) (declare (type window window)) (declare (values (member :unmapped :unviewable :viewable))) (with-attributes (window :sizes 8) (member8-get 26 :unmapped :unviewable :viewable))) ;;;----------------------------------------------------------------------------- ;;; Group G: (for GetGeometry) ;;;----------------------------------------------------------------------------- (defun drawable-root (drawable) (declare (type drawable drawable)) (declare (values window)) (with-geometry (drawable :sizes 32) (window-get 8 (drawable-display drawable)))) (defun drawable-x (drawable) ;; setf'able (declare (type drawable drawable)) (declare (values int16)) (with-geometry (drawable :sizes 16) (int16-get 12))) (defun set-drawable-x (drawable x) (change-drawable-geometry drawable 0 (encode-type int16 x)) x) (defsetf drawable-x set-drawable-x) (defun drawable-y (drawable) ;; setf'able (declare (type drawable drawable)) (declare (values int16)) (with-geometry (drawable :sizes 16) (int16-get 14))) (defun set-drawable-y (drawable y) (change-drawable-geometry drawable 1 (encode-type int16 y)) y) (defsetf drawable-y set-drawable-y) (defun drawable-width (drawable) ;; setf'able ;; Inside width, excluding border. (declare (type drawable drawable)) (declare (values card16)) (with-geometry (drawable :sizes 16) (card16-get 16))) (defun set-drawable-width (drawable width) (change-drawable-geometry drawable 2 (encode-type card16 width)) width) (defsetf drawable-width set-drawable-width) (defun drawable-height (drawable) ;; setf'able ;; Inside height, excluding border. (declare (type drawable drawable)) (declare (values card16)) (with-geometry (drawable :sizes 16) (card16-get 18))) (defun set-drawable-height (drawable height) (change-drawable-geometry drawable 3 (encode-type card16 height)) height) (defsetf drawable-height set-drawable-height) (defun drawable-depth (drawable) (declare (type drawable drawable)) (declare (values card8)) (with-geometry (drawable :sizes 8) (card8-get 1))) (defun drawable-border-width (drawable) ;; setf'able (declare (type drawable drawable)) (declare (values integer)) (with-geometry (drawable :sizes 16) (card16-get 20))) (defun set-drawable-border-width (drawable width) (change-drawable-geometry drawable 4 (encode-type card16 width)) width) (defsetf drawable-border-width set-drawable-border-width) (defun set-window-priority (mode window sibling) (declare (type (member :above :below :top-if :bottom-if :opposite) mode) (type window window) (type (or null window) sibling)) (with-state (window) (change-drawable-geometry window 6 (encode-type (member :above :below :top-if :bottom-if :opposite) mode)) (when sibling (change-drawable-geometry window 5 (encode-type window sibling)))) mode) #+Genera (eval-when (compile) (compiler:function-defined 'window-priority)) (defsetf window-priority (window &optional sibling) (mode) ;; A bit strange, but retains setf form. `(set-window-priority ,mode ,window ,sibling))