Subject: Re: bug#65183: 29.1; Child frame moving and resizing problems

From: Eli Zaretskii <[email-masked]>
Date: Thu, 10 Aug 2023 11:55:31 +0300

> From: 陈宇迪 <[email-masked]>
> Date: Wed, 9 Aug 2023 15:28:16 +0100
> 
> Start Emacs with `emacs -Q' and evaluate the following code:
> 
> ;;;;; CODE BEGIN ;;;;;
> 
> (defun test-child-frame ()
>   (interactive)
>   (let ((f (make-frame `((parent-frame . ,(selected-frame))
>                          (internal-border-width . 3)
>                          (vertical-scroll-bars . nil)
>                          (menu-bar-lines . 0)
>                          (tool-bar-lines . t)
>                          (left . 20)
>                          (top . 20)
>                          (width . 50)
>                          (height . 20))))
>         (b (generate-new-buffer "*child-frame-test*")))
>     ;; Setup the frame and the buffer.
>     (with-selected-frame f
>       (switch-to-buffer b)
>       (with-current-buffer b
>         (set-background-color "black")
>         (setq mode-line-format nil)))
>     (sit-for 0.3)
>     ;; inhibit redisplay
>     (let ((inhibit-redisplay t))
>       ;; resize
>       (set-frame-size f 50 10)
>       ;; move
>       (set-frame-position f 20 60))
>     (sit-for 0.3)
>     ;; clean up
>     (delete-frame f)
>     (kill-buffer b)))
> 
> (test-child-frame) ;; Call the function defined above.
> 
> ;;;;; CODE END ;;;;;
> 
> I recorded what I saw and sent it as the attachment "bug_slow_motion.mp4".
> Briefly, the child frame appeared, then moved downwards, and then resized.
> The moving and resizing are very quick so I slowed down the video (about 10x slower).
> 
> There are two problems:
> 
> 1. I wrap the set size and set position code in a `(let ((inhibit-redisplay t)) ...)'. 
> The docstring of `inhibit-redisplay' says "Non-nil means don’t actually do any redisplay.",
> but the process of setting size and setting position is displayed.

Your interpretation of that variable is incomplete and inaccurate.
Binding it to non-nil inhibits redisplay during the time the binding
is active, but in your case redisplay happens after the function
exits, when the binding is no longer in effect.  The function
set-frame-size doesn't call redisplay, it just modifies the frame
dimension, and the next redisplay cycle then adjusts the frame
accordingly, but that redisplay cycle happens after your function
returns.

> 2. In the code I gave, `set-frame-size' should be executed before `set-frame-position'.
> But in fact, the child frame was first moved, and then resized. It is in the wrong order.

I don't think you can trust the order in this case, as at least some
of the actual move/resize is performed by the window-manager.

Adding Po Lu and Martin, who know this stuff better than I do.