anchor.diff:          (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
  +  ;; clear all virtual-frame-changed to nil because of applying redraw
     (maphash (lambda (k vf)
                (declare (ignore k))
  -             (setf (vf-changed vf) nil))
  -           *vf-map*)
  +             (setf (virtual-frame-changed vf) nil))
  +           *virtual-frame-map*)
     (call-next-method))
   
   (defun frame-multiplexer-init ()
  -  (setf *vf-map* (make-hash-table))
  +  (clrhash *virtual-frame-map*)
     (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))))))
  +    :do (let ((vf (make-virtual-frame impl (lem:get-frame impl))))
  +          (setf (gethash impl *virtual-frame-map*) vf)
  +          (setf (gethash (virtual-frame-current vf) (virtual-frame-buffer-list-map vf))
  +                (copy-list (buffer-list)))
  +          (lem:map-frame (implementation) (%frame-frame (virtual-frame-current vf))))))
  +
  +(defun kill-buffer-from-all-frames (buffer)
  +  ;; update buffer-list-map
  +  (let ((vf (gethash (implementation) *virtual-frame-map*)))
  +    (setf (gethash (virtual-frame-current vf) (virtual-frame-buffer-list-map vf))
  +          (copy-list (buffer-list))))
  +  ;; kill buffer from all frames in all virtual frames
  +  (loop
  +    :for display :being :each :hash-key :of *virtual-frame-map*
  +    :using (hash-value vf)
  +    :do (let ((current-frame (virtual-frame-current vf)))
  +          (declare (type %frame current-frame))
  +          (dolist (frame (alexandria:hash-table-keys (virtual-frame-buffer-list-map vf)))
  +            (unwind-protect
  +                 (progn
  +                   ;; temporary switched current frame and buffer-list
  +                   (map-frame display (%frame-frame frame))
  +                   (setf (virtual-frame-current vf) frame)
  +                   (set-to-current-buffer-list vf frame)
  +                   ;; switch buffers that will be deleted
  +                   (dolist (window (get-buffer-windows buffer))
  +                     (with-current-window window
  +                       (switch-to-buffer (or (get-previous-buffer buffer)
  +                                             (car (last (buffer-list)))))))
  +                   ;; delete buffer from the frame
  +                   (lem-base::set-buffer-list (delete buffer (buffer-list))))
  +              ;; restore current frame and buffer-list
  +              (progn
  +                (setf (virtual-frame-current vf) current-frame
  +                      (virtual-frame-changed vf) t)
  +                (set-to-frame-buffer-list vf frame)
  +                (map-frame display (%frame-frame current-frame))))))))
  +
  +(defun enabled-frame-multiplexer-p ()
  +  (variable-value 'frame-multiplexer :global))
  +
  +(defun check-frame-multiplexer-enabled ()
  +  (unless (enabled-frame-multiplexer-p)
  +    (editor-error "fm-mode is not enabled")))
   
   (defun frame-multiplexer-on ()
  -  (unless (variable-value 'frame-multiplexer :global)
  +  (unless (enabled-frame-multiplexer-p)
  +    (add-hook (variable-value 'kill-buffer-hook :global) 'kill-buffer-from-all-frames)
       (frame-multiplexer-init)))
   
   (defun frame-multiplexer-off ()
  -  (when (variable-value 'frame-multiplexer :global)
  +  (when (enabled-frame-multiplexer-p)
  +    (remove-hook (variable-value 'kill-buffer-hook :global) 'kill-buffer-from-all-frames)
       (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))))
  +             *virtual-frame-map*)
  +    (clrhash *virtual-frame-map*)))
   
   (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))
  +(defun create-frame (new-buffer-list-p)
  +  (check-frame-multiplexer-enabled)
  +  (let* ((vf (gethash (implementation) *virtual-frame-map*))
  +         (id (find-unused-frame-id vf)))
  +    (when (null id)
  +      (editor-error "it's full of frames in virtual frame"))
  +    (set-to-frame-buffer-list vf (virtual-frame-current vf))
  +    (let* ((frame (lem:make-frame))
  +           (%frame (%make-frame id frame)))
  +      (lem:setup-frame frame)
  +      ;;create new-window with *tmp* buffer by default
  +      (let* ((tmp-buffer (find "*tmp*" (append (buffer-list) (all-buffer-list))
  +                               :key (lambda (b) (buffer-name b))
  +                               :test #'string=))
  +             (buffer-list (if new-buffer-list-p
  +                              (list tmp-buffer)
  +                              (copy-list (buffer-list)))))
  +        ;; set buffer-list to virtual frame and global buffer-list
  +        (setf (gethash %frame (virtual-frame-buffer-list-map vf)) buffer-list)
  +        (lem-base::set-buffer-list buffer-list)
  +        ;; create window and set to frame
           (when tmp-buffer
  +          (push vf (lem:frame-header-windows frame))
             (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)
  +                  (virtual-frame-current vf) %frame)
  +            ;; expose frame
  +            (allocate-frame vf %frame)
               (lem:map-frame (implementation) frame))))
  -      (setf (vf-changed vf) t))))
  -
  -(define-key *global-keymap* "c-z d" 'fm-delete)
  +      ;; new window should be redraw
  +      (setf (virtual-frame-changed vf) t))))
  +
  +(define-key *global-keymap* "C-z c" 'fm-create-with-new-buffer-list)
  +(define-command fm-create-with-new-buffer-list () ()
  +  (create-frame t))
  +
  +(define-key *global-keymap* "C-z C" 'fm-create)
  +(define-command fm-create () ()
  +  (create-frame nil))
  +
  +(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))))
  +  (check-frame-multiplexer-enabled)
  +  (let* ((vf (gethash (implementation) *virtual-frame-map*))
  +         (num (num-frames vf)))
  +    (when (= num 1)
  +      (editor-error "cannot delete this virtual frame"))
  +    (remhash (virtual-frame-current vf) (virtual-frame-buffer-list-map vf))
  +    (free-frame vf (virtual-frame-current vf))
  +    (let ((%frame (search-previous-frame vf (virtual-frame-current vf))))
  +      (setf (virtual-frame-current vf) %frame)
  +      (lem:map-frame (implementation) (%frame-frame %frame)))
  +    (setf (virtual-frame-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))))
  +  (check-frame-multiplexer-enabled)
  +  (let* ((vf (gethash (implementation) *virtual-frame-map*)))
  +    (let ((%frame (search-previous-frame vf (virtual-frame-current vf))))
  +      (when %frame
  +        (let ((prev-current (virtual-frame-current vf)))
  +          (set-to-frame-buffer-list vf prev-current))
  +        (setf (virtual-frame-current vf) %frame)
  +        (set-to-current-buffer-list vf %frame)
  +        (lem:map-frame (implementation) (%frame-frame %frame))))
  +    (lem::change-display-size-hook)
  +    (setf (virtual-frame-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))))
  +  (check-frame-multiplexer-enabled)
  +  (let* ((vf (gethash (implementation) *virtual-frame-map*)))
  +    (let ((%frame (search-next-frame vf (virtual-frame-current vf))))
  +      (when %frame
  +        (let ((prev-current (virtual-frame-current vf)))
  +          (set-to-frame-buffer-list vf prev-current))
  +        (setf (virtual-frame-current vf) %frame)
  +        (set-to-current-buffer-list vf %frame)
  +        (lem:map-frame (implementation) (%frame-frame %frame))))
  +    (lem::change-display-size-hook)
  +    (setf (virtual-frame-changed vf) t)))
  +
  +(defun completion-buffer-name-from-all-frames (str)
  +  (completion-strings str (mapcar #'buffer-name (all-buffer-list))))
  +
  +(define-key *global-keymap* "C-z b" 'fm-select-buffer-from-all-frames)
  +(define-command fm-select-buffer-from-all-frames (name)
  +    ((list (let ((lem:*minibuffer-buffer-complete-function*
  +                   #'completion-buffer-name-from-all-frames))
  +             (prompt-for-buffer "Use buffer: " (buffer-name (current-buffer))
  +                                t (all-buffer-list)))))
  +  (check-frame-multiplexer-enabled)
  +  (let ((buffer (find name (all-buffer-list) :test #'string= :key #'buffer-name)))
  +    (when (null (find buffer (buffer-list)))
  +      (lem-base::set-buffer-list (cons buffer (buffer-list))))
  +    (select-buffer buffer)))
  +
  +(define-command fm-test () ()
  +  (labels ((vf ()
  +             (maphash (lambda (k v)
  +                        (declare (ignore k))
  +                        (return-from vf v))
  +                      *virtual-frame-map*))
  +           (check-nth-frame (expected-id)
  +             (let ((actual-id (%frame-id (virtual-frame-current (vf)))))
  +               (assert (= expected-id actual-id))))
  +           (check-tabs (&rest nums)
  +             (assert (equal nums (mapcar #'%frame-id (virtual-frame-frames (vf)))))))
  +    (when (enabled-frame-multiplexer-p)
  +      (editor-error "fm-mode is already enabled"))
  +    ;; fm-create-with-new-buffer-list
  +    (fm-mode)
  +    (fm-create-with-new-buffer-list)
  +    (check-nth-frame 1)
  +    (fm-create-with-new-buffer-list)
  +    (check-nth-frame 2)
  +    (fm-create-with-new-buffer-list)
  +    (check-nth-frame 3)
  +    (fm-next)
  +    ;; fm-next, fm-prev
  +    (fm-next)
  +    (check-nth-frame 1)
  +    (fm-prev)
  +    (check-nth-frame 0)
  +    (fm-prev)
  +    (check-nth-frame 3)
  +    (fm-next)
  +    (check-nth-frame 0)
  +    (check-tabs 0 1 2 3)
  +    ;; fm-delete
  +    (fm-delete)
  +    (check-tabs 1 2 3)
  +    (check-nth-frame 3)
  +    (fm-prev)
  +    (check-nth-frame 2)
  +    (fm-delete)
  +    (check-tabs 1 3)
  +    (check-nth-frame 1)
  +    ))
  
positive.code:                          :attribute 'fm-background-attribute)))
        (line-offset p 0 charpos))
      ;; redraw windows in current frame
      (let* ((%frame (vf-current (gethash (lem:implementation) *vf-map*)))
             (frame (%frame-frame %frame)))
        (dolist (w (lem::window-tree-flatten (lem:frame-window-tree frame)))
          (lem:window-redraw w 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"))
  
  