diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 44ce292..9b9a46b 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -314,7 +314,13 @@ minibuffer-prompt-properties--setter (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 "Use '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) diff --git a/lisp/window.el b/lisp/window.el index 39f4fa1..90a2d0f 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -2753,7 +2753,7 @@ window--resize-mini-window ;; 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 @@ window--resize-root-window-vertically 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 nil nil nil nil 'vertically))) + (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 diff --git a/src/frame.c b/src/frame.c index 1219569..a194c48 100644 --- a/src/frame.c +++ b/src/frame.c @@ -6045,6 +6045,19 @@ either customize it (see the info node `Easy Customization') 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' with the ONLY argument 'vertically'. */); + 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 diff --git a/src/window.c b/src/window.c index 8543cbf..3754220 100644 --- a/src/window.c +++ b/src/window.c @@ -5134,118 +5134,111 @@ SIDE t (or `right') specifies that the new window shall be located on 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)) @@ -5254,26 +5247,18 @@ SIDE t (or `right') specifies that the new window shall be located on 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 @@ -8012,6 +7997,7 @@ static void init_window_once_for_pdumper (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"); diff --git a/src/window.h b/src/window.h index d816bb1..b450173 100644 --- a/src/window.h +++ b/src/window.h @@ -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); diff --git a/src/xdisp.c b/src/xdisp.c index 6ceb5c9..953cf7f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -11259,15 +11259,10 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) 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 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) 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 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) /* 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 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) } 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; }