From 0943cc18b18e2df90c7aa0fbc4dab72d418aa700 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Sun, 30 Apr 2017 10:02:53 +0200 Subject: [PATCH] Fix `delete-frame' behavior including Bug#26682 * src/frame.c (other_frames): Accept two arguments now. Don't care about minibuffer window. Don't care about visibility when called from delete_frame with FORCE true (Bug#26682). (delete_frame, Fmake_frame_invisible): Adjust other_frames calls. * src/w32term.c (w32_read_socket): Don't add a move frame event for an invisible frame. * lisp/frame.el (handle-delete-frame): Don't kill Emacs when attempting to delete a surrogate minibuffer frame. --- lisp/frame.el | 7 ++----- src/frame.c | 46 ++++++++++++++++++++++------------------------ src/w32term.c | 2 +- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/lisp/frame.el b/lisp/frame.el index cec262499d1..05db8cf6fd4 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -118,13 +118,10 @@ appended when the minibuffer frame is created." (let* ((frame (posn-window (event-start event)))) (if (catch 'other-frame (dolist (frame-1 (frame-list)) - ;; A valid "other" frame is visible, owns its minibuffer - ;; window, has its `delete-before' parameter unset and is - ;; not a child frame. + ;; A valid "other" frame is visible, has its `delete-before' + ;; parameter unset and is not a child frame. (when (and (not (eq frame-1 frame)) (frame-visible-p frame-1) - (window-live-p (minibuffer-window frame-1)) - (eq (window-frame (minibuffer-window frame-1)) frame-1) (not (frame-parent frame-1)) (not (frame-parameter frame-1 'delete-before))) (throw 'other-frame t)))) diff --git a/src/frame.c b/src/frame.c index 681a245ee05..4d17a071dc7 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1560,15 +1560,16 @@ DEFUN ("last-nonminibuffer-frame", Flast_nonminibuf_frame, * Return true if there exists at least one visible or iconified frame * but F. Return false otherwise. * - * Always return false when all remaining frames are either tooltip or - * child frames or frames with a non-nil `delete-before' parameter. If - * INVISIBLE is false, also return false when the minibuffer window of - * all remaining frames is on F. - + * INVISIBLE true means we are called from make_frame_invisible where + * such a frame must be visible or iconified. INVISIBLE nil means we + * are called from delete_frame. In that case FORCE true means that the + * visibility status of such a frame can be ignored. + * * If F is the terminal frame and we are using X, return true if at - * least one X frame exists. */ + * least one X frame exists. + */ static bool -other_frames (struct frame *f, bool invisible) +other_frames (struct frame *f, bool invisible, bool force) { Lisp_Object frames, frame, frame1; struct frame *f1; @@ -1591,23 +1592,20 @@ other_frames (struct frame *f, bool invisible) x_sync (f1); #endif if (NILP (Fframe_parameter (frame1, Qtooltip)) - /* Tooltips and child frames don't count. */ + /* Tooltips and child frames count neither for + invisibility nor for deletions. */ && !FRAME_PARENT_FRAME (f1) /* Frames with a non-nil `delete-before' parameter don't - count - either they depend on us or they depend on a - frame that we will have to find right here. */ - && NILP (get_frame_param (f1, Qdelete_before)) - /* Frames whose minibuffer window is on F don't count - unless INVISIBLE is set - in that case F is either made - invisible and may be autoraised from such a frame or - the FORCE argument of delete_frame was non-nil. */ - && (invisible || NILP (minibuffer_window) - || !EQ (FRAME_MINIBUF_WINDOW (f1), minibuffer_window)) - /* At least one visible/iconified frame must remain. */ + count for deletions. */ + && (invisible || NILP (get_frame_param (f1, Qdelete_before))) + /* For invisibility and normal deletions, at least one + visible or iconified frame must remain (Bug#26682). */ && (FRAME_VISIBLE_P (f1) || FRAME_ICONIFIED_P (f1) - /* Allow deleting the terminal frame when at least one - X frame exists. */ - || (FRAME_WINDOW_P (f1) && !FRAME_WINDOW_P (f)))) + || (!invisible + && (force + /* Allow deleting the terminal frame when at + least one X frame exists. */ + || (FRAME_WINDOW_P (f1) && !FRAME_WINDOW_P (f)))))) return true; } } @@ -1680,7 +1678,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force) if (!FRAME_LIVE_P (f)) return Qnil; - else if (!EQ (force, Qnoelisp) && !other_frames (f, !NILP (force))) + else if (!EQ (force, Qnoelisp) && !other_frames (f, false, !NILP (force))) { if (NILP (force)) error ("Attempt to delete the sole visible or iconified frame"); @@ -1752,7 +1750,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force) one. */ if (!FRAME_LIVE_P (f)) return Qnil; - else if (!EQ (force, Qnoelisp) && !other_frames (f, !NILP (force))) + else if (!EQ (force, Qnoelisp) && !other_frames (f, false, !NILP (force))) { if (NILP (force)) error ("Attempt to delete the sole visible or iconified frame"); @@ -2275,7 +2273,7 @@ displayed in the terminal. */) { struct frame *f = decode_live_frame (frame); - if (NILP (force) && !other_frames (f, true)) + if (NILP (force) && !other_frames (f, true, false)) error ("Attempt to make invisible the sole visible or iconified frame"); /* Don't allow minibuf_window to remain on an invisible frame. */ diff --git a/src/w32term.c b/src/w32term.c index 6b0da0cb3e9..b3608accb34 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -5110,7 +5110,7 @@ w32_read_socket (struct terminal *terminal, case WM_MOVE: f = x_window_to_frame (dpyinfo, msg.msg.hwnd); - if (f && !FRAME_ICONIFIED_P (f)) + if (f && FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P(f)) { x_real_positions (f, &f->left_pos, &f->top_pos); inev.kind = MOVE_FRAME_EVENT; -- 2.39.5