aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Rudalics2019-03-05 10:46:19 +0100
committerMartin Rudalics2019-03-05 10:46:19 +0100
commita552cc21dc324b1be71c181684b0ab2e6cf0a60f (patch)
tree64ba993180246d1837d5a1ef3c30c1c8ed749ac2
parenteb8dbafff11fded9c96294a0680455bcde70882c (diff)
downloademacs-a552cc21dc324b1be71c181684b0ab2e6cf0a60f.tar.gz
emacs-a552cc21dc324b1be71c181684b0ab2e6cf0a60f.zip
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.
-rw-r--r--doc/lispref/frames.texi20
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/frame.el81
-rw-r--r--src/frame.c99
4 files changed, 170 insertions, 35 deletions
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 820006a5675..9b3e02f4de0 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -1884,6 +1884,12 @@ minibuffer window to @code{t} and vice-versa, or from @code{t} to
1884@code{nil}. If the parameter specifies a minibuffer window already, 1884@code{nil}. If the parameter specifies a minibuffer window already,
1885setting it to @code{nil} has no effect. 1885setting it to @code{nil} has no effect.
1886 1886
1887The special value @code{child-frame} means to make a minibuffer-only
1888child frame (@pxref{Child Frames}) whose parent becomes the frame
1889created. As if specified as @code{nil}, Emacs will set this parameter
1890to the minibuffer window of the child frame but will not select the
1891child frame after its creation.
1892
1887@vindex buffer-predicate@r{, a frame parameter} 1893@vindex buffer-predicate@r{, a frame parameter}
1888@item buffer-predicate 1894@item buffer-predicate
1889The buffer-predicate function for this frame. The function 1895The buffer-predicate function for this frame. The function
@@ -3214,9 +3220,17 @@ top-level frame which also always appears on top of its parent
3214window---the desktop's root window. When a parent frame is iconified or 3220window---the desktop's root window. When a parent frame is iconified or
3215made invisible (@pxref{Visibility of Frames}), its child frames are made 3221made invisible (@pxref{Visibility of Frames}), its child frames are made
3216invisible. When a parent frame is deiconified or made visible, its 3222invisible. When a parent frame is deiconified or made visible, its
3217child frames are made visible. When a parent frame is about to be 3223child frames are made visible.
3218deleted (@pxref{Deleting Frames}), its child frames are recursively 3224
3219deleted before it. 3225 When a parent frame is about to be deleted (@pxref{Deleting
3226Frames}), its child frames are recursively deleted before it. There
3227is one exception to this rule: When the child frame serves as a
3228surrogate minibuffer frame (@pxref{Minibuffers and Frames}) for
3229another frame, it is retained until the parent frame has been deleted.
3230If, at this time, no remaining frame uses the child frame as its
3231minibuffer frame, Emacs will try to delete the child frame too. If
3232that deletion fails for whatever reason, the child frame is made a
3233top-level frame.
3220 3234
3221 Whether a child frame can have a menu or tool bar is window-system or 3235 Whether a child frame can have a menu or tool bar is window-system or
3222window manager dependent. Most window-systems explicitly disallow menus 3236window manager dependent. Most window-systems explicitly disallow menus
diff --git a/etc/NEWS b/etc/NEWS
index fc4e2c57268..3e347b5318a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1166,6 +1166,11 @@ the 128...255 range, as expected.
1166+++ 1166+++
1167*** New command 'make-frame-on-monitor' makes a frame on the specified monitor. 1167*** New command 'make-frame-on-monitor' makes a frame on the specified monitor.
1168 1168
1169+++
1170*** New value of 'minibuffer' frame parameter 'child-frame'.
1171This allows to create and parent immediately a minibuffer-only child
1172frame when making a frame.
1173
1169 1174
1170* New Modes and Packages in Emacs 27.1 1175* New Modes and Packages in Emacs 27.1
1171 1176
diff --git a/lisp/frame.el b/lisp/frame.el
index d71a3fe5e8e..cdb2ac4af11 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -316,10 +316,15 @@ there (in decreasing order of priority)."
316 ;; want to use save-excursion here, because that may also try to set 316 ;; want to use save-excursion here, because that may also try to set
317 ;; the buffer of the selected window, which fails when the selected 317 ;; the buffer of the selected window, which fails when the selected
318 ;; window is the minibuffer. 318 ;; window is the minibuffer.
319 (let ((old-buffer (current-buffer)) 319 (let* ((old-buffer (current-buffer))
320 (window-system-frame-alist 320 (window-system-frame-alist
321 (cdr (assq initial-window-system 321 (cdr (assq initial-window-system
322 window-system-default-frame-alist)))) 322 window-system-default-frame-alist)))
323 (minibuffer
324 (cdr (or (assq 'minibuffer initial-frame-alist)
325 (assq 'minibuffer window-system-frame-alist)
326 (assq 'minibuffer default-frame-alist)
327 '(minibuffer . t)))))
323 328
324 (when (and frame-notice-user-settings 329 (when (and frame-notice-user-settings
325 (null frame-initial-frame)) 330 (null frame-initial-frame))
@@ -410,11 +415,7 @@ there (in decreasing order of priority)."
410 ;; default-frame-alist in the parameters of the screen we 415 ;; default-frame-alist in the parameters of the screen we
411 ;; create here, so that its new value, gleaned from the user's 416 ;; create here, so that its new value, gleaned from the user's
412 ;; init file, will be applied to the existing screen. 417 ;; init file, will be applied to the existing screen.
413 (if (not (eq (cdr (or (assq 'minibuffer initial-frame-alist) 418 (if (not (eq minibuffer t))
414 (assq 'minibuffer window-system-frame-alist)
415 (assq 'minibuffer default-frame-alist)
416 '(minibuffer . t)))
417 t))
418 ;; Create the new frame. 419 ;; Create the new frame.
419 (let (parms new) 420 (let (parms new)
420 ;; MS-Windows needs this to avoid inflooping below. 421 ;; MS-Windows needs this to avoid inflooping below.
@@ -442,7 +443,15 @@ there (in decreasing order of priority)."
442 parms 443 parms
443 nil)) 444 nil))
444 445
445 ;; Get rid of `reverse', because that was handled 446 (when (eq minibuffer 'child-frame)
447 ;; When the minibuffer shall be shown in a child frame,
448 ;; remove the 'minibuffer' parameter from PARMS. It
449 ;; will get assigned by the usual routines to the child
450 ;; frame's root window below.
451 (setq parms (cons '(minibuffer)
452 (delq (assq 'minibuffer parms) parms))))
453
454 ;; Get rid of `reverse', because that was handled
446 ;; when we first made the frame. 455 ;; when we first made the frame.
447 (setq parms (cons '(reverse) (delq (assq 'reverse parms) parms))) 456 (setq parms (cons '(reverse) (delq (assq 'reverse parms) parms)))
448 457
@@ -465,7 +474,18 @@ there (in decreasing order of priority)."
465 ;; the only frame with a minibuffer. If it is, create a 474 ;; the only frame with a minibuffer. If it is, create a
466 ;; new one. 475 ;; new one.
467 (or (delq frame-initial-frame (minibuffer-frame-list)) 476 (or (delq frame-initial-frame (minibuffer-frame-list))
468 (make-initial-minibuffer-frame nil)) 477 (and (eq minibuffer 'child-frame)
478 ;; Create a minibuffer child frame and parent it
479 ;; immediately. Take any other parameters for
480 ;; the child frame from 'minibuffer-frame-list'.
481 (let* ((minibuffer-frame-alist
482 (cons `(parent-frame . ,new) minibuffer-frame-alist)))
483 (make-initial-minibuffer-frame nil)
484 ;; With a minibuffer child frame we do not want
485 ;; to select the minibuffer frame initially as
486 ;; we do for standard minibuffer-only frames.
487 (select-frame new)))
488 (make-initial-minibuffer-frame nil))
469 489
470 ;; If the initial frame is serving as a surrogate 490 ;; If the initial frame is serving as a surrogate
471 ;; minibuffer frame for any frames, we need to wean them 491 ;; minibuffer frame for any frames, we need to wean them
@@ -795,7 +815,7 @@ the new frame according to its own rules."
795 (t window-system))) 815 (t window-system)))
796 (oldframe (selected-frame)) 816 (oldframe (selected-frame))
797 (params parameters) 817 (params parameters)
798 frame) 818 frame child-frame)
799 819
800 (unless (get w 'window-system-initialized) 820 (unless (get w 'window-system-initialized)
801 (let ((window-system w)) ;Hack attack! 821 (let ((window-system w)) ;Hack attack!
@@ -811,17 +831,44 @@ the new frame according to its own rules."
811 (dolist (p default-frame-alist) 831 (dolist (p default-frame-alist)
812 (unless (assq (car p) params) 832 (unless (assq (car p) params)
813 (push p params))) 833 (push p params)))
814 ;; Now make the frame.
815 (run-hooks 'before-make-frame-hook)
816 834
817;; (setq frame-size-history '(1000)) 835;; (setq frame-size-history '(1000))
818 836
819 (setq frame (let ((window-system w)) ;Hack attack! 837 (when (eq (cdr (or (assq 'minibuffer params) '(minibuffer . t)))
838 'child-frame)
839 ;; If the 'minibuffer' parameter equals 'child-frame' make a
840 ;; frame without minibuffer first using the root window of
841 ;; 'default-minibuffer-frame' as its minibuffer window
842 (setq child-frame t)
843 (setq params (cons '(minibuffer)
844 (delq (assq 'minibuffer params) params))))
845
846 ;; Now make the frame.
847 (run-hooks 'before-make-frame-hook)
848
849 (setq frame (let ((window-system w)) ; Hack attack!
820 (frame-creation-function params))) 850 (frame-creation-function params)))
851
852 (when child-frame
853 ;; When we want to equip the new frame with a minibuffer-only
854 ;; child frame, make that frame and reparent it immediately.
855 (setq child-frame
856 (make-frame
857 (append
858 `((display . ,display) (minibuffer . only)
859 (parent-frame . ,frame))
860 minibuffer-frame-alist)))
861 (when (frame-live-p child-frame)
862 ;; Have the 'minibuffer' parameter of our new frame refer to
863 ;; its child frame's root window.
864 (set-frame-parameter
865 frame 'minibuffer (frame-root-window child-frame))))
866
821 (normal-erase-is-backspace-setup-frame frame) 867 (normal-erase-is-backspace-setup-frame frame)
822 ;; Inherit the original frame's parameters. 868 ;; Inherit original frame's parameters unless they are overridden
869 ;; by explicit parameters.
823 (dolist (param frame-inherited-parameters) 870 (dolist (param frame-inherited-parameters)
824 (unless (assq param parameters) ;Overridden by explicit parameters. 871 (unless (assq param parameters)
825 (let ((val (frame-parameter oldframe param))) 872 (let ((val (frame-parameter oldframe param)))
826 (when val (set-frame-parameter frame param val))))) 873 (when val (set-frame-parameter frame param val)))))
827 874
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)
1849 Lisp_Object frames, frame1; 1849 Lisp_Object frames, frame1;
1850 int minibuffer_selected, is_tooltip_frame; 1850 int minibuffer_selected, is_tooltip_frame;
1851 bool nochild = !FRAME_PARENT_FRAME (f); 1851 bool nochild = !FRAME_PARENT_FRAME (f);
1852 Lisp_Object minibuffer_child_frame = Qnil;
1852 1853
1853 if (!FRAME_LIVE_P (f)) 1854 if (!FRAME_LIVE_P (f))
1854 return Qnil; 1855 return Qnil;
@@ -1865,13 +1866,33 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
1865 /* Softly delete all frames with this frame as their parent frame or 1866 /* Softly delete all frames with this frame as their parent frame or
1866 as their `delete-before' frame parameter value. */ 1867 as their `delete-before' frame parameter value. */
1867 FOR_EACH_FRAME (frames, frame1) 1868 FOR_EACH_FRAME (frames, frame1)
1868 if (FRAME_PARENT_FRAME (XFRAME (frame1)) == f 1869 {
1870 struct frame *f1 = XFRAME (frame1);
1871
1872 if (EQ (frame1, frame) || FRAME_TOOLTIP_P (f1))
1873 continue;
1874 else if (FRAME_PARENT_FRAME (f1) == f)
1875 {
1876 if (FRAME_HAS_MINIBUF_P (f1) && !FRAME_HAS_MINIBUF_P (f)
1877 && EQ (FRAME_MINIBUF_WINDOW (f), FRAME_MINIBUF_WINDOW (f1)))
1878 /* frame1 owns frame's minibuffer window so we must not
1879 delete it here to avoid a surrogate minibuffer error.
1880 Unparent frame1 and make it a top-level frame. */
1881 {
1882 Fmodify_frame_parameters
1883 (frame1, Fcons (Fcons (Qparent_frame, Qnil), Qnil));
1884 minibuffer_child_frame = frame1;
1885 }
1886 else
1887 delete_frame (frame1, Qnil);
1888 }
1889 else if (nochild
1890 && EQ (get_frame_param (XFRAME (frame1), Qdelete_before), frame))
1869 /* Process `delete-before' parameter iff FRAME is not a child 1891 /* Process `delete-before' parameter iff FRAME is not a child
1870 frame. This avoids that we enter an infinite chain of mixed 1892 frame. This avoids that we enter an infinite chain of mixed
1871 dependencies. */ 1893 dependencies. */
1872 || (nochild 1894 delete_frame (frame1, Qnil);
1873 && EQ (get_frame_param (XFRAME (frame1), Qdelete_before), frame))) 1895 }
1874 delete_frame (frame1, Qnil);
1875 1896
1876 /* Does this frame have a minibuffer, and is it the surrogate 1897 /* Does this frame have a minibuffer, and is it the surrogate
1877 minibuffer for any other frame? */ 1898 minibuffer for any other frame? */
@@ -2136,18 +2157,27 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
2136 { 2157 {
2137 struct frame *f1 = XFRAME (frame1); 2158 struct frame *f1 = XFRAME (frame1);
2138 2159
2139 /* Consider only frames on the same kboard 2160 /* Set frame_on_same_kboard to frame1 if it is on the same
2140 and only those with minibuffers. */ 2161 keyboard. Set frame_with_minibuf to frame1 if it also
2141 if (kb == FRAME_KBOARD (f1) 2162 has a minibuffer. Leave the loop immediately if frame1
2142 && FRAME_HAS_MINIBUF_P (f1)) 2163 is also minibuffer-only.
2164
2165 Emacs 26 does _not_ set frame_on_same_kboard here when it
2166 finds a minibuffer-only frame and subsequently fails to
2167 set default_minibuffer_frame below. Not a great deal and
2168 never noticed since make_frame_without_minibuffer creates
2169 a new minibuffer frame in that case (which can be a minor
2170 annoyance though). To consider for Emacs 26.3. */
2171 if (kb == FRAME_KBOARD (f1))
2143 { 2172 {
2144 frame_with_minibuf = frame1; 2173 frame_on_same_kboard = frame1;
2145 if (FRAME_MINIBUF_ONLY_P (f1)) 2174 if (FRAME_HAS_MINIBUF_P (f1))
2146 break; 2175 {
2176 frame_with_minibuf = frame1;
2177 if (FRAME_MINIBUF_ONLY_P (f1))
2178 break;
2179 }
2147 } 2180 }
2148
2149 if (kb == FRAME_KBOARD (f1))
2150 frame_on_same_kboard = frame1;
2151 } 2181 }
2152 2182
2153 if (!NILP (frame_on_same_kboard)) 2183 if (!NILP (frame_on_same_kboard))
@@ -2180,7 +2210,46 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
2180 = Fcons (list3 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame), 2210 = Fcons (list3 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame),
2181 pending_funcalls); 2211 pending_funcalls);
2182 else 2212 else
2183 safe_call2 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame); 2213 safe_call2 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame);
2214
2215 if (!NILP (minibuffer_child_frame))
2216 /* If minibuffer_child_frame is non-nil, it was FRAME's minibuffer
2217 child frame. Delete it unless it's also the minibuffer frame
2218 of another frame in which case we make sure it's visible. */
2219 {
2220 struct frame *f1 = XFRAME (minibuffer_child_frame);
2221
2222 if (FRAME_LIVE_P (f1))
2223 {
2224 Lisp_Object window1 = FRAME_ROOT_WINDOW (f1);
2225 Lisp_Object frame2;
2226
2227 FOR_EACH_FRAME (frames, frame2)
2228 {
2229 struct frame *f2 = XFRAME (frame2);
2230
2231 if (EQ (frame2, minibuffer_child_frame) || FRAME_TOOLTIP_P (f2))
2232 continue;
2233 else if (EQ (FRAME_MINIBUF_WINDOW (f2), window1))
2234 {
2235 /* minibuffer_child_frame serves as minibuffer frame
2236 for at least one other frame - so make it visible
2237 and quit. */
2238 if (!FRAME_VISIBLE_P (f1) && !FRAME_ICONIFIED_P (f1))
2239 Fmake_frame_visible (frame1);
2240
2241 return Qnil;
2242 }
2243 }
2244
2245 /* No other frame found that uses minibuffer_child_frame as
2246 minibuffer frame. If FORCE is Qnoelisp or there are
2247 other visible frames left, delete minibuffer_child_frame
2248 since it presumably was used by FRAME only. */
2249 if (EQ (force, Qnoelisp) || other_frames (f1, false, !NILP (force)))
2250 delete_frame (minibuffer_child_frame, Qnoelisp);
2251 }
2252 }
2184 2253
2185 return Qnil; 2254 return Qnil;
2186} 2255}