CLIM mail archive


Caching CLIM generated menus?

   Date: Wed, 1 Jun 94 17:51:10 CDT

   > The Sparc 10 I have generates such menus with 15 to 20 items in about
   > 1 second.  How big are your menus?
   Our longest menus are 15 items long. After mouse-right selection, they
   take 2-3 seconds to appear the first time. If all I do is a lot of
   right selection, the lapse time seems to go down to 1 second. Even
   1 second for these feels slow in this case.

   In some cases the menu gets redisplayed twice (redrawn) adding another
   1/2 second before the user will feel like selecting something that's not
   a moving target, and this happens once out of every 3-5 selections.
   Nothing ever changes in the menu except for the name of the presentation
   object. I could live with a mode where when a command is added the
   menu needs be recomputed.
   > The presentation menus can't really be saved, because there are many
   > things that dynamically change that can affect the contents of the
   > menu.
   > You could always define a new mouse-right translator for your own
   > type(s) that simply exposes a previously-generated menu.  Then you
   > have to worry yourself about fixing up the menu if it becomes "stale".
   > (The staleness problem is exactly why CLIM doesn't do this.)
   I'd like to try this:
   could you elaborate on this briefly, how would I grab the first
   menu, I can figure out how to reuse it after that I think. But I have no clue
   how the CLIM menu gets generated at first. Or are you saying I should walk
   down the applicable commands myself and generate something appropriate
   for my application? I'll start with that.

Check this out.  There's a sample usage at the end of the file.  It
appears to be 2 or 3 times faster than the general case.  It could be
made somewhat faster by caching the translators, too, but then it
would be even more static.

;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Package: CLIM-INTERNALS; Base: 10; Lowercase: Yes -*-

(in-package :clim-internals)

;; This is like CALL-PRESENTATION-MENU, except that it caches the menu
;; it computes and then reuses it later.  The fact that we are caching
;; stuff means that we have to use a much simpler model than the normal
;; presentation-menu translator.  In particular, we can't assume that
;; we're doing any of the presentation-with-shared-box stuff, and we
;; can't even search up input contexts.  Too bad, at least it's fast.
(defun call-cached-presentation-menu (presentation the-context frame window x y
				      &key (for-menu t) label)
  (let* ((context-type (input-context-type the-context))
         (tag (input-context-tag the-context))
         ;;--- Should we cache the result of this?
         ;;--- If so, the cache value for MENU-CHOOSE should be constant
         (translators (find-translators-for-context-type
                        presentation context-type frame window x y
			:for-menu for-menu)))
    (when translators
      (flet ((translator-documentation (translator stream)
               (document-presentation-translator translator presentation context-type
						 frame nil window x y
						 :stream stream
						 :documentation-type :pointer)))
	(declare (dynamic-extent #'translator-documentation))
	(let ((translator (menu-choose translators
				       :associated-window window
				       :label label
				       :printer #'translator-documentation
				       :cache t
				       :unique-id (list (presentation-type presentation)
						        (evacuate-list context-type))
				       :id-test #'equal
				       :cache-value translators
                                       :cache-test #'equal)))
	  (when translator
	    (multiple-value-bind (translated-object translated-type options)
		(call-presentation-translator translator presentation context-type
					      frame nil window x y)
	      (throw tag (values translated-object
				 (or translated-type context-type)

(defun find-translators-for-context-type (presentation context-type frame window x y
				          &key modifier-state (for-menu nil for-menu-p))
  (let* ((applicable-translators nil)
         (from-type (presentation-type presentation))
         (translators (find-presentation-translators
		        from-type context-type (frame-command-table frame))))
    (when translators
      (dolist (translator translators)
	(when (and (or (not for-menu-p)
		       (eq (presentation-translator-menu translator) for-menu))
		   (test-presentation-translator translator
						 presentation context-type
						 frame window x y
                                                 :event nil
						 :modifier-state modifier-state
						 :for-menu for-menu))
	  (push translator applicable-translators))))
    (nreverse (delete-duplicates applicable-translators))))

(define-presentation-action pathname-presentation-menu
    (pathname command clim-env::lisp-listener
     :documentation "Pathname menu"
     :menu nil				;this doesn't go into any menu
     :gesture :menu
     :priority 1)
    (object presentation frame window x y context-type)
  (let ((the-context (assoc context-type *input-context*)))
    (call-cached-presentation-menu presentation the-context
			           frame window x y
                                   :label (file-namestring object))))
#+ignore (remove-presentation-translator 'pathname-presentation-menu)


Main Index | Thread Index