summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Rudalics <rudalics@gmx.at>2019-03-05 10:46:19 +0100
committerMartin Rudalics <rudalics@gmx.at>2019-03-05 10:46:19 +0100
commita552cc21dc324b1be71c181684b0ab2e6cf0a60f (patch)
tree64ba993180246d1837d5a1ef3c30c1c8ed749ac2 /src
parenteb8dbafff11fded9c96294a0680455bcde70882c (diff)
downloademacs-a552cc21dc324b1be71c181684b0ab2e6cf0a60f.tar.gz
Fix handling of minibuffer-only child frames (Bug#33498)
* doc/lispref/frames.texi (Buffer Parameters): Describe how to make a minibuffer-only child frame. (Child Frames): Describe how minbuffer child frames are deleted. * src/frame.c (delete_frame): Handle deletion of minibuffer child frames (Bug#33498). In the course, fix reassigning of 'default-minibuffer-frame' with minibuffer-only frames. * lisp/frame.el (frame-notice-user-settings): Handle creation of initial minibuffer-only child frame. (make-frame): Handle creation of frame with a minibuffer-only child frame.
Diffstat (limited to 'src')
-rw-r--r--src/frame.c99
1 files changed, 84 insertions, 15 deletions
diff --git a/src/frame.c b/src/frame.c
index 165ed4a4e52..3d83dc0a0d8 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1849,6 +1849,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
Lisp_Object frames, frame1;
int minibuffer_selected, is_tooltip_frame;
bool nochild = !FRAME_PARENT_FRAME (f);
+ Lisp_Object minibuffer_child_frame = Qnil;
if (!FRAME_LIVE_P (f))
return Qnil;
@@ -1865,13 +1866,33 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
/* Softly delete all frames with this frame as their parent frame or
as their `delete-before' frame parameter value. */
FOR_EACH_FRAME (frames, frame1)
- if (FRAME_PARENT_FRAME (XFRAME (frame1)) == f
+ {
+ struct frame *f1 = XFRAME (frame1);
+
+ if (EQ (frame1, frame) || FRAME_TOOLTIP_P (f1))
+ continue;
+ else if (FRAME_PARENT_FRAME (f1) == f)
+ {
+ if (FRAME_HAS_MINIBUF_P (f1) && !FRAME_HAS_MINIBUF_P (f)
+ && EQ (FRAME_MINIBUF_WINDOW (f), FRAME_MINIBUF_WINDOW (f1)))
+ /* frame1 owns frame's minibuffer window so we must not
+ delete it here to avoid a surrogate minibuffer error.
+ Unparent frame1 and make it a top-level frame. */
+ {
+ Fmodify_frame_parameters
+ (frame1, Fcons (Fcons (Qparent_frame, Qnil), Qnil));
+ minibuffer_child_frame = frame1;
+ }
+ else
+ delete_frame (frame1, Qnil);
+ }
+ else if (nochild
+ && EQ (get_frame_param (XFRAME (frame1), Qdelete_before), frame))
/* Process `delete-before' parameter iff FRAME is not a child
frame. This avoids that we enter an infinite chain of mixed
dependencies. */
- || (nochild
- && EQ (get_frame_param (XFRAME (frame1), Qdelete_before), frame)))
- delete_frame (frame1, Qnil);
+ delete_frame (frame1, Qnil);
+ }
/* Does this frame have a minibuffer, and is it the surrogate
minibuffer for any other frame? */
@@ -2136,18 +2157,27 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
{
struct frame *f1 = XFRAME (frame1);
- /* Consider only frames on the same kboard
- and only those with minibuffers. */
- if (kb == FRAME_KBOARD (f1)
- && FRAME_HAS_MINIBUF_P (f1))
+ /* Set frame_on_same_kboard to frame1 if it is on the same
+ keyboard. Set frame_with_minibuf to frame1 if it also
+ has a minibuffer. Leave the loop immediately if frame1
+ is also minibuffer-only.
+
+ Emacs 26 does _not_ set frame_on_same_kboard here when it
+ finds a minibuffer-only frame and subsequently fails to
+ set default_minibuffer_frame below. Not a great deal and
+ never noticed since make_frame_without_minibuffer creates
+ a new minibuffer frame in that case (which can be a minor
+ annoyance though). To consider for Emacs 26.3. */
+ if (kb == FRAME_KBOARD (f1))
{
- frame_with_minibuf = frame1;
- if (FRAME_MINIBUF_ONLY_P (f1))
- break;
+ frame_on_same_kboard = frame1;
+ if (FRAME_HAS_MINIBUF_P (f1))
+ {
+ frame_with_minibuf = frame1;
+ if (FRAME_MINIBUF_ONLY_P (f1))
+ break;
+ }
}
-
- if (kb == FRAME_KBOARD (f1))
- frame_on_same_kboard = frame1;
}
if (!NILP (frame_on_same_kboard))
@@ -2180,7 +2210,46 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
= Fcons (list3 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame),
pending_funcalls);
else
- safe_call2 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame);
+ safe_call2 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame);
+
+ if (!NILP (minibuffer_child_frame))
+ /* If minibuffer_child_frame is non-nil, it was FRAME's minibuffer
+ child frame. Delete it unless it's also the minibuffer frame
+ of another frame in which case we make sure it's visible. */
+ {
+ struct frame *f1 = XFRAME (minibuffer_child_frame);
+
+ if (FRAME_LIVE_P (f1))
+ {
+ Lisp_Object window1 = FRAME_ROOT_WINDOW (f1);
+ Lisp_Object frame2;
+
+ FOR_EACH_FRAME (frames, frame2)
+ {
+ struct frame *f2 = XFRAME (frame2);
+
+ if (EQ (frame2, minibuffer_child_frame) || FRAME_TOOLTIP_P (f2))
+ continue;
+ else if (EQ (FRAME_MINIBUF_WINDOW (f2), window1))
+ {
+ /* minibuffer_child_frame serves as minibuffer frame
+ for at least one other frame - so make it visible
+ and quit. */
+ if (!FRAME_VISIBLE_P (f1) && !FRAME_ICONIFIED_P (f1))
+ Fmake_frame_visible (frame1);
+
+ return Qnil;
+ }
+ }
+
+ /* No other frame found that uses minibuffer_child_frame as
+ minibuffer frame. If FORCE is Qnoelisp or there are
+ other visible frames left, delete minibuffer_child_frame
+ since it presumably was used by FRAME only. */
+ if (EQ (force, Qnoelisp) || other_frames (f1, false, !NILP (force)))
+ delete_frame (minibuffer_child_frame, Qnoelisp);
+ }
+ }
return Qnil;
}