CLIM mail archive


CLIM philosophy wrt to X.

Platform: SUN, LISP: Lucid 4.0, CLIM: 1.0 Beta, 
listener: Gnuemacs buffer (CMU Ilisp)

One of the things about X that is different from other window system
is the buffering of commands.  What is the general rule of thumb here?
Does one always set *CLX-FORCE-OUTPUT* to T so that all commands are
immediately rendered on the medium?  Or only in development mode?  Is
it all a question of efficiency (ie., it is faster to perform all
operations and then flush the buffer than to flush after any
operation)?  It would seem that to ensure that it behaves similarly to
other window systems like Dynamic window, it should be T.  What window
substrate be taken to be the "standard"?

It seems to me that there is a dichotomy between operations that work
on the windows itself vs graphical operations, ie., window operations
like expose, raise, bury, etc., vs drawing operations, etc.  One
prolly want operations on windows to happen immediately (eg., if I
execute an EXPOSE-WINDOW command, I expect to see the window exposed
immediately, not in the indefinite future when some operation flushes
the buffer).  Whereas when one is doing many graphical operations,
immediate flushing seems to be a loser, things slows down
significantly.  This is rather important for some user-interface
programs like ACCEPT for eg., especially if one is to pop it up in
it's own window - if *CLX-FORCE-OUTPUT* is not true, the window is not
gonna pop.

What do more experienced CLIM users/designers think?  Here's a simple
program that illustrate the difference rather nicely, plus some
additional questions...

(setq *root* (clim::open-root-window :clx :host ""))

(defmacro mid-point (pt1 pt2)
  `(round (/ (+ ,pt1 ,pt2) 2)))

(defun get-options (w force-p)
  (let ((clim::*clx-force-output* t)
	a b)
    (clim::accepting-values (w :own-window t)
			    (setq a (clim::accept 'integer
                                                   :prompt "Maximum number of iteration" 
                                                   :default 1000))
			    ;; problem here, what is *query-io*?
			    (terpri *query-io*)
			    (setq b (clim::accept '(member t nil)
                                                  :prompt "Immediate Flushing"
                                                  :default force-p)))
    ;; Makes sure the window is still on top ...
    (clim::window-stack-on-top w)
    (values a b)))

(defun chaos (&key (offset 10) (random-shape t) &aux chaos-window)
  (declare (special *root* clim::*clx-force-output*))
  (let ((chaos-window (clim::open-window-stream :parent sims::*root* :width 300 :height 500
						:scroll-bars nil :save-under t
						:stream-background clim::+misty-rose+
						:stream-foreground clim::+black+))
	(old-flush clim::*clx-force-output*)
	max-iteration width height vertices cur-x cur-y line-orig dice)

    (clim::window-expose chaos-window)
    (multiple-value-setq (max-iteration clim::*clx-force-output*)
      (get-options chaos-window clim::*clx-force-output*))

    ;; wished dimensional info was updated if user rubberbanded the size...
    (setf width (- (clim::window-inside-width chaos-window) offset)
	  height (- (clim::window-inside-height chaos-window) offset)
	  ;; two of the vertex are fixed at the bottom, the third one is random
	  vertices (make-array '(3 2) :element-type 'integer :initial-contents
			       `((,offset ,height)
				 (,(if random-shape
				       (+ offset (random (- width offset)))
				       (round (/ width 2)))
				 (,width ,height)))
	  cur-x (+ offset (random (- width offset)))
	  cur-y (+ offset (random (- height offset)))
	  line-orig (ash offset -1))

    (clim::draw-point* chaos-window cur-x cur-y)
    (clim::draw-line* chaos-window line-orig (1- line-orig) width (1- line-orig))
	 (loop do (loop for i from 0 to max-iteration
			with w = (- width line-orig) do
                        (setf dice (random 3))	
			(setf cur-x (ash (+ cur-x (aref vertices dice 0)) -1)
			      cur-y (ash (+ cur-y (aref vertices dice 1)) -1))

			;; Makes it easier to tell where the point is by moving the mouse there
			(when clim::*clx-force-output*
			  (clim::stream-set-pointer-position* chaos-window cur-x cur-y))

			(clim::draw-point* chaos-window cur-x cur-y )
			(when (zerop (mod i 100))
			    (clim::draw-line* chaos-window line-orig line-orig
					      (round (+ line-orig (* (/ i max-iteration) w))) line-orig)
			    (clim::clx-force-output-if-necessary *root* t)))

	       when (zerop (multiple-value-setq (max-iteration clim::*clx-force-output*)
			     (get-options chaos-window clim::*clx-force-output*)))
	       return 'done
	       else do (clim::with-drawing-options (chaos-window :ink clim::+misty-rose+)
			 (clim::draw-line* chaos-window line-orig line-orig width line-orig)
			 (clim::clx-force-output-if-necessary *root* t)
      (setq clim::*clx-force-output* old-flush)
      (clim::close chaos-window))))


Additional questions:
1. Is there a way to automatically make the window popped up by
   ACCEPTING-VALUES be near the mouse (even better have the mouse in
   it) - I believe DW in Genera did it so (:near-mouse?).  Pretty
   important in X as the input focus is by default associated with the
   window the mouse is in.

2. The standard streams, (*terminal-io*, *query-io*, etc.) are not
   CLIM stream, and as such cannot be used as arguments for functions
   like ACCEPTING-VALUES.  How do people handle this?  I've taken to
   using *ROOT* which is my root window, which is really not good
   when an OWN-WINDOW option is used since the standard streams are
   then bound to something else, and TERPRI doesn't do the right

3. Updating of window size.  If one uses the middle button when
   placing the window, one can rubberband the window size and hence
   end up with a window whose size is different from what is
   specified.  How does one force the updating to happen so that
   the new info. is now accessible?

4. I think CLIM::CLOSE is wrong when *CLX-FORCE-OUTPUT* is non-nil,
   it tries to do a CLX-FORCE-OUTPUT-IF-NECESSARY on the stream arg.
   after it destroys it.  Destroy apparently munges up the stream
   arg so that it is no longer a valid instance, which means that
   CLX-FORCE-OUTPUT-IF-NECESSARY will barf.  The right thing to do
   is prolly do a CLX-FORCE-OUTPUT-IF-NECESSARY on it's parent. ie.,

(in-package 'clim)

(defmethod close ((STREAM clx-window) &KEY ABORT &ALLOW-OTHER-KEYS)
  abort					;; not sure what to do with this
  (xlib::destroy-window (clx-stream-window stream))
  (when *clx-force-output*
    (clx-force-output-if-necessary (window-parent stream) t)))


Main Index | Thread Index