aboutsummaryrefslogtreecommitdiff
path: root/modules/cj-window-geometry-lib.el
diff options
context:
space:
mode:
Diffstat (limited to 'modules/cj-window-geometry-lib.el')
-rw-r--r--modules/cj-window-geometry-lib.el69
1 files changed, 58 insertions, 11 deletions
diff --git a/modules/cj-window-geometry-lib.el b/modules/cj-window-geometry-lib.el
index 047fe7c45..4484a1d15 100644
--- a/modules/cj-window-geometry-lib.el
+++ b/modules/cj-window-geometry-lib.el
@@ -42,21 +42,34 @@ fails to span the full height."
((not spans-full-height) (if (= top root-top) 'above 'below))
(t (or default 'right)))))
-(defun cj/window-body-size (window direction)
- "Return WINDOW's body size on the axis matching DIRECTION.
+(defun cj/window-replay-size (window direction)
+ "Return WINDOW's size to capture for geometry replay, on DIRECTION's axis.
Returns body-width (columns) when DIRECTION is right or left.
-Returns body-height (lines) when DIRECTION is below or above.
-
-Body size, not total size, is the right thing to capture for
-geometry replay: total-width includes the right-side divider when
-the window has a right sibling but excludes it at the frame edge,
-so a captured rightmost window replayed into a middle position
-would leave the body 1 col short. Body size is divider-
-independent and matches what the user actually sees."
+Returns total-height (lines) when DIRECTION is below or above.
+
+The axis choice is deliberately asymmetric, for two different reasons:
+
+- Width: body-width, not total-width. Total-width includes the right-side
+ divider when the window has a right sibling but excludes it at the frame
+ edge, so a captured rightmost window replayed into a middle position would
+ leave the body 1 col short. Body-width is divider-independent and matches
+ what the user sees.
+
+- Height: total-height, not body-height. Every window carries exactly one
+ mode line regardless of position, so total-height has no analog of the
+ divider-position problem -- it is position-independent. Body-height does
+ NOT work here: it subtracts the mode line's *pixel* height, which differs
+ between an active (full-height) and an inactive (theme-shrunk) mode line.
+ Capturing body-height while the window is active and replaying it while the
+ window is displayed inactive then re-measuring active drifts the value down
+ by ~1 line per toggle whenever the inactive mode line is shorter than a text
+ line (e.g. a theme that sets `mode-line-inactive' to a sub-line height).
+ Total-height is identical active or inactive, so the capture/replay
+ round-trip is a fixed point."
(if (memq direction '(right left))
(window-body-width window)
- (window-body-height window)))
+ (window-total-height window)))
(defun cj/cardinal-to-edge-direction (direction)
"Map cardinal DIRECTION to its `display-buffer-in-direction' edge variant.
@@ -129,5 +142,39 @@ the fraction at toggle-off, replay it on the next toggle-on."
(hi (or max-frac 0.95)))
(max lo (min hi (/ (float window-size) frame-size))))))
+(defcustom cj/window-dock-min-columns 80
+ "Minimum body columns each pane must keep for a side-by-side dock.
+
+`cj/preferred-dock-direction' docks a companion panel as a side-by-side
+column only when both the panel and the main window would stay at least
+this wide; otherwise it stacks the panel below. 80 is the classic
+terminal/code width."
+ :type 'integer
+ :group 'windows)
+
+(defun cj/preferred-dock-direction (frame-cols fraction &optional min-cols)
+ "Return the dock direction for a companion panel beside the main window.
+
+Returns `right' (a side-by-side column) when a split that gives the panel
+FRACTION of FRAME-COLS would leave both panes at least MIN-COLS columns
+wide; otherwise `below' (a stacked panel). FRAME-COLS is the frame's
+total column count; FRACTION is the panel's share of the width, in the
+open interval (0, 1). MIN-COLS defaults to `cj/window-dock-min-columns'.
+
+The narrower of the two resulting panes governs: the panel takes
+round(FRACTION * FRAME-COLS) columns, the main window takes the rest less
+one divider column, and `right' is returned only when the smaller of the
+two clears MIN-COLS. Returns `below' for degenerate input (non-positive
+FRAME-COLS, or FRACTION outside (0, 1)) so a caller always gets a usable
+stacked fallback."
+ (let ((min-cols (or min-cols cj/window-dock-min-columns)))
+ (if (and (numberp frame-cols) (> frame-cols 0)
+ (numberp fraction) (< 0 fraction 1))
+ (let* ((panel (round (* fraction frame-cols)))
+ (main (- frame-cols panel 1))
+ (narrower (min panel main)))
+ (if (>= narrower min-cols) 'right 'below))
+ 'below)))
+
(provide 'cj-window-geometry-lib)
;;; cj-window-geometry-lib.el ends here