diff options
| author | Martin Rudalics | 2019-03-05 10:46:19 +0100 |
|---|---|---|
| committer | Martin Rudalics | 2019-03-05 10:46:19 +0100 |
| commit | a552cc21dc324b1be71c181684b0ab2e6cf0a60f (patch) | |
| tree | 64ba993180246d1837d5a1ef3c30c1c8ed749ac2 /src | |
| parent | eb8dbafff11fded9c96294a0680455bcde70882c (diff) | |
| download | emacs-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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/frame.c | 99 |
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) | |||
| 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 | } |