emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 95373b6: Rewrite minibuffer window resizing code


From: Martin Rudalics
Subject: [Emacs-diffs] master 95373b6: Rewrite minibuffer window resizing code
Date: Mon, 11 Mar 2019 04:58:20 -0400 (EDT)

branch: master
commit 95373b69b34f9756d2f05b19798b763d22aa5f0a
Author: Martin Rudalics <address@hidden>
Commit: Martin Rudalics <address@hidden>

    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'.
---
 doc/lispref/minibuf.texi |  19 +++++
 etc/NEWS                 |   5 ++
 lisp/cus-start.el        |   8 ++-
 lisp/window.el           |   8 ++-
 src/frame.c              |  13 ++++
 src/window.c             | 180 ++++++++++++++++++++++-------------------------
 src/window.h             |   4 +-
 src/xdisp.c              |  92 +++++++++---------------
 8 files changed, 169 insertions(+), 160 deletions(-)

diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi
index a2b6e14..6c37fa9 100644
--- a/doc/lispref/minibuf.texi
+++ b/doc/lispref/minibuf.texi
@@ -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.
+
address@hidden 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 address@hidden value means to resize minibuffer-only frames
+by calling @code{fit-frame-to-buffer} (@pxref{Resizing Windows}).
address@hidden defopt
+
 
 @node Minibuffer Contents
 @section Minibuffer Contents
diff --git a/etc/NEWS b/etc/NEWS
index 3dc21df..410c182 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1469,6 +1469,11 @@ 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
 created by 'display-buffer'.
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 44ce292..baa05d0 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -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)
diff --git a/lisp/window.el b/lisp/window.el
index a8b6565..b769be0 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -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
diff --git a/src/frame.c b/src/frame.c
index c336369..46bdf22 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -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
diff --git a/src/window.c b/src/window.c
index c498ae8..ae039b7 100644
--- a/src/window.c
+++ b/src/window.c
@@ -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");
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 0af5e39..6d30afd 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]