Hello, Martin. On Thu, Jan 07, 2021 at 19:26:02 +0100, martin rudalics wrote: > > Actualy, I don't think it's as ugly as all that. > > select-frame-set-input-focus is an extremely coherent function; it does > > one thing and does it well, i.e. switch frames. Maybe it's a pity that > > it's a Lisp function rather than a C function, but it is as it is. > It does call 'raise-frame' something people with 'focus-follows-mouse' t > (not 'auto-raise') might not want here. And it may have to move the > mouse cursor according to the 'mouse-autoselect-window' and > 'focus-follows-mouse' policies. Most window managers don't handle the > latter well (IIRC only the otherwise abominable mutter and KDE could do > it approximately). And the former wants the selected window to be set > up well before calling 'select-frame-set-input-focus'. It is nevertheless the standard function to call to move focus to a different frame. If there are problems with focus-follows-mouse, they should surely be fixed in frame.el as a separate problem. > > I've been trying to think through the bit about redirect-frame-focus. > > It's difficult. Are you aware of any particular scenarios where it might > > go wrong with select-frame-set-input-focus? Or is it more a general > > concern, possibly from past experience? For example if the source frame > > has focus redirected to a MB-only frame, and s-f-s-i-focus is called, > > should that redirected focus be undone? I'm a little confused about the > > difference between a MB-only frame being the selected frame, and it being > > the focus frame of a different "normal" frame. > I already had to revert one change because I got that wrong. It's again > mostly about using 'focus-follows-mouse' t with a standalone minibuffer > frame and I've never been able to understand how people manage that when > the normal frame practically completely covers the minibuffer frame. > But sooner or later this point will get moot because with Wayland people > will be no more able to put a standalone minibuffer frame wherever they > want to. OK. My gut feeling is just to ignore this potential problem at the moment. > >> We're right in hell's kitchen here. > > I've actually implemented the above, on a trial basis. It was actually > > surprisingly easy. The C-g bit was just 9 extra lines (plus comments) in > > internal_catch (eval.c), and another small function in minibuf.c. > > You say "hell's kitchen". Again, is this on general principles, > Just gut feeling. OK. I can understand that. ;-) > > or can > > you see some specific problems which might crop up? My feeling is that > > this way of dealing with "not the innermost minibuffer" is simple, and > > possibly as good as we're going to get. My intention at the moment is to commit my current state of work. I'm attaching the patch. Here's a commit message to go with it: Fix incompleteness in the implementation of minibuffer-follows-selected-frame In particular, add a new value to the variable, and fix several bugs apparent with the implementation up till now. * doc/emacs/mini.texi (Basic Minibuffer): Add a description of the new non-nil, non-t value of minibuffer-follows-selected-frame. * doc/emacs/trouble.texi (Quitting): Add a description of how C-g handles recursive minibuffers when typed in one which isn't the most nested. * doc/lispref/minibuf.texi (Intro to Minibuffers): Add an @dfn for "active minibuffer". (Minibuffer Commands): Document that exit-minibuffer throws an error when not invoked from the innermost Minibuffer. (Recursive Mini): Amend the description of the visibility of outer level minibuffers. (Minibuffer Misc): In the description of the minibuffer hooks, replace "the minibuffer" with "a minibuffer". * etc/NEWS (Entry announcing minibuffer-follows-selected-frame): Add a description of the new non-nil, non-t value. * lisp/cus-start.el (top level): make the customize entry for minibuffer-follows-selected-frame a choice between three entries. * lisp/minibuffer.el (exit-minibuffer): throw an error when we're not in the most nested minibuffer. * lisp/window.el (window-deletable-p): return the symbol `frame' when (amongst other things) minibuffer-follows-selected-frame is t. * src/eval.c (internal_catch): Add a mechanism to (throw 'exit t) repeatedly when the throw currently being processed doesn't terminate the current minibuffer. * src/lisp.h (this_minibuffer_depth): New extern declaration (minibuf_level): extern declaration moved here from window.h. * src/minibuf.c (minibuffer_follows_frame, minibuf_stays_put) (minibuf_moves_frame_when_opened): New and amended functions to query the value of minibuffer-follows-selected-frame. (choose_minibuf_frame): check (minibuf > 1) in place of (minibufer > 0) at a particular place. At another place, check that an alleged frame is so and is live. Before selecting a non-miniwindow on a different frame, ensure it really is a different frame. (move_minibuffer_onto_frame): Stack up all recursive minibuffers on the target frame. Check the minibuf_window isn't in the old frame before setting that frame's miniwindow to an inactive minibuffer. (Finnermost_minibuffer_p): New primitive. (this_minibuffer_depth): New function. (read_minibuf): Record the calling frame in a variable, and switch back to it after the recursive edit has terminated normally, using select-frame-set-input-focus. Stack up all the recursive minibuffers on the miniwindow where a new minibuffer is being opened. After the recursive edit, switch the selected window away from the expired minibuffer's window. (nth_minibuffer): New function. (minibuffer-follows-selected-frame): Change from a DEFVAR_BOOL to a DEFVAR_LISP. * src/window.c (decode_next_window_args): Set *minibuf to w's mini-window's content when that content is a minibuffer. * src/window.h (minibuf_level) Declaration moved from here to lisp.h. > martin -- Alan Mackenzie (Nuremberg, Germany).