]> git.eshelyaron.com Git - emacs.git/commitdiff
Rewrite minibuffer window resizing code
authorMartin Rudalics <rudalics@gmx.at>
Mon, 11 Mar 2019 08:57:23 +0000 (09:57 +0100)
committerMartin Rudalics <rudalics@gmx.at>
Mon, 11 Mar 2019 08:57:23 +0000 (09:57 +0100)
* 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'.

doc/lispref/minibuf.texi
etc/NEWS
lisp/cus-start.el
lisp/window.el
src/frame.c
src/window.c
src/window.h
src/xdisp.c

index a2b6e145502dab7934d8273ab3c2079cef7d58d8..6c37fa92d6cd1172d0e32ab00d542613a09de1db 100644 (file)
@@ -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
index 3dc21dfe89b51033d3026033e5ad5992c87b6876..410c1821ae9819c6e168fda5c018aedb6c197a75 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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
index 44ce2929d661616fbf7c320832848a5b00fc2345..baa05d0a89a665a7835fbe4e61d01a527d0f7070 100644 (file)
@@ -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)
index a8b65657a49e0a47fe11e13a5a72379436b668f1..b769be06337222f9825128faada5df262530561c 100644 (file)
@@ -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
index c336369dbb5d9b896e775ddd9f79f2998454595a..46bdf2223159137c4596d1df174955c14324ae76 100644 (file)
@@ -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
index c498ae81cdb4ce2aa87714ea87e456a2778902b3..ae039b76add6b44ef7b0a5f5a78feac52995fa87 100644 (file)
@@ -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");
 }
 \f
 /* 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");
index d816bb1683d199bbc072c88eeb0ea2ce5d197a45..b450173eb2f8f48eb543a1d18c766752e896666c 100644 (file)
@@ -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);
index 0af5e39dfb6de671148756c80e49ef1a34dcdf14..6d30afda6d886d88c33d2abbcc38b420ffe5602d 100644 (file)
@@ -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.