emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

undisplay temporary dialog buffers when done [was: ... dedicated windows


From: Drew Adams
Subject: undisplay temporary dialog buffers when done [was: ... dedicated windows and popup frames]
Date: Sun, 10 Jul 2011 16:45:26 -0700

For code that temporarily displays a buffer for the duration of a user-input
dialog, I suggested that we might wrap that code, so that when the dialog is
finished the buffer's display disappears: it is undisplayed as part of unwinding
the dialog.

This pertains to buffer displays such as *Completions* and the Dired
marked-files list (e.g. when you delete, copy, etc. files).  Such buffers are
popped up in a window that might be dedicated, in a separate frame, etc.,
depending on user settings.  We generally want to get rid of the buffer's
display in such cases.

This was the suggestion:

> Perhaps we could add a way for code to indicate that it is 
> displaying a given buffer only for the purpose and duration
> of a user dialog, and thus:
> 
> a. For that duration the buffer's frame (if separate) would 
>    have its input focus redirected to the minibuffer's frame.
> b. After the dialog finishes, the buffer's frame (if 
>    separate) would be deleted.
> 
> E.g., something like: (with-dialog-buffer BUF ...)
> Perhaps something like that could be a way to handle the 
> general case (providing that coders actually used it).

This approach gives the code that carries out the user-input dialog and displays
the supporting information buffer the responsibility and possibility of making
that buffer disappear when the dialog is over.  IOW, it keeps control over such
behavior local to where it is needed.

Here is an example of what I meant by such a macro (not tested much).  Instead
of `with-dialog-buffer' I named it `undisplay-on-unwind'.  It need not be
associated with dialog code, but that is probably the typical case.

(defmacro undisplay-on-unwind (buffer &rest body)
  "Undisplay BUFFER after evaluating BODY.
If BUFFER is not shown in the selected window or
`minibuffer-selected-window', then bury BUFFER (`bury-buffer') and
delete all windows showing it, if possible.
Use this in particular when BODY pops up BUFFER as part of a temporary
dialog and there is no need to show BUFFER after the dialog is
finished."
  (let ((buf  (make-symbol "buf")))
    `(unwind-protect
          (progn ,@body)
       (let ((,buf  ,buffer))
         (when (bufferp ,buf) (setq ,buf  (buffer-name ,buf)))
         (when (stringp ,buf)
           (let ((swin  (selected-window)))
             ;; Do nothing if BUFFER is in the selected window
             ;; or the minibuffer window is selected now
             ;;    and BUFFER's window was selected just before.
             (when (window-minibuffer-p swin)
               (setq swin  (minibuffer-selected-window)))
             (when (and (get-buffer-window ,buf 'visible)
                        (window-live-p swin) ; Needed?
                        (not (eq (window-buffer swin)
                                 (get-buffer ,buf))))
               ;; Ignore, in particular, "Attempt to delete
               ;; the sole visible or iconified frame".
               (ignore-errors (delete-windows-on ,buf))
               (bury-buffer (get-buffer ,buf)))))))))

This is adapted from part of how I treat `*Completions*' in Icicles.  The point
here is to give an idea of what such a macro might be - I don't argue that this
particular implementation is necessarily correct, complete, what we want, etc.

The idea is to couple (a) the display of a buffer whose only purpose is to
provide info for some input dialog with (b) that dialog.  The BODY for the macro
would typically be code that displays BUFFER and asks for some user input.
After that dialog is finished, we remove all display of BUFFER.

You can try it a bit.  E.g.:

(defun bar (f1 &optional f2)
  (let ((foo  (get-buffer-create "*FOO*")))
    (with-current-buffer foo
      (erase-buffer)(insert "HHHHHHHHHHHHHHHHHHHHHHHHHHHH"))
    (funcall f1 foo)
    (when f2
      (save-selected-window
        (select-window (get-buffer-window "*FOO*" 'visible))
        (funcall f2 foo))))
  (redisplay t)(sleep-for 3))

;; 1. Show *FOO* in a separate window (by default).
(undisplay-on-unwind "*FOO*" (bar 'display-buffer))

;; 2. Like previous, but with *FOO* in a separate frame.
(undisplay-on-unwind "*FOO*" (bar 'display-buffer-other-frame))

Those two represent the typical case, but we can imagine that `*FOO*' might be
displayed in more than one window.

;; 3. Like previous, but two *FOO*s, one in a separate frame.
(undisplay-on-unwind "*FOO*" (bar 'display-buffer
                                  'display-buffer-other-frame))

;; 4. Like previous, but won't delete the frame
;;    from `make-frame-command'.
(undisplay-on-unwind "*FOO*" (bar 'display-buffer
                                  '(lambda (f)
                                    (make-frame-command))))




reply via email to

[Prev in Thread] Current Thread [Next in Thread]