anchor.diff:  (define-attribute fm-background-attribute
     (t :underline-p t))
   
  -(defstruct %frame
  +(define-editor-variable frame-multiplexer nil ""
  +  (lambda (value)
  +    (if value
  +        (frame-multiplexer-on)
  +        (frame-multiplexer-off))))
  +
  +(defstruct (%frame (:constructor %make-frame (id frame)))
     (id 0 :type integer)
     (frame nil :type lem:frame))
   
  -(defun %make-frame (id frame)
  -  (make-%frame :id id :frame frame))
  -
  -(defclass vf (header-window)
  +(defclass virtual-frame (header-window)
     ((implementation
       :initarg :impl
       :initform nil
  -    :accessor vf-impl
  +    :accessor virtual-frame-impl
       :type lem:implementation)
  -   (frames
  -    :initarg :frames
  -    :accessor vf-frames
  +   (id/frame-table
  +    :initarg :id/frame-table
  +    :accessor virtual-frame-id/frame-table
       :type array)
      (current
       :initarg :current
  -    :accessor vf-current
  +    :accessor virtual-frame-current
       :type %frame)
  +   (buffer-list-map
  +    :initarg :buffer-list-map
  +    :accessor virtual-frame-buffer-list-map)
      (display-width
       :initarg :width
  -    :accessor vf-width)
  +    :accessor virtual-frame-width)
      (display-height
       :initarg :height
  -    :accessor vf-height)
  +    :accessor virtual-frame-height)
      (changed
       :initform t
  -    :accessor vf-changed)
  +    :accessor virtual-frame-changed)
      (buffer
       :initarg :buffer
  -    :accessor vf-header-buffer)))
  -
  -(defun make-vf (impl frame)
  +    :accessor virtual-frame-header-buffer)))
  +
  +(defun make-virtual-frame (impl frame)
  +  (declare (type frame frame))
     (let* ((buffer (make-buffer "*fm*" :enable-undo-p nil :temporary t))
            (%frame (%make-frame 0 frame))
  -         (frames (make-array +fm-max-number-of-frames+ :initial-element nil)))
  -    (setf (aref frames 0) %frame)
  +         (id/frame-table (make-array +fm-max-number-of-frames+ :initial-element nil)))
  +    (setf (aref id/frame-table 0) %frame)
       (setf (lem:variable-value 'truncate-lines :buffer buffer) nil)
  -    (let ((vf (make-instance 'vf
  +    (let ((vf (make-instance 'virtual-frame
                                :impl impl
                                :buffer buffer
                                :width (display-width)
                                :height (display-height)
  -                             :frames frames
  -                             :current %frame)))
  +                             :id/frame-table id/frame-table
  +                             :current %frame
  +                             :buffer-list-map (make-hash-table))))
         vf)))
   
  -(defparameter *vf-map* nil)
  -
  -(defun search-previous-frame (vf id)
  -  (let* ((frames (vf-frames vf))
  -         (len (length frames)))
  -    (flet ((wrap (n)
  -             (if (minusp n)
  -                 (+ (1- len) n)
  -                 n)))
  -      (loop
  -        :for n := (wrap (1- id)) :then (wrap (1- n))
  -        :until (= n id)
  -        :do (unless (null (aref frames n))
  -              (return-from search-previous-frame (aref frames n)))))))
  -
  -(defun search-next-frame (vf id)
  -  (let* ((frames (vf-frames vf))
  -         (len (length frames)))
  -    (flet ((wrap (n)
  -             (if (>= n len)
  -                 (- len n)
  -                 n)))
  -      (loop
  -        :for n := (wrap (1+ id)) :then (wrap (1+ n))
  -        :until (= n id)
  -        :do (unless (null (aref frames n))
  -              (return-from search-next-frame (aref frames n)))))))
  -
  -(defun vf-require-update (vf)
  -  (cond ((vf-changed vf) t)
  +(defun all-buffer-list ()
  +  (remove-duplicates
  +   (loop
  +     :for k :being :each :hash-key :of *virtual-frame-map*
  +     :using (hash-value vf)
  +     :append (loop
  +               :for k :being :each :hash-key :of (virtual-frame-buffer-list-map vf)
  +               :using (hash-value buffer-list)
  +               :append buffer-list))))
  +
  +(defun find-unused-frame-id (virtual-frame)
  +  (position-if #'null (virtual-frame-id/frame-table virtual-frame)))
  +
  +(defun num-frames (virtual-frame)
  +  (count-if-not #'null (virtual-frame-id/frame-table virtual-frame)))
  +
  +(defun allocate-frame (virtual-frame frame)
  +  (declare (type %frame frame))
  +  (setf (aref (virtual-frame-id/frame-table virtual-frame) (%frame-id frame))
  +        frame))
  +
  +(defun free-frame (virtual-frame frame)
  +  (declare (type %frame frame))
  +  (setf (aref (virtual-frame-id/frame-table virtual-frame) (%frame-id frame))
  +        nil))
  +
  +(defun get-frame-from-id (virtual-frame id)
  +  (aref (virtual-frame-id/frame-table virtual-frame) id))
  +
  +(defun liner-search-frame (virtual-frame frame dir wrap)
  +  (let ((id (%frame-id frame)))
  +    (loop :for n := (funcall wrap (+ id dir)) :then (funcall wrap (+ n dir))
  +          :until (= n id)
  +          :do (unless (null (get-frame-from-id virtual-frame n))
  +                (return-from liner-search-frame (get-frame-from-id virtual-frame n))))))
  +
  +(defun search-previous-frame (virtual-frame frame)
  +  (declare (type %frame frame))
  +  (let ((len (length (virtual-frame-id/frame-table virtual-frame))))
  +    (liner-search-frame virtual-frame
  +                        frame
  +                        -1
  +                        (lambda (n)
  +                          (if (minusp n)
  +                              (+ (1- len) n)
  +                              n)))))
  +
  +(defun search-next-frame (virtual-frame frame)
  +  (declare (type %frame frame))
  +  (let ((len (length (virtual-frame-id/frame-table virtual-frame))))
  +    (liner-search-frame virtual-frame
  +                        frame
  +                        1
  +                        (lambda (n)
  +                          (if (>= n len)
  +                              (- len n)
  +                              n)))))
  +
  +(defun virtual-frame-frames (virtual-frame)
  +  (coerce (remove-if #'null (virtual-frame-id/frame-table virtual-frame))
  +          'list))
  +
  +(defun require-update-p (virtual-frame)
  +  (cond ((virtual-frame-changed virtual-frame) t)
           ((not (= (display-width)
  -                 (vf-width vf)))
  +                 (virtual-frame-width virtual-frame)))
            t)
           ((not (= (display-height)
  -                 (vf-height vf)))
  +                 (virtual-frame-height virtual-frame)))
            t)))
   
  -(defmethod window-redraw ((window vf) force)
  +(defun set-to-frame-buffer-list (virtual-frame frame)
  +  (let ((buffer-list-map (virtual-frame-buffer-list-map virtual-frame))
  +        (buffer-list (copy-list (buffer-list))))
  +    (setf (gethash frame buffer-list-map) buffer-list)))
  +
  +(defun set-to-current-buffer-list (virtual-frame frame)
  +  (let* ((buffer-list-map (virtual-frame-buffer-list-map virtual-frame))
  +         (buffer-list (gethash frame buffer-list-map)))
  +    (lem-base::set-buffer-list buffer-list)))
  +
  +(defmethod window-redraw ((window virtual-frame) force)
     (when (or force
  -            (loop :for k :being :each :hash-key :of *vf-map*
  +            (loop :for k :being :each :hash-key :of *virtual-frame-map*
                     :using (hash-value vf)
  -                  :thereis (vf-require-update vf)))
  +                  :thereis (require-update-p vf)))
       ;; draw button for frames
  -    (let* ((buffer (vf-header-buffer window))
  +    (let* ((buffer (virtual-frame-header-buffer window))
              (p (buffer-point buffer))
              (charpos (point-charpos p)))
         (erase-buffer buffer)
  -      (loop
  -        :for %frame :across (vf-frames window)
  -        :unless (null %frame)
  -        :do (let* ((focusp (eq %frame (vf-current window)))
  -                   (start-pos (point-charpos p)))
  -              (insert-button p
  -                             ;; virtual frame name on header
  -                             (let* ((frame (%frame-frame %frame))
  -                                    (buffer (window-buffer (lem:frame-current-window frame)))
  -                                    (name (buffer-name buffer)))
  -                               (format nil "~a~a:~a "
  -                                       (if focusp #\# #\space)
  -                                       (%frame-id %frame)
  -                                       (if (>= (length name) +fm-max-width-of-each-frame-name+)
  -                                           (format nil "~a..."
  -                                                   (subseq name 0 +fm-max-width-of-each-frame-name+))
  -                                           name)))
  -                             ;; set action when click
  -                             (let ((%frame %frame))
  -                               (lambda ()
  -                                 (setf (vf-current window) %frame)
  -                                 (setf (vf-changed window) t)))
  -                             :attribute (if focusp
  -                                            'fm-active-frame-name-attribute
  -                                            'fm-frame-name-attribute))
  -              ;; increment charpos
  -              (when focusp
  -                (let ((end-pos (point-charpos p)))
  -                  (unless (<= start-pos charpos (1- end-pos))
  -                    (setf charpos start-pos))))))
  +      (dolist (%frame (virtual-frame-frames window))
  +        (let* ((focusp (eq %frame (virtual-frame-current window)))
  +               (start-pos (point-charpos p)))
  +          (insert-button p
  +                         ;; virtual frame name on header
  +                         (let* ((frame (%frame-frame %frame))
  +                                (buffer (window-buffer (lem:frame-current-window frame)))
  +                                (name (buffer-name buffer)))
  +                           (format nil "~a~a:~a "
  +                                   (if focusp #\# #\space)
  +                                   (%frame-id %frame)
  +                                   (if (>= (length name) +fm-max-width-of-each-frame-name+)
  +                                       (format nil "~a..."
  +                                               (subseq name 0 +fm-max-width-of-each-frame-name+))
  +                                       name)))
  +                         ;; set action when click
  +                         (let ((%frame %frame))
  +                           (lambda ()
  +                             (setf (virtual-frame-current window) %frame)
  +                             (setf (virtual-frame-changed window) t)))
  +                         :attribute (if focusp
  +                                        'fm-active-frame-name-attribute
  +                                        'fm-frame-name-attribute))
  +          ;; increment charpos
  +          (when focusp
  +            (let ((end-pos (point-charpos p)))
  +              (unless (<= start-pos charpos (1- end-pos))
  +                (setf charpos start-pos))))))
         ;; fill right margin
         (let ((margin-right (- (display-width) (point-column p))))
           (when (> margin-right 0)
  
positive.code:         (unless (eq w window)
            (lem:window-redraw w t))))
      (lem-if:update-display (lem:implementation)))
    ;; clear all vf-changed to nil because of applying redraw
    (maphash (lambda (k vf)
               (declare (ignore k))
               (setf (vf-changed vf) nil))
             *vf-map*)
    (call-next-method))
  
  (defun frame-multiplexer-init ()
    (setf *vf-map* (make-hash-table))
    (loop
      :for impl :in (list (implementation))  ; for multi-frame support in the future...
      :do (let ((vf (make-vf impl (lem:get-frame impl))))
            (setf (gethash impl *vf-map*) vf)
            (lem:map-frame (implementation) (%frame-frame (vf-current vf))))))
  
  (defun frame-multiplexer-on ()
    (unless (variable-value 'frame-multiplexer :global)
      (frame-multiplexer-init)))
  
  (defun frame-multiplexer-off ()
    (when (variable-value 'frame-multiplexer :global)
      (maphash (lambda (k v)
                 (declare (ignore k))
                 (delete-window v))
               *vf-map*)
      (setf *vf-map* nil)))
  
  (define-editor-variable frame-multiplexer nil ""
    (lambda (value)
      (if value
          (frame-multiplexer-on)
          (frame-multiplexer-off))))
  
  (define-command fm-mode () ()
    (setf (variable-value 'frame-multiplexer :global)
          (not (variable-value 'frame-multiplexer :global))))
  
  (define-key *global-keymap* "c-z c" 'fm-create)
  (define-command fm-create () ()
    (block exit
      (when (null *vf-map*)
        (editor-error "fm-mode is not enabled")
        (return-from exit))
      (let* ((vf (gethash (implementation) *vf-map*))
             (id (position-if #'null (vf-frames vf))))
        (when (null id)
          (editor-error "it's full of frames in virtual frame")
          (return-from exit))
        (let* ((frame (lem:make-frame))
               (%frame (%make-frame id frame))
               (tmp-buffer (find "*tmp*" lem-base::*buffer-list*
                                 :key (lambda (b) (slot-value b 'lem-base::name))
                                 :test #'string=)))
          (lem:setup-frame frame)
          (push vf (lem:frame-header-windows frame))
          (when tmp-buffer
            (let ((new-window (lem::make-window tmp-buffer
                                                (lem::window-topleft-x) (lem::window-topleft-y)
                                                (lem::window-max-width) (lem::window-max-height)
                                                t)))
              (setf (lem:frame-window-tree frame) new-window
                    (lem:frame-current-window frame) new-window
                    (aref (vf-frames vf) id) %frame
                    (vf-current vf) %frame)
              (lem:map-frame (implementation) frame))))
        (setf (vf-changed vf) t))))
  
  (define-key *global-keymap* "c-z d" 'fm-delete)
  (define-command fm-delete () ()
    (block exit
      (when (null *vf-map*)
        (editor-error "fm-mode is not enabled")
        (return-from exit))
      (let* ((vf (gethash (implementation) *vf-map*))
             (num (count-if-not #'null (vf-frames vf)))
             (id (position (vf-current vf) (vf-frames vf))))
        (when (= num 1)
          (editor-error "cannot delete this virtual frame")
          (return-from exit))
        (when (null id)
          (editor-error "something wrong... fm-mode broken?")
          (return-from exit))
        (setf (aref (vf-frames vf) id) nil)
        (let ((%frame (search-previous-frame vf id)))
          (setf (vf-current vf) %frame)
          (lem:map-frame (implementation) (%frame-frame %frame)))
        (setf (vf-changed vf) t))))
  
  (define-key *global-keymap* "C-z p" 'fm-prev)
  (define-command fm-prev () ()
    (block exit
      (when (null *vf-map*)
        (editor-error "fm-mode is not enabled")
        (return-from exit))
      (let* ((vf (gethash (implementation) *vf-map*))
             (id (position (vf-current vf) (vf-frames vf))))
        (when (null id)
          (editor-error "something wrong... fm-mode broken?")
          (return-from exit))
        (let ((%frame (search-previous-frame vf id)))
          (when %frame
            (setf (vf-current vf) %frame)
            (lem:map-frame (implementation) (%frame-frame %frame))))
        (lem::change-display-size-hook)
        (setf (vf-changed vf) t))))
  
  (define-key *global-keymap* "C-z n" 'fm-next)
  (define-command fm-next () ()
    (block exit
      (when (null *vf-map*)
        (editor-error "fm-mode is not enabled")
        (return-from exit))
      (let* ((vf (gethash (implementation) *vf-map*))
             (id (position (vf-current vf) (vf-frames vf))))
        (when (null id)
          (editor-error "something wrong... fm-mode broken?")
          (return-from exit))
        (let ((%frame (search-next-frame vf id)))
          (when %frame
            (setf (vf-current vf) %frame)
            (lem:map-frame (implementation) (%frame-frame %frame))))
        (lem::change-display-size-hook)
        (setf (vf-changed vf) t))))
  
negative.code: (defconstant +fm-max-number-of-frames+ 256)
  (defconstant +fm-max-width-of-each-frame-name+ 20)
  
  (defvar *virtual-frame-map* (make-hash-table))
  
  (define-attribute fm-active-frame-name-attribute
    (t :foreground "white" :background "blue"))
  
  