Commit 95373b69 authored by Martin Rudalics's avatar Martin Rudalics

Rewrite minibuffer window resizing code

* src/frame.c (resize_mini_frames): New variable.
* src/window.c (resize_mini_window_apply): New function.
(grow_mini_window, shrink_mini_window): Remove PIXELWISE
argument.  Call resize_mini_window_apply to apply changes.
(Fresize_mini_window_internal): Call resize_mini_window_apply
to apply changes.
(Qwindow__resize_mini_frame): New symbol.
* src/window.h (grow_mini_window, shrink_mini_window): Adjust
external declarations.
* src/xdisp.c (resize_mini_window): For minibuffer-only frames
call 'window--resize-mini-frame' if resize_mini_frames is
non-nil.  Offload parts of logic to grow_mini_window and
shrink_mini_window which are now called without the PIXELWISE
argument.
(Vresize_mini_windows): Mention 'resize-mini-frames' in
doc-string.
* lisp/cus-start.el (resize-mini-frames): Add customization
support.
* lisp/window.el (window--resize-mini-window): Simplify code.
(window--resize-mini-frame): New function.
* doc/lispref/minibuf.texi (Minibuffer Windows): Describe new
option 'resize-mini-frames'.
* etc/NEWS: Mention new option 'resize-mini-frames'.
parent 27466c62
Pipeline #982 passed with stage
in 49 minutes and 3 seconds
......@@ -2402,6 +2402,25 @@ will not work. If you want to prevent resizing of minibuffer windows
when displaying long messages, bind the @code{message-truncate-lines}
variable instead (@pxref{Echo Area Customization}).
The option @code{resize-mini-windows} does not affect the behavior of
minibuffer-only frames (@pxref{Frame Layout}). The following option
allows to automatically resize such frames as well.
@defopt resize-mini-frames
If this is @code{nil}, minibuffer-only frames are never resized
automatically.
If this is a function, that function is called with the
minibuffer-only frame to be resized as sole argument. At the time
this function is called, the buffer of the minibuffer window of that
frame is the buffer whose contents will be shown the next time that
window is redisplayed. The function is expected to fit the frame to
the buffer in some appropriate way.
Any other non-@code{nil} value means to resize minibuffer-only frames
by calling @code{fit-frame-to-buffer} (@pxref{Resizing Windows}).
@end defopt
@node Minibuffer Contents
@section Minibuffer Contents
......
......@@ -1468,6 +1468,11 @@ return the total and body sizes of any window during last redisplay.
See the section "(elisp) Window Hooks" in the Elisp manual for a
detailed explanation of the new behavior.
+++
*** New option 'resize-mini-frames'.
This option allows to automatically resize minibuffer-only frames
similarly to how minibuffer windows are resized on "normal" frames.
+++
** New buffer display action alist entry 'dedicated'.
Such an entry allows to specify the dedicated status of a window
......
......@@ -314,7 +314,13 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of
(other :tag "hidden by keypress" 1))
"22.1")
(make-pointer-invisible mouse boolean "23.2")
(menu-bar-mode frames boolean nil
(resize-mini-frames
frames (choice
(const :tag "Never" nil)
(const :tag "Fit frame to buffer" t)
(function :tag "User-defined function"))
"27.1")
(menu-bar-mode frames boolean nil
;; FIXME?
;; :initialize custom-initialize-default
:set custom-set-minor-mode)
......
......@@ -2753,7 +2753,7 @@ as small) as possible, but don't signal an error."
;; Sanitize DELTA.
(cond
((<= (+ height delta) 0)
(setq delta (- (frame-char-height (window-frame window)) height)))
(setq delta (- (frame-char-height frame) height)))
((> delta min-delta)
(setq delta min-delta)))
......@@ -3381,6 +3381,12 @@ routines."
pixel-delta
(/ pixel-delta (frame-char-height frame)))))
(defun window--resize-mini-frame (frame)
"Resize minibuffer-only frame FRAME."
(if (functionp resize-mini-frames)
(funcall resize-mini-frames frame)
(fit-frame-to-buffer frame)))
(defun window--sanitize-window-sizes (horizontal)
"Assert that all windows on selected frame are large enough.
If necessary and possible, make sure that every window on frame
......
......@@ -6079,6 +6079,19 @@ setting this variable does not change that frame's previous association.
This variable is local to the current terminal and cannot be buffer-local. */);
DEFVAR_LISP ("resize-mini-frames", resize_mini_frames,
doc: /* Non-nil means resize minibuffer-only frames automatically.
If this is nil, do not resize minibuffer-only frames automatically.
If this is a function, call that function with the minibuffer-only
frame that shall be resized as sole argument. The buffer of the root
window of that frame is the buffer whose text will be eventually shown
in the minibuffer window.
Any other non-nil value means to resize minibuffer-only frames by
calling `fit-frame-to-buffer'. */);
resize_mini_frames = Qnil;
DEFVAR_LISP ("focus-follows-mouse", focus_follows_mouse,
doc: /* Non-nil if window system changes focus when you move the mouse.
You should set this variable to tell Emacs how your window manager
......
......@@ -5168,118 +5168,111 @@ Signal an error when WINDOW is the only window on its frame. */)
Resizing Mini-Windows
***********************************************************************/
/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we
can. */
/**
* resize_mini_window_apply:
*
* Assign new window sizes after resizing a mini window W by DELTA
* pixels. No error checking performed.
*/
static void
resize_mini_window_apply (struct window *w, int delta)
{
struct frame *f = XFRAME (w->frame);
Lisp_Object root = FRAME_ROOT_WINDOW (f);
struct window *r = XWINDOW (root);
block_input ();
w->pixel_height = w->pixel_height + delta;
w->total_lines = w->pixel_height / FRAME_LINE_HEIGHT (f);
window_resize_apply (r, false);
w->pixel_top = r->pixel_top + r->pixel_height;
w->top_line = r->top_line + r->total_lines;
/* Enforce full redisplay of the frame. */
/* FIXME: Shouldn't some of the caller do it? */
fset_redisplay (f);
adjust_frame_glyphs (f);
unblock_input ();
}
/**
* grow_mini_window:
*
* Grow mini-window W by DELTA pixels. If DELTA is negative, this may
* shrink the minibuffer window to the minimum height to display one
* line of text.
*/
void
grow_mini_window (struct window *w, int delta, bool pixelwise)
grow_mini_window (struct window *w, int delta)
{
struct frame *f = XFRAME (w->frame);
struct window *r;
Lisp_Object root, height;
int line_height, pixel_height;
int old_height = WINDOW_PIXEL_HEIGHT (w);
int min_height = FRAME_LINE_HEIGHT (f);
eassert (MINI_WINDOW_P (w));
eassert (delta >= 0);
if (delta > 0)
{
root = FRAME_ROOT_WINDOW (f);
r = XWINDOW (root);
height = call3 (Qwindow__resize_root_window_vertically,
root, make_fixnum (- delta), pixelwise ? Qt : Qnil);
if (FIXNUMP (height) && window_resize_check (r, false))
{
block_input ();
window_resize_apply (r, false);
if (old_height + delta < min_height)
/* Never shrink mini-window to less than its minimum
height. */
delta = old_height > min_height ? min_height - old_height : 0;
if (pixelwise)
{
pixel_height = min (-XFIXNUM (height), INT_MAX - w->pixel_height);
line_height = pixel_height / FRAME_LINE_HEIGHT (f);
}
else
{
line_height = min (-XFIXNUM (height),
((INT_MAX - w->pixel_height)
/ FRAME_LINE_HEIGHT (f)));
pixel_height = line_height * FRAME_LINE_HEIGHT (f);
}
if (delta != 0)
{
Lisp_Object root = FRAME_ROOT_WINDOW (f);
struct window *r = XWINDOW (root);
Lisp_Object grow;
/* Grow the mini-window. */
w->pixel_top = r->pixel_top + r->pixel_height;
w->top_line = r->top_line + r->total_lines;
/* Make sure the mini-window has always at least one line. */
w->pixel_height = max (w->pixel_height + pixel_height,
FRAME_LINE_HEIGHT (f));
w->total_lines = max (w->total_lines + line_height, 1);
/* Enforce full redisplay of the frame. */
/* FIXME: Shouldn't window--resize-root-window-vertically do it? */
fset_redisplay (f);
adjust_frame_glyphs (f);
unblock_input ();
}
else
error ("Failed to grow minibuffer window");
FRAME_WINDOWS_FROZEN (f) = true;
grow = call3 (Qwindow__resize_root_window_vertically,
root, make_fixnum (- delta), Qt);
if (FIXNUMP (grow) && window_resize_check (r, false))
resize_mini_window_apply (w, -XFIXNUM (grow));
}
}
/* Shrink mini-window W to one line. */
/**
* shrink_mini_window:
*
* Shrink mini-window W to the minimum height needed to display one
* line of text.
*/
void
shrink_mini_window (struct window *w, bool pixelwise)
shrink_mini_window (struct window *w)
{
struct frame *f = XFRAME (w->frame);
struct window *r;
Lisp_Object root, delta;
EMACS_INT height, unit;
int delta = WINDOW_PIXEL_HEIGHT (w) - FRAME_LINE_HEIGHT (f);
eassert (MINI_WINDOW_P (w));
height = pixelwise ? w->pixel_height : w->total_lines;
unit = pixelwise ? FRAME_LINE_HEIGHT (f) : 1;
if (height > unit)
if (delta > 0)
{
root = FRAME_ROOT_WINDOW (f);
r = XWINDOW (root);
delta = call3 (Qwindow__resize_root_window_vertically,
root, make_fixnum (height - unit),
pixelwise ? Qt : Qnil);
if (FIXNUMP (delta) && window_resize_check (r, false))
{
block_input ();
window_resize_apply (r, false);
/* Shrink the mini-window. */
w->top_line = r->top_line + r->total_lines;
w->total_lines = 1;
w->pixel_top = r->pixel_top + r->pixel_height;
w->pixel_height = FRAME_LINE_HEIGHT (f);
/* Enforce full redisplay of the frame. */
/* FIXME: Shouldn't window--resize-root-window-vertically do it? */
fset_redisplay (f);
adjust_frame_glyphs (f);
unblock_input ();
}
/* If the above failed for whatever strange reason we must make a
one window frame here. The same routine will be needed when
shrinking the frame (and probably when making the initial
*scratch* window). For the moment leave things as they are. */
else
error ("Failed to shrink minibuffer window");
Lisp_Object root = FRAME_ROOT_WINDOW (f);
struct window *r = XWINDOW (root);
Lisp_Object grow;
FRAME_WINDOWS_FROZEN (f) = false;
grow = call3 (Qwindow__resize_root_window_vertically,
root, make_fixnum (delta), Qt);
if (FIXNUMP (grow) && window_resize_check (r, false))
resize_mini_window_apply (w, -XFIXNUM (grow));
}
}
DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini_window_internal, 1, 1, 0,
doc: /* Resize minibuffer window WINDOW. */)
DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal,
Sresize_mini_window_internal, 1, 1, 0,
doc: /* Resize mini window WINDOW. */)
(Lisp_Object window)
{
struct window *w = XWINDOW (window);
struct window *r;
struct frame *f;
int height;
int old_height, delta;
CHECK_WINDOW (window);
CHECK_LIVE_WINDOW (window);
f = XFRAME (w->frame);
if (!EQ (FRAME_MINIBUF_WINDOW (XFRAME (w->frame)), window))
......@@ -5288,26 +5281,18 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini
error ("Cannot resize a minibuffer-only frame");
r = XWINDOW (FRAME_ROOT_WINDOW (f));
height = r->pixel_height + w->pixel_height;
old_height = r->pixel_height + w->pixel_height;
delta = XFIXNUM (w->new_pixel) - w->pixel_height;
if (window_resize_check (r, false)
&& XFIXNUM (w->new_pixel) > 0
&& height == XFIXNUM (r->new_pixel) + XFIXNUM (w->new_pixel))
&& old_height == XFIXNUM (r->new_pixel) + XFIXNUM (w->new_pixel))
{
block_input ();
window_resize_apply (r, false);
w->pixel_height = XFIXNAT (w->new_pixel);
w->total_lines = w->pixel_height / FRAME_LINE_HEIGHT (f);
w->pixel_top = r->pixel_top + r->pixel_height;
w->top_line = r->top_line + r->total_lines;
resize_mini_window_apply (w, delta);
fset_redisplay (f);
adjust_frame_glyphs (f);
unblock_input ();
return Qt;
}
else
error ("Failed to resize minibuffer window");
error ("Cannot resize mini window");
}
/* Mark window cursors off for all windows in the window tree rooted
......@@ -8047,6 +8032,7 @@ syms_of_window (void)
DEFSYM (Qwindow__resize_root_window, "window--resize-root-window");
DEFSYM (Qwindow__resize_root_window_vertically,
"window--resize-root-window-vertically");
DEFSYM (Qwindow__resize_mini_frame, "window--resize-mini-frame");
DEFSYM (Qwindow__sanitize_window_sizes, "window--sanitize-window-sizes");
DEFSYM (Qwindow__pixel_to_total, "window--pixel-to-total");
DEFSYM (Qsafe, "safe");
......
......@@ -1063,8 +1063,8 @@ extern Lisp_Object window_from_coordinates (struct frame *, int, int,
extern void resize_frame_windows (struct frame *, int, bool, bool);
extern void restore_window_configuration (Lisp_Object);
extern void delete_all_child_windows (Lisp_Object);
extern void grow_mini_window (struct window *, int, bool);
extern void shrink_mini_window (struct window *, bool);
extern void grow_mini_window (struct window *, int);
extern void shrink_mini_window (struct window *);
extern int window_relative_x_coord (struct window *, enum window_part, int);
void run_window_change_functions (void);
......
......@@ -11259,15 +11259,10 @@ bool
resize_mini_window (struct window *w, bool exact_p)
{
struct frame *f = XFRAME (w->frame);
bool window_height_changed_p = false;
int old_height = WINDOW_PIXEL_HEIGHT (w);
eassert (MINI_WINDOW_P (w));
/* By default, start display at the beginning. */
set_marker_both (w->start, w->contents,
BUF_BEGV (XBUFFER (w->contents)),
BUF_BEGV_BYTE (XBUFFER (w->contents)));
/* Don't resize windows while redisplaying a window; it would
confuse redisplay functions when the size of the window they are
displaying changes from under them. Such a resizing can happen,
......@@ -11278,19 +11273,30 @@ resize_mini_window (struct window *w, bool exact_p)
return false;
/* Nil means don't try to resize. */
if (NILP (Vresize_mini_windows)
if ((NILP (Vresize_mini_windows)
&& (NILP (resize_mini_frames) || !FRAME_MINIBUF_ONLY_P (f)))
|| (FRAME_X_P (f) && FRAME_X_OUTPUT (f) == NULL))
return false;
if (!FRAME_MINIBUF_ONLY_P (f))
/* By default, start display at the beginning. */
set_marker_both (w->start, w->contents,
BUF_BEGV (XBUFFER (w->contents)),
BUF_BEGV_BYTE (XBUFFER (w->contents)));
if (FRAME_MINIBUF_ONLY_P (f))
{
if (!NILP (resize_mini_frames))
safe_call1 (Qwindow__resize_mini_frame, WINDOW_FRAME (w));
}
else
{
struct it it;
int total_height = (WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_ROOT_WINDOW (f)))
+ WINDOW_PIXEL_HEIGHT (w));
int old_height = WINDOW_PIXEL_HEIGHT (w);
int unit = FRAME_LINE_HEIGHT (f);
int height, max_height;
struct text_pos start;
struct buffer *old_current_buffer = NULL;
int windows_height = FRAME_WINDOWS_HEIGHT (f);
if (current_buffer != XBUFFER (w->contents))
{
......@@ -11302,14 +11308,14 @@ resize_mini_window (struct window *w, bool exact_p)
/* Compute the max. number of lines specified by the user. */
if (FLOATP (Vmax_mini_window_height))
max_height = XFLOAT_DATA (Vmax_mini_window_height) * total_height;
max_height = XFLOAT_DATA (Vmax_mini_window_height) * windows_height;
else if (FIXNUMP (Vmax_mini_window_height))
max_height = XFIXNUM (Vmax_mini_window_height) * unit;
else
max_height = total_height / 4;
max_height = windows_height / 4;
/* Correct that max. height if it's bogus. */
max_height = clip_to_bounds (unit, max_height, total_height);
max_height = clip_to_bounds (unit, max_height, windows_height);
/* Find out the height of the text in the window. */
if (it.line_wrap == TRUNCATE)
......@@ -11335,63 +11341,27 @@ resize_mini_window (struct window *w, bool exact_p)
}
else
SET_TEXT_POS (start, BEGV, BEGV_BYTE);
SET_MARKER_FROM_TEXT_POS (w->start, start);
if (EQ (Vresize_mini_windows, Qgrow_only))
{
/* Let it grow only, until we display an empty message, in which
case the window shrinks again. */
if (height > WINDOW_PIXEL_HEIGHT (w))
{
int old_height = WINDOW_PIXEL_HEIGHT (w);
FRAME_WINDOWS_FROZEN (f) = true;
grow_mini_window (w, height - WINDOW_PIXEL_HEIGHT (w), true);
window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
}
else if (height < WINDOW_PIXEL_HEIGHT (w)
&& (exact_p || BEGV == ZV))
{
int old_height = WINDOW_PIXEL_HEIGHT (w);
FRAME_WINDOWS_FROZEN (f) = false;
shrink_mini_window (w, true);
window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
}
}
else
{
/* Always resize to exact size needed. */
if (height > WINDOW_PIXEL_HEIGHT (w))
{
int old_height = WINDOW_PIXEL_HEIGHT (w);
FRAME_WINDOWS_FROZEN (f) = true;
grow_mini_window (w, height - WINDOW_PIXEL_HEIGHT (w), true);
window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
}
else if (height < WINDOW_PIXEL_HEIGHT (w))
{
int old_height = WINDOW_PIXEL_HEIGHT (w);
FRAME_WINDOWS_FROZEN (f) = false;
shrink_mini_window (w, true);
if (height)
{
FRAME_WINDOWS_FROZEN (f) = true;
grow_mini_window (w, height - WINDOW_PIXEL_HEIGHT (w), true);
}
window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
}
if (height > old_height)
grow_mini_window (w, height - old_height);
else if (height < old_height && (exact_p || BEGV == ZV))
shrink_mini_window (w);
}
else if (height != old_height)
/* Always resize to exact size needed. */
grow_mini_window (w, height - old_height);
if (old_current_buffer)
set_buffer_internal (old_current_buffer);
}
return window_height_changed_p;
return WINDOW_PIXEL_HEIGHT (w) != old_height;
}
......@@ -33091,7 +33061,11 @@ A value of nil means don't automatically resize mini-windows.
A value of t means resize them to fit the text displayed in them.
A value of `grow-only', the default, means let mini-windows grow only;
they return to their normal size when the minibuffer is closed, or the
echo area becomes empty. */);
echo area becomes empty.
This variable does not affect resizing of the minibuffer window of
minibuffer-only frames. These are handled by 'resize-mini-frames'
only. */);
/* Contrary to the doc string, we initialize this to nil, so that
loading loadup.el won't try to resize windows before loading
window.el, where some functions we need to call for this live.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment