Subject: Re: 31.0.50; Change in fit-frame-to-buffer doesn't work with transient-posframe

From: Gerd Möllmann <[email-masked]>
Date: Wed, 14 May 2025 18:20:14 +0200

martin rudalics <[email-masked]> writes:

>>>> 1: height 199
>>>> 2: height 199
>>>> height 199 text-minus-body-height 0
>>>> 1: height 199
>>>> 2: height 216
>>>> remainder 0 text-minus-body-height 0 char-height 18
>>>> height 216 text-minus-body-height 0
> [...]
>> First call. At this point, the transient is not yet visible on the
>> display.
>>
>>    fit-frame-to-buffer-1(#<frame window.el 0x10b830000> 55 1 120 83 nil nil nil)
>>    posframe--fit-frame-to-buffer(#<frame window.el 0x10b830000> 55 1 120 83 nil)
>>    posframe--set-frame-size((:posframe #<frame window.el 0x10b830000> :width nil :height nil :max-width 120 :max-height 55 :min-width 83 :min-height 1))
>>    posframe-show(#<buffer *transient*> :font nil :position 432383
>> :poshandler posframe-poshandler-frame-center :background-color
>> "gray15" :foreground-color "white" :min-width 83
>> :internal-border-width 1 :internal-border-color "gray50"
>> :override-parameters nil)
>>    transient-posframe--show-buffer(#<buffer  *transient*> nil)
>>    display-buffer(#<buffer  *transient*> (transient-posframe--show-buffer))
>>    transient--show()
>>    transient--redisplay()
>>    #f(compiled-function () #<bytecode -0x1b4f9e178d9e629f>)()
>>    transient--env-apply(#f(compiled-function () #<bytecode -0x1b4f9e178d9e629f>) #<transient-prefix 2b8339>)
>>    transient-setup(my-grab-bag)
>>    my-grab-bag()
>
> The mysterious thing is that in the first call 'fit-frame-to-buffer-1'
> did _not_ round from 199 to 216.
>
>> Second call. The child frame is visible already.
>>
>>    fit-frame-to-buffer-1(#<frame  0x10b830000> nil nil nil 83 nil t t)
>>    fit-frame-to-buffer(#<frame  0x10b830000> nil nil nil 83)
>>    transient--fit-window-to-buffer(#<window 14 on  *transient*>)
>>    transient--show()
>>    transient--redisplay()
>>    #f(compiled-function () #<bytecode -0x1b4f9e178d9e629f>)()
>>    transient--env-apply(#f(compiled-function () #<bytecode -0x1b4f9e178d9e629f>) #<transient-prefix 2b8339>)
>>    transient-setup(my-grab-bag)
>>    my-grab-bag()
>>
>> Naively, I would assume that that all happens in the same
>> transient--redisplay -> transient--show, but I'm not sure of course.
>
> And in the second call it did round.  But note that this call has many
> arguments that differ from the first.
>
>> The fit-frame-to-buffer in the second case is from here:
>
> And that from the first case?

That's

posframe.el:
  840 (defun posframe--fit-frame-to-buffer (posframe max-height min-height max-width min-width only)
  841   "POSFRAME version of function `fit-frame-to-buffer'.
  842 Arguments HEIGHT, MAX-HEIGHT, MIN-HEIGHT, WIDTH, MAX-WIDTH,
  843 MIN-WIDTH and ONLY are similar function `fit-frame-to-buffer''s."
  844   ;; This only has effect if the user set the latter var to `hide'.
  845   (let ((x-gtk-resize-child-frames posframe-gtk-resize-child-frames))
  846     ;; More info: Don't skip empty lines when fitting mini frame to buffer (Bug#44080)
  847     ;; http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=e0de9f3295b4c46cb7198ec0b9634809d7b7a36d
  848     (if (functionp 'fit-frame-to-buffer-1)
  849         (fit-frame-to-buffer-1
  850          posframe max-height min-height max-width min-width only nil nil)
  851       (fit-frame-to-buffer
  852        posframe max-height min-height max-width min-width only))))

And after some digging, I found several bindings for
frame-resize-pixel-wise, for example in posframe-show which is in the
backtrace.

posframe.el:
  419                               (window-tab-line-height)
  420                             0))
  421          (mouse-position (cdr (mouse-pixel-position)))
  422          (frame-resize-pixelwise t)
  423          posframe)

If I understand correctly what you write further down, this should not
be done, right? (Feng Shu <[email-masked]> added to CC, the posframe
author).

Si I guess that explains that difference.

>
>> (defun transient--fit-window-to-buffer (window)
>>    (set-window-parameter window 'window-preserved-size nil)
>>    (let ((fit-window-to-buffer-horizontally t)
>>          (window-resize-pixelwise t)
>>          (window-size-fixed nil))
>>      (cond ((not (window-parent window))
>>             (fit-frame-to-buffer (window-frame window) nil nil nil
>>                                  transient-minimal-frame-width))
>>            ((eq (car (window-parameter window 'quit-restore)) 'other)
>>             ;; Grow but never shrink window that previously displayed
>>             ;; another buffer and is going to display that again.
>>             (fit-window-to-buffer window nil (window-height window)))
>>            ((fit-window-to-buffer window nil 1))))
>>    (set-window-parameter window 'window-preserved-size
>>                          (list (window-buffer window)
>>                                (window-body-width window t)
>>                                (window-body-height window t))))
>>
>> Should that have bound frame-resize-pixelwise?
>
> It should _not_ since 'frame-resize-pixelwise' is a user variable.
>
>> I think I
>> understand more or less what the doc string of that variable says, but
>> the transient doesn't have anything I recognize that would make
>> pixel-wise resizing necessary. Or is some internal border or something?
>> Sorry, I'm in unknown territory here.
>
> If 'fit-frame-to-buffer' resizes pixelwise and 'frame-resize-pixelwise'
> is globally nil, the WM may round down to character sizes which usually
> means that text gets truncated.

If you express it that way, I almost understand what it does :-). So, if
my WM is not ever rounding down, I should set it to t? Might be a good
default for macOS...