Subject: bug#11939: 24.1; `save-buffers-kill-emacs' loses minibuffer focus when it calls `list-processes'

From: "Drew Adams" <[email-masked]>
Date: Sat, 14 Jul 2012 07:51:58 -0700

Thanks for looking at this, Martin.

> What is your value of `minibuffer-auto-raise'?

It is `t'.

> Maybe `yes-or-no-p'
> should do `select-frame-set-input-focus' in your case.  What happens
> usually when you ask a `yes-or-no-p' question in a 
> non-minibuffer frame?

No problem.  The typed answer (yes/no) is inserted in the minibuffer, as
expected.  E.g., I type this in a buffer/frame foo.el, and then use C-x C-e to
evaluate it:

(yes-or-no-p "Really? ")

I type "yes" and it appears in the minibuffer frame.  All is fine.

In the problematic contexts, a new frame is popped up and given the focus (by MS
Windows).  That is apparently somehow different from starting from a frame that
already has the focus.

If I had to guess blindly, I'd guess that it has to do with the
timing/sequencing of things: Maybe in the problematic case the question is FIRST
posed in the minibuffer/echo area (giving the minibuffer frame focus) and THEN
the new frame is popped up and it gets the focus.

Whereas maybe in the case I just tested the focus never comes back to the frame
that originally had it - once the focus goes to the minibuffer frame, there is
nothing that puts it back in the original frame.  Just a hunch.

If that is the case, maybe a fix (ugly hack) would be to do this: Whenever the
minibuffer frame has focus and some other frame is created, immediately return
focus to the minibuffer frame.  (Dunno _how_ that might be done.)

>  > Please do something to fix this.
> 
> I'm afraid, most people here can't reproduce your problem.  
> We probably have to invent some new option to handle it.
> In any case, we'd have to investigate the underlying problem.

Or perhaps look to what Dired does...

>  > For inspiration, perhaps look to `dired-mark-pop-up' which
>  > does something similar but gets it right.  See perhaps
>  > `dired-pop-to-buffer'.
>  >
>  > Better would be to fix this ask-for-input-after-popping-up-some-info
>  > problem generally, obviously.  But a fix for just this particular
>  > query will be better than nothing.
>  >
>  > At least Dired DTRT now wrt focus - that's already something.
>  >
>  > Of course, for Dired I still have to modify `dired-mark-pop-up'
>  > anyway, to have it delete the window or frame popped up, afterward,
>  > and bury its buffer.  See bug #7533 - a patch was provided for
>  > this but AFAIK Emacs Dev has never applied it.
> 
> Try to load the attached file and tell me which problems you see.

OK, thanks for trying seriously to solve this.  I know that you look into things
carefully.

1. FYI - I can test only with 24.1, not something later, since other bugs still
prevent my using the later Windows builds.  I'm still waiting for a build more
recent than 2012-07-02.  Dunno whether this matters here.

2. I tried to quit Emacs (C-x C-c) after creating a shell buffer (which is in a
dedicated window in a separate frame).

The informative buffer that lists the active processes was popped up correctly
in a separate frame as the yes-or-no question was asked.  But when I tried to
type yes or no, that typed input appeared nowhere.

I would guess, from the fact that Windows gives the new frame the input focus,
that that new frame had the focus and the input was trying to go there.  But
that buffer is created read-only and I saw no error message indicating that
Emacs was trying to insert the input (yes/no) into a read-only buffer.  No
feedback at all - it's as if my typed input was silently sent to /dev/null.
(That in itself is not good.)

In any case, what's important is that the typed input did not go to the
minibuffer frame.

C-g did not then exit the question, but C-] did.  But then, instead of the
process-list informative buffer and frame simply disappearing, that buffer was
replaced in its frame (which should have been temporary) by the buffer that was
current when I hit C-x C-c.

3. I marked 3 files in Dired and hit `C'.  When I tried to type the destination
directory I got an error saying that buffer *Marked Files* is read-only.  IOW,
the typed input was sent to that information buffer (in its popped up frame) and
not to the minibuffer frame.

Worse: just as above for the active processes popup, after canceling the copy
operation the *Marked Files* frame did not disappear.  Instead, the *Marked
Files* buffer was replaced in its frame by the Dired buffer.  So now I had two
frames with the Dired buffer, one of which was a special-display frame (which
has different frame parameters, e.g. colors).

I thought that the focus problem was already fixed for this in vanilla Emacs,
and that the patch I sent was needed only to take care of removing the frame and
burying the buffer.  But with the code you sent both problems are there.

In any case, if I then use the definition of `dired-mark-pop-up' that I provided
then the problems (both focus and removal) go away.  IOW, even after loading the
code you sent, all I need to do is evaluate this and the Dired dialog works
perfectly again:

;; REPLACE ORIGINAL in `dired.el':
;;
;; Delete the window or frame popped up, afterward, and bury its buffer.
;; Fixes Emacs bug #7533.
;;
(defun dired-mark-pop-up (bufname op-symbol files function &rest args)
  "Return FUNCTION's result on ARGS after showing which files are marked.
Displays the file names in a buffer named BUFNAME;
 nil gives \" *Marked Files*\".
This uses function `dired-pop-to-buffer' to do that.

FUNCTION should not manipulate files, just read input
 (an argument or confirmation).
The window is not shown if there is just one file or
 OP-SYMBOL is a member of the list in `dired-no-confirm'.
FILES is the list of marked files.  It can also be (t FILENAME)
in the case of one marked file, to distinguish that from using
just the current file."
  (or bufname (setq bufname  " *Marked Files*"))
  (let (result)
    (if (or (eq dired-no-confirm t)
            (memq op-symbol dired-no-confirm)
            ;; If FILES defaulted to the current line's file.
            (= (length files) 1))
        (setq result  (apply function args))
      (with-current-buffer (get-buffer-create bufname)
        (erase-buffer)
        ;; Handle (t FILE) just like (FILE), here.
        ;; That value is used (only in some cases), to mean
        ;; just one file that was marked, rather than the current line file.
        (dired-format-columns-of-files (if (eq (car files) t) (cdr files)
files))
        (remove-text-properties (point-min) (point-max)
                                '(mouse-face nil help-echo nil)))
      (unwind-protect
           (save-window-excursion
             (dired-pop-to-buffer bufname)
             (setq result  (apply function args)))
        (save-excursion
          (condition-case nil           ; Ignore error if user already deleted
window.
              (progn
                (select-window (get-buffer-window bufname 0))
                (if (one-window-p) (delete-frame) (delete-window)))
            (error nil)))
        (bury-buffer bufname)))
    result))

I thought that the patch I sent for this was going to be applied to Emacs - but
it never was.  I use this code everyday, with no problem.  But the dialog is
still broken in vanilla Emacs.

Thanks for working on this, Martin.  It would be great if this problem could be
fixed in general (i.e., beyond just Dired).