static Lisp_Object minibuf_prompt;
+/* The frame containinug the most recently opened Minibuffer. This is
+ used only when `minibuffer-follows-selected-frame' is neither nil
+ nor t. */
+
+static Lisp_Object MB_frame;
+
/* Width of current mini-buffer prompt. Only set after display_line
of the line that contains the prompt. */
static Lisp_Object nth_minibuffer (EMACS_INT depth);
static EMACS_INT minibuf_c_loop_level (EMACS_INT depth);
static void set_minibuffer_mode (Lisp_Object buf, EMACS_INT depth);
+static bool live_minibuffer_p (Lisp_Object);
\f
/* Return TRUE when a frame switch causes a minibuffer on the old
Qt);
}
+#if 0
/* Return TRUE when a minibuffer always remains on the frame where it
was first invoked. */
static bool
{
return NILP (Fdefault_toplevel_value (Qminibuffer_follows_selected_frame));
}
+#endif
/* Return TRUE when opening a (recursive) minibuffer causes
minibuffers on other frames to move to the selected frame. */
emacs_abort ();
minibuf_window = sf->minibuffer_window;
- /* If we've still got another minibuffer open, use its mini-window
- instead. */
- if (minibuf_level > 1 && minibuf_stays_put ())
- {
- Lisp_Object buffer = get_minibuffer (minibuf_level);
- Lisp_Object tail, frame;
-
- FOR_EACH_FRAME (tail, frame)
- if (EQ (XWINDOW (XFRAME (frame)->minibuffer_window)->contents,
- buffer))
- {
- minibuf_window = XFRAME (frame)->minibuffer_window;
- break;
- }
- }
}
+}
- if (minibuf_moves_frame_when_opened ()
- && FRAMEP (selected_frame)
- && FRAME_LIVE_P (XFRAME (selected_frame)))
- /* Make sure no other frame has a minibuffer as its selected window,
- because the text would not be displayed in it, and that would be
- confusing. Only allow the selected frame to do this,
- and that only if the minibuffer is active. */
- {
- Lisp_Object tail, frame;
- struct frame *of;
-
- FOR_EACH_FRAME (tail, frame)
- if (!EQ (frame, selected_frame)
- && minibuf_level > 1
- /* The frame's minibuffer can be on a different frame. */
- && ! EQ (XWINDOW ((of = XFRAME (frame))->minibuffer_window)->frame,
- selected_frame))
- {
- if (MINI_WINDOW_P (XWINDOW (FRAME_SELECTED_WINDOW (of))))
- Fset_frame_selected_window (frame, Fframe_first_window (frame),
- Qnil);
-
- if (!EQ (XWINDOW (of->minibuffer_window)->contents,
- nth_minibuffer (0)))
- set_window_buffer (of->minibuffer_window,
- nth_minibuffer (0), 0, 0);
- }
- }
+/* If ENT1 has a higher minibuffer index than ENT2, return true. More
+precisely, compare the buffer components of each window->prev_buffers
+entry. */
+static bool
+minibuffer_ent_greater (Lisp_Object ent1, Lisp_Object ent2)
+{
+ return this_minibuffer_depth (Fcar (ent1))
+ > this_minibuffer_depth (Fcar (ent2)) ;
}
-/* If `minibuffer_follows_selected_frame' is t and we have a
- minibuffer, move it from its current frame to the selected frame.
- This function is intended to be called from `do_switch_frame' in
- frame.c. */
-void move_minibuffer_onto_frame (void)
+/* Move the ordered "stack" of minibuffers from SOURCE_WINDOW to
+ DEST_WINDOW, interleaving those minibuffers with any in DEST_WINDOW
+ to produce an ordered combination. The ordering is by minibuffer
+ depth. A stack of minibuffers consists of the minibuffer currently
+ in DEST/SOURCE_WINDOW together with any recorded in the
+ ->prev_buffers field of the struct window. */
+static void
+zip_minibuffer_stacks (Lisp_Object dest_window, Lisp_Object source_window)
{
- if (!minibuf_level)
- return;
- if (!minibuf_follows_frame ())
- return;
- if (FRAMEP (selected_frame)
- && FRAME_LIVE_P (XFRAME (selected_frame))
- && !EQ (minibuf_window, XFRAME (selected_frame)->minibuffer_window))
+ struct window *dw = XWINDOW (dest_window);
+ struct window *sw = XWINDOW (source_window);
+ Lisp_Object acc;
+ Lisp_Object d_ent; /* Entry from dw->prev_buffers */
+
+ if (!live_minibuffer_p (dw->contents)
+ && NILP (dw->prev_buffers))
{
- EMACS_INT i;
- struct frame *sf = XFRAME (selected_frame);
- Lisp_Object old_frame = XWINDOW (minibuf_window)->frame;
- struct frame *of = XFRAME (old_frame);
+ set_window_buffer (dest_window, sw->contents, 0, 0);
+ Fset_window_start (dest_window, Fwindow_start (source_window), Qnil);
+ Fset_window_point (dest_window, Fwindow_point (source_window));
+ dw->prev_buffers = sw->prev_buffers;
+ set_window_buffer (source_window, get_minibuffer (0), 0, 0);
+ sw->prev_buffers = Qnil;
+ return;
+ }
- /* Stack up all the (recursively) open minibuffers on the selected
- mini_window. */
- for (i = 1; i <= minibuf_level; i++)
- set_window_buffer (sf->minibuffer_window, nth_minibuffer (i), 0, 0);
- minibuf_window = sf->minibuffer_window;
- if (of != sf)
- {
- Lisp_Object temp = get_minibuffer (0);
+ if (live_minibuffer_p (dw->contents))
+ call1 (Qrecord_window_buffer, dest_window);
+ if (live_minibuffer_p (sw->contents))
+ call1 (Qrecord_window_buffer, source_window);
- set_window_buffer (of->minibuffer_window, temp, 0, 0);
- set_minibuffer_mode (temp, 0);
- }
+ acc = merge_c (dw->prev_buffers, sw->prev_buffers, minibuffer_ent_greater);
+
+ if (!NILP (acc))
+ {
+ d_ent = Fcar (acc);
+ acc = Fcdr (acc);
+ set_window_buffer (dest_window, Fcar (d_ent), 0, 0);
+ Fset_window_start (dest_window, Fcar (Fcdr (d_ent)), Qnil);
+ Fset_window_point (dest_window, Fcar (Fcdr (Fcdr (d_ent))));
+ }
+ dw->prev_buffers = acc;
+ sw->prev_buffers = Qnil;
+ set_window_buffer (source_window, get_minibuffer (0), 0, 0);
+}
+
+/* If `minibuffer_follows_selected_frame' is t, or we're about to
+ delete a frame which potentially "contains" minibuffers, move them
+ from the old frame to the selected frame. This function is
+ intended to be called from `do_switch_frame' in frame.c. OF is the
+ old frame, FOR_DELETION is true if OF is about to be deleted. */
+void
+move_minibuffers_onto_frame (struct frame *of, bool for_deletion)
+{
+ struct frame *f = XFRAME (selected_frame);
+
+ minibuf_window = f->minibuffer_window;
+ if (!(minibuf_level
+ && (for_deletion || minibuf_follows_frame () || FRAME_INITIAL_P (of))))
+ return;
+ if (FRAME_LIVE_P (f)
+ && !EQ (f->minibuffer_window, of->minibuffer_window))
+ {
+ zip_minibuffer_stacks (f->minibuffer_window, of->minibuffer_window);
+ if (for_deletion && XFRAME (MB_frame) != of)
+ MB_frame = selected_frame;
}
}
/* Actual minibuffer invocation. */
static void read_minibuf_unwind (void);
+static void minibuffer_unwind (void);
static void run_exit_minibuf_hook (void);
Lisp_Object histval;
Lisp_Object empty_minibuf;
- Lisp_Object dummy, frame;
specbind (Qminibuffer_default, defalt);
specbind (Qinhibit_read_only, Qnil);
mini_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
if (minibuf_level > 1
+ && !EQ (XWINDOW (XFRAME (selected_frame)->minibuffer_window)->frame,
+ MB_frame)
&& minibuf_moves_frame_when_opened ()
- && (!minibuf_follows_frame ()
- || (!EQ (mini_frame, selected_frame))))
+ && (!minibuf_follows_frame ()))
{
- EMACS_INT i;
+ struct frame *of = XFRAME (MB_frame);
- /* Stack up the existing minibuffers on the current mini-window */
- for (i = 1; i < minibuf_level; i++)
- set_window_buffer (minibuf_window, nth_minibuffer (i), 0, 0);
+ zip_minibuffer_stacks (minibuf_window, of->minibuffer_window);
+ /* MB_frame's minibuffer can be on a different frame. */
+ if (MINI_WINDOW_P (XWINDOW (FRAME_SELECTED_WINDOW (of))))
+ Fset_frame_selected_window (MB_frame,
+ Fframe_first_window (MB_frame), Qnil);
}
+ MB_frame = XWINDOW (XFRAME (selected_frame)->minibuffer_window)->frame;
+ if (live_minibuffer_p (XWINDOW (minibuf_window)->contents))
+ call1 (Qrecord_window_buffer, minibuf_window);
+ record_unwind_protect_void (minibuffer_unwind);
record_unwind_protect (restore_window_configuration,
Fcons (Qt, Fcurrent_window_configuration (Qnil)));
empty_minibuf = get_minibuffer (0);
set_minibuffer_mode (empty_minibuf, 0);
- FOR_EACH_FRAME (dummy, frame)
- {
- Lisp_Object root_window = Fframe_root_window (frame);
- Lisp_Object mini_window = XWINDOW (root_window)->next;
- Lisp_Object buffer;
-
- if (!NILP (mini_window) && !EQ (mini_window, minibuf_window)
- && !NILP (Fwindow_minibuffer_p (mini_window)))
- {
- buffer = XWINDOW (mini_window)->contents;
- if (!live_minibuffer_p (buffer))
- /* Use set_window_buffer instead of Fset_window_buffer (see
- discussion of bug#11984, bug#12025, bug#12026). */
- set_window_buffer (mini_window, empty_minibuf, 0, 0);
- }
- }
-
/* Display this minibuffer in the proper window. */
/* Use set_window_buffer instead of Fset_window_buffer (see
discussion of bug#11984, bug#12025, bug#12026). */
unbind_to (count, Qnil);
/* Switch the frame back to the calling frame. */
- if (!EQ (selected_frame, calling_frame)
+ if ((!EQ (selected_frame, calling_frame)
+ || !EQ (XWINDOW (XFRAME (calling_frame)->minibuffer_window)->frame,
+ calling_frame))
&& FRAMEP (calling_frame)
&& FRAME_LIVE_P (XFRAME (calling_frame)))
call2 (intern ("select-frame-set-input-focus"), calling_frame, Qnil);
safe_run_hooks (Qminibuffer_exit_hook);
}
+/* This variable records the expired minibuffer's frame between the
+ calls of `read_minibuf_unwind' and `minibuffer_unwind'. It should
+ be used only by these two functions. Note that the same search
+ method for the MB's frame won't always work in `minibuffer_unwind'
+ because the intervening `restore-window-configuration' will have
+ changed the buffer in the mini-window. */
+static Lisp_Object exp_MB_frame;
+
/* This function is called on exiting minibuffer, whether normally or
not, and it restores the current window, buffer, etc. */
Lisp_Object calling_frame;
Lisp_Object calling_window;
Lisp_Object future_mini_window;
+ Lisp_Object saved_selected_frame = selected_frame;
+ Lisp_Object window, frames;
+ struct window *w;
+ struct frame *f;
+
+ /* Locate the expired minibuffer. */
+ FOR_EACH_FRAME (frames, exp_MB_frame)
+ {
+ f = XFRAME (exp_MB_frame);
+ window = f->minibuffer_window;
+ w = XWINDOW (window);
+ if (EQ (w->frame, exp_MB_frame)
+ && EQ (w->contents, nth_minibuffer (minibuf_level)))
+ goto found;
+ }
+ return; /* expired minibuffer not found. Maybe we should output an
+ error, here. */
+
+ found:
+ if (!EQ (exp_MB_frame, saved_selected_frame))
+ do_switch_frame (exp_MB_frame, 0, 0, Qt); /* This also sets
+ minibuff_window */
/* To keep things predictable, in case it matters, let's be in the
minibuffer when we reset the relevant variables. Don't depend on
away from the expired minibuffer window, both in the current
minibuffer's frame and the original calling frame. */
choose_minibuf_frame ();
- if (!EQ (WINDOW_FRAME (XWINDOW (minibuf_window)), calling_frame))
- {
- Lisp_Object prev = Fprevious_window (minibuf_window, Qnil, Qnil);
- /* PREV can be on a different frame when we have a minibuffer only
- frame, the other frame's minibuffer window is MINIBUF_WINDOW,
- and its "focus window" is also MINIBUF_WINDOW. */
- if (!EQ (prev, minibuf_window)
- && EQ (WINDOW_FRAME (XWINDOW (prev)),
- WINDOW_FRAME (XWINDOW (minibuf_window))))
- Fset_frame_selected_window (selected_frame, prev, Qnil);
- }
- else
- Fset_frame_selected_window (calling_frame, calling_window, Qnil);
+ if (NILP (XWINDOW (minibuf_window)->prev_buffers))
+ {
+ if (!EQ (WINDOW_FRAME (XWINDOW (minibuf_window)), calling_frame))
+ {
+ Lisp_Object prev = Fprevious_window (minibuf_window, Qnil, Qnil);
+ /* PREV can be on a different frame when we have a minibuffer only
+ frame, the other frame's minibuffer window is MINIBUF_WINDOW,
+ and its "focus window" is also MINIBUF_WINDOW. */
+ if (!EQ (prev, minibuf_window)
+ && EQ (WINDOW_FRAME (XWINDOW (prev)),
+ WINDOW_FRAME (XWINDOW (minibuf_window))))
+ Fset_frame_selected_window (selected_frame, prev, Qnil);
+ }
+ else
+ Fset_frame_selected_window (calling_frame, calling_window, Qnil);
+ }
+
+ /* Restore the selected frame. */
+ if (!EQ (exp_MB_frame, saved_selected_frame))
+ do_switch_frame (saved_selected_frame, 0, 0, Qt);
+}
+
+/* Replace the expired minibuffer in frame exp_MB_frame with the next less
+ nested minibuffer in that frame, if any. Otherwise, replace it
+ with the null minibuffer. MINIBUF_WINDOW is not changed. */
+static void
+minibuffer_unwind (void)
+{
+ struct frame *f;
+ struct window *w;
+ Lisp_Object window;
+ Lisp_Object entry;
+
+ f = XFRAME (exp_MB_frame);
+ window = f->minibuffer_window;
+ w = XWINDOW (window);
+ if (FRAME_LIVE_P (f))
+ {
+ /* minibuf_window = sf->minibuffer_window; */
+ if (!NILP (w->prev_buffers))
+ {
+ entry = Fcar (w->prev_buffers);
+ w->prev_buffers = Fcdr (w->prev_buffers);
+ set_window_buffer (window, Fcar (entry), 0, 0);
+ Fset_window_start (window, Fcar (Fcdr (entry)), Qnil);
+ Fset_window_point (window, Fcar (Fcdr (Fcdr (entry))));
+ /* set-window-configuration may/will have unselected the
+ mini-window as the selected window. Restore it. */
+ Fset_frame_selected_window (exp_MB_frame, window, Qnil);
+ }
+ else
+ set_window_buffer (window, nth_minibuffer (0), 0, 0);
+ }
}
+
\f
void
{
staticpro (&minibuf_prompt);
staticpro (&minibuf_save_list);
+ staticpro (&MB_frame);
+ MB_frame = Qnil;
+ staticpro (&exp_MB_frame);
DEFSYM (Qminibuffer_follows_selected_frame,
"minibuffer-follows-selected-frame");